bug in OpenGL setup for NSOpenGL subclass (I think)

Member
Posts: 245
Joined: 2005.11
Post: #1
or "I've managed to write a Universal Binary that doesn't work on Intel!"

Having just bought a shiny new MacBook, I decided to try out my pre-pre-alpha game (there's actually no gameplay whatsoever at the moment) on it. Amazingly, it runs, everything initialises and all behaviour is working as it does on my G4 Mac Mini, except that my graphics don't draw unless I cover the window with another app or push it off the side of the screen.
I've subclassed NSOpenGLView and used a Custom View thingy in Interface Builder to plant it in a window. An NSTimer fires off my game loop every 20ms, and the game loop tells the NSOpenGLView subclass to setNeedsDisplay:YES.
I've verified that drawRect is getting called, and there are no OpenGL errors. I've spent many hours scouring Google and trying various plausible solutions, but with no success. I thought it might be something to do with my previous strategy of putting the NSOpenGLView into an NSPanel and setting that to be the content of the NSWindow, but changing that has made no difference. I stripped the project to a version with only the GameController and TNeb_OpenGLView classes and no third party libraries, and the same thing happened, so I think it must be something to do with the way I'm setting up my OpenGL context or the view, but I'm a bit stumped as to what it might be. So I thought maybe a fresh pair of eyes (attached to someone who actually knows what they're doing!) might be able to point the obvious mistake for me.
Here's the relevant bits of TNeb_OpenGLView.m
Code:
static NSOpenGLPixelFormatAttribute MyAttributes[] =
{
    NSOpenGLPFAAccelerated,
    NSOpenGLPFADoubleBuffer,
    NSOpenGLPFAColorSize, 8,
    NSOpenGLPFAAlphaSize, 8,
    NSOpenGLPFADepthSize, 8,
    0
};


@implementation TNeb_OpenGLView

- (id)initWithFrame:(NSRect)frameRect        //this is the init method used on PPC Mac OS X 10.4.9
{
    NSOpenGLPixelFormat* pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:MyAttributes];
    if (pixelFormat == nil)
        {
        NSLog(@"Error in OpenGl pixel format");
        return nil;
        }
    [pixelFormat autorelease];
    
    self = [super initWithFrame:frameRect pixelFormat:pixelFormat];
    if (self == nil)
        {
        NSLog(@"openGl initialisation error in -initWithFrame:");
        return nil;
        }
    
    [ [ self openGLContext ] makeCurrentContext ];
    [self prepareOpenGL];
    
    leftDrag = NO;
    draw3D = NO;
    
    return self;
}


- (void)prepareOpenGL    /* do one-off OpenGL initialization stuff here */
{
    glShadeModel( GL_SMOOTH );                // Enable smooth shading
    glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );            // Black background
    glClearDepth( 1.0f );                    // Depth buffer setup
    glDepthFunc( GL_LESS );                    // Type of depth test to do
    glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );    // Really nice perspective calculations
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
    glEnable( GL_BLEND );
    glDrawBuffer(GL_FRONT);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
}


- (void)reshape
{
    NSLog(@"-reshape");
    bounds = [self bounds];
    
    //set up the 3D matrix
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
        glViewport(0, 0, bounds.size.width, bounds.size.height);
    gluPerspective( 45.0f, bounds.size.width / bounds.size.height, 0.1f, 200.0f );
    
    if (glGetError()) NSLog(@"OpenGL error detected in -reshape");
    glPushMatrix();        // -drawrect: pops it when it wants to do 3D drawing
    
    //setup 2D stuff (it won't be done unless 3D drawing was done previously in the loop)
    glDisable(  GL_DEPTH_TEST );
    glMatrixMode( GL_PROJECTION );
    glPushMatrix();        //save the 3D setup for later
    glLoadIdentity();
    glOrtho(0.0, bounds.size.width, 0.0, bounds.size.height, 0.0, 100.0);
    
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
}


- (BOOL) isOpaque
{
    return YES;
}

/*            RENDERING    FUNCTIONS            */

- (void)drawRect:(NSRect)rect
{
    [ [ self openGLContext ] makeCurrentContext ];
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    //Do the 3D stuff
    if (draw3D)
        {
        glEnable( GL_DEPTH_TEST );
        glMatrixMode( GL_PROJECTION );
        glPopMatrix();
        glPushMatrix();        //save it for next time round
        gluLookAt(    camera.eye.x, camera.eye.y, camera.eye.z,
                    camera.centre.x, camera.centre.y, camera.centre.z,
                    camera.up.x, camera.up.y, camera.up.z );
        
        glMatrixMode( GL_MODELVIEW );
        glLoadIdentity();
        
        objc_msgSend(gameData, gameDataDraw3Dsel);    //this gets the objects to draw themselves in different ways depending on the engine state
    
        if (glGetError()) NSLog(@"OpenGL error detected in -drawRect: after 3D drawing");

    //Do the 2D stuff
        //first reload the 2D setup
        glDisable(  GL_DEPTH_TEST );
        glMatrixMode( GL_PROJECTION );
        glLoadIdentity();
        glOrtho(0.0, bounds.size.width, 0.0, bounds.size.height, 0.0, 100.0);
        
        glMatrixMode( GL_MODELVIEW );
        glLoadIdentity();
        }
    
    [gui drawInterface];    //call to my Interface object which draws all my onscreen controls
    if (glGetError()) NSLog(@"OpenGL error detected in -drawRect: after 2D drawing (gui)");
    
    glFlush();
}
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #2
Replace
glFlush()
with
[[self openGLContext] flushBuffer];

glFlush only flushes the command queue, it does not swap back buffer to the display. Since you have a double buffered context, all of your rendering stays in the back buffer (until you drag a another window on top of yours, then the compositor picks up partially drawn bits.)
Quote this message in a reply
Member
Posts: 245
Joined: 2005.11
Post: #3
Thank you - that's worked great... on the MacBook. The Mac Mini started giving me a window full of garbage after that change. At that point I remember not being able to figure out how to swap the buffers a while back and putting in the line glDrawBuffer(GL_FRONT) as a temporary hack, which I forgot about. I changed it to glDrawBuffer(GL_BACK) and now all is happy on both machines. Does the GMA950 refuse to draw to the front buffer, or something.
I've also just discovered that my Mac Mini has updated to 10.4.10 when I wasn't paying attention, but I doubt that is it.
Anyway, buffering never even occurred to me. You are indeed a genius. Smile
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  OpenGL Pixel Buffer Object setup issue dotbianry 2 3,229 Jan 6, 2013 11:03 AM
Last Post: dotbianry
  OpenGL ES2 matrix setup (humbly crawling back) Fenris 2 6,604 Aug 31, 2011 06:47 AM
Last Post: Fenris
  multiple nsopengl subviews problem NelsonMandella 0 2,232 Nov 9, 2009 09:44 PM
Last Post: NelsonMandella
  When to create custom OpenGL view instead of subclass NSOpenGL view Coyote 37 22,570 Oct 20, 2009 08:16 PM
Last Post: Coyote
  xCode/SDL Setup hammonjj 2 4,786 Mar 2, 2007 06:37 AM
Last Post: hammonjj