问题
So im trying to create an openGL view (in my window). Im making a Cocoa app. Ive managed to create one through Interface Builder, but for educational purposes i want to go on and make one without it. Just on papers.
And here is the point im telling you im struggling with it. So what ive basically done-tried so far is this: I ve created a new class "MyOpenGLView.h/m" inheriting from NSOpenGLView. I ve added no private vars or methods to it just the class name. The only thing i did, was override initWithFrame: (adding a self = [super initWithFrame:pixelFormat:] inside it.) I read about it on the Web that you have to instantiate it with something like this first before you can use it). here is the code:
- (id) initWithFrame:(NSRect)frameRect
{
NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc]
initWithAttributes:(NSOpenGLPixelFormatAttribute[])
{
NSOpenGLPFAWindow,
NSOpenGLPFADoubleBuffer,
NSOpenGLPFADepthSize, 32,
nil
}];
self = [super initWithFrame:frameRect pixelFormat:pixelFormat];
[[self openGLContext] makeCurrentContext];
}
So i have another class named by "MyViewController.h/m" which handles my View? and there i have my MyOpenGLView *myView. In the .m file i go with something like this:
myView = [[MyOpenGLView alloc] initWithFrame:CGRectMake(0,0,100.0,100.0)];
if (!myView) { NSLog(@"ERROR"); }
and of course, i get error.
There is no openGL view ported in my window application. I would guess its something about the hierarchy on methods being called but then again.. im not sure. Can you aid me with it?
回答1:
They way I have gotten this to work is I don't implement an init
method in my view. Then in my controller or app delegate I have.
@implementation AppDelegate
@synthesize window = _window;
@synthesize view = _view;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSRect mainDisplayRect = [[NSScreen mainScreen] frame]; // I'm going to make a full screen view.
NSOpenGLPixelFormatAttribute attr[] = {
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, // Needed if using opengl 3.2 you can comment this line out to use the old version.
NSOpenGLPFAColorSize, 24,
NSOpenGLPFAAlphaSize, 8,
NSOpenGLPFAAccelerated,
NSOpenGLPFADoubleBuffer,
0
};
NSOpenGLPixelFormat *pix = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];
self.view = [[OpenGLViewCoreProfile alloc] initWithFrame:mainDisplayRect pixelFormat:pix];
// Below shows how to make the view fullscreen. But you could just add to the contact view of any window.
self.window = [[NSWindow alloc] initWithContentRect:mainDisplayRect
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:YES];
self.window.opaque = YES;
self.window.hidesOnDeactivate = YES;
self.window.level = NSMainMenuWindowLevel + 1; // Show window above main menu.
self.window.contentView = self.view;
[self.window makeKeyAndOrderFront:self]; // Display window.
}
@end
Can can make call -makeCurrentContext
in your -prepareOpenGl
method. All that I have written below is not necessary but nice for performance reasons. I have started using the CVDisplayLink
to sync frame drawing with the screen refresh rate so my openGLview looks like
// This is the callback function for the display link.
static CVReturn OpenGLViewCoreProfileCallBack(CVDisplayLinkRef displayLink,
const CVTimeStamp* now,
const CVTimeStamp* outputTime,
CVOptionFlags flagsIn,
CVOptionFlags *flagsOut,
void *displayLinkContext) {
@autoreleasepool {
OpenGLViewCoreProfile *view = (__bridge OpenGLViewCoreProfile*)displayLinkContext;
[view.openGLContext makeCurrentContext];
CGLLockContext(view.openGLContext.CGLContextObj); // This is needed because this isn't running on the main thread.
[view drawRect:view.bounds]; // Draw the scene. This doesn't need to be in the drawRect method.
CGLUnlockContext(view.openGLContext.CGLContextObj);
CGLFlushDrawable(view.openGLContext.CGLContextObj); // This does glFlush() for you.
return kCVReturnSuccess;
}
}
- (void)reshape {
[super reshape];
CGLLockContext(self.openGLContext.CGLContextObj);
... // standard opengl reshape stuff goes here.
CGLUnlockContext(self.openGLContext.CGLContextObj);
}
- (void)prepareOpenGL {
[super prepareOpenGL];
[self.openGLContext makeCurrentContext];
GLint swapInt = 1;
[self.openGLContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
CGLLockContext(self.openGLContext.CGLContextObj);
... // all opengl prep goes here
CGLUnlockContext(self.openGLContext.CGLContextObj);
// Below creates the display link and tell it what function to call when it needs to draw a frame.
CVDisplayLinkCreateWithActiveCGDisplays(&_displayLink);
CVDisplayLinkSetOutputCallback(self.displayLink, &OpenGLViewCoreProfileCallBack, (__bridge void *)self);
CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(self.displayLink,
self.openGLContext.CGLContextObj,
self.pixelFormat.CGLPixelFormatObj);
CVDisplayLinkStart(self.displayLink);
}
回答2:
While the answers above give more information about OpenGL the reason for the specific issue you are having is that your initWithFrame method needs to return self.
Without that initWithFrame will always return Nil. (You should also call super's initWithFrame and take the other OpenGL advice).
来源:https://stackoverflow.com/questions/8559493/creating-an-opengl-view-without-interface-builder