Thoughts on supporting @2x resolution ..

Member
Posts: 129
Joined: 2009.03
Post: #1
.. with the latest gen of iPhone and iPod touch, with the retina displays; and debating if to bother supporting them, at this time.

I'm only a small, one man band 'team', and my initial thoughts are that it could be more trouble than it's worth. Time would be better spent knocking out a few games, in as fast a time as possible.

I'm also thinking about the technical considerations for supporting @2x graphics, in openGL.

For example:

I use texture atlases with a look-up-table for each sprite, defining x,y,width,height etc. So, I guess I would have to create all my game graphics at 2x size, process them all in to texture atlases, making sure that everything falls neatly in to 2 pixel boundarys, with a 2 pixel border between sprites on each atlas.

I can then create a scaled down texture atlas from this 2x size one. Taking care that I scale down with the correct filter, so as not to create any bleed etc; also, that the look-up-table, will work for both the 2x version and the 1x version of each atlas.

*groan*

Also, I'm thinking textures will take approx. 4x memory of normal textures, and memory could get low.

Also, I'm thinking it would require blitting of 4x the amount of pixels, so that means I can use less sprites, or even a slower frame rate.


I guess it would be 'nice' to support @2x, and my inner geek would love to do so, but from a business stand-point, I'm thinking it may not be the best idea, for someone in my position (lone, indie-developer).

Any thoughts on all that?

Cheers,
Quote this message in a reply
Moderator
Posts: 1,560
Joined: 2003.10
Post: #2
(Nov 17, 2010 01:56 PM)Jamie W Wrote:  Also, I'm thinking textures will take approx. 4x memory of normal textures, and memory could get low.

Also, I'm thinking it would require blitting of 4x the amount of pixels, so that means I can use less sprites, or even a slower frame rate.

You're working with a device with more RAM and a more powerful GPU (I think?) than the previous generation, so those could quite possibly balance out due to the better hardware.
Quote this message in a reply
Moderator
Posts: 3,570
Joined: 2003.06
Post: #3
Having a retina display device myself, I would say "Yes, definitely support Retina!". The difference is quite noticeable IMHO, and I think users really do care about the quality of graphics for their shiny new toys.

Also, as ThemsAllTook pointed out, Apple took the higher rez into account, so there is a lot more room on Retina devices -- plenty to fit whatever you need for 2x graphics.
Quote this message in a reply
Member
Posts: 129
Joined: 2009.03
Post: #4
Thanks guys.

Does the similator correctly(ish) emulate the @2x graphics, or do I really need a device to test stuff out on?
Quote this message in a reply
Moderator
Posts: 3,570
Joined: 2003.06
Post: #5
Yeah, the simulator does appear to show the graphics correctly, but it's slow. You could probably use it to do your development and then have someone with a Retina device test it to be sure it works.

The iPod Touch 4G is pretty affordable, and I have to say I really like it a lot, so if you think you might be interested in getting a new device to develop with, I can easily recommend it.
Quote this message in a reply
Member
Posts: 129
Joined: 2009.03
Post: #6
Oh yeah, I have to admit, it's pretty high on my list of 'goodies I'm hoping Santa will bring me this year'! Smile

I guess using the simulator is ok to get stuff up and running, and check it will all fit in fine with my way of doing things.

I did try, for a quick test, creating a ABC@2x.png (scaled up ver. of ABC.png); but it didn't display at all. I'm not using UIImage to load in my PNG's though, and apparently I need to.

Is there a correct way of loading in PNG's from disk to OpenGL texture?
Quote this message in a reply
Moderator
Posts: 3,570
Joined: 2003.06
Post: #7
(Nov 17, 2010 03:48 PM)Jamie W Wrote:  Is there a correct way of loading in PNG's from disk to OpenGL texture?

You can do it a few different ways. Loading via Apple's stuff (Core Graphics), you can use Texture2D. That way will force you to use a premultiplied alpha, which isn't a problem but you need to be aware of it. Yes, you need to use UIImage to get the auto @2x thing AFAIK. Texture2D takes a UIImage, so that might be convenient. You'll have to use imageWithContentsOfFile to avoid images being cached and sucking up more RAM, but I don't know for sure if that works with the @2x thing.

Another way to load PNGs is to use SOIL, which is incredibly easy to use and doesn't use premultiplied alpha (not that premultiplied alpha is bad). This is what I've been using lately. You have to make a few slight modifications to get SOIL to compile for iOS, but it's not hard to do at all -- just chase down the few errors.

There are four approaches to loading 2x graphics, one obvious and three others that I've thought of:
1) use Apple's way of doing it with UIImage
2) use your own system to load alternate graphics, perhaps mimicking Apple's way of doing it by searching for @2x, or some other approach entirely
3) scale down on-load depending on if using Retina or not (not as efficient as loading alternate graphic, but if you're fighting for disk space, this could be an option).
4) always load high rez graphics and scale down via the GL. Since this is a 50% scale, it actually works pretty well, but obviously you pay for it with RAM

#1 or #2 are preferable. I use #2 because I have my own asset management system which makes it easy for me to do, plus I don't use Apple's loader anymore anyway.
Quote this message in a reply
Member
Posts: 129
Joined: 2009.03
Post: #8
I'm thinking option 2 could work for me too. I could use Apple's naming convention, or something else.

I imagine, when running on retina display enabled devices; I just load in bitmaps that are 2x width and 2x height (and have the @2x in the filename).

Also, I need to think about creating a bigger back-buffer etc; in OpenGL. Or do I just set some scale parameter in OpenGL to 0.5, and it all works auto-magically?
Quote this message in a reply
Moderator
Posts: 3,570
Joined: 2003.06
Post: #9
(Nov 17, 2010 04:26 PM)Jamie W Wrote:  Also, I need to think about creating a bigger back-buffer etc; in OpenGL. Or do I just set some scale parameter in OpenGL to 0.5, and it all works auto-magically?

Yeah, it's real easy to do with just a few minor modifications. One thing in particular is that you can't get screen scale on pre iOS 4. Here's a pseudo-code-ish example of what I do in my UIView for ES1. Most of it should be familiar, but you can see how I fit in my rez-dependent stuff:

Code:
// interface stuff
// I use these to determine how to layout my graphics between iPad/iPhone/retina and determine which rez graphic to load. "TQ" is just my namespace prefix
enum
{
    TQ_LAYOUT_IPHONE,
    TQ_LAYOUT_IPHONE_RETINA,
    TQ_LAYOUT_IPAD,
    TQ_LAYOUT_UNKNOWN
}:
float tqLayout;
float osViewWidth;
float osViewHeight;
float osViewAspect;
float screenScale; // I use this to determine touch coord scaling
EAGLContext *context;
GLuint viewRenderbuffer;
GLuint viewFramebuffer;

- (id)initWithCoder:(NSCoder*)coder
{
    if(!(self = [super initWithCoder:coder])) return nil;
    
    // init OpenGL
    CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
    eaglLayer.opaque = YES;
    eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
       [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
    context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
    if (!context || ![EAGLContext setCurrentContext:context])
    {
        [self release];
        return nil;
    }
    
    // screen scale not available when less than iOS 4
    NSString *reqSysVer = @"4.0";
    NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
    if ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending)
    {
        screenScale = [[UIScreen mainScreen] scale];
        [self setContentScaleFactor:screenScale];
    }
    else
    {
        screenScale = 1.0f;
    }
    
    // need to do this now to determine view size
    [self createFramebuffer];
    
    // checking for <= because of space taken by status bar
    if (osViewHeight <= 480 && osViewWidth == 320)
        tqLayout = TQ_LAYOUT_IPHONE;
    else if (osViewHeight <= 960 && osViewWidth == 640)
        tqLayout = TQ_LAYOUT_IPHONE_RETINA;
    else if (osViewHeight <= 1024 && osViewWidth == 768)
        tqLayout = TQ_LAYOUT_IPAD;
    else
        tqLayout = TQ_LAYOUT_UNKNOWN;
    
    ...
    
    return self;
}

- (BOOL)createFramebuffer
{
    glGenFramebuffersOES(1, &viewFramebuffer);
    glGenRenderbuffersOES(1, &viewRenderbuffer);
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
    [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
    
    GLint    backingWidth;
    GLint    backingHeight;
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
    
    osViewWidth = backingWidth;
    osViewHeight = backingHeight;
    osViewAspect = osViewWidth / osViewHeight;
    
    if (USE_DEPTH_BUFFER)
    {
        glGenRenderbuffersOES(1, &depthRenderbuffer);
        glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
        glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, osViewWidth, osViewHeight);
        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
    }
    
    if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES)
    {
        NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
        return NO;
    }
    
    return YES;
}

This just reminded me that one thing you also need to pay attention to is that just because the screen graphics are scaled, the touch coords are still at the original iPhone size of 320x480, so you might need to scale your touch coords yourself to determine touch locations in your retina scaled game.
Quote this message in a reply
Member
Posts: 440
Joined: 2002.09
Post: #10
(Nov 17, 2010 01:56 PM)Jamie W Wrote:  I use texture atlases with a look-up-table for each sprite, defining x,y,width,height etc. So, I guess I would have to create all my game graphics at 2x size, process them all in to texture atlases, making sure that everything falls neatly in to 2 pixel boundarys, with a 2 pixel border between sprites on each atlas.

That's what I do - works great, though I think I used 4 pixel borders to be safe.

For loading images I use SOIL's precursor stb_image and check for @2x versions myself.

As far as fill rate goes, I find a 4th gen iPod touch at native res performs very close to a 2nd gen iPod touch at native res - assuming the scene is bound by the GPU. One trick to get more bang for your buck on retina displays is to use a 1.5X scaling instead of 2X. I didn't some tests with @2X textures and a 1.5X scaling factor and found that it actually looks quite good (especially for 2D stuff) and you get way more headroom in the fillrate department.
Quote this message in a reply
Member
Posts: 81
Joined: 2007.07
Post: #11
Well it depends, if its a 3d game then of course support higher res, very easy to support and switch between them. If your game is sprite based though I definitely wouldn't do it, you are going to make orders of magnitude more on having more games than having one that supports hirez. I have a sprite based game and have read comments about how terrible games look that don't support high rez devices, after actually seeing games on an iPhone 4 I can say they are mostly without merit, my guess is people feel a bit slighted after dropping the money that they aren't using the high rez feature. I think my lowres game looks better on the iPhone 4 than the 3gs due to the better color saturation.

It also depends on the type of game, if the screen is always moving (action type game) I would much rather have smooth game play than hirez graphics which you are barely going to notice the difference with fast moving scenes. However if its a find the object type game, or something with detailed scenes hirez is definitely going to be worth the time and work.
Quote this message in a reply
Moderator
Posts: 3,570
Joined: 2003.06
Post: #12
(Nov 17, 2010 09:21 PM)Rasterman Wrote:  I would much rather have smooth game play than hirez graphics

Me app-tard and no understand what you say. I pay big money for new toy and want pretty pictures. APP-TARD MAADDDD!!!! I give you ONE STARRRR!!!!! I want give you ZERO stars but Apple no let me. MadMadMadMad
Quote this message in a reply
Member
Posts: 440
Joined: 2002.09
Post: #13
LOL @ AnotherJake

I don't see how this is easier in 3D than 2D. Just pretend you're targeting 360x480 pixels (though technically you're working in points) then for retina displays do two things: Load bigger textures, and scale the model view. Done.

If you're porting an existing 2D game the art could be a problem, but it's simple to do @2x art if you're working from scratch. Normally you'd be working at 4X or more anyway.
Quote this message in a reply
Member
Posts: 129
Joined: 2009.03
Post: #14
Smile @ app-tard!!

It's for 2D, sprite-based games.

I definitely think it's worth doing a couple of days research; and even if it's something I don't integrate in to my system right now; it makes sense to work how exactly how I would integrate it (before going ahead and making more games).

Makes sense to use @2x art for iPhone retina displays and iPad (and desktop versions), and @1x art for older iPhones. Will experiment with the 1.5 scaling too..

Just curious about one thing..

With my current system; one point is equal to one screen pixel; so I have a coordinate system of 0,0 to 320,480.

I'm thinking that may need to change; and probably should use a system of 0,0 to 640,960; to cover the entire screen, on both older iPhones and retina iPhones. Then whichever my game is running on; it's using the same coordinate system.

So that, 1 point equates to 1 retina pixel, or 0.5 ordinary pixels.

For iPad; I can either equate 0,0 to 640,960 to fill the entire screen (using the correct scaling factor); or, keep with the 1 point equals 1 pixel, and have a coordinate system of 0,0 to 1024,768 (which my game would need to make use of the extra space).

That all seems better somehow; than forcing 0,0 to 320,480 on the new retina iPhones.

I guess it all comes down to personal taste, and what the most workable coordinate system is, that fits with how I'm doing stuff etc. Just getting my head around it...

@Frank, you create your source graphics @ 4x scale? Are you using something like illustrator for that?
Quote this message in a reply
Member
Posts: 440
Joined: 2002.09
Post: #15
You're thinking backwards Wink. Retina displays are still 320x480 points, and touch events also come in at that size, so it's easiest to create the game based on 320x480 pixels then set up the buffers and viewport like AnotherJake described, and scale the model view by the screen's scaling factor before drawing. Everything should "just work" with that setup - assuming you've also loaded @2x textures as appropriate.

iPad is a different story - that screen really is bigger, so you'll usually have to do some rekajiggering for that. I've seen universal games that letterbox and/or stretch to fit but that's not ideal.

EDIT: Ya I do my graphics mostly in Illustrator, but they usually end up in Photoshop at 4X size for final editing. By using smart objects and filters in Photoshop a lot of stuff can actually scale much higher if needed.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Thoughts on our event app template JoelleAyala 0 79 Yesterday 02:21 PM
Last Post: JoelleAyala
  Thoughts on this article? Elphaba 1 2,307 Jun 11, 2009 02:04 PM
Last Post: Bachus