Search code examples
cocoamacosquartz-2d

How to draw to an NSView graphics context from inside a CVDisplayLink callback?


I have a simple game that renders 2D graphics to a frame buffer (not using any OpenGL). I was going to use a CVDisplayLink to get a clean framerate, however most examples on the web deal with OpenGL or QuickTime.

So far I have a sub class of NSView:

@interface GameView : NSView {
@private
    CVDisplayLinkRef displayLink;
}

- (CVReturn)getFrameForTime:(const CVTimeStamp*)outputTime;
@end

And I set up the CVDisplayLink callback:

CVDisplayLinkSetOutputCallback(displayLink, MyDisplayLinkCallback, self);

And I have the callback function:

CVReturn MyDisplayLinkCallback (CVDisplayLinkRef displayLink,
                                const CVTimeStamp *inNow,
                                const CVTimeStamp *inOutputTime,
                                CVOptionFlags flagsIn,
                                CVOptionFlags *flagsOut,
                                void *displayLinkContext)
{
    CVReturn error = [(GameView*)displayLinkContext getFrameForTime:inOutputTime];

    return error;
}

The part where I'm stuck is what to do in getFrameForTime: to draw to the graphics context in the GameView. My first guess was to do the drawing the same way you would in drawRect:

- (CVReturn)getFrameForTime:(const CVTimeStamp*)outputTime
{
    CGContextRef ctxCurrent = [[NSGraphicsContext currentContext] graphicsPort];

    //.. Drawing code follows
}

But ctxCurrent is nil which I think I understand - normally there is some setup that happens before the drawRect: that makes your view the current context. I think this is the part I'm missing. How do I get the context for my view?

Or am I going about this in all the wrong ways?


Solution

  • You could leave your drawing code in ‑drawRect: and then in your MyDisplayLinkCallback() set an ivar to the current time and call ‑display on your view. This will force your view to immediately redraw itself.

    In your ‑drawRect: method, just use the value of the time ivar to do whatever drawing is necessary to update the view appropriately for the current animation frame.