I've been trying to make a scene with OpenGL in Objective-C for weeks, and I just can't seem to get it to work. I started with Drawing to an NSOpenGLView Class: A Tutorial, and that worked fine for me, and I was even able to expand it a little, but the the OpenGL Programming Guide leaves a sort of hole after that step. They explain the details of how to double buffer and synchronize refresh rates and all of that, but they don't provide any actual examples of how to update your view. So currently I can draw lots of cool stuff to the screen, but once it's there it's just a static image. No moving, no spinning.
Does anyone know of a good, simple example of how this is actually done?
3 Answers
You could try using a display link for repeated drawing synchronized with the display. Set one up:
GLint swapInt = 1;
[yourContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
CVDisplayLinkCreateWithActiveCGDisplays(&displayLink);
CVDisplayLinkSetOutputCallback(displayLink, &displayLinkCallback, self);
CGLContextObj cglContext = [yourContext CGLContextObj];
CGLPixelFormatObj cglPixelFormat = [[NSOpenGLView defaultPixelFormat] CGLPixelFormatObj];
CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, cglContext, cglPixelFormat);
CVDisplayLinkStart(displayLink);
Then, your callback runs once per frame:
static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext)
{
NSAutoreleasePool* pool = [NSAutoreleasePool new];
if ([self lockFocusIfCanDraw])
{
//Your drawing code
[self unlockFocus];
}
[pool drain];
return kCVReturnSuccess;
}
5 Comments
[IRGL gl] returns an NSOpenGLContext (or subclass thereof), should I just ignore that part?.m file rather than a .c, so that the compiler knows you're using Objective-C.This is a problem I frequently encounter, and it surprises me that this crucial step isn't part of the NSOpenGLView tutorial documentation.
You need to set up a callback timer to notify the view that it needs to be redrawn:
- (void)awakeFromNib
{
NSTimer *updateTimer = [NSTimer timerWithTimeInterval:1.0f/30.0f target:self selector:@selector(idle:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:updateTimer forMode:NSDefaultRunLoopMode];
}
Notice that this happens in awakeFromNib.
The timer will fire off at an interval of 1/30, which you can change if you like.
Each time it fires, it calls a function named idle. This function can be implemented like so:
- (void)idle:(NSTimer*)timer
{
[self setNeedsDisplay:YES];
}
This causes the view to redraw itself every update, including your OpenGL graphics.
1 Comment
That's a very general question and how to finally design the whole structure of a rendering engine is up to you. It would be a lot a lot to tell you how to implement that, but there are loads of books and tutorials online to get startet.
A quite nice serious on how to slowly create a simple structure suitable for games (in this case 2D) can be found here, but it's for Win32, so you would need to adapt that, but assuming you have a general understanding of programming, you should be able to understand the general design he is building up.