Continuing with my extensions to Apple's Texture2D class, this post is about extending it to render a sprite from a sprite sheet, which is basically just rendering only part of the texture. Sprite sheets are useful for storing all of the frames for an animated sprite, or simply for storing multiple images in a single texture. It's not only convenient, but can have a positive effect on performance as the texture does not need to be changed from one sprite to the next (although I haven't made this optimisation in the example code, which selects the texture each time).

This simple implementation requires all the sprites to be the same size, laid out from left-to-right and top-to-bottom in the texture. For example, the following sprite sheet was created using some sprites from Prince of Persia:

A sprite sheet

Each sprite here is 45x45 pixels, numbered 0 (top left sprite) to 12 (bottom-most sprite).

To render one of the sprites from this sprite sheet, the texture co-ordinates passed to the glTexCoordPointer OpenGL call needs to be selected to bound the appropriate sprite. First, let's look at how Texture2D renders an image. Texture2D creates a texture large enough to fit the entire image - an OpenGL texture needs to be a power of 2, so for a 180x180 image, a texture size of 256x256 is used.

A rectangle with a bounding box starting from (0, 0) with a width of 1.0 and a height of 1.0 represents the full texture. To render part of the texture a smaller rectangle needs to be passed to glTexCoordPointer before drawing the texture. Texture2D keeps two variables representing the x and y scale of the original image to the texture size (maxS and maxT), which it uses to render the image by passing glTexCoordPointer a rectangle starting at (0, 0) with a width of maxS and a height of maxT.

Sprite sheet layout and dimensions

To render one of the sprites in the image, the origin and dimensions need to be determined. If we know how many sprites there are across (dimx) and down (dimy), and the index of the sprite to render (index), then the bounding box can be determined as fractions of maxS and maxT:

x = maxS * (index % dimx) / dimx  
y = maxT * int(index / dimy) / dimy  
width = maxS / dimx  
height = maxT / dimy

Have a look at MyTexture2D class in the code on github for a full implementation of this. The project also includes a small iOS demonstration app showing an animated figure using the sprite sheet from this post.


Posted Tue 01 Nov 2011 by Michael Patricios

Tags: Development, Objective-C, OpenGL

Post a comment