How can I optimize this mesh?

I didn’t know before today how slow using globals can be compared to locals. So I wrote a function that used local variables to make my mesh vertices. This is a practice run for my tiled map in Scratchpad. One benefit of these practice runs, the code is a lot shorter and I can happily throw out my early bad code

-- Gr2test02

function verts(n)
    local m = mesh()
    local ind = 0
    local u,v
    for i = 1,n do
        for ii = 1,n do
            ind = ind + 1
            u,v = i%4*.25, ii%4*.25
            m:addRect(i*64,ii*64,64,64)
            m:setRectTex(ind,u,v, .25, .25)
        end
    end
    return m
end

function setup()
    local mapsize = 480
    local gr2 = verts(mapsize)
    gr2.texture = readImage("Documents:Grass 02") --256x256 image
    Grass02 = gr2
end

function draw()
    pushMatrix()
    rotate(45)
    Grass02:draw()
    popMatrix()
end
    

I’ve set map size to 480 - it shows a noticable pause at the start compared to 240. Running on an iPad Air 2. Is there anything easy I can do to make it faster? Something simple I’m missing? How about complex?

@xThomas The size of the mesh and the number of vertices can alter the FPS, it might be that the mesh is too big. I found a discussion that can tile images seamlessly.
https://codea.io/talk/discussion/5780/image-tiling-for-background
In the discussion, there is a link to Ignatz’s website where he describes it and provides code. Hope you find what your looking for!

@xThomas you could try using coroutines to stagger your mesh computation over multiple frames. It may be a more complex solution than you need.

But in this case, each frame the mesh will get another rect added, until the loop in your verts function is complete. You can move the yield call to after the inner loop, this will make the mesh update after each row instead of at each rect.

function verts(n)
    local m = mesh()
    local ind = 0
    local u,v
    for i = 1,n do
        for ii = 1,n do
            ind = ind + 1
            u,v = i%4*.25, ii%4*.25
            m:addRect(i*64,ii*64,64,64)
            m:setRectTex(ind,u,v, .25, .25)
            coroutine.yield(m)
        end
        --coroutine.yield(m)
    end
    return m
end

function setup()
    local mapsize = 480
    
    thread = coroutine.create(verts)

    _, Grass02 = coroutine.resume(thread, mapsize)

    Grass02.texture = readImage("Documents:Grass 02") --256x256 image
end

function draw()
    if coroutine.status(thread) ~= 'dead' then
        _, Grass02 = coroutine.resume(thread)
    end
    
    pushMatrix()
    rotate(45)
    Grass02:draw()
    popMatrix()
end

480 * 480 is 230,400. That’s a lot of rects, I would expect it to take a long time. Each rect is 64 x 64 points, so you should only need 16 x 16 or so to cover the screen. If you’re implementing a map of that size, I wouldn’t attempt to have all of it on the GPU at once. As you scroll, you should add and remove chunks/ strips of the map just before they come into view and just after they go out of view.

@xThomas I’m not quite sure what your doing, but as @yojimbo2000 pointed out you’re creating 230,400 rects. In the comments for your texture, you have an image of 256x256, yet you’re adding rects with a size of 64x64. You’re then altering the image by .25 and then covering 4x4 rects with the texture to show the full image. I modified your code to add rects with a size of 256x256 and not altering the texture size. This allowed me to reduce the 480x480 size to 120x120. Your original code runs at 25 FPS on my iPad Air, but the modified code runs at 60 FPS. I don’t have access to your Documents:Grass 02 image so I substituted a Codea image that’s close to the 256x256 size.

EDIT: Added code to scroll the mesh around the screen.

displayMode(FULLSCREEN)

function verts(n)
    local m = mesh()
    for i = 1,n do
        for ii = 1,n do
            m:addRect(i*256,ii*256,256,256)
        end
    end
    return m
end

function setup()
    dx,dy=0,0
    mapsize = 120
    gr2 = verts(mapsize)
    gr2.texture = readImage("Cargo Bot:Pack Crazy") --256x251 image
    Grass02 = gr2
end

function draw()
    background(0)
    pushMatrix()
    translate(dx,dy)
    --rotate(45)
    Grass02:draw()
    popMatrix()
end

function touched(t)
    dx=dx+t.deltaX
    dy=dy+t.deltaY
end

A small point, you don’t need to increment your own counter for the rects, addRect will return the rect number. Get rid of ind = ind + 1 and instead put local ind = m:addRect(i*64,ii*64,64,64). Not that this will effect performance.

@xThomas I changed my code above to allow the mesh to be scrolled right/left/up/down.

Oh wow, lots of helpful replies. Thanks guys, give me a bit of time to go through this, ok :slight_smile: