views:

74

answers:

1

I have a Quartz 2D game which draws directly onto a context. For this reason I am having to adapt the code so that it scales if appropriate for a Retina display. I am doing this using the following code:

- (CGFloat) displayScale
{
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {

    return [[UIScreen mainScreen]scale];

}

else  

{
    return 1.0;
}

}

What I am now struggling with is how to manipulate my Quartz context in my -drawRect: method to mulitply by the returned scale value. Can anyone help me with this code ?

+2  A: 

You don't need to change anything in your Quartz code to account for the Retina display. If the correct contentScaleFactor is set on your UIView or CALayer using code like the following:

if ([view respondsToSelector:@selector(setContentScaleFactor:)])
{
    view.contentScaleFactor = [[UIScreen mainScreen] scale];
}

the 2-D drawing you do within -drawRect: or -drawInContext: will be automatically rendered sharply for the Retina display. Remember that the coordinates you specify for the Quartz drawing will be in points, not pixels. With a scale factor of 2.0 for a Retina display, 1 point = 2 pixels.

See the "Updating Your Custom Drawing Code" section in the iOS Application Programming Guide for more.

Brad Larson
Thanks Brad but that code does not work ? I am using the following code in my drawrect method : CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState(context); CGAffineTransform t0 = CGContextGetCTM(context); t0 = CGAffineTransformInvert(t0); CGContextConcatCTM(context,t0);
Ohnomycoco
@Ohnomycoco - What do you mean by "doesn't work"? What is that transform intended to do? As I state above, you don't need to do anything in your Quartz drawing code to account for the Retina display. That transform is unnecessary and should be removed from your code. I use this in more than one application, and they all display crisply on the Retina displays without any alterations to the Quartz drawing code.
Brad Larson
If I take out the following three lines :CGAffineTransform t0 = CGContextGetCTM(context); t0 = CGAffineTransformInvert(t0); CGContextConcatCTM(context,t0); The content scales up correctly, however the entire game is now back to front (!)
Ohnomycoco
In my sprite class I have the following :CGContextSaveGState(context); // Position the sprite CGAffineTransform t = CGAffineTransformIdentity; t = CGAffineTransformTranslate(t,y+160,240-x); t = CGAffineTransformRotate(t,rotation - 3.141592*0.5); t = CGAffineTransformScale(t,scale,scale); CGContextConcatCTM(context, t); [self drawBody: context]; CGContextRestoreGState(context);
Ohnomycoco
perhaps this is the problem ?
Ohnomycoco
@Ohnomycoco - If you need to flip the coordinate space of a UIView to have the bottom-left corner be the origin (to match the default Quartz coordinate space) you can use the code `CGContextTranslateCTM(context, 0.0f, self.frame.size.height);CGContextScaleCTM(context, 1.0f, -1.0f);`
Brad Larson
@Ohnomycoco - Also, you really should be drawing the sprites within separate UIViews or CALayers, not directly on your main view. You will see terrible performance if you are animating by redrawing your Quartz views for every frame. Instead, split the drawing elements apart into separate layers so that they can be independently animated using Core Animation. Compositing is much, much faster than redrawing.
Brad Larson
Brad - thank you - you're a genius - it now displays correctly. Interesting point about the CG Layers, but I'm not sure I fully understand. I have a one custom UIView which handles drawing all my sprites - are you saying I should create a separate UIView for each sprite ?
Ohnomycoco
@Ohnomycoco - Yes, individual UIViews or CALayers would be the way I'd go for this. Even the first-generation iPhones can animate 50 translucent UIViews at 60 frames per second in my benchmarks. Redrawing that content is a much slower process, and you'd be lucky to get 10 FPS on that same hardware. Even if you need to redraw something, containing it within a less complex view will lead to better performance. Think about how they use cels in animated cartoons.
Brad Larson
How would I separate out my one UIView - do I just create one for each sprite update and then update each one in my game loop ? E.g [view1 tic] [view2 tic] [view3 tic] etc.
Ohnomycoco
@Ohnomycoco - Yes, I'd split out each animating element in its own view. If you can, have Core Animation handle as much of the visual updates as you can (tell it to animate something between point A and point B over a set duration and just let it do the work), rather than manually updating positions every frame. You might want to check out the video for my classes on Core Animation in my course on iTunes U: http://deimos.apple.com/WebObjects/Core.woa/Browse/matcmadison.edu.3989485784.03989485786
Brad Larson