iPhone 3D Programming : Textures and Image Capture - Texture Formats and Types

2/5/2011 9:53:01 AM
Recall that two of the parameters to glTexImage2D stipulate format, and one stipulates type, highlighted in bold here:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, 
The allowed formats are as follows:

Three-component color.


Four-component color; includes alpha.


Same as GL_RGBA but with the blue and red components swapped. This is a nonstandard format but available on the iPhone because of the GL_IMG_texture_format_BGRA8888 extension.


Single component format used as an alpha mask.


Single component format used as grayscale.


Two component format: grayscale + alpha. This is very useful for storing text.

Don’t dismiss the non-RGB formats; if you don’t need color, you can save significant memory with the one- or two-component formats.

The type parameter in glTexImage2D can be one of these:


Each color component is 8 bits wide.


Each pixel is 16 bits wide; red and blue have five bits each, and green has six. Requires the format to be GL_RGB. The fact that green gets the extra bit isn’t random—the human eye is more sensitive to variation in green hues.


Each pixel is 16 bits wide, and each component is 4 bits. This can be used only with GL_RGBA.


This dedicates only one bit to alpha; a pixel can be only fully opaque or fully transparent. Each pixel is 16 bits wide. This requires format to be GL_RGBA.

It’s also interesting to note the various formats supported by the PNG file format, even though this has nothing to do with OpenGL:

  • Five grayscale formats: each pixel can be 1, 2, 4, 8, or 16 bits wide.

  • Two RGB formats: each color component can be 8 or 16 bits.

  • Two “gray with alpha” formats: each component can be 8 or 16 bits.

  • Two RGBA formats: each component can be 8 or 16 bits.

  • Paletted formats—we’ll ignore these.


Just because a PNG file looks grayscale doesn’t mean that it’s using a grayscale-only format! The iPhone SDK includes a command-line tool called pngcrush that can help with this. You can also right-click an image file in Mac OS X and use the Get Info option to learn about the internal format.

1. Hands-On: Loading Various Formats

We can start by enhancing the IResourceManager interface so that it returns some format information in an API-agnostic way. (Remember, we’re avoiding all platform-specific code in our interfaces.) For simplicity’s sake, let’s support only the subset of formats that are supported by both OpenGL and PNG. Open Interfaces.hpp, and make the changes shown in Example 1. New and modified lines are shown in bold. Note that the GetImageSize method has been removed because size is part of TextureDescription.

Example 1. Adding format support to IResourceManager
enum TextureFormat {

struct TextureDescription {
TextureFormat Format;
int BitsPerComponent;
ivec2 Size;

struct IResourceManager {
virtual string GetResourcePath() const = 0;
virtual TextureDescription LoadPngImage(const string& filename) = 0;
virtual void* GetImageData() = 0;
virtual void UnloadImage() = 0;
virtual ~IResourceManager() {}

Example 2 shows the implementation to the new LoadPngImage method. Note the Core Graphics functions used to extract format and type information, such as CGImageGetAlphaInfo, CGImageGetColorSpace, and CGColorSpaceGetModel. I won’t go into detail about these functions because they are fairly straightforward; for more information, look them up on Apple’s iPhone Developer site.

Example 2. Update to
TextureDescription LoadPngImage(const string& file)
NSString* basePath = [NSString stringWithUTF8String:file.c_str()];
NSString* resourcePath = [[NSBundle mainBundle] resourcePath];
NSString* fullPath = [resourcePath stringByAppendingPathComponent:basePath];

NSLog(@"Loading PNG image %s...", fullPath);

UIImage* uiImage = [UIImage imageWithContentsOfFile:fullPath];
CGImageRef cgImage = uiImage.CGImage;
m_imageData = CGDataProviderCopyData(CGImageGetDataProvider(cgImage));

TextureDescription description;
description.Size.x = CGImageGetWidth(cgImage);
description.Size.y = CGImageGetHeight(cgImage);
bool hasAlpha = CGImageGetAlphaInfo(cgImage) != kCGImageAlphaNone;
CGColorSpaceRef colorSpace = CGImageGetColorSpace(cgImage);
switch (CGColorSpaceGetModel(colorSpace)) {
case kCGColorSpaceModelMonochrome:
description.Format =
hasAlpha ? TextureFormatGrayAlpha : TextureFormatGray;
case kCGColorSpaceModelRGB:
description.Format =
hasAlpha ? TextureFormatRgba : TextureFormatRgb;
assert(!"Unsupported color space.");
description.BitsPerComponent = CGImageGetBitsPerComponent(cgImage);

return description;

Next, we need to modify the rendering engines so that they pass in the correct arguments to glTexImage2D after examining the API-agnostic texture description. Example 3 shows a private method that can be added to both rendering engines; it works under both ES 1.1 and 2.0, so add it to both renderers (you will also need to add its signature to the private: section of the class declaration).

Example 3. RenderingEngine::SetPngTexture()
void SetPngTexture(const string& name) const;
// ...

void RenderingEngine::SetPngTexture(const string& name) const
TextureDescription description = m_resourceManager->LoadPngImage(name);

GLenum format;
switch (description.Format) {
case TextureFormatGray: format = GL_LUMINANCE; break;
case TextureFormatGrayAlpha: format = GL_LUMINANCE_ALPHA; break;
case TextureFormatRgb: format = GL_RGB; break;
case TextureFormatRgba: format = GL_RGBA; break;

GLenum type;
switch (description.BitsPerComponent) {
case 8: type = GL_UNSIGNED_BYTE; break;
case 4:
if (format == GL_RGBA) {
type = GL_UNSIGNED_SHORT_4_4_4_4;
// intentionally fall through
assert(!"Unsupported format.");

void* data = m_resourceManager->GetImageData();
ivec2 size = description.Size;
glTexImage2D(GL_TEXTURE_2D, 0, format, size.x, size.y,
0, format, type, data);

Now you can remove the following snippet in the Initialize method (both rendering engines, but leave the call to glGenerateMipmap(GL_TEXTURE_2D) in the 2.0 renderer):

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

Replace it with a call to the new private method:


At this point, you should be able to build and run and get the same results as before.

  •  iPhone 3D Programming : Textures and Image Capture - Fight Aliasing with Filtering
  •  iPhone 3D Programming : Textures and Image Capture - Texture Coordinates Revisited
  •  Programming with DirectX : Additional Texture Mapping - Sprites
  •  Programming with DirectX : Additional Texture Mapping - Alpha Mapping
  •  Microsoft XNA Game Studio 3.0 : Writing Your First Program (part 2) - Running the Same XNA Game on Different Devices
  •  Microsoft XNA Game Studio 3.0 : Writing Your First Program (part 1)
  •  Programming with DirectX : Shading and Surfaces - Additional Texturing Topics
  •  iPhone 3D Programming : Adding Textures to ModelViewer (part 4) - Enabling Textures with ES2::RenderingEngine
  •  iPhone 3D Programming : Adding Textures to ModelViewer (part 3) - Enabling Textures with ES1::RenderingEngine
  •  iPhone 3D Programming : Adding Textures to ModelViewer (part 2) - Generating Texture Coordinates
  •  iPhone 3D Programming : Adding Textures to ModelViewer (part 1) - Enhancing IResourceManager
  •  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
    Top 10
    Nikon 1 J2 With Stylish Design And Dependable Image And Video Quality
    Canon Powershot D20 - Super-Durable Waterproof Camera
    Fujifilm Finepix F800EXR – Another Excellent EXR
    Sony NEX-6 – The Best Compact Camera
    Teufel Cubycon 2 – An Excellent All-In-One For Films
    Dell S2740L - A Beautifully Crafted 27-inch IPS Monitor
    Philips 55PFL6007T With Fantastic Picture Quality
    Philips Gioco 278G4 – An Excellent 27-inch Screen
    Sony VPL-HW50ES – Sony’s Best Home Cinema Projector
    Windows Vista : Installing and Running Applications - Launching Applications
    Most View
    Bamboo Splash - Powerful Specs And Friendly Interface
    Powered By Windows (Part 2) - Toshiba Satellite U840 Series, Philips E248C3 MODA Lightframe Monitor & HP Envy Spectre 14
    MSI X79A-GD65 8D - Power without the Cost
    Canon EOS M With Wonderful Touchscreen Interface (Part 1)
    Windows Server 2003 : Building an Active Directory Structure (part 1) - The First Domain
    Personalize Your iPhone Case
    Speed ​​up browsing with a faster DNS
    Using and Configuring Public Folder Sharing
    Extending the Real-Time Communications Functionality of Exchange Server 2007 : Installing OCS 2007 (part 1)
    Google, privacy & you (Part 1)
    iPhone Application Development : Making Multivalue Choices with Pickers - Understanding Pickers
    Microsoft Surface With Windows RT - Truly A Unique Tablet
    Network Configuration & Troubleshooting (Part 1)
    Panasonic Lumix GH3 – The Fastest Touchscreen-Camera (Part 2)
    Programming Microsoft SQL Server 2005 : FOR XML Commands (part 3) - OPENXML Enhancements in SQL Server 2005
    Exchange Server 2010 : Track Exchange Performance (part 2) - Test the Performance Limitations in a Lab
    Extra Network Hardware Round-Up (Part 2) - NAS Drives, Media Center Extenders & Games Consoles
    Windows Server 2003 : Planning a Host Name Resolution Strategy - Understanding Name Resolution Requirements
    Google’s Data Liberation Front (Part 2)
    Datacolor SpyderLensCal (Part 1)