GUI Texture Atlases in Shiva

As you probably know, it’s important to use Texture Atlases for efficiency reasons on mobile devices. The idea is that you pack lots of textures into one big one, and then use UV offsets to define which region of this large texture to display in your HUD components. This means that only one texture has to be referenced by the graphics hardware. But it can be a bit fiddly calculating the UVs, especially if you want to add new textures to it later.

I have put together a nice workflow for this, so I thought it might be useful for other people too..

Step 1: Create your texture atlas. I use a program called Texture Packer for this, which combines your textures into a single PNG and also exports an XML description of it (which we’ll need later; we could of course manually write the XML but it’s a bit more work that way..)

Texture Packer

Step 2: Write or export your XML. My Shiva code a bit later will assume the following format, which is what Texture Packer gives us. It simply encodes the names of the images (sprites), along with their positions and sizes in the atlas.

<TextureAtlas imagePath="ZS_icons.png" width="512" height="512">
<sprite n="backpack" x="204" y="2" w="160" h="186"/>
<sprite n="rotate_left" x="366" y="51" w="48" h="47"/>
<sprite n="rotate_right" x="416" y="2" w="48" h="47"/>
<sprite n="search" x="366" y="2" w="48" h="47"/>
<sprite n="shotgun" x="2" y="2" w="200" h="86"/>
</TextureAtlas>


Step 3:
Import the xml file and texture atlas in to Shiva

Step 4: Create your HUD. Anywhere you want a texture out of the atlas, just set that HUD component to the Atlas texture (it looks a bit weird at design-time..)

HUD at design time

Step 5: Add an XML variable to an AI, and set it initialised from the imported xml. (I call my xml variable xmlZS_icons, and hard-code that in the code below)

Step 6: Add the following function to your AI:

--------------------------------------------------------------------------------
function MyAI.SetUvsFromTextureAtlas ( sComp,sIcon )
--------------------------------------------------------------------------------

local r = xml.getRootElement ( this.xmlZS_icons ( ) )

local imgWid = string.toNumber ( xml.getAttributeValue ( xml.getElementAttributeWithName ( r, "width" ) ) )
local imgHgt = string.toNumber ( xml.getAttributeValue ( xml.getElementAttributeWithName ( r, "height" ) ) )

local c = xml.getElementChildCount ( r )

for i=0, c-1 do


local e = xml.getElementChildAt ( r,i )
if ( sIcon==xml.getAttributeValue ( xml.getElementAttributeWithName ( e, "n" ) ) ) then


local uscale = string.toNumber ( xml.getAttributeValue ( xml.getElementAttributeWithName ( e, "w" ) ) ) / imgWid
local vscale = string.toNumber ( xml.getAttributeValue ( xml.getElementAttributeWithName ( e, "h" ) ) ) / imgHgt
local u = string.toNumber ( xml.getAttributeValue ( xml.getElementAttributeWithName ( e, "x" ) ) ) / imgWid
local v = 1-( string.toNumber ( xml.getAttributeValue ( xml.getElementAttributeWithName ( e, "y" ) ) ) / imgHgt )-vscale
local comp = hud.getComponent ( application.getCurrentUser ( ),sComp )
hud.setComponentBackgroundImageUVOffset ( comp, u, v )
hud.setComponentBackgroundImageUVScale ( comp, uscale, vscale )
return


end

end

log.message ( "Unable to find icon '"..sIcon.."' in texture atlas!" )

 

 

--------------------------------------------------------------------------------
end
--------------------------------------------------------------------------------

 

Step 7: And finally, whenever you instantiate your HUD, call the following for each HUD component that’s included in the texture atlas:

this.SetUvsFromTextureAtlas ( "MyHUD.MyComponent", "sprite_name" )

 

final result

You can leave a response, or trackback from your own site.