Full-screen with NSOpenGLView not working

forseti
Unregistered
 
Post: #1
Hi,

I posted a help on macosxdev at Omnigroup about my problem but so far haven't received any help. One person also had this problem and suggests just using CGDirectDisplay for the whole procress. Unless NSOpenGLView is not meant to work with full-screen (but there IS a setFullScreen method, and some documentation about it in the OpenGL section of programming topics at Apple's developer site), I'd like to go with NSOpenGLView.

Here's the thread:
http://cocoa.mamasam.com/MACOSXDEV/2002/06/2/37154.php

Thanks for any suggestions / possible solutions!

-forseti
Quote this message in a reply
Jeff Binder
Unregistered
 
Post: #2
NSOpenGLView isn't for full screen. If you're looking for fullscreen OpenGL, then what you should do is just use NSOpenGLContext alone and forget the whole Window/View structure. After calling setFullScreen and makeCurrentContext, any OpenGL calls go to that context, whether there's a view or not.
Quote this message in a reply
wally
Unregistered
 
Post: #3
Check out Omni's GDC 2001 slides, they show how to get the underlying CGContext of the NSOpenGLView so you can check the error code when calling CGSetFullScreen().

http://www.omnigroup.com/developer/gamed...t/gdc2001/

I haven't been able to get this (fullscreen OpenGL) to work for software OpenGL contexts, that may be what your problem is. I kept getting an invalid drawable error when using my Rage Pro card.
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #4
The software renderer doesn't support fullscreen contexts; you have to use a window as big as the screen.
Quote this message in a reply
Feanor
Unregistered
 
Post: #5
It's on my idisk. Download the project called "Light Box". What you might have missed is that "-setFullScreen" is an NSOpenGLContext method, and NSOpenGLView doesn't respond to it.

You have to use Core Graphics calls to capture the screen as well. I learned how to do this thanks to sample code by GoodDoug, but I don't know where he keeps his. -- FÎanor
Quote this message in a reply
forseti
Unregistered
 
Post: #6
Thanks for the example!
The full-screen mode doesn't work as expected though, does it for others?
Maybe it's just the screen positioning problem with my monitor... but I don't have that problem with other programs in 800x600 resolution. Graphics are drawn just fine though.

Anyway, I used bits of code from your example, and I also implemented a drawScene method with the gameWorld object. It works great in windowed mode, but with full-screen, just garbage is drawn and flashes everytime drawScene is called. I've been wondering why it wouldn't work for mine, and for your project it works (at least graphics are drawn properly).

Is it posible to just use CGDirectDisplay for full-screen and get the full-screen context wrapped in NSOpenGLContext? Otherwise I'd have to make 2 separate drawing operations for 2 different types of contexts... and no one would want to do that.

I'll examine it more tommorow and try to get graphics drawn properly for my project...


Here's my code if anyone is willing to help me!

Code:
- (id)initWithFrame:(NSRect)frame
{
    NSOpenGLPixelFormatAttribute windowedAttributes[] =
    {
        NSOpenGLPFADoubleBuffer,
        NSOpenGLPFAAccelerated,
        NSOpenGLPFAColorSize, [[[NSUserDefaults standardUserDefaults] objectForKey:@"colorDepth"] intValue],
        NSOpenGLPFAAlphaSize, 16,
        NSOpenGLPFADepthSize, 16,
        0
    };

    //  Create pixel format from attributes.
    NSOpenGLPixelFormat * windowedPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:windowedAttributes];
    NSAssert(windowedPixelFormat, @"Error: windowedPixelFormat is nil.");
    
    NSLog(@"Setting up main window.");
    
    //  Initialize NSOpenGLView with the pixel format.
    [super initWithFrame:frame pixelFormat:windowedPixelFormat];
    
    //  No longer needed.
    [windowedPixelFormat release];

    //  Initialize our variables.
    isFullScreen = NO;
    
    //  Create the game world and pass the context.
    theWorld = [[VSGameWorld alloc] initWithContext:[self openGLContext]];

    //  Set the current OpenGL context.
    [[self openGLContext] makeCurrentContext];

    //  Prepare OpenGL (viewport setup done in -drawRect:).
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glEnable(GL_DEPTH_TEST);
    
    //  User wants full-screen mode.
    if([[[NSUserDefaults standardUserDefaults] objectForKey:@"displayMode"] isEqualToString:@"fullScreen"])
    {
        NSOpenGLPixelFormatAttribute fullScreenAttributes[] =
        {
            NSOpenGLPFADoubleBuffer,
            NSOpenGLPFAFullScreen,
            NSOpenGLPFAAccelerated,
            NSOpenGLPFAColorSize, [[[NSUserDefaults standardUserDefaults] objectForKey:@"colorDepth"] intValue],
            NSOpenGLPFAAlphaSize, 16,
            NSOpenGLPFADepthSize, 16,
            0
        };
        
        //  Create pixel format from attributes.
        NSOpenGLPixelFormat * fullScreenPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:fullScreenAttributes];
        NSAssert(fullScreenPixelFormat, @"Error: fullScreenPixelFormat is nil.");
        
        NSLog(@"Setting up full-screen context.");
        
        //  Initialize an NSOpenGLContext for full-screen.
        fullScreenContext = [[NSOpenGLContext alloc] initWithFormat:fullScreenPixelFormat shareContext:nil];
        
        //  No longer needed.
        [fullScreenPixelFormat release];
        
        //  Make current.
        [fullScreenContext makeCurrentContext];
        
        //  Prepare OpenGL.
        glClearColor(0.0, 0.0, 0.0, 0.0);
        glEnable(GL_DEPTH_TEST);
        
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        
        glViewport(0, 0, [[[NSUserDefaults standardUserDefaults] objectForKey:@"viewWidth"] intValue],
            [[[NSUserDefaults standardUserDefaults] objectForKey:@"viewHeight"] intValue]);
        
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
        
        //  Use CGDirectDisplay for full-screen.
        {
            CGDisplayErr        err;
            
            [self setupGamma];
            CGDisplayHideCursor(kCGDirectMainDisplay);
            [self fadeOutGamma];
            
            //  Capture display first.
            CGDisplayCapture(kCGDirectMainDisplay);
            
            //  Save previous mode so we know how to restore.
            prevDisplayMode = CGDisplayCurrentMode(kCGDirectMainDisplay);
            
            //  Also save new mode.
            newDisplayMode = CGDisplayBestModeForParameters(kCGDirectMainDisplay, 24,
                [[[NSUserDefaults standardUserDefaults] objectForKey:@"viewWidth"] intValue],
                [[[NSUserDefaults standardUserDefaults] objectForKey:@"viewHeight"] intValue], 0);
            NSAssert(newDisplayMode, @"Error: newDisplayMode is nil.");
            
            err = CGDisplaySwitchToMode(kCGDirectMainDisplay, newDisplayMode);
            NSAssert(err == CGDisplayNoErr, @"Error switching resolution.");
            
            [fullScreenContext makeCurrentContext];
            [fullScreenContext setFullScreen];
            [theWorld setContext:fullScreenContext];
            
            isFullScreen = YES;
            
            [self fadeInGamma];
            CGDisplayShowCursor(kCGDirectMainDisplay);
        }
    }
    
    //  Create a timer and retain it, because we need it running all the time.
    drawTimer = [[NSTimer scheduledTimerWithTimeInterval:kFramePause
        target:self selector:@selector(drawScene) userInfo:nil repeats:YES] retain];
    
    return self;
}

- (void)drawRect:(NSRect)frame
{
    NSLog(@"drawRect called.");
    
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    glViewport(0, 0, frame.size.width, frame.size.height);
    
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

-(void)drawScene
{
    if(isFullScreen == NO)
    {
        [self lockFocus];
        [theWorld drawScene];
        [self unlockFocus];
    }
    else
        [theWorld drawScene];
}
;

And the drawScene in gameWorld:

Code:
- (void)drawScene
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    
    glBegin(GL_QUADS);
    glColor4f(1.0, 0.0, 0.0, 1.0);
    glVertex3f(-0.5, -0.5, 0.0);

    glColor4f(0.0, 1.0, 0.0, 1.0);
    glVertex3f(0.5, -0.5, 0.0);

    glColor4f(0.0, 0.0, 1.0, 1.0);
    glVertex3f(0.5, 0.5, 0.0);

    glColor4f(1.0, 0.0, 1.0, 1.0);
    glVertex3f(-0.5, 0.5, 0.0);
    glEnd();
    
    glRotatef(-0.5, 0.6, -0.6, 0.5);

    // Update the GL context
    [[self worldContext] flushBuffer];
}
Quote this message in a reply
forseti
Unregistered
 
Post: #7
Oh my god... I just tracked down the bug I couldn't figure out for 3 days! I'm so happy.
You could say it's stupid... but I realized that in my code, drawRect was being called AFTER the full-screen context was set up, and after it ENETERED full-screen mode. So I'm assuming drawRect couldn't find it's proper windowed context and messed things up. So I want to enter full-screen mode after drawRect is being called... which means I have to initially draw things on the windowed view. But then if I showed it and entered full-screen right after, my contents would be drawn in the windowed view for just a millisecond and then immediately switch to full-screen, having my contents drawn for the second time. How should I avoid this? Unlike Feanor's example code, I want my app to run full-screen or windowed mode based on preferences, not by user interaction in windowed mode.

Thanks. Smile
Quote this message in a reply
forseti
Unregistered
 
Post: #8
Maybe I should separate the class into two, one for windowed (NSOpenGLView) and one for full-screen (NSObject), and have my delegate control the two. Or call orderOut on the window to hide the windowed drawing before entering full-creen. But if there are any other ideas... it's welcome.
Quote this message in a reply
Feanor
Unregistered
 
Post: #9
If you are using a captured display and a fullscreen context, you can't use NSOpenGLView, as Jeff Binder noted in his post. You don't want to do any fullscreen setup in your view object at all. You would want to do that in a custom object. The view should only manage its own contexts.

In Light Box, the drawable is controlled in a controller object, not the view itself. In the other sample called CocoaFullScreen, the view controls both contexts, because both are used by that view, which gets move back and forth between two windows -- one from the Nib, the other created programmatically. Let me know if this helps clarify things. -- FÎanor
Quote this message in a reply
forseti
Unregistered
 
Post: #10
Thanks,
I thought LightBox attempted to set up both windowed and full-screen in the same NSOpenGLView subclass (athough the drawing was done in the game world object), but if that's wrong, that would probably be why my code is not working... attempting to set up two completely different views in the same class.
I learned how to separate the two using multiple Nibs just now, so this will be the way to go for me.. not to mention just to avoid unnecessary confusion. Smile
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Cocoa/OpenGL drawing full-screen problem ultitech 5 8,018 Jan 13, 2011 01:11 PM
Last Post: SethWillits
  Full screen mouse events Mister T 17 8,293 Jan 4, 2010 02:55 PM
Last Post: MacMan
  Carbon events in windowed/full screen mode. Help needed. Anton Petrov 1 3,540 Dec 18, 2008 05:35 AM
Last Post: DoG
  Full Screen Event Handling kodex 4 4,623 Jun 27, 2008 08:37 PM
Last Post: OneSadCookie
  Full-screen without OpenGL George Marlin 2 2,908 May 11, 2007 01:38 PM
Last Post: George Marlin