Monday, July 30, 2012

Zissou2d Part 3: The Sprite (Textures and Programs)

As I mentioned in my previous post, the Sprite is where all the action takes place, and by that, I mean the drawing. In CC2d, they've made it so that each object that has to draw itself can chose from a set of shading programs pre-loaded in the ShaderCache. The choice is made depending on what the Sprite has to draw.

Usually, a Sprite will be loaded with a texture image, which means that you will need a shader that can sample those textures. If you have no idea what I'm talking about, you can refer to my previous blog post about texturing and compression. On the other hand, you could have a Sprite that only contains a primitive shape, like a triangle, and no texture. For this, you obviously wouldn't need a program that can sample textures, thus that program would be simpler.

In this post, I will show you how to build a basic ShaderCache, as well as a TextureCache (insures an image, or texture, is loaded only once and can be re-used for different Sprites). Our ShaderCache will only contain one program for now; one that can draw textured objects (because I've already covered that in the previous post I mentioned, and that I've already written the shading program to do just that).

Also, from now on I'll have a Git of the project on GitHub.

First, let me show you a little diagram that summarizes what I just said:

Note: When I drew the diagram, I thought that I would have to implement a Texture2d object that wraps a texture image, just like in CC2d. It turns out that if you use GLKTextureLoader to load an image, a GLKTextureInfo instance is created and you can pass it around to objects that want to use that texture. That thing contains all the information you need to make calls to OpenGL.

ShaderCache and GLProgram

The first thing I'm going to do is implement the ShaderCache and the Program because it's going to require a bit more code (even though I'll be copy-pasting some stuff I already wrote). I'm also going to leave the Texture and TextureCache for last because I will be using the GLKTextureLoader which will make our job quite easy.

Here's the code for the program (this is almost exactly like what I posted here. The only difference being that it's now a normal class with instance methods instead of a helper class with only class methods):

As you can see, it's quite simple. The class has an initializer which takes the .glsl file name for both the vertex and the fragment shader. That initializer then takes care of compiling each file, and linking them inside a newly created OpenGL program. It also logs any errors in the process. The use method is going to be used later, when we want to tell GL which program it should use.

And now here's the code for the ProgramManager:

Key points:
  • You can access it from anywhere
  • The first time it is accessed through the sharedProgramManager, it will be instantiated and the default program will be created
  • There's only a single program in it right now but you could have an array of programs instead

How do we use this thing, and where?

Well, when you initialize your sprite, you will use the following call to give that sprite the default program (The Sprite object needs to have a program property):

self.program = [[ProgramManager sharedProgramManager] getDefaultProgram];


The TextureCache is fairly simple:

  • You add images to it by passing a file name
  • The object checks if it already exists
  • If it doesn't exist, it will load the texture using GLKTextureLoader and add it to it's cache
  • The object return a GLKTextureInfo object containing all the information to use that texture

The code:

Key points:

  • This one is also accessible from anywhere
  • GLKTextureLoader returns a GLKTextureInfo instance when a texture is created. This is what we will pass to the Sprite (In CC2d, there is a Texture2d object being passed around, just like in the diagram I made)
  • The keys in the dictionary are the file names, so you can't load two textures with the same name

Back to the Sprite

With all of the work we've done, we have to change the interface of the Sprite object to this:

The interface contains the three following elements:
  1. Texture property
  2. Program property
  3. Class method that returns a Sprite initialized with the given image
And now the implementation:


Here's a summary of what we've done:
  • ProgramManager
    • Responsible for creating and holding the default programs
    • Other objects that need to draw something can ask for one of those programs
  • GLProgram
    • Loads the .GLSL files, compiles and links the vertex and fragment shader
  • TextureCache
    • Contains information (GLKTextureInfo) about all the textures that have been loaded
    • Insures an image can only be loaded once
  • Sprite
    • Added a class method that initializes a Sprite with a given image
    • This image is added to the TextureCache which returns a GLKTextureInfo
    • Now has both a texture and a program to work with

What now?

Well, we have to use that texture and the program to draw the texture on screen, but that will be the subject of another post!

Link to the project so far

1 comment:

Bob S said...

What is the demo supposed to do? All I get is a pink screen in the iOS simulator?