Simple Skeleton Framework for Cocoa OSX OpenGL application

I found over the web that even official document on Apple’s Developers Network is quite rich in the aspect many people over the web ask for basic tutorial how to jump into OpenGL programming on OSX/IOS platforms.

One of the reasons I presume it’s so is because even if documentation and the library is complete in many aspects details are quite.. disconnected. For that reason I decided to show small tutorial how to start with OpenGL programming on OSX platform.

It’s not a tutorial about OpenGL itself, I assume developer knows it very well or enough to continue on it’s own, yet is not very much familiar with general development skills required to target Apple’s platform.

It was my case when after more than a decade of sticking in Microsoft’s platform I decided to learn OSX/IOS programming.
With such personal experience I crafted this text carefully looking for Microsoft’s analogies to ease the learning path for developers coming from that ecosystem.

Initial requirements:

If you’re complete newbie to Apple’s software development ecosystem please mind that to continue with this tutorial you need:
- OSX platform (one of Mac computers)

Note: I played with Hackintosh some time ago and aside of legal part of the experience when we speak about graphics programming where it simply lacks of good drivers and it’s very unstable. If you started your Mac experience from such configuration I really recommend you to buy a Mac to continue. Honestly speaking, I started with Hackintosh virtual machine in times when I worked at Microsoft. Just for curiosity to check the competitive platform without the need of buying it and without alternatives that could help me evaluate it’s value proposition. I fell in love and purchased the real hardware and for the main topic of this article as said I really recommend to you to go and buy one too.

- Xcode tools – available for download from App Store (free of charge)
- Some additional OpenGL libraries which you may like to use (like glem for example)

 Initializing OpenGL project

My approach to this tutorial is very raw, to keep it simple on those aspects that require integration with native Cocoa platform.
So our starting point is simply starting new app project, targeting OSX (Cocoa Application)

From that point you should have MainMenu.xib file which is Xml format to describe UI and it’s basic behavior. It’s quite comparable to Xaml as an idea. On the right pane’s bottom part you should have Object’s library. Select Data Views section to ease search for right view  control and find OpenGL View into the window. Change the properties to let this view cover whole the area of the window, set the window size according to your initial expectation.

Creating Custom OpenGL view

Standard view still needs some massage to fit your individual requirement. For that custom Objective C class has to be created. In my example let’s call it OGLDemoView. Its interface and implementation code looks like follow:

<HEADER>

 #import <Cocoa/Cocoa.h>
 #include "tut01_renderer.h" // I'll explain this include later, 
                             //shortly it's our pure C/C++ renderer
@interface OGLDemoView : NSOpenGLView
{
//system timer, needed to synchronize the frame rate
    NSTimer* renderTimer;
//our C++ renderer as I aim to minimize
//ObjectiveC footprint and use clean C/C++ only, if possible
    tut01_renderer renderer;
}
//it's analogical to WM_PAINT event in Windows
- (void) drawRect: (NSRect)bounds;
@end

<BODY>

 #import "OGLDemoView.h"
 @implementation OGLDemoView
- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
 //below code helps optimize Open GL context
 // initialization for the best available resolution 
 // important for Retina screens for example
    if (self) {    
       [self wantsBestResolutionOpenGLSurface];
}
   return self;
}
- (void)prepareOpenGL
{
    // Synchronize buffer swaps with vertical refresh rate
    GLint swapInt = 1;
    [[self openGLContext] 
         setValues:&swapInt 
         forParameter:NSOpenGLCPSwapInterval];
    renderer.init();
}
-(void)awakeFromNib
{
//when UI is created and properly initialized,
// we set the timer to continual, real-time rendering
//a 1ms time interval
   renderTimer = [NSTimer timerWithTimeInterval:0.001  
                     target:self
                     selector:@selector(timerFired:)
                    userInfo:nil
                     repeats:YES];
   [[NSRunLoop currentRunLoop] addTimer:renderTimer
                                 forMode:NSDefaultRunLoopMode];
//Ensure timer fires during resize
    [[NSRunLoop currentRunLoop]
          addTimer:renderTimer
          forMode:NSEventTrackingRunLoopMode];
}
// Timer callback method
- (void)timerFired:(id)sender
{
// it's the update routine for our C/C++ renderer
   renderer.update();
//it sets the flag that windows has to be redrawn
   [self setNeedsDisplay:YES];
}
// Each time window has to be redrawn, this method is called
- (void)drawRect:(NSRect)bounds
{
  //below code sets the viewport of Open GL context into
  //correct size (assuming resize, fullscreen operations may trigger change)
  NSRect backingBounds = [self convertRectToBacking:[self bounds]];    
    glViewport(0,0, backingBounds.size.width, backingBounds.size.height);
 //our renderer's drawing routine
   renderer.render();
}
@end

Having above code defined correctly in the project last step we need is to assign it as the class handling OpenGL view put on our window (right pane and correct properties can assign this class to the visual object).

Toggling Fullscreen

The easiest way to toggle our OpenGL application between fullscreen and windowed modes is explained by below code, which I put into my app delegate and assigned as menu item’s action:

- (IBAction)fullscreenToggled:(id)sender {
    if (![self isFullscreen])
    {
        [self.view enterFullScreenMode:[NSScreen mainScreen]
                   withOptions: nil];
        self.isFullscreen = true;
    } else {
        [self.view exitFullScreenModeWithOptions:nil];
        self.isFullscreen = false;
    }
}

This simplified approach can be easily extended to cover all possible scenarios and with above implementation is far from complete but for certain circumstances works quite stable as base point for further investigation. One of the consequences of above implementation is the behavior when your app goes fullscreen and then will come back to windowed and you will manually resize the window. OpenGL rendering will stop working because your OpenGL context is not aware of all the circumstances for the change. I’m not covering that in this post. To keep it simple stupid you can window’s resizing by setting the same values for min/max width/heights and continue.

C/C++ renderer and coding continuation without ObjectiveC/Cocoa impact.

If your application from that point needs only to render 2d/3d images with OpenGL and that’s all you need to know from the platform perspective. Of course if you need input (keyboard/mouse) interaction and handling other events then fun continues.

If we want to continue with the rendering code from pure C/C++ perspective our next step is to build base class C++ class for our renderer:

   class base_renderer
    {
    public:
       virtual void init() = 0;
        virtual void render() = 0;
       virtual void update() = 0;
    protected:
       void clear(float r=0,
                  float g=0, 
                  float b=0,
                  float a=1,
                  bool depth=true);
        void flush();
    };

Class is abstract so the only important (and base elements) are those which clear the buffers and flush, their Open GL code are represented below:

void base_renderer::clear(float r, float g, float b,
                          float a, bool depth)
{
    glClearColor(r, g, b, a);
    if (depth)
        glClear(GL_COLOR_BUFFER_BIT);
}
void base_renderer::flush()
{
    glFlush();
}

Now let’s see our tut01_renderer example which I used in the OGLDemoView code above. It’s not sophisticated and visually compelling but show the point how to make real-time renderer in Open GL that is bound to above basic infrastructure:

<HEADER>

class tut01_renderer : base_renderer
{
public:
    virtual void init();
    virtual void update();
    virtual void render();
private:
    float shift;
    float shift_direction;
    void draw_triangles();
};

<BODY>

void tut01_renderer::init()
{
    shift_direction = 1;
   shift = 0.0f;
}
void tut01_renderer::update()
{
#define SHIFT_MOVE 0.005f
    if (shift_direction==1)
    {
        shift +=SHIFT_MOVE;
        if (shift>=1.0)
            shift_direction = 0;
    } else
    {
        shift -=SHIFT_MOVE;
        if (shift<=0.0)
            shift_direction = 1;
    }
}
void tut01_renderer::render()
{
    clear();
    draw_triangles();
    flush();
}
void tut01_renderer::draw_triangles()
{
    glColor3f(1.0f, 0.85f, 0.35f);
    glBegin(GL_TRIANGLES);
    glVertex3f( -1.0+shift,  1.0, 0.0);
    glVertex3f( -1.0, -1.0, 0.0);
    glVertex3f(  1.0, -1.0 ,0.0);
    glColor3f(1.0f, 0.0f, 0.35f);
   glVertex3f(  1.0-shift,  1.0, 0.0);
    glVertex3f( -1.0, -1.0, 0.0);
    glVertex3f(  1.0, -1.0 ,0.0);
    glEnd();
}

Summary

Above example is very simple and doesn’t cover all possible scenarios but to people who are familiar with OpenGL (or general 3d programming) and are starting with OSX development it should be enough to focus on learning Open GL and having basic skeletal framework on OSX already done.


4 Responses to “Simple Skeleton Framework for Cocoa OSX OpenGL application”

  • Clay Says:

    First of all, thank you for this! I have been searching for days for an implementation such as this.

    I have a question: I am currently trying to implement this tutorial: http://lazyfoo.net/tutorials/OpenGL/02_matrices_and_coloring_polygons/index.php with your classes. I have done these all before, but wanted to go through each again and see what I need to do that is different. The first tutorial worked fine, but this second one is causing me all kinds of fits. I haven’t even implemented the input in this tutorial yet because the program already does weird thing when the logic is simple. In the tutorial render class, I have added the variable gColorMode as an integer equal to 0. I have tried initializing it with this value in the header, in the init method, or both. In my tutorial renderer class in the render method, I have an if statement that if gColorMode is equal to 0 display the rectangle as cyan. Else, multi.

    The results I get are baffling: 1) Crashes with error of trying to manipulate freed object 2) Displays Cyan 3) Displays Multi! I even have set gColorMode as a const just to see if it always would be cyan, and sure enough it sometimes was multi!

    I don’t think there is anything wrong with your code, and lazyfoo’s tutorial completely works with GLUT, I was just wondering if you would know why I can’t seem to be able to use an if/else statement in the render method?

  • admin Says:

    First, sorry for delay. Can you please post your source code somewhere to help me check how did you put all that stuff into the skeletal framework I’ve proposed?

  • Tim Says:

    The part where you add the fullscreen toggle to the AppDelegate. I’ve tried to replicate this, but I end up with:

    Property .view. not found on object of type .AppDelegate *.

    I’m not sure where this property should be defined, or how?

    Thanks for the tutorial, nice to have made it this far.

  • admin Says:

    after a while and playing more with OGL on OSX I can say It’s been much easier to me to handle the whole framework with SDL joint to OGL functionality. It was fun though to experiment with the bare metal of OSX core platform. Thanks for comments.

Leave a Reply