Remove rect from mesh?

I have a mesh I’m using to draw a load of moving objects on the screen. The mesh has a texture, and I’m adding and updating objects using addRect and setRect. However, I also need to remove objects once they go offscreen or get destroyed. Is there any way that I’ve missed of removing rects from a mesh, or should I clear() the whole thing and re-add all the rects? That seems like it might be rather an expensive operation, and I’m going to need to remove rects very often!

Thanks

I’m sure I’ve asked the same question before but can’t find the thread. I think answer is there’s no way to remove, you just set the size to 0,0 to make it disappear. And if you want keep track of the index so you can reuse it later, but unclear if that actually provides a benefit (ie does a rect of size 0,0 have a cost? I don’t know)

Okay, thanks @ruilov. I guess I can code up some kind or rudimentary dequeueing system, like the way iOS handles tableview cells. Keep a list of unused rects, and use one of those any time I need a new rect. If there aren’t unused rects, create a new one.

ah here, and Simeon’s and John’s answers a few posts down

http://twolivesleft.com/Codea/Talk/discussion/comment/4361#Comment_4361

I’m having the same issue as frosty, and trying to access the link in ruilov’s post above. I can’t access, getting an error message “Permission Problems”. Does this link point to a restricted area?

@fglette same here, can’t seem to access the page.

@ruilov: afaict there is little or no cost to setting the rect’s size to 0.

@frosty If you don’t need z-ordering on your sprites based on draw order, then a simple free list (actually a stack) will suffice for removed rects. If you need z-ordering based on draw order, life gets a little more…complicated (I did this the other day, it was a bit of a pain, but if you need to do it lemme know and I’ll show you how I did it). Here’s some simple code for implementing meshes with a free list. It keeps a hash table where each mesh is a key, and the value is another table that is the stack of free indices. The hash table has weak keys, so if no other references exist to the mesh it will be collected and won’t hang around forever.

meshFreeListHash = setmetatable({}, {__mode = "k"})

function meshNewRect(m, x, y, w, h, r)
    local stack = meshFreeListHash[m]
    
    if stack and #stack > 0 then
        local index = table.remove(stack)
        m:setRect(index, x, y, w, h, r or 0)
        return index
    end

    return m:addRect(x, y, w, h, r or 0)
end

function meshFreeRect(m, index)
    local stack = meshFreeListHash[m]
    
    if not stack then
        stack = {}
        meshFreeListHash[m] = stack        
    end
    
    table.insert(stack, index)
    m:setRect(index, 0, 0, 0, 0, 0)
end

Just use meshNewRect(myMesh, x, y, w, h, [r]) instead of myMesh:addRect(x, y, w, h, [r]), and when you are done with a rect use meshFreeRect(myMesh, index), and everything should work as you’d expect.

please exuse me for bumping an old thread, but I didn’t want to duplicate an existing topic…

I needed the same functionality (removing a mesh rect). And it seems you can actually impliment it yourself. You can remove vertices and still retain correct vert-id’s … I think. Here’s what I got:

...
function Mesh:removeFace(id)
    local positionBuffer = self.mesh:buffer("position")
    local textureBuffer = self.mesh:buffer("texCoord")
    local colorBuffer = self.mesh:buffer("color")
    local normalBuffer = self.mesh:buffer("normal")
    
    local vertices = positionBuffer:get()
    local textures = textureBuffer:get()
    local colors = colorBuffer:get()
    local normals = normalBuffer:get()
    
    for i = id * 6, id * 6 - 5, -1 do
        table.remove(vertices, i)
        table.remove(textures, i)
        table.remove(colors, i)
        table.remove(normals, i)
    end
    
    if #vertices < 6 then self.mesh:clear()
    else
        positionBuffer:set(vertices)
        textureBuffer:set(textures)
        colorBuffer:set(colors)
        normalBuffer:set(normals)
    end
end

Easier just to setrect to 0,0,0,0. Then reuse the rect later

Oh, I forgot that I had a question too :slight_smile:

There is OpenGL culling/clipping in Codea. Mesh vertices going to be clipped outside the view depending on what? Do I have to use camera() and ortho() in order for GPU to know what’s outside the view, or are all matrix transformation valid too, like translate(), scale()

@yojimbo2000 true, but if you want to save memory this could help

The perspective command has optional parameters to set the furthest and closest thing that will be drawn, and these, along with the field of view parameter, define a 3D cone shaped space that will be visible

See here for my explanation

https://coolcodea.wordpress.com/2014/12/31/190-figuring-out-the-borders-of-a-3d-screen/

@se24vad Here’s something you might find interesting. I was curious about how much memory a single mesh takes up. I wrote some code to check the memory usage at different steps. Here’s the results I got.

My program took up 374,102 bytes before creating a mesh.

I executed the mesh command.
     m=mesh()
     The memory usage increased to 374,630 bytes.
     The mesh used 528 bytes.

I then did a for loop that added 1,000,000 rects and color.
     m:addRect(...)          1,000,000 times
     m:setRectColor(...)     1,000,000 times
     The memory usage stayed the same, 374,630 bytes.

I then cleared the mesh.
     m:clear()
     The memory usage stayed the same, 374,630 bytes.

I then cleared the mesh variable m.
     m=nil
     The memory usage dropped back to the original 374,102 bytes. 

So removing mesh entries doesn’t seem to have any effect on the memory used by the mesh. Once a mesh is created, m=mesh(), the memory doesn’t seem to change until you set the mesh variable to nil. If I created 2 meshes, the memory increased by 1056 bytes, a 2 times increase. It doesn’t make sense, but that’s what I got.

It doesn’t make sense that it costs no memory to store 1,000,000 rects, that can’t be right!

@dave1707 Interesting, but something must be wrong there. It’s weird thats the memory stays constant as you add 1M rects. If that was really the case I would not even bother deleting vertices… I could even draw infinite meshes in one go.

Could you post your test-code?

@Ignatz thank you for explanation, but what if I need orthographic projection?

Basically, I have an ‘infinite’ tile map. Each tile is 8x8px. I translate(cam.x, cam.y) and scale(8, 8) and then draw my tiles. But when I calculate which tiles are visible on screen(not applying the scale) then the current visible scene is basically smaller that WIDTHxHEIGHT.

So my question is: if I was to draw my scene like that (by directly modifying the matrix), wouldn’t it draw chunks that are actually outside the screen (based on my 8x scale factor), because it thinks that the real camera(eye) is sitting somewhere different?

I hope you understand what I mean or i can try to sketch it out :slight_smile:

Sorry, I don’t understand yet

If it’s 2D, can’t you just divide by the scale to work out whether it’s on screen? You’d need to subtract the centre point of the view, which would be translation + vec2(WIDTH, HEIGHT) * 0.5 / scale. I think?

This isn’t tested, and it can be quite tricky to get right. Depends on when you scale. You’re scaling after the translation, so you’ll probably have to play with the formula

centre = vec2(WIDTH * 0.5, HEIGHT * 0.5) -- maybe do / size here?
translate(cam.x, cam.y)
scale(size)

-- you'd have to play around with this. It depends on whether you scale before or after moving the cam
viewCenter = cam + centre / size  -- maybe (cam + centre)/ size ?

--whatever you do to iterate entities

for _, entity in entities do
  --pos of entity relative to centre of view
  pos = entity.pos - viewCenter
  if math.abs(pos.x) < centre.x and math.abs(pos.y) < centre.y then
    --onscreen

@yojimbo2000 @Ignatz I open up a separate thread for my question since its going to be a bigger problem that I try to solve and meshes are only a part of it, regarding the rendering performance…

\#edit: here is my question https://codea.io/talk/discussion/7613/rendering-huge-tilemaps

@se24vad @Ignatz I rewrote my test to make it easier to run and understand, but the results are about the same as my original test. Tap the screen to step thru each state. I show the command that was executed for each state and the current memory for that state and the difference from state 1 which is the program size without any meshes. Loop thru all the states a few time so the memory sizes settles down. The mesh size I get is 624 the first round and then 528 if I keep looping the tests. Not sure why it’s different. Let me know if you get similar results or what I’m doing wrong in this test. As I said above, it doesn’t make sense, but I don’t see what I’m doing wrong. Change the number (nbr) of the rects being created if you want.

displayMode(FULLSCREEN)

function setup()
    textMode(CORNER)
    fill(255)
    font("Courier")
    tab1={"state 1  'current'  ","state 2  'm=mesh'   ",
            "state 3  'addRect'  ","state 4  'm:clear'  ","state 5  'm=nil'    "}
    setup1()
end

function setup1()
    tab={0,0,0,0,0} -- hold memory size for executing state
    state=0         -- state number
    nbr=100        -- number of addRects and setRectColor to create
end

function draw()
    background(40, 40, 50)
    if m~=nil then
        m:draw()    -- draw mesh rects
    end
    collectgarbage()    -- remove unused memory
    text("Executed state  "..state.."\
\
Tap screen for next state.",100,HEIGHT-100)
    text("Will do  "..nbr.."  addRects and setRectColor this test.",100,HEIGHT-150)
    if state>0 then
        tab[state]=collectgarbage("count")*1024    -- get current state memory size       
    end
    for a,b in pairs(tab) do    -- show different state memory sizes
        text(tab1[a].."   "..b,50,HEIGHT-a*20-200)
        text("this state - state 1   "..tab[a]-tab[1],400,HEIGHT-a*20-200)
    end
end

function touched(t)
    if t.state==BEGAN then
        state=state+1
        if state==1 then        -- do nothing for current program size
        elseif state==2 then    -- create a mesh
            m=mesh()
        elseif state==3 then    -- addRect and addRectColor
            for z=1,nbr do
                m:addRect(math.random(WIDTH),math.random(HEIGHT),50,50)
                m:setRectColor(z,0,100,100,120)
            end
        elseif state==4 then    -- clear the mesh
            m:clear()
        elseif state==5 then    -- remove the mesh
            m=nil
        elseif state==6 then    -- reset everything for another round
            setup1()
        end
    end
end

@dave1707 I believe you now, because I tested it myself. The only thing I notices is that it took a bit more time at the of the app, and my fps dropped as I added more vertices … but other than that … lua memory stayed the same no matter how much verts I push into the buffer… It’s really weird!