More Pixels Equals More Panic

The March 2012 Apple Keynote brought no real surprises. The new iPad (hereinafter iPad 3 despite protestations) has a Retina Display with a whopping 1.572864 million pixels. I have some worries about whether the device will have enough oomph to push those pixels, but we will burn that bridge when we get to it.

Like a good little Apple dev, I downloaded the newest XCode and iOS Simulator to test out my apps. The rest of the cocos2d community was doing the same and that is when the excrement came in contact with the bladed cooling device. Devs started to report that their apps were showing a black screen on the iPad 3 simulator. More reports were coming in of other strange behavior.

I had only tested out my current project when I first heard the buzz. It hadn't shown any problems but I was worried about my apps that were already for sale. I fired up every project and tested them one by one. They all behaved exactly as expected, but why? What was the difference between my apps and all of the apps that were having problems?

The Issue

The root of the problem was that the iPad 3 was behaving exactly as it should. Universal cocos2d applications that support the Retina Display on the iPhone often have this snippet of code in the app delegate:

The enableRetinaDisplay method attempts to turn on the Retina Display if the hardware supports it. Turns out that the iPad 3, with its Retina Display, activates the Retina Display when asked to do so. The problem is that since the rest of cocos2d and our apps aren't expecting this to happen on an iPad all sorts of craziness happens.

The good news is that Apple didn't go crazy and that things are behaving as one might expect. The bad news is that we have code built around an assumption that is now wrong. So why did my code work? Clearly I must not have had that handy snippet of Retina enabling code from above. WHAT?!?! I did? Oh, something else must be going on then.

Pixel Pushers

The solution to the problem was a bit of an accident. I wanted to create universal apps that took advantage of the iPad's resolution without needing new assets. With careful asset management and a few hacks it is easy to use your Retina iPhone assets on the iPad. This helps you reduce your app's footprint and take advantage of additional pixels. DOUBLE RAINBOW!

The method that I use is partially outlined in this forum post. It adds a makeUniversal method to CCDirector which you call immediately after instantiation of the director in your app delegate. Here is the code:

This method sets the __ccPointScaleFactor to 2. This sets the scaling between points and pixels. This also causes an escape to be skipped in enableRetinaDisplay display which causes the content scale factor to be updated to 2. The content scale factor is used by cocos2d to determine if the "-hd" assets should be used.

This has another side effect due to a check in updateContentScaleFactor which is indirectly called by the enableRetinaDisplay method:

If __ccContentScaleFactor is 2, then the method forces the display's scaleFactor to 1. This means that we don't actually activate the Retina Display even though we call enableRetinaDisplay. We are now safely using iPhone Retina assets on all (existing) models of the iPad. WOOOOOOOT!

But All Those Pixels!

You are right, this does not take advantage of all the extra pixels that the iPad 3 has available. You will need higher resolution assets to fully take advantage of the new iPad, so we need another approach. We can go over that in another post. (Edit: In fact, I just wrote up a post on how to make a truly universal iOS application here.)