Jimmy Bouker
Jimmy Bouker

Reputation: 118

Setting up Continuous rendering in a mac osx cocoa application using OpenGL

I'm starting to work on a 3D particle system editor and evolver. Ive done something similar in the past with OpenGL but this time I'm making a mac os x cocoa application. I just have a few questions regarding some code I keep running into on setting up OpenGL.

1) Why do I see a lot of people on the web using...

[self setNeedsDisplay:YES];

Is this the proper way to get OpenGL to render, I now understand it leads to drawRect being called, but is it the correct way?

2) Is drawRect the proper method I should be overriding for my render frame method?

Heres the code that I continue to run into on the web:

-(void) prepareOpenGL {
    [[self window] makeFirstResponder:self];
    glClearColor(1.0f, 1.0f, 0.0f, 10.f);

    NSTimer *timer = [NSTimer timerWithTimeInterval:1.0/60.0 target:self selector:@selector(idle:) userInfo:nil repeats:YES];
   [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
}

-(void)idle:(NSTimer *)timer {
    if(![[NSApplication sharedApplication] isHidden])
        [self setNeedsDisplay:YES];
}
-(void) drawRect:(NSRect)dirtyRect {
    glClear(GL_COLOR_BUFFER_BIT);
}

Upvotes: 2

Views: 2732

Answers (1)

Brad Larson
Brad Larson

Reputation: 170317

You haven't indicated whether you will be drawing your OpenGL content within an NSOpenGLView or a CAOpenGLLayer. These two have slightly different ways of updating their content for display to the screen.

For an NSOpenGLView, you don't need to update the view within it's -drawRect: method. In fact, I think you won't want to trigger -setNeedsDisplay: to do a refresh of the NSView because of some overhead that might incur. In one of my applications, I use a CVDisplayLink to trigger updates at 60 FPS within my own custom rendering methods in an NSOpenGLView. None of these touch -drawRect:. Frames are presented to the screen upon calling [[self openGLContext] flushBuffer], not by forcing a redraw of the NSView.

CAOpenGLLayers are a little different, in that you override - drawInCGLContext:pixelFormat:forLayerTime:displayTime: with your custom rendering code. This method is triggered in response to a manual -setNeedsDisplay or by the CAOpenGLLayer itself if its asynchronous property is set to YES. It knows when it's ready to present new content by the boolean value you provide in response to -canDrawInCGLContext:pixelFormat:forLayerTime:displayTime:.

I've used both of these, and each has its advantages. CAOpenGLLayers make it much easier to overlay other UI elements on your OpenGL rendering, but their rendering methods can be difficult to get to work correctly from a background thread. NSOpenGLViews can be updated easily on a background thread using a CVDisplayLink, but are a bear to overlay content on.

Upvotes: 4

Related Questions