iPhone 3D Programming : Adding Textures to ModelViewer (part 3) - Enabling Textures with ES1::RenderingEngine

1/21/2011 7:42:46 PM

3. Enabling Textures with ES1::RenderingEngine

As always, let’s start with the ES 1.1 rendering engine since the 2.0 variant is more complex. The first step is adding a pointer to the resource manager as shown in Example 7. Note we’re also adding a GLuint for the grid texture. Much like framebuffer objects and vertex buffer objects, OpenGL textures have integer names.

Example 7. RenderingEngine.ES1.cpp
class RenderingEngine : public IRenderingEngine {
RenderingEngine(IResourceManager* resourceManager);
void Initialize(const vector<ISurface*>& surfaces);
void Render(const vector<Visual>& visuals) const;
vector<Drawable> m_drawables;
GLuint m_colorRenderbuffer;
GLuint m_depthRenderbuffer;
mat4 m_translation;
GLuint m_gridTexture;
IResourceManager* m_resourceManager;

IRenderingEngine* CreateRenderingEngine(IResourceManager* resourceManager)
return new RenderingEngine(resourceManager);

RenderingEngine::RenderingEngine(IResourceManager* resourceManager)
m_resourceManager = resourceManager;
glGenRenderbuffersOES(1, &m_colorRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorRenderbuffer);

Example 8 shows the code for loading the texture, followed by a detailed explanation.

Example 8. Creating the OpenGL texture
vector<ISurface*>::const_iterator surface;
for (surface = surfaces.begin(); surface != surfaces.end(); ++surface) {

// Create the VBO for the vertices.
vector<float> vertices;
(*surface)->GenerateVertices(vertices, VertexFlagsNormals

// ...

// Load the texture.
glGenTextures(1, &m_gridTexture);
glBindTexture(GL_TEXTURE_2D, m_gridTexture);

void* pixels = m_resourceManager->GetImageData();
ivec2 size = m_resourceManager->GetImageSize();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.x,
size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);

// Set up various GL state.


Example 8 introduces the glTexImage2D function, which unfortunately has more parameters than it needs because of historical reasons. Don’t be intimidated by the eight parameters; it’s much easier to use than it appears. Here’s the formal declaration:

void glTexImage2D(GLenum target, GLint level, GLint internalformat,
GLsizei width, GLsizei height, GLint border,
GLenum format, GLenum type, const GLvoid* pixels);


This specifies which binding point to upload the texture to. For ES 1.1, this must be GL_TEXTURE_2D.


This specifies the mipmap level. We’ll learn more about mipmaps soon. For now, use zero for this.


This specifies the format of the texture. We’re using GL_RGBA for now, and other formats will be covered shortly. It’s declared as a GLint rather than a GLenum for historical reasons.

width, height

This specifies the size of the image being uploaded.


Set this to zero; texture borders are not supported in OpenGL ES. Be happy, because that’s one less thing you have to remember!


In OpenGL ES, this has to match internalFormat. The argument may seem redundant, but it’s yet another carryover from desktop OpenGL, which supports format conversion. Again, be happy; this is a simpler API.


This describes the type of each color component. This is commonly GL_UNSIGNED_BYTE, but we’ll learn about some other types later.


This is the pointer to the raw data that gets uploaded.

Next let’s go over the Render method. The only difference is that the vertex stride is larger, and we need to call glTexCoordPointer to give OpenGL the correct offset into the VBO. See Example 9.

Example 9. ES1::RenderingEngine::Render with texture
void RenderingEngine::Render(const vector<Visual>& visuals) const
glClearColor(0.5f, 0.5f, 0.5f, 1);

vector<Visual>::const_iterator visual = visuals.begin();
for (int visualIndex = 0;
visual != visuals.end();
++visual, ++visualIndex)

// ...

// Draw the surface.
int stride = sizeof(vec3) + sizeof(vec3) + sizeof(vec2);
const GLvoid* texCoordOffset = (const GLvoid*) (2 * sizeof(vec3));
const Drawable& drawable = m_drawables[visualIndex];
glBindBuffer(GL_ARRAY_BUFFER, drawable.VertexBuffer);
glVertexPointer(3, GL_FLOAT, stride, 0);
const GLvoid* normalOffset = (const GLvoid*) sizeof(vec3);
glNormalPointer(GL_FLOAT, stride, normalOffset);
glTexCoordPointer(2, GL_FLOAT, stride, texCoordOffset);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drawable.IndexBuffer);
glDrawElements(GL_TRIANGLES, drawable.IndexCount, GL_UNSIGNED_SHORT, 0);

That’s it for the ES 1.1 backend! Incidentally, in more complex applications you should take care to delete your textures after you’re done with them; textures can be one of the biggest resource hogs in OpenGL. Deleting a texture is done like so:

glDeleteTextures(1, &m_gridTexture)

This function is similar to glGenTextures in that it takes a count and a list of names. Incidentally, vertex buffer objects are deleted in a similar manner using glDeleteBuffers.

  •  Programming with DirectX : Shading and Surfaces - Implementing Texture Mapping (part 2) - Multi Texture Demo
  •  Programming with DirectX : Shading and Surfaces - Implementing Texture Mapping (part 1) - 2D Texture Mapping Demo
  •  Building Out Of Browser Silverlight Applications - Using COM Interoperability and File System Access
  •  Building Out Of Browser Silverlight Applications - Controlling the Application Window
  •  iPhone 3D Programming : Adding Depth and Realism - Loading Geometry from OBJ Files
  •  iPhone 3D Programming : Adding Depth and Realism - Better Wireframes Using Polygon Offset
  •  Programming with DirectX : Textures in Direct3D 10 (part 2)
  •  Programming with DirectX : Textures in Direct3D 10 (part 1) - Textures Coordinates
  •  Programming with DirectX : Shading and Surfaces - Types of Textures
  •  iPhone 3D Programming : Adding Shaders to ModelViewer (part 2)
  •  iPhone 3D Programming : Adding Shaders to ModelViewer (part 1) - New Rendering Engine
  •  iPhone 3D Programming : Adding Depth and Realism - Shaders Demystified
  •  Programming with DirectX : Transformation Demo
  •  Programming with DirectX : View Transformations
  •  Programming with DirectX : World Transformations
  •  Programming with DirectX : Projection Transformations
  •  iPhone 3D Programming : Adding Depth and Realism - Lighting Up (part 2)
  •  iPhone 3D Programming : Adding Depth and Realism - Lighting Up (part 1)
  •  iPhone 3D Programming : Adding Depth and Realism - Surface Normals (part 2)
  •  iPhone 3D Programming : Adding Depth and Realism - Surface Normals (part 1)
    Most View
    Rosewill Launches Armor Evolution Mid-Tower Case
    Keep Kids Online Safely (Part 1)
    Extending the Real-Time Communications Functionality of Exchange Server 2007 : Installing OCS 2007 (part 2)
    Buyer’s Guide: e-Readers That Fits Your Needs Best (Part 1)
    Thunderbolt External Drives (Part 1)
    Apple iPhone 5 - Fails To Return To The Top (Part 2)
    Syncing And Streaming (Part 2) - Apple TV, The remote app
    Preparing Your Windows 8 PC : Adding Devices in Windows 8 (part 1) - Viewing Installed Devices
    Group Test: Free Office Suites (Part 3) - LibreOffice
    Turn An Old Computer Into A Server Using Ubuntu (Part 2)
    Top 10
    The NZXT Kraken X40 Compact Liquid Cooler Review (Part 3)
    The NZXT Kraken X40 Compact Liquid Cooler Review (Part 2)
    T-Mobile’s Samsung Galaxy Note II Review (Part 6)
    T-Mobile’s Samsung Galaxy Note II Review (Part 5)
    T-Mobile’s Samsung Galaxy Note II Review (Part 4)
    T-Mobile’s Samsung Galaxy Note II Review (Part 3)
    T-Mobile’s Samsung Galaxy Note II Review (Part 2)
    T-Mobile’s Samsung Galaxy Note II Review (Part 1)
    Sony Cybershot DSC-TF1 - Affordable Water-Resistant Camera
    Buffalo MiniStation Slim 500GB External Hard Drive