Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Remove rect from mesh?

edited May 2012 in Questions Posts: 159

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

Tagged:

Comments

  • Posts: 447

    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)

  • Posts: 159

    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.

  • Posts: 447

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

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

  • Posts: 9

    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?

  • edited June 2012 Posts: 580

    @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.

  • Posts: 419

    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
    
  • Posts: 1,979
    Easier just to setrect to 0,0,0,0. Then reuse the rect later
  • Posts: 419

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

    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()

  • Posts: 419

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

  • IgnatzIgnatz Mod
    Posts: 5,396

    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/

  • dave1707dave1707 Mod
    edited July 2016 Posts: 5,806

    @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.

  • IgnatzIgnatz Mod
    Posts: 5,396

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

  • edited July 2016 Posts: 419

    @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?

  • Posts: 419

    @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 :)

  • IgnatzIgnatz Mod
    Posts: 5,396

    Sorry, I don't understand yet

  • Posts: 1,979

    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
    
  • edited July 2016 Posts: 419

    @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

  • dave1707dave1707 Mod
    Posts: 5,806

    @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.."\n\nTap 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
    
  • Posts: 419

    @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!

  • Posts: 1,979

    My guess is that collectgarbage is only telling us about the memory assignment of the lua part of Codea, and that rects are stored elsewhere. I imagine that they're fairly light thought. Just 4 or 6 points with position and texCoords.

  • dave1707dave1707 Mod
    Posts: 5,806

    See this link for mesh memory. I'm not sure if this applies or not.

    https://codea.io/talk/discussion/2028/adding-texture-to-a-single-rectangle-mesh
    
Sign In or Register to comment.