Xcode с OpenGL: новые окна автоматически не становятся активным контекстом
У меня странная проблема, когда я создаю проект на основе документов XCode с NSOpenGLView. Приложение отлично работает с одним документом, реагируя на щелчки мышью. Когда вы выбираете Файл / Новый, чтобы открыть второй документ, в верхней части появляется новое переднее окно, но щелчки мыши отправляются на предыдущий (фоновый) объект. Вы можете переместить новое окно, и клики по-прежнему отправляются на предыдущий объект. Однако если вы измените размер нового окна или нажмете назад и вперед с предыдущим окном, все будет работать хорошо. Таким образом, проблема заключается в том, что новое (переднее) окно не становится активным контекстом. Можете ли вы предложить решение? Я разместил код Xcode 4.4 (44 КБ) по адресу http://www.mccauslandcenter.sc.edu/CRNL/sw/GLdoc.zip.
- Создать новое приложение на основе документов
- Добавьте файлы MyOpenGLView.m и MyOpenGLView.h в проект
- Для Targets/BuildPhases добавьте OpenGL.framework в "Связать двоичные файлы с библиотеками".
- Для Targets/BuildPhases добавьте MyOpenGLView.m в "Исходники компиляции"
- В конструкторе интерфейса a.) Выберите Окно документа и в инспекторе атрибутов отключите "Один снимок" b.) Добавьте представление OpenGL из библиотеки объектов c.) С помощью инспектора идентификации установите класс вновь созданного NSOpenGLView в MyOpenGLView
- Запустить проект
---- НАЧАТЬ MyOpenGLView.h
#import <Cocoa/Cocoa.h>
#import <GLUT/GLUT.h>
@interface MyOpenGLView : NSOpenGLView
{
NSTimer* timer; //animation timer
NSPoint mouseloc;
NSPoint screenSize;
int hourglassSize;
BOOL updateGL;
}
@end
---- НАЧАТЬ MyOpenGLView.m
// document based OpenGL application inspired by http://www.alecjacobson.com/weblog/?p=2110
#import "MyOpenGLView.h"
@implementation MyOpenGLView
-(void)prepareOpenGL
{
//NSLog(@"preparing");
}
- (void)reshape
{
//NSLog(@"reshaping");
NSRect rectView = [self bounds];
screenSize.x = rectView.size.width;
screenSize.y = rectView.size.height;
}
void enter2D (int width, int height) //Enter2D = reshapeGL
{
glDisable(GL_DEPTH_TEST);
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, width, 0, height,-1,1); //map view to match pixel size, e.g. gluOrtho2D(0, width, 0, height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnable (GL_BLEND); //allow transparent objects
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
void drawTriangle (int sz, int left, int bottom)
{
glLoadIdentity ();
glTranslatef(left,bottom,0.0f);
glBegin(GL_TRIANGLES);
glVertex3f( sz/2, sz, 0.0f);// Top
glVertex3f(0.0,0.0, 0.0); // Bottom Left
glVertex3f( sz,0.0f, 0.0f); // Bottom Right
glEnd(); // Finished Drawing The Triangle
}
void drawHourGlass (int sz, NSPoint center)
{
glLoadIdentity ();
glTranslatef(center.x,center.y,0.0f);
glBegin(GL_TRIANGLES); //lower triangle
glVertex3f( 0.0, 0.0, 0.0f); // Top
glVertex3f(-sz,-sz, 0.0);// Bottom Left
glVertex3f( sz,-sz, 0.0f);// Bottom Right
glEnd();
glBegin(GL_TRIANGLES); //upper triangle
glVertex3f( 0.0, 0.0, 0.0f); // bottom
glVertex3f(-sz,sz, 0.0);// Top Left
glVertex3f( sz,sz, 0.0f);// Top Right
glEnd();
}
-(void)drawRect:(NSRect)rect
{
updateGL = FALSE;
//NSLog(@" %f %f",rect.size.width,rect.size.height);
enter2D(screenSize.x,screenSize.y);
glClearColor(0.8,0.9,1,1); //background - blue sky
glClear(GL_COLOR_BUFFER_BIT);
glColor4f(0.6,0.3,0.1,1.0); //mountains - brown opaque
drawTriangle(100,10,0);
drawTriangle(70,80,0);
glColor4f(0.1,0.1,0.1,0.7); //crosshair - gray, slightly translucent
drawHourGlass (hourglassSize, mouseloc);
glFlush(); // Flush all OpenGL calls
}
- (void)mouseDown:(NSEvent *)event
{
mouseloc = [self convertPoint:[event locationInWindow] fromView:nil];
updateGL = TRUE;
}
int constrain (int size)
{
if (size < 5)
return 5;
else if (size > 50)
return 50;
else
return size;
}
- (void) magnifyWithEvent:(NSEvent *)event;
{
if ([event magnification] > 0)
hourglassSize = hourglassSize + 5;
else
hourglassSize = hourglassSize - 5;
hourglassSize = constrain(hourglassSize);
updateGL = TRUE;
}
- (void)scrollWheel:(NSEvent *)event
{
if (event.deltaY < 0)
hourglassSize = hourglassSize + 5;
if (event.deltaY > 0)
hourglassSize = hourglassSize - 5;
hourglassSize = constrain(hourglassSize);
updateGL = TRUE;
}
- (void)animationTimer:(NSTimer *)timer
{
if (updateGL == TRUE)
[self drawRect:[self bounds]];
}
-(BOOL)acceptsFirstResponder { return YES; }
-(BOOL)becomeFirstResponder { return YES; }
-(BOOL)resignFirstResponder { return YES; }
- (void) awakeFromNib
{
// [[self window] setAcceptsMouseMovedEvents:YES];
mouseloc.x = 30;
mouseloc.y = 40;
hourglassSize = 30;
timer = [NSTimer timerWithTimeInterval:(1.0f/60.0f) target:self selector:@selector(animationTimer:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
// ensure timer fires during resize
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSEventTrackingRunLoopMode];
updateGL = TRUE;
}
@end
1 ответ
Для тех, кто сталкивается с этой проблемой (которая присутствует в некоторых старых демонстрационных версиях, распространяемых Apple), в современных версиях OSX (10.4 и более поздних) вы используете CVDisplayLink вместо таймера для обновления представлений OpenGL.
http://developer.apple.com/library/mac/
Алек Якобсон обрисовывает в общих чертах это решение здесь http://www.alecjacobson.com/weblog/?p=2185