Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 610
John Avatar asked Nov 04 '22 19:11

John


1 Answers

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.

like image 196
Rob Keniger Avatar answered Nov 14 '22 09:11

Rob Keniger