Question How to Shift UV Coordinates of a Mesh Group Texture in Lua?

Thunder Chicken

Fine Threads since 2008
Donator
Joined
Mar 22, 2008
Messages
4,565
Reaction score
3,479
Points
138
Location
Massachusetts
I am flailing away at a J-3 add-on, and one of the things I want to do is shift the UV coordinates of a texture to animate a switch toggle on the panel.

Here is where I started: https://www.orbiter-forum.com/threa...ntures-and-questions.41799/page-3#post-619969.

This image shows the 1024 x 512 pixel texture associated with the instrument panel. The panel showing the OFF position is the upper half with UV coordinates from (0,0) to (1,0.5). To show the switch in the ON position, I need to change the UV coordinates to the lower half of the texture, coordinates (0,0.5) to (1,1). Only the V coordinate needs to be modified.

j-3_panel_switches.png
This texture is associated with the following meshgroup (23) in my mesh:

Code:
LABEL Instrument_Panel
MATERIAL 7
TEXTURE 1
GEOM 4 2
-0.358 0.102 0.895 0 0 -1 0 0.5
0.358 0.102 0.895 0 0 -1 1 0.5
0.102 0.256 0.895 0 0 -1 0.6425 0
-0.102 0.256 0.895 0 0 -1 0.3575 0
0 3 1
3 2 1

The UV coordinates (last two digits on each vertex entry) are set to show the upper portion of the texture on the panel.

The question is how to get and edit the meshgroup to change the V coordinates so the bottom half of the texture is shown.

I am trying to figure out how to implement oapi.get_meshgroup and oapi.set_meshgroup to do this. I am rummaging around the Orbiter code and have some snippets, but certain things are not working and I am not seeing why.

First thing I am trying to do is access the current vertex information in the mesh. From what I gathered looking through the code, I need to specify the number of vertices (4), and allocate vertex and index arrays. From there, I need to create a group mesh spec structure (grs), and I thought that running get_meshgroup would populate that structure with the data. This is the code I have for that so far.

Code:
    --Load mesh and set visibility

    hmesh = oapi.load_mesh_global('J-3/J-3')
    vi:add_mesh(hmesh)
    vi:set_mesh_visibility_mode(0, MESHVIS.ALWAYS)

    --Get mesh group spec for instrument panel group 23

    nvtx = 4
    vtx = oapi.create_ntvertexarray(nvtx)
    vperm = oapi.create_indexarray(nvtx)

    grs = {}
    grs.Vtx = vtx
    grs.VtxPerm = vperm
    oapi.get_meshgroup(hmesh, 23, grs) --get mesh group spec for instrument panel with switch OFF

This gives me the following error for the last line: bad argument #1 to 'get_meshgroup' (DEVMESHHANDLE expected, got userdata).

OK, some reading into the API_Reference.pdf, there is this to get the DEVMESHHANDLE mesh instance:

DEVMESHHANDLE VESSEL::GetDevMesh ( VISHANDLE vis, UINT idx ) const
Returns a handle for a device-specific mesh instance.
Parameters
vis identifies the visual for which the mesh was created.
idx mesh index (0 <= idx < GetMeshCount()

There does appear to be a Lua equivalent v:get_devmesh(vis, idx) to do this. idx is 0 as there is only one mesh file, but I can't make sense of how to reference the "visual" vis (or even know what it is), and there is no further description of what vis is in the API_Reference.pdf or that I can find rummaging around in the code.

I'm sure I'll have more questions on how to edit the group spec to have the two specs needed to toggle the UV coordinates, but let's start with what I have above. Has anyone done this in Lua and does anyone see where I am going amiss?

Thanks again for your help.
 
Last edited:

Thunder Chicken

Fine Threads since 2008
Donator
Joined
Mar 22, 2008
Messages
4,565
Reaction score
3,479
Points
138
Location
Massachusetts
Another deep foray into the OpenOrbiter code suggests I get the VISHANDLE vis from clbk_visualcreated:

Code:
function clbk_visualcreated(vis, refcount)
    hdevmesh = vi:get_devmesh(vis,0)
    nvtx = 4
    vtx = oapi.create_ntvertexarray(nvtx)
    vperm = oapi.create_indexarray(nvtx)
    grs = {}
    grs.Vtx = vtx
    grs.VtxPerm = vperm
    oapi.get_meshgroup(hdevmesh, 23, grs) --get mesh group spec for instrument panel with switch OFF
    --create new mesh group spec for instrument panel based on original, but edit V coordinates to set switch ON
    ges = grs
    for i = 1, nvtx do
        ges.Vtx[i].tv = grs.Vtx[i].tv + 0.5
    end
end

I am trying to toggle the mesh group spec like this:

Code:
function set_feature.Toggle_Autocoordinate()
    
    if coordinate_hold == false then
    
        oapi.edit_meshgroup(hmesh, 23, grs)

    elseif coordinate_hold == true then

        oapi.edit_meshgroup(hmesh, 23, ges)

    end

end

I think this is populating the mesh group specs. But when I attempt to set the mesh group spec with edit_meshgroup I get this:

Config/Vessels/J3Script/set_feature.lua:197: Missing flags member in GROUPEDITSPEC

I tried adding this right after getting the grs spec:

Code:
grs.flags = GRPEDIT_VTXTEXV

But that didn't seem to do anything.
 
Last edited:

Gondos

Well-known member
Joined
Apr 18, 2022
Messages
256
Reaction score
307
Points
78
Location
On my chair
oapi.get_meshgroup will fill the vertexarray with the requested indices provided in vperm through the equivalent of GROUPREQUESTSPEC in Lua (grs in the samples).
You're missing the initialisation of vperm in your code example.
oapi.edit_meshgroup will update the mesh according to the GROUPEDITSPEC (ges in the samples) provided. Initialising ges with grs may work in Lua because of duck typing but it can be confusing. Doing so will just make a shallow copy of the vertex/index arrays so that ges.Vtx and grs.Vtx are basically the same array with a different name.
One way of doing it would be with 2 ntvertexarray and 2 groupeditspec (you can share the indexarray between them).
You can fill the arrays with 2 calls to get_meshgroup, or using the copy method of the vertexarray.
Then on toogle you call oapi.edit_meshgroup with the correct ges.
Seems like the Lua doc is not generated in the mainline, there is an extract in the original PR, you may find something useful.
Finally, it should be GRPEDIT.VTXTEXV, not GRPEDIT_VTXTEXV.
Good luck
 

Thunder Chicken

Fine Threads since 2008
Donator
Joined
Mar 22, 2008
Messages
4,565
Reaction score
3,479
Points
138
Location
Massachusetts
oapi.get_meshgroup will fill the vertexarray with the requested indices provided in vperm through the equivalent of GROUPREQUESTSPEC in Lua (grs in the samples).

You're missing the initialisation of vperm in your code example.
I thought that was this: vperm = oapi.create_indexarray(nvtx)?
oapi.edit_meshgroup will update the mesh according to the GROUPEDITSPEC (ges in the samples) provided. Initialising ges with grs may work in Lua because of duck typing but it can be confusing. Doing so will just make a shallow copy of the vertex/index arrays so that ges.Vtx and grs.Vtx are basically the same array with a different name.
grs and ges should be identical except for the (eventually) edited V coordinates.
One way of doing it would be with 2 ntvertexarray and 2 groupeditspec (you can share the indexarray between them).
This was what I was attempting to do. So it is not sufficient to just create ges by ges = grs, I need to create a second vertexarray and fill it somehow?
You can fill the arrays with 2 calls to get_meshgroup, or using the copy method of the vertexarray.
I think this answers my previous question with regard to vertexarray. I am looking for the copy method.
Then on toogle you call oapi.edit_meshgroup with the correct ges.
That's the hope.
Seems like the Lua doc is not generated in the mainline, there is an extract in the original PR, you may find something useful.
Thanks for this. Eager for any documentation.
Finally, it should be GRPEDIT.VTXTEXV, not GRPEDIT_VTXTEXV.
Of course.
Good luck
:hailprobe:
 

Gondos

Well-known member
Joined
Apr 18, 2022
Messages
256
Reaction score
307
Points
78
Location
On my chair
Taking a look at the Lua DG, this function may be of use to you :
Code:
function DeltaGlider:UpdateStatusIndicators ()
    if not self.vcmesh then return end
    local x

    local vtx = oapi.create_ntvertexarray(16)
    local vidx = oapi.create_indexarray({0,1,4,5,20,21,8,9,24,25,16,17,12,13,28,29})
    local ges = {}
    ges.flags = GRPEDIT.VTXTEXU
    ges.vIdx = vidx
    ges.Vtx = vtx

    -- gear indicator
    x = BlinkStateCoord(self.ssys_gear:GearState())
    vtx[1].tu = x
    vtx[2].tu = x

    -- retro cover indicator
    x = BlinkStateCoord(self.ssys_mainretro:RetroCoverState())
    vtx[3].tu = x
    vtx[4].tu = x

    -- airbrake indicator
    x = BlinkStateCoord(self.ssys_aerodyn:AirbrakeState())
    vtx[5].tu = x
    vtx[6].tu = x

    -- nose cone indicator
    x = BlinkStateCoord(self.ssys_docking:NconeState())
    vtx[7].tu = x
    vtx[8].tu = x

    -- top hatch indicator
    x = BlinkStateCoord(self.ssys_pressurectrl:HatchState())
    vtx[9].tu = x
    vtx[10].tu = x

    -- radiator indicator
    x = BlinkStateCoord(self.ssys_thermal:RadiatorState())
    vtx[11].tu = x
    vtx[12].tu = x

    -- outer airlock indicator
    x = BlinkStateCoord(self.ssys_pressurectrl:OLockState())
    vtx[13].tu = x
    vtx[14].tu = x

    -- inner airlock indicator
    x = BlinkStateCoord(self.ssys_pressurectrl:ILockState())
    vtx[15].tu = x
    vtx[16].tu = x

    oapi.edit_meshgroup (self.vcmesh, GRP_VC.STATUS_INDICATOR, ges)
end
There is no need to request the old data if you overwrite it completely when needed.

With the vcmesh initialised in clbkCreateVisual :
Code:
function DeltaGlider:clbkVisualCreated (vis, refcount)
...
    self.vcmesh = self:get_devmesh (vis, 1)
...
end
function DeltaGlider:clbkVisualDestroyed (vis, refcount)
...
    self.vcmesh = nil
...
end

Since it's a straight C++ adaptation, it is grossly misoptimized, you may want to create the arrays once and for all.
 

Thunder Chicken

Fine Threads since 2008
Donator
Joined
Mar 22, 2008
Messages
4,565
Reaction score
3,479
Points
138
Location
Massachusetts
Taking a look at the Lua DG, this function may be of use to you :
Code:
function DeltaGlider:UpdateStatusIndicators ()
    if not self.vcmesh then return end
    local x

    local vtx = oapi.create_ntvertexarray(16)
    local vidx = oapi.create_indexarray({0,1,4,5,20,21,8,9,24,25,16,17,12,13,28,29})
    local ges = {}
    ges.flags = GRPEDIT.VTXTEXU
    ges.vIdx = vidx
    ges.Vtx = vtx

    -- gear indicator
    x = BlinkStateCoord(self.ssys_gear:GearState())
    vtx[1].tu = x
    vtx[2].tu = x

    -- retro cover indicator
    x = BlinkStateCoord(self.ssys_mainretro:RetroCoverState())
    vtx[3].tu = x
    vtx[4].tu = x

    -- airbrake indicator
    x = BlinkStateCoord(self.ssys_aerodyn:AirbrakeState())
    vtx[5].tu = x
    vtx[6].tu = x

    -- nose cone indicator
    x = BlinkStateCoord(self.ssys_docking:NconeState())
    vtx[7].tu = x
    vtx[8].tu = x

    -- top hatch indicator
    x = BlinkStateCoord(self.ssys_pressurectrl:HatchState())
    vtx[9].tu = x
    vtx[10].tu = x

    -- radiator indicator
    x = BlinkStateCoord(self.ssys_thermal:RadiatorState())
    vtx[11].tu = x
    vtx[12].tu = x

    -- outer airlock indicator
    x = BlinkStateCoord(self.ssys_pressurectrl:OLockState())
    vtx[13].tu = x
    vtx[14].tu = x

    -- inner airlock indicator
    x = BlinkStateCoord(self.ssys_pressurectrl:ILockState())
    vtx[15].tu = x
    vtx[16].tu = x

    oapi.edit_meshgroup (self.vcmesh, GRP_VC.STATUS_INDICATOR, ges)
end
There is no need to request the old data if you overwrite it completely when needed.
So it really is only writing the data specified by the flag. Since I know those numbers I can just assign them?

I am confused by the allocations, vtx, vtperm, vidx, and why they differ in different examples.
 

Thunder Chicken

Fine Threads since 2008
Donator
Joined
Mar 22, 2008
Messages
4,565
Reaction score
3,479
Points
138
Location
Massachusetts
Got it! This works:

Code:
function clbk_visualcreated(vis, refcount)

    hdevmesh = vi:get_devmesh(vis,0)

    nvtx = 4
    vtx = oapi.create_ntvertexarray(nvtx)
    vidx = oapi.create_indexarray({0,1,2,3})

    ges = {}
    ges.flags = GRPEDIT.VTXTEXV
    ges.Vtx = vtx
    ges.VIdx = vidx

end

Code:
if oapi.keydown(kstate, OAPI_KEY.A) then     -- toggle auto-coordinate rudder feature

        if coordinate_hold == false then

            ges.Vtx[1].tv = 1.0
            ges.Vtx[2].tv = 1.0
            ges.Vtx[3].tv = 0.5
            ges.Vtx[4].tv = 0.5

            oapi.edit_meshgroup(hdevmesh, 23, ges)

            coordinate_hold = true

        elseif coordinate_hold == true then

            vi:set_adclevel(AIRCTRL.RUDDER, 0)

            ges.Vtx[1].tv = 0.5
            ges.Vtx[2].tv = 0.5
            ges.Vtx[3].tv = 0.0
            ges.Vtx[4].tv = 0.0

            oapi.edit_meshgroup(hdevmesh, 23, ges)
            
            coordinate_hold = false

        end

Thanks again!
 
Top