Search code examples
iphonecocoaopenglgraphicsboilerplate

What is the minimum boilerplate code for a OpenGL 2D View?


What's the minimum boilerplate code required to setup an OpenGL view (with the necessary projections,camera angles etc) for drawing a 2D game?

For example, the minimum required to do Quartz 2D drawing in a custom view (and, say, load a background image) is the following:

#import <Cocoa/Cocoa.h>

@interface MyView : NSView {
}

@end

= = =

#import "MyView.h"

@implementation MyView

- (id)initWithFrame:(NSRect)frame {
    self = [super initWithFrame:frame];
    return self;
}

- (void)drawRect:(NSRect)rect {
    CGContextRef myContext = [[NSGraphicsContext currentContext] graphicsPort];
    CGRect frame = CGRectMake(bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
    CFBundleRef mainBundle = CFBundleGetMainBundle();
    CFURLRef url = CFBundleCopyResourceURL(mainBundle, CFSTR("background"), CFSTR("png"), NULL);
    CGDataProviderRef provider = CGDataProviderCreateWithURL (url);
    CGImageRef image = CGImageCreateWithPNGDataProvider (provider, NULL, true, kCGRenderingIntentDefault);
    CGDataProviderRelease (provider);
    CGContextDrawImage (myContext, frame, image);
    CGImageRelease (image);

    //rest of drawing code here...
}

@end

Would anything in the boilerplate code be different for Open GS ES on the iPhone as opposed to using Open GL on a Mac?


Solution

  • The easiest way to setup an OpenGL application on the iPhone is to create a "OpenGL ES Application" through Xcode. It generates the boilerplate source code you'll need to get started.

    Here is the boilerplate source I am using for an OpenGL iPhone game:

    @implementation EAGLView
    
    @synthesize context;
    
    // You must implement this method
    + (Class)layerClass {
       return [CAEAGLLayer class];
    }
    
    //The GL view is stored in the nib file. When it's unarchived it's sent -initWithCoder:
    - (id)initWithCoder:(NSCoder*)coder {
    
       if ((self = [super initWithCoder:coder])) {
          // Get the layer
          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;
          }
       }
       return self;
    }
    
    - (void)drawView 
    {
       [EAGLContext setCurrentContext:context];
    
       glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
       glViewport(0, 0, ScreenWidth, ScreenHeight);
    
       glMatrixMode(GL_PROJECTION);
       glLoadIdentity();
    
       // Setup the coordinate system to use 0,0 as the lower left corner
       // and 320,480 as the upper right corner of the screen (in portrait mode).
       glOrthof(0.0f, ScreenWidth, 0.0f, ScreenHeight, -1.0f, 1.0f);
    
       glMatrixMode(GL_MODELVIEW);
       glLoadIdentity();
    
       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
       // Here is where you draw everything in your world.
       DrawWorld();
    
       glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
       [context presentRenderbuffer:GL_RENDERBUFFER_OES];
    }
    
    
    - (void)layoutSubviews {
       [EAGLContext setCurrentContext:context];
       [self destroyFramebuffer];
       [self createFramebuffer];
       [self drawView];
    }
    
    
    - (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);
    
       glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &ScreenWidth);
       glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &ScreenHeight);
    
       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;
    }
    
    
    - (void)destroyFramebuffer {
    
       glDeleteFramebuffersOES(1, &viewFramebuffer);
       viewFramebuffer = 0;
       glDeleteRenderbuffersOES(1, &viewRenderbuffer);
       viewRenderbuffer = 0;
    }
    
    - (void)dealloc {
    
       if ([EAGLContext currentContext] == context) {
          [EAGLContext setCurrentContext:nil];
       }
    
       [context release];  
       [super dealloc];
    }
    
    @end
    

    As an alternative, this article provides a nice walkthrough in creating an OpenGL ES application on the iPhone.