Is there an official guide for retina devices?

I have an iOS app where I need to support retina graphics (as all iOS/Android apps do).

If I set retinaEnable to false, then everything is correctly displayed on the device in terms of size, proportion, ratios, etc. However, fonts, images, etc are all pixelated since the GLView uses the non-retina size.

To fix the pixelation issues, I can use the enableRetina setting. Doing so make the fonts and images crips, but they’re scaled down to account for full retina resolution and the non-pixel dimensions I use become incorrect.

For the longest time, I’ve been using this addon https://github.com/armadillu/ofxEasyRetina for enabling retina graphics without having to go in and manually change every image and font size. However, this addon is going on 4 years old and I’m wondering if there is something in OF core now that would allow for this.

Personally, I’d like OF to behave like iOS or Android doesn’t natively and pixel dimensions not have to be aware of retina or not; this should be internal to OF just like it is to the native OS, right? When developing native iOS/Android apps, the app doesn’t need to know whether it’s retina or not or put a bunch of checks in place for each retina scale. Pixel dimensions are independent of full retina resolution. Is there something like this in OF now? What are the best practices as this seems like a very common issue now.

+1 here

Scaling could be helpful if some stretching of graphics can be allowed for on some devices. I’m not sure if this will help you, but I’ll post the code I’m currently using for my iOS game.I believe the original version of this solution was presented by OF user @kkkkkkkk. I’m sure it’s possible to do this on Android as well.

The trick is to render your app at a fixed resolution and then simply scale it to your devices native resolution:

//in main() before running the app, calculate the scaling int main() { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height;
CGFloat iOSScaling = [UIScreen mainScreen].scale;

[pool release];

screenWidth *= iOSScaling;
screenHeight *= iOSScaling;
gameWindowWidth = 480;
gameWindowHeight = 320;

/*scaleWidth and scaleHeight needs to be declared globally somehow to be accessed later in your ofApp::draw() method*/
scaleWidth = (float) screenWidth/(float) gameWindowWidth;
scaleHeight = (float)screenHeight/(float) gameWindowHeight;

//do your normal ofApp stuff here:

ofAppiOSWindow * iOSWindow = new ofAppiOSWindow();
ofSetupOpenGL(iOSWindow, gameWindowWidth, gameWindowHeight, OF_FULLSCREEN);
iOSWindow->enableRetina();

ofRunApp(new testApp);
}

Now in the ofApp::draw() method do the following:

void ofApp::draw()
{
//remember that scaleWidth and scaleHeight needs to be declared globally somehow
ofScale(scaleWidth, scaleHeight);
renderMyGame();
}

Sorry for the messy formatting, if someone could point me in the right direction on how to format forum posts like a grownup I would be most grateful :wink:

That’s an interesting approach @Wiklund. I think ofxEasyRetina is doing something similar. I’ll give it a try to see what the difference is.

In my case though, my app runs on iOS and Android and ideally i’d like a solution that can work across both. I’m surprised that this isn’t a common topic since generally things should maintain size across devices and default OF retina won’t do this alone.

You’re absolutely right @cerupcat, I’m also surprised this hasn’t been discussed more. Maybe everyone else know of some better solution? :slight_smile:

The only thing you need to make the previously mentioned code cross platform is to retrieve the screen properties of your device for each OS. The rest of the code should work on any platform with OF. Note that the code below has not been tested, consider it to be pseudo code.


float screenWidth = 0;
float screenHeight = 0;
float deviceScaling = 1;

\#if defined(TARGET_IOS)
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

CGRect screenRect = [[UIScreen mainScreen] bounds]; 
screenWidth = screenRect.size.width;
screenHeight = screenRect.size.height;
deviceScaling = [UIScreen mainScreen].scale;  //this was named iOSScaling in previous post
[pool release];
\#elif defined(TARGET_ANDROID)
   //This has not been tested at all!  
   DisplayMetrics metrics = new DisplayMetrics();
   getWindowManager().getDefaultDisplay().getMetrics(metrics);
   screenWidth = metrics.widthPixels;
   screenHeight = metrics.heightPixels;
   deviceScaling = metrics.density; //Not 100% this is the actual scaling 
\#endif

That’s great! Looking forward to giving this a try. I’ll report that how it goes (it might be a while though). :slight_smile:

@Wiklund I can’t seem to get your example working. Maybe it’s just me, but I don’t actually see where in OF that settings.height or settings.width is ever actually used to setup the size of the GL view on iOS.

It may also because I’m setting up the Window this way:

ofAppiOSWindow * window = (ofAppiOSWindow *)(ofCreateWindow(settings).get());
window->startAppWithDelegate("MyAppDelegate");

Also, as soon as I enable retina on a window ofGetHeight and ofGetWidth are equal to the full resolution of the device instead of non-retina resolution which is what we need to use same px coordinates/sizes across platforms.

BTW, looks like there’s discussion of getting this into OF core here: https://github.com/openframeworks/openFrameworks/issues/4789

Unfortunately, this issue on github also dates back more than 4 years.

@cerupcat, Interesting stuff, I’m surprised no one ever implemented a solution since it was brought up.
I think the way you instantiate your window may very well be part of the problem. Remember my code looked like this:

    ofAppiOSWindow * iOSWindow = new ofAppiOSWindow();
    ofSetupOpenGL(iOSWindow, gameWindowWidth, gameWindowHeight, OF_FULLSCREEN);
    iOSWindow->enableRetina();
    ofRunApp(new testApp);

since gameWindowWidth is set to 480 and gameWindowHeight to 320 the window is created with those values.
The code I presented in my first post is the one I’m using in my current project that I work on almost daily. The OF version I’m using is 0.9.3. I know the example isn’t the most easy one to follow since it involves both main(), draw() and then som variables that has to be declared globally/static, so just let me know if you run into any issues.
This solution has spared me so much trouble since it simply just works for all rendering once you have it up and running, I hope you get it sorted out, let me know otherwise.

Also! Theres been some issues with ofiOS and rotation. It may be worth swapping width and height depending on what version of OF you have.

Thanks @Wiklund! Looks like I’m on an older version of OF. I’ll try updating and see if that helps.

Looks like they’re aiming to get this into core which will be nice. Since this solution would still have issue with images and fonts not being retina.

Thanks again for the help and we’ll see how things go. If @theo has a branch with this in core i’ll probably give that a try too. :slight_smile:

Great @cerupcat, would be great to have a solid solution in core for this. The game
I’m working on uses a lot of png files and also some fonts, and I’m having no issues so far. Here’s a video of the game in action, the text at the end is made from a ttf font.

Edit:
Ah, now I understand that you were referring to the stretching of images and fonts as being a problem, and yes that is true when you need to keep your width/height ratios constant independent of the device resolution. It all depends on what type of app you’re working on…In my case, a little stretching is OK :wink:

And maybe we should alert @Dorald since he was interested in the topic as well.

1 Like

Yeah, currently I have wrappers around ofTrueTypeFont and ofImage where it’ll loads an image or font @2x or @3x the size depending on the scale of the device, but then it’ll scale it to 1x the size. It’s just annoying to rely on that since whenever OF core updates I have to test and make sure it didn’t break my code. Having this in core solves a lot of upkeep and makes the code a lot easier to maintain.

Nice game BTW :slight_smile:

Any progress on this ?