OpenGL with Cocoa: Part 3

Another part to my series of guides for programming in OpenGL with Cocoa. Yesterday I showed you how to actively render in OpenGL with Cocoa: Part 2.

CocoaGL - New Header Functions and AttributesThis entry however will show you how to make the OpenGL view the first responder to ‘messages’, so that you can get key input and control turning of the triangle. All of the new functions with the exception of “keyAction” are overloaded and so a part of the Cocoa view system.

The new attribute “m_keys” will be used for storing the status of the key being pressed, true if it is pressed, false if it isn’t.

CocoaGL - Reset Key StatusNow when the application is started, we need to reset the values for “m_keys” to false so that we don’t have uninitialized data. We can do this within the functions “awakeFromNib” or “initWithCoder” but I have chose to do it within “initWithFrame“.

With that done we need to implement our new functions. For “acceptsFirstResponder“, “becomeFirstResponder” and “resignFirstResponder” we return “YES” so that the OpenGL view class we are using gets the messages first instead of the main window.

CocoaGL - Handling Input and ResponseFor “keyDown” and “keyUp” we check to see if there is any input and then forward the information onto one of our own classes, “keyAction” with a value which specifies if the key is pressed or not. This is they set to the Boolean array a the appropriate index.

We could just use the “keyAction” function to control the triangle, however we would be limited in update cycles depending on the repeat rate of messages during a key press.

CocoaGL - Checking for InputNow during the “drawRect” function, we check the status of key presses within the Boolean array. If the key ‘A’ is pressed, we rotate the triangle left by one degree per frame. However if ‘D’ is pressed, it will rotate the triangle right by one degree per frame. And if neither are pressed, nothing will happen.

As before we are not using glLoadIdentity() so the resultant matrix from the last frame is being modified, not a new one which we would have to store and increment a rotational value for.

CocoaGL - Controlling the TriangleWith the new changes, build and run the application, and pressed ‘A’ and ‘D’ to watch the triangle rotate differently. In the previous guide it rotated constantly, however now it requires key input of specific keys to rotate it, and you have control over the direction of rotation.

Thats all for OpenGL with Cocoa for the moment. Still working out some of the bugs in my own applications as I convert them from GLUT, so hopefully the next guide will show you how to switched between window and fullscreen modes.

CocoaGL Source (Part 3) (463 downloads)

OpenGL with Cocoa: Part 2

Following on from yesterdays entry, OpenGL with Cocoa: Part 1, this entry will expand upon that.

CocoaGL - New Header FunctionsFirst of all, we need to add some new functions to our OpenGL view class, as well as a few attributes. “m_rectView” will be used to store the current window rectangle, whilst “m_timer” will be used for updating the window for redraw.

The “initWithFrame” function is called before the OpenGL context is setup, it is used to set the pixel format conditions for the context. The other functions are called by our own code.

CocoaGL - New Source FunctionsI’ve image to the right shows the source for the new functions. Within the “initWithFrame” you can see we’re requesting a format with a double buffer, accelerated hardware, 32 bit colour buffer, with 24 bit depth buffer and an 8 bit stencil buffer. We then call the same function within the NSOpenGLView class we’re inheriting off.

The “setupAnimationTimerWithInterval” function sets up a timer object that fires “timerUpdate” at a specified interval. That function calls “setNeedsDisplay” to make the window redraw. The framerate can be killed if we draw in both the “timerUpdate” function and the “drawRect” function.

CocoaGL - More New Source ChangesWithin the “prepareOpenGL” function, we call the “setupAnimationTimerWithInterval“. Now within the “drawRect” function, we call “resizeGL” which if the rectangle is different to a previously stored one, we make a call to glViewport() to update the destination bounds.

We also change the glFlush() call to a call to a call to “flushBuffer” call from the current OpenGL context, this is because we are now rendering with a double buffer instead of a single buffer.

CocoaGL - Final Output Window

You may have also noticed there is a call to glRotated(), since we don’t call glLoadIdentity() every frame, this will rotate our rectangle, showing that our application is running and updating consistently.

If all goes well, you should have an output like the one in the right image (well at some point since it is rotating).

Well that is all for using OpenGL with Cocoa for the moment, the next part will cover basic keyboard input.

CocoaGL Source (Part 2) (440 downloads)

OpenGL with Cocoa: Part 1

CocoaGL - Creating an Application

In a previous entry I said I would show how to setup an OpenGL application using Cocoa. This guide will be slightly more thorough than the one written on the Apple Developer Site. The version of XCode I’m using is 3.1.3, but I’ve included lots of pictures, which will hopefully work around problems with changes in versions.

CocoaGL - Project is Setup

First off, this is an extremely basic program, single buffer which is only redrawn when the window’s rectangle is dirty. To start off, open up a copy of XCode and create a new “Cocoa Application” and give it a name. I named mine “CocoaGL“.

Once created you should have something that looks kinda like the image on the right.

CocoaGL - Adding Framework

Now you have setup a basic Cocoa application, if you click “Build and Go” you will have a Cocoa window being displayed, however if you click the Red button to close the window, the debugger is still running because the application is still active.

But we’ll get around to fixing that later. Now for using OpenGL, we’ll need the OpenGL framework (a framework is a special folder that contains headers, resources, libraries, etc for a particular third party library).

CocoaGL - Select OpenGL Framework

To add a framework to an application, right click on any folder in the project (I use an already created one), select “Add” and then “Existing Frameworks…“. Now to find the OpenGL framework, navigate to “/System/Library/Frameworks/“. Now search through the folder and select “OpenGL.framework“, and select “Add“, and “Add” again.

CocoaGL - Add Files

With the OpenGL library now linked to the application, we need an Objective-C class for our OpenGL window to be associated with. To do this, we’ll need to inherit off NSView or NSOpenGLView (with NSView we’ll need setup OpenGL ourselves, so for now we’ll use NSOpenGLView). Right click on a folder in the project again, but this time select “Add” and then “New File…“.

CocoaGL - Cocoa Class Source File

Select “Objective-C class” from the list. You can also “Objective-C NSView subclass“, which will create a class with the functions “initWithFrame” and “drawRect“, as well as inheriting off NSView. But I’ll be providing the code for the class so any Objective-C class will be fine.

CocoaGL - Name Source and Header

Upon clicking “Next” you’ll be presented with a screen similar to the one on the left. Choose a filename, for my code I used the name “OpenGLView” (this will also determine the class name. Make sure a header is created with this source file, one nice thing about XCode compared to Visual Studio is that it gives you this option.

CocoaGL - Default Objective-C Class

Click “Finish” and your source and header files will be created for you, opening the header for you to view straight away. I’ve shown what is given by default, this can be used for normal window associated stuff, but it lacks an OpenGL context as well as setting up the pixel format information, that will allow us to use OpenGL.

CocoaGL - New Class Header

Change the inherited class to NSOpenGLView (this does all the default stuff for us). Now add two addition functions, “prepareOpenGL” and “drawRect“, check the header for NSOpenGLView or the Cocoa documentation for more information. The image to the left shows what parameters and return value the functions use.

CocoaGL - New Class Source

Now open the source file (Objective-C uses the extension .m, while Objective-C++ uses .mm). Within the “prepareOpenGL” function, this is where we setup our OpenGL context, I’ve set the clear color and I’ve set the swap interval to be synchronized with the vertical refresh (vblSynch value needs to be set to 1, 0 is as immediate).

CocoaGL - Selecting a XIB

And the “drawRect” function is used for, as you may have guessed, redrawing our screen. For now I’ve added code to clear the screen, draw a yellow triangle and flush the buffer (glFlush is used for a single buffer, rather than double).

With that done we need to link a window to the class we’ve just created. So find the XIB file within the project, and double-click it to open it up Interface Builder.

CocoaGL - Adding a Custom Object

Within the Library window of Interface Builder, do a search for “Custom View“, then drag and drop the found object onto the window, and resize it if you want to be the same size as the window. There is also an “OpenGL View” object that gives you more control over the default settings, however I find it more restrictive to use.

CocoaGL - Sub Window Resize

Now open the “Size Inspector” window for the object we’ve just created, if it isn’t already open, goto the “Tools” menu and select “Size Inspector“. Click all arrows within “Autosizing” so that the object will automatically resize when the parent window is resized. See the image to the left for more information.

CocoaGL - Setting Sub Window ClassNow open up the “Identity Inspector“, if it isn’t open already you can access it from the “Tools” menu as well. Within the “Class Identity” section, set the “Class” to the name of the OpenGL view class we created, the auto-complete will help you find it. Once this is done, goto the “File” menu and select “Build and Go in XCode” – this will exit Interface Builder, build the project and then start it running.

CocoaGL - Build and Run

If all has gone well, you’ll see a window like the one on the left image. However, if you try to resize it, it will remain in the same place (this is because we didn’t change the viewport size when the window is resized, this will be covered in the next part of this guide to using OpenGL in Cocoa).

One other thing you’ll notice is that if you close the window the application will still be running as mentioned earlier.

CocoaGL - Setup a Delegate Class Header

To fix this, we need to setup an object to handle delegations from the application, one of which is whether the application should end if a window is closed. So as before when we created our “OpenGLView” class, create a new class, I’ve called mine “AppDelegate“.

When it is created, add the function “applicationShouldTerminateAfterLastWindowClosed“.

CocoaGL - Setup a Delegate Class Source

Now add the function to the source file as well, returning “YES” so that the application will end when a window is closed.

Now find the XIB file again and double-click to open it up with Interface Builder again.

CocoaGL - Add an Object to use as a Delegate

Now search for “Object“, and drag and drop the NSObject (the blue cube on its own, not the blue cube within the green circle) into the XIB window. Open up the “Identity Inspector” for the Object just created and then set the Class to the application delegate class we just created.

CocoaGL - Set Object Class

Now we just need to link the application delegate to this newly created Object associated with our delegate class. To do this, select “Application” from the XIB window, then open the “Connections Inspector“, available from the “Tools” menu.

CocoaGL - Set Object as Application Delegate

Now drag from the “delegate” selection circle, to the delegate object. If done successfully, “delegate” will have a shaded box around it and the name of your delegate class you created on the right.

Go to the “File” menu and select “Build and Go in XCode“, you should now have a basic OpenGL application made in Cocoa, with a window that will shutdown the application if the window is closed.

The next guide will cover rendering with a double buffer, handling resizing, and a render loop of 60 frames per second.

CocoaGL Source (Part 1) (531 downloads)