Mesh Tutorial

@mpilgrem: that’s what I figured, and it makes sense. table.insert() won’t work because under the hood I’m sure that mesh just uses a straightforward memory buffer (don’t have the code in front of me at the moment, but I’ll bet it’s a std::vector). It might be cool to have an addVertex() method to tack on a vertex to the end of the existing buffer, and/or an insertVertex() method that would shift higher indexed vertices up (though that would be a bit expensive). Dunno, I’ll have to think about it some more. Not sure that there are enough common use cases to warrant the API additions.

Continuing my experiments in how Lua can be used to rewire built-in functionality, the following code rewires rawset, table.insert and the mesh userdata to make m.vertices = vertexTable behave like its syntax implies - linking the table with the mesh userdata.


-- Rewire rawset()
local oldrawset = rawset
rawset = function (t, k, v)
    local r = oldrawset(t, k, v)
    local mt = getmetatable(t) or {}
    local mm = mt["__linkedToMesh"]
    -- Is the table linked to meshes?
    if mm then
        -- Update each mesh
        for _, m in pairs(mm) do 
            m.clear()
            m.vertices = t
        end
    end
    return r
end

-- Rewire table.insert()
local oldtableinsert = table.insert
table["insert"] = function (t, a1, a2)
    if a2 then 
        oldtableinsert(t, a1, a2)
    else
        oldtableinsert(t, a1)
    end
    local mt = getmetatable(t) or {}
    local mm = mt["__linkedToMesh"]
    -- Is the table linked to meshes?
    if mm then
        -- Update each mesh
        for _, m in pairs(mm) do
            m.clear()
            m.vertices = t
        end
    end
end

-- Rewire __newindex of mesh userdata         
local mmt = getmetatable(mesh())
local oldmeshnewindex = mmt["__newindex"]
local linkedVT = {}
mmt["__newindex"] = function(m1, k1, v1)
    if k1=="vertices" then
        local VT = linkedVT[m1]
        -- Is a vertex table linked to mesh?
        if VT then
            -- Clear the table's link to the mesh
            local VTmt = getmetatable(VT)
            VTmt["__linkedToMesh"][m1] = nil
        end
        -- Link the vertex table to the mesh
        linkedVT[m1] = v1
        local vmt1 = getmetatable(v1) or {}
        vmt1["__newindex"] = vmt1["__newindex"] or rawset
        -- Add a link the mesh to the table
        vmt1["__linkedToMesh"] = vmt1["__linkedToMesh"] or {}
        vmt1["__linkedToMesh"][m1] = m1
        setmetatable(v1, vmt1)
    end
    oldmeshnewindex(m1, k1, v1)
    return
end

-- Example of use
function setup()
    m1 = mesh()
    m2 = mesh()
    vertexTable1 = {vec2(0,0), vec2(100,0), vec2(0, 100)}
    -- Link one vertex table to two meshes
    m1.vertices = vertexTable1
    m2.vertices = vertexTable1
    print("Size of mesh 1:", m1.size) -- Outputs 3
    print("Size of mesh 2:", m2.size) -- Outputs 3
    
    vertexTable1[#vertexTable1 + 1] = vec2(0, 100)
    vertexTable1[#vertexTable1 + 1] = vec2(100, 100)
    vertexTable1[#vertexTable1 + 1] = vec2(100, 0)        
    print("New size of mesh 1:", m1.size) -- Outputs 6
    print("New size of mesh 2:", m2.size) -- Outputs 6
    
    vertexTable2 = {}
    -- Link a new vertex table to one of the meshes
    m1.vertices = vertexTable2
    table.insert(vertexTable2, vec2(100, 0))
    table.insert(vertexTable2, vec2(200, 0))
    table.insert(vertexTable2, vec2(100, 100))
    print("Final size of mesh 1:", m1.size) -- Outputs 3
    print("Final size of mesh 2:", m2.size) -- Outputs 6 
end

function draw()
    background(40, 40, 50)
end

@mpilgrem from a glance at the code, that will clear the mesh every time the vertex table is modified? I think it’s a great piece of code — especially if you use it to set up a fairly static mesh. But for dynamic meshes you might not want to do that (if they get large).

@Simeon, you’re absolutely right, of course. I should have made clear that - currently - extending a general mesh userdata’s vertices, once they have been set initially, will involve an inefficient ‘reset’, no matter what syntactic approach is adopted. I was experimenting with syntax, really - rather than proposing something useful for dynamic situations.

Looks interesting. What you could do is have a flag that is set when you modify the table, and alter mesh’s draw function to copy the vertices over and reset the flag before drawing.

I have added this page to the wiki. My aim was to provide reference-type material to complement @Vega’s tutorial, and add to what is set out in the in-app reference.

Good info there, @mpilgrem. I wish I had that when I was learning about Meshes.

Nice work @Vega and @mpilgrem.

Learning is getting easier with everyone’s help.

Thanks a lot.

Update - the Wiki mesh page by mpilgrem moved to https://bitbucket.org/TwoLivesLeft/core/wiki/mesh

(added this update in case anyone thought the page had been deleted as the link above doesn’t work).

Vega’s tutorial is at https://bitbucket.org/TwoLivesLeft/core/wiki/mesha

thanks for the tips, folks!