Hello everyone! A few months have passed since I posted Simple Platformer Using Cocos2d and Box2d with Collision Detection. I have received many positive feedbacks and interest on the tutorial. I am glad that it has been helpful for so many in the community!
Also, I would like to share the good news that the game we have been working on has been picked up by a major publisher. We hope to release it around September, so please stay tuned! The game has been built using the very same articles and tutorials found on this blog.
What Is It?
PVRTC-I and -II are a family of lossy, fixed-rate texture compression formats used in PowerVR’s MBX and SGX technologies. PVRTC is the compressed texture format used in all generations of the iPhone, iPod Touch and iPad (source). You will see PVR and PVRTC being used interchangeably. They are not the same. They key thing to keep in mind is that a PVR is uncompressed, and PVRTC is compressed. Also, a PVR is a container which may contain various formats (a PVRTC is contained within a PVR file, for example). Some uncompressed PVR types are:
- RGBA8888: 32-bit texture with alpha channel, best image quality
- RGBA4444: 16-bit texture with alpha channel, good image quality
- RGB565: 16-bit texture without alpha channel, good image quality but no alpha (transparency)
Here are the PVRTC types, which are compressed and lossy (meaning, quality is degraded):
- PVRTC4BPP: Compressed format, 4 bits per pixel, ok image quality
- PVRTC2BPP: Compressed format, 2 bits per pixel, poor image quality
Pros and Cons
Why would you want to use a PVRTC texture? Because, it is the native texture format and is hardware accelerated. This translates to faster loading time than PNGs. Have you ever been plagued by long load times? Then PVRTC may be the answer. But even better, it will use less memory on the device and give you a performance boost.
It all sounds great! But wait, there is a downside. The downside is that because it is a lossy compression, the quality of your textures will suffer. Given a PNG of the same dimension, a PVRTC4BPP texture will take up more disk space and it will look worse (you will see artifacts, especially if you rely heavily on transparency or have a lot of gradients).
Why Size Does Matter
As you may have already guessed, the amount of space used increases as the quality increases. This means RGBA8888 uses the most amount of space (in memory AND on disk). Here is a handy formula to calculate how much space will be used.
numBytes = width * height * bitsPerPixel / 8
What this means is that given a 1024×1024 image, a RGBA8888 texture will require 4 MB of space. And a PVRTC4BPP will take 512 KB space. Why does size on disk matter at all? There is a very good reason for keeping the amount of space taken by your textures as low as possible.
This is due to the 20 MB size limit imposed by AT&T (I do not know about Verizon or other international providers). If your application is over 20 MB, users will not be able to download your application over the air from their devices. They will have to go to a computer that has iTunes installed and download it from their Mac or PC. If you are working on a game, then you have to start rationing out disk space as textures aren’t the only assets that will require disk space (the other big one being audio).
So which one should you pick? A PNG will take less space on disk, but the loading time will be longer. The amount of space a PNG will take once loaded to memory is dependent on the pixel format that you set in Cocos2d, like so:
[CCTexture2D setDefaultAlphaPixelFormat:kTexture2DPixelFormat_RGBA4444]; // Available textures // kCCTexture2DPixelFormat_RGBA8888 - 32-bit texture with Alpha channel // kCCTexture2DPixelFormat_RGB565 - 16-bit texture without Alpha channel // kCCTexture2DPixelFormat_A8 - 8-bit textures used as masks // kCCTexture2DPixelFormat_I8 - 8-bit intensity texture // kCCTexture2DPixelFormat_AI88 - 16-bit textures used as masks // kCCTexture2DPixelFormat_RGBA4444 - 16-bit textures: RGBA4444 // kCCTexture2DPixelFormat_RGB5A1 - 16-bit textures: RGB5A1 // kCCTexture2DPixelFormat_PVRTC4 - 4-bit PVRTC-compressed texture: PVRTC4 // kCCTexture2DPixelFormat_PVRTC2 - 2-bit PVRTC-compressed texture: PVRTC2
Using a PVRTC will give you better performance and faster loading times, but worse quality and more disk space. Well, I guess you’ll have to pick the lesser of the two evils 🙂 You can always mix PNGs and PVRTCs, so that is another option. It is definitely a balancing act.
Tools of the Trade
So, how exactly do you create a PVRTC texture from a PNG? There are a few tools available.
- TexturePacker allows you create sprite sheets with an option for saving the textures as a PVRTC.
- TextureTool is a tool in the iOS SDK that allows you to compress your textures into a PVR texture format.
- PVRTexTool is the one I use. It is a free tool which comes with both a GUI and a command line utility.
I can’t speak for TexturePacker because I haven’t used it before, but with the other two, you will have to tinker with it to have it generate the correct textures. Let me save you the frustration and give you a simple PVRTexTool command-line command that I use to convert my Zwoptex created texture atlas from a PNG to a PVR.
PVRTexTool -fOGLPVRTC4 -iMyAtlas.png -yflip0 -premultalpha -pvrtiterations8
The command above will create a PVRTC4BPP texture which will be saved as MyAtlas.pvr. If you are curious about what all the options mean, then take a look at the manual that comes with PVRTexTool, which has detailed information about them.
How to Load it Using Cocos2d
This part is pretty trivial. Here is the code to load the PVRTC texture in Cocos2d. I’m assuming that you are loading a sprite atlas.
CCTexture2D *tex = [[CCTextureCache sharedTextureCache] addImage:@"MyAtlas.pvr"]; [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"MyAtlas.plist" texture:tex];
I hope this has been helpful. And for those in the United States, happy 4th of July! I live near Washington D.C., but I am not courageous enough to brave the traffic to go see the fireworks 🙂 I-66 will do that to you (if you live around here, you’ll know what I mean!).