Howdy, Stranger!

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

mesh atlas

edited January 2012 in Beta Posts: 447

(putting in beta for now, but will open when 1.3 is out)

So I'm planning to implement the atlas trick and wanted to bounce ideas/questions.

I'm thinking the atlas has a single mesh whose texture is an image with all the drawings that this atlas knows how to render. Then addRect/setRect creates the mesh rect. So something like:

  • Atlas:map( name, drawingFunc, width, height) adds a new drawing to the texture. drawingFunc draws a single image which will be rendered to the texture with dimensions (width,height)

  • Atlas:addRect(name, x, y, width, height) adds a new rect to the mesh. Return the index of the rect. width, height are optional

  • Atlas:setRect( index, x, w, width, height) moves an existing rect around

  • Atlas:draw() renders the mesh onto the screen

Does this make sense?

A couple of questions

  • @Simon said there's a limit on the size of mesh textures. Does this mean that my atlas should have multiple meshes to get around that? If so, then Atlas:draw() will need to draw multiple meshes. And addRect will need to do some house keeping to map from each mesh index to the atlas index.

  • If so, is it worth adding my background image (768x1024) to the atlas? In which case it will take a whole mesh - I might as well just draw the background image outside the atlas no?

  • Edit: the way I'm planning to construct the texture is with setContext. Is that the best way? One problems seems to be that setContext actually limits drawing to the dimensions of the screen (which surprised me). That is I can't draw onto an image at position say 769x1025 with setContext

Comments

  • BortelsBortels Mod
    Posts: 1,557

    Interesting project!

    I've been operating under the assumption that a single mesh:draw() call and a single sprite() call are about the same speed, or will be. I have not actually checked out that supposition.

    Suggest adding rotation to the addRect/setRect calls, simply because it's supported.

    Also suggest a function to replace the texture in a given rect with another named region of the atlas.

    Extra points for automatically per-draw handling a series of atlas textures for animation. You could either add them as a set, or add them and then take a table of the names to iterate thru.

    TLL: Be on the lookout for free graphics data that could be for a sprite pack for mesh stuff - I'd like to see something with some animation cells for a platformer. I know it's going to be too late for this beta, but that will be in demand.

  • Posts: 447

    Bortels, good point on rotation. Will also need to handle z-order if I want to use my atlas as the single draw() call I make in my program.

    Didn't understand this - would you mind clarifying?

    "Extra points for automatically per-draw handling a series of atlas textures for animation. You could either add them as a set, or add them and then take a table of the names to iterate thru."

  • BortelsBortels Mod
    edited January 2012 Posts: 1,557

    Yeah, I confused myself when I wrote it.

    What I'd like is to be able to say:

    a=atlas()
    gemanim = {}
    for i=1,6 do
       a:map("gem"..i, sprite("Tyrian Remastered:Gem Shine "..i), 19, 27)
       gemanim.insert("gem"..i)
    end
    a:addRect("gem", 0, 0, 19, 27)
    a:setAnim(gemanim)
    

    The above is all yours up to the last line; we make an atlas "a", and add 6 images (from the Tyrian Remastered spritepack) to it as "gem1" thru "gem6". I save those names in a table, add the rect to draw, then tell the atlas "draw the following animation" - idea being each time I call a:draw, it draws the next frame in the gem1 thru gem6 animation, without me having to keep track manually or set graphics.

    I think a lot of games are going to revolve around moving the mesh to scroll, and changing which chunk of an atlas texture each rect maps to, to do things like turn switches on/off, open doors, and do character animation.

  • edited January 2012 Posts: 447

    here's a start: http://ruilov.posterous.com/atlas-01

    using the most stupid packing algorithm for now

    and how to use:

    function setup()
        noSmooth()
        atlas = Atlas()
        
        -- map a few test functions
        atlas:map("test1",draw1,200,100)
        atlas:map("test2",draw2,200,100)
        atlas:map("test3",draw3,101,171)
        
        -- draw1. Note that x and y coords are in CENTER mode
        test1Idx = atlas:addRect("test1",100,50)
        -- update the position of test 1 to make sure it updates the internal data structures
        atlas:setRect(test1Idx,150,50)
        -- draw2. Passing z-coord of -1 to draw under the first one
        test2Idx = atlas:addRect("test2",200,50,nil,nil,nil,-1)
        -- passing a width, height and rotation angle, just like in mesh:addRect
        atlas:addRect("test2",400,400,50,50,math.rad(45))
        test3x = 100
        test3Idx = atlas:addRect("test3",test3x,400)
    end
    
    function draw()
        background(0,0,0)
        atlas:draw()
        -- move test 3 one pixel over to the right
        test3x = test3x + 1
        -- also test passing a new width to make sure that works
        atlas:setRect(test3Idx,test3x,400,300-test3x)
        
        -- set test2 on top or below test1 as a test that setRect is working
        if ElapsedTime > 1 and ElapsedTime < 2 then 
            atlas:setRect(test2Idx,200,50,nil,nil,nil,1) 
        end
        -- some more z order tests
        if ElapsedTime > 2 and ElapsedTime < 3 then 
            atlas:setRect(test1Idx,150,50,nil,nil,nil,2)
        end
        if ElapsedTime > 3 then atlas:setRect(test2Idx,200,50,nil,nil,nil,3) end
    end
    
    function draw1()
        stroke(9, 255, 0, 255)
        strokeWidth(2)
        fill(0,0,255,255)
        rectMode(CORNER)
        rect(0,0,200,100)
    end
    
    function draw2()
        stroke(255, 255, 255, 255)
        strokeWidth(2)
        fill(255, 0, 176, 255)
        rectMode(CORNER)
        rect(0,0,200,100)
    end
    
    function draw3()
        spriteMode(CORNER)
        sprite("Planet Cute:Character Pink Girl",0,0,101,171)
    end
    
  • Posts: 447

    hm just realized that if I really want to handle z-order well across multiple meshes, it's going to get messy. Maybe best to just not handle z-order at all, and let the user create multiple atlases and draw them in the desired order.

  • BortelsBortels Mod
    Posts: 1,557

    That, or allow the user to assign z-order either before or after. I like the concept of setting up the object, and all you need to do during draw is "a:draw()" and it takes care of everything.

  • Posts: 447

    the problem is that mesh1 might have a sprite at z=0 and another at z=2 and then mesh2 have a sprite at z = 1. In that case I'll have to move the sprites around from one texture to another based on the z order...and I could, but well I'm lazy.

  • BortelsBortels Mod
    Posts: 1,557

    If the only reason for multiple meshes is to handle images larger than the maximum texture size, the user doesn't care how you do them internally... but, yeah, management of them would be messy.

    But I'd not let that prevent you from doing it... I'd rather see z-level handled well instead of support for gimungous images. If someone wants to have a really big image, they can do it themselves.

    The more I think about it, the uglier it gets. :-)

  • SimeonSimeon Admin Mod
    Posts: 5,363

    @ruilov in general I would keep big images (such as background) out of an atlas, except for special circumstances. What you want in the atlas are the small textures, items that are drawn constantly and repeatedly. So characters, power ups, icons, enemies, logos, buttons, particles and so on.

    A background is generally drawn once and accounts for a constant state-change overhead, so it's really not worth filling up your atlas with it.

  • edited January 2012 Posts: 447

    Bortels, I might. Working on something else and I want to integrate this simple atlas version in it to see how it goes first. The reason for multiple meshes is just that the aggregated size of all sprites you want to draw might be larger than the screen. Not necessarily because the images are large (though I agree that's probably rare)

    Edit: actually the version I posted does handle z-order just fine as long as all sprites fit into one mesh. The packing algorithm is stupid so if you add too many sprites it will wastefully create a new mesh, but improving the packing algorithm to something a little less stupid is easy.

    Simon, ok that makes sense, thanks.

Sign In or Register to comment.