The low-precision uncompressed formats (565,
5551, and 4444) are often overlooked. Unlike block compression, they do
not cause speckle artifacts in the image. While they work poorly with
images that have smooth color gradients, they’re quite good at preserving
detail in photographs and keeping clean lines in simple vector
art.At the time of this writing, the iPhone SDK
does not contain any tools for encoding images to these formats, but the
free PowerVR SDK from Imagination Technologies includes a tool called
PVRTexTool just for this purpose.
After opening up the tarball, execute the
application in
Utilities/PVRTexTool/PVRTexToolGUI/MacOS.
Open your source image in the GUI, and select
Edit→Encode. After you choose a format
(try RGB 565), you can save the output image to a PVR file. Save it as
Grid16-PVRTool.pvr, and add it to Xcode as described
in Step [click here]. Next, go into both renderers,
and find the following:
SetPvrTexture("Grid16.pvr");
And replace it with the following:
SetPvrTexture("Grid16-PVRTool.pvr");
You may have noticed that
PVRTexTool has many of the same capabilities as the
texturetool program presented in
the previous section, and much more. It can encode images to a plethora of
formats, generate mipmap levels, and even dump out C header files that
contain raw image data. This tool also has a command-line variant to allow
integration into a script or an Xcode build.
Let’s go ahead and flesh out some of the
image-loading code to support the uncompressed low-precision formats. New
lines in ResourceManager.mm are shown in bold in
Example 1.Example 1. New texture formats in ResourceManager.mm
TextureDescription LoadPvrImage(const string& file) { // ...
TextureDescription description; switch (header->dwpfFlags & PVRTEX_PIXELTYPE) { case OGL_RGB_565: description.Format = TextureFormat565; Break; case OGL_RGBA_5551: description.Format = TextureFormat5551; break; case OGL_RGBA_4444: description.Format = TextureFormatRgba; description.BitsPerComponent = 4; break; case OGL_PVRTC2: description.Format = hasAlpha ? TextureFormatPvrtcRgba2 : TextureFormatPvrtcRgb2; break; case OGL_PVRTC4: description.Format = hasAlpha ? TextureFormatPvrtcRgba4 : TextureFormatPvrtcRgb4; break; }
// ... }
|
Next we need to add some new code to the
SetPvrTexture method in the rendering engine class,
shown in Example 2. This code works for both
ES 1.1 and 2.0.
Example 2. New texture formats in the rendering engines
void RenderingEngine::SetPvrTexture(const string& filename) const {
// ... int bitsPerPixel; GLenum format; bool compressed = false; switch (description.Format) { case TextureFormatPvrtcRgba2: case TextureFormatPvrtcRgb2: case TextureFormatPvrtcRgba4: case TextureFormatPvrtcRgb4: compressed = true; break; } if (!compressed) { GLenum type; switch (description.Format) { case TextureFormatRgba: assert(description.BitsPerComponent == 4); format = GL_RGBA; type = GL_UNSIGNED_SHORT_4_4_4_4; bitsPerPixel = 16; break; case TextureFormat565: format = GL_RGB; type = GL_UNSIGNED_SHORT_5_6_5; bitsPerPixel = 16; break; case TextureFormat5551: format = GL_RGBA; type = GL_UNSIGNED_SHORT_5_5_5_1; bitsPerPixel = 16; break; } for (int level = 0; width > 0 && height > 0; ++level) { GLsizei size = width * height * bitsPerPixel / 8; glTexImage2D(GL_TEXTURE_2D, level, format, width, height, 0, format, type, data); data += size; width >>= 1; height >>= 1; } m_resourceManager->UnloadImage(); return; } }
|
Next, we need to make a change to
Interfaces.hpp:
enum TextureFormat {
TextureFormatGray,
TextureFormatGrayAlpha,
TextureFormatRgb,
TextureFormatRgba,
TextureFormatPvrtcRgb2,
TextureFormatPvrtcRgba2,
TextureFormatPvrtcRgb4,
TextureFormatPvrtcRgba4,
TextureFormat565,
TextureFormat5551,
};