Создание представления OpenGL без Interface Builder
Поэтому я пытаюсь создать представление OpenGL (в моем окне). Я делаю приложение Какао. Мне удалось создать его с помощью Interface Builder, но в образовательных целях я хочу продолжить и сделать его без него. Просто на бумагах.
И вот тут-то я и говорю, что борюсь с этим. Итак, что я в основном сделал, попробовал до сих пор: я создал новый класс "MyOpenGLView.h/m", унаследованный от NSOpenGLView. Я не добавил к нему никаких приватных переменных или методов, только имя класса. Единственное, что я сделал, это переопределил initWithFrame: (добавив в него self = [super initWithFrame:pixelFormat:].) Я читал об этом в Интернете, и вам нужно сначала создать что-то подобное, прежде чем вы сможете его использовать), вот код:
- (id) initWithFrame:(NSRect)frameRect
{
NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc]
initWithAttributes:(NSOpenGLPixelFormatAttribute[])
{
NSOpenGLPFAWindow,
NSOpenGLPFADoubleBuffer,
NSOpenGLPFADepthSize, 32,
nil
}];
self = [super initWithFrame:frameRect pixelFormat:pixelFormat];
[[self openGLContext] makeCurrentContext];
}
Итак, у меня есть другой класс с именем "MyViewController.h/m", который обрабатывает мой вид? и там у меня есть MyOpenGLView *myView. В файле.m я иду с чем-то вроде этого:
myView = [[MyOpenGLView alloc] initWithFrame:CGRectMake(0,0,100.0,100.0)];
if (!myView) { NSLog(@"ERROR"); }
и, конечно, я получаю ошибку.
В моем оконном приложении нет портированного представления openGL. Я бы догадался, что это что-то про иерархию вызываемых методов, но опять же... я не уверен. Вы можете помочь мне с этим?
2 ответа
Они так, как я получил это на работу, я не реализую init
метод на мой взгляд. Тогда в моем контроллере или приложении делегата у меня есть.
@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
Могу позвонить -makeCurrentContext
в вашем -prepareOpenGl
метод. Все, что я написал ниже, не обязательно, но хорошо по соображениям производительности. Я начал использовать CVDisplayLink
синхронизировать рисование кадров с частотой обновления экрана, так что мой openGLview выглядит
// 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);
}
Хотя приведенные выше ответы дают больше информации об OpenGL, причина конкретной проблемы заключается в том, что ваш метод initWithFrame должен возвращать self.
Без этого initWithFrame всегда будет возвращать ноль. (Вам также следует вызвать initWithFrame из super и воспользоваться другим советом OpenGL).