Wednesday, May 16, 2012

Creating an OpenGL 3 application on Mac

Except for a brief adventure into the world of Ubuntu, most development of Decade was completed in Windows therefore to transition to Mac and IOS new projects have to be created.

Using XCode to create an IOS (iPhone or iPad) application, the IDE pretty much does all the setup for you when you select an OpenGL project.


self.context = [[[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2] autorelease];

allows you choose between OpenGL ES 1 and OpenGL ES 2.

Creating an OS X application does not present the same OpenGL option. This is your responsibility but I found to my frustration that allot of the tutorials online are insufficient. The standard approach seems to be create your own view which inherits from NSOpenGLView and Cocos handles allot of the setup for you. Rather than repeat what is already documented on may sites you can find an informative and easy to follow tutorial here.

This initially worked great. Using the fixed function pipeline I could position, rotate and render a cube. Since OpenGL ES 2 does not support the fixed function pipeline I needed to modify this code to remove all fixed functions and use GLSL, the programmable pipeline, instead.

The issues were obvious immediately. The shaders would not compile.

glGetShaderiv(shader, GL_COMPILE_STATUS, &status);

always returned 0, and

glGetShaderInfoLog(shader, logLength, &logLength, log);

the function used to get the errors when compiling shaders always returned an empty string. It took quiet a long time browsing forums to find out why this was happening. It turns out that Apple have decided that when NSOpenGLView is used as above, it will always uses OpenGL version 1, which doesn't support shaders. Interface builder does not allow you change the version of OpenGL used. This makes me question why the code even compiled and ran if it was using a version of OpenGL which did not support shaders.

The Solution:
To create a view which inherited from NSObject and create your own NSOpenGLView in code.
My interface now looks like

@interface DecadeEngine : NSObject

@property (nonatomic, readwrite, retain) IBOutlet NSWindow *window;
@property (nonatomic, readwrite, retain) IBOutlet NSOpenGLView *view;


and OpenGL can be initialised in

- (void)awakeFromNib
     NSOpenGLPixelFormatAttribute pixelFormatAttributes[] =
          NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
          NSOpenGLPFAColorSize        , 24                            ,
          NSOpenGLPFAAlphaSize        , 8                             ,
          NSOpenGLPFADepthSize        , 32                           ,
          NSOpenGLPFADoubleBuffer  ,
          NSOpenGLPFAAccelerated     ,
          NSOpenGLPFANoRecovery    ,
    NSOpenGLPixelFormat *pixelFormat = [[[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttributes] autorelease];
    [self setView:[[[NSOpenGLView alloc] initWithFrame:[[[self window] contentView] bounds] pixelFormat:pixelFormat] autorelease]];
    [[[self window] contentView] addSubview:[self view]];

The shaders now compiled successfully and I could again see the rotating cubes on screen. :)

No comments:

Post a Comment