My game now runs at 60FPS on iPod! This is mainly thanks to 16bit texturing and mipmapping.
Previously, the game was running pretty slowly on the iPod touch 2G: 24 FPS while rendering 1028 triangles, with 7 different materials groups. My geometry is still far from optimized (my meshes are too high-res for the iPod), so only textures are optimized for now.
16 bit textures are a must on iPod: Not only they use half the amount of video memory and are handled really fast by the GPU, the quality loss is barely noticeable. However, I had to convert my 32 bit PNG data into 16 bit. Here is how to do it. Please note that this is done offline so I didn’t bother to optimize it. If it was done in real-time, the divisions by 255 would have been the first thing to go.
u16* pData = snew u16[width*height];
switch (info_ptr->color_type)
{
case PNG_COLOR_TYPE_RGBA: // convert RGBA8888 to RGBA4444
{
channels = 4;
for (s32 i=0; i<height; ++i)
{
for (s32 j=0; j<row_bytes; j += channels)
{
u8 r = pngData[i*row_bytes + j + 0];
u8 g = pngData[i*row_bytes + j + 1];
u8 b = pngData[i*row_bytes + j + 2];
u8 a = pngData[i*row_bytes + j + 3];
r = u8((f32(r)*0xf)/0xff)&0xf;
g = u8((f32(g)*0xf)/0xff)&0xf;
b = u8((f32(b)*0xf)/0xff)&0xf;
a = u8((f32(a)*0xf)/0xff)&0xf;
s32 column = j/channels;
s32 index = i*width + column;
pData[index] = (r<<12) | (g<<8) | (b<<4) | a;
}
}
}
break;
case PNG_COLOR_TYPE_RGB: // convert RGB888 to RGB565
{
channels = 3;
for (s32 i=0; i<height; ++i)
{
for (s32 j=0; j<row_bytes; j += channels)
{
u8 r = pngData[i*row_bytes + j + 0];
u8 g = pngData[i*row_bytes + j + 1];
u8 b = pngData[i*row_bytes + j + 2];
r = u8((f32(r)*0x1f)/0xff)&0x1f;
g = u8((f32(g)*0x3f)/0xff)&0x3f;
b = u8((f32(b)*0x1f)/0xff)&0x1f;
s32 column = j/channels;
s32 index = i*width + column;
pData[index] = (r<<11) | (g<<5) | b;
}
}
}
break;
default: SHOOT_ASSERT(false, "Unsupported PNG format");
}
Finally, here is how to pass the 16bit texture data to OpenGL, with mipmaps enabled:
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &m_GLTextureID);
glBindTexture(GL_TEXTURE_2D, m_GLTextureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
switch(m_eFormat)
{
case TF_RGB: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, s32(m_vSize.X), s32(m_vSize.Y), 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, m_pData);
break;
case TF_RGBA: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, s32(m_vSize.X), s32(m_vSize.Y), 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, m_pData);
break;
}
On the windows port, 16bit textures become noticeable, so I will probably make them exclusive to iPod. Here is how 16bit textures with mipmapping look in the editor (click to enlarge):