Fullscreen GL with Save Panel on top

Sage
Posts: 1,403
Joined: 2005.07
Post: #1
How do I make a full screen opengl context and then open a save panel over it?

I can do a fullscreen context, just displaying a save panel over that does not work.

Sir, e^iπ + 1 = 0, hence God exists; reply!
Quote this message in a reply
Moderator
Posts: 1,560
Joined: 2003.10
Post: #2
I did this for memset 0x801. It took a bit of trickery, and you'll want to be aware that due to the way you have to do it, your full screen performance will be slower than it would be otherwise, but as long as you don't mind that, it's quite doable.

Rather than creating a full-screen NSOpenGLContext and using setFullScreen on it, what I did was create a borderless NSWindow the size of the display I was putting into full-screen mode, allocated an NSOpenGLView and added it to it, and attached the NSOpenGLContext to that. You can then set the full-screen window's level to CGShieldingWindowLevel(), and display it while you have the display captured. Set the save panel's level to also be at CGShieldingWindowLevel(), and it's visible on top of the full-screen window.

Here's code:

Code:
@interface MyOpenGLView : NSOpenGLView {
  NSOpenGLContext * fullScreenContext;
  NSWindow * fullScreenWindow;
  BOOL fullScreen;
}

...

@interface FullScreenWindow : NSWindow {}
@end
@implementation FullScreenWindow
- (BOOL) canBecomeKeyWindow { return YES; }
@end

...

#define FADE_INTERVAL 0.2

- (id) initWithFrame: (NSRect) frame {
  NSOpenGLPixelFormat * pixelFormat;
  NSOpenGLPixelFormatAttribute attributes[] = {NSOpenGLPFAWindow,
                                               NSOpenGLPFADoubleBuffer,
                                               NSOpenGLPFAColorSize, 32,
                                               NSOpenGLPFADepthSize, 32,
                                               NSOpenGLPFANoRecovery,
                                               NSOpenGLPFASingleRenderer,
                                               NSOpenGLPFAScreenMask,
                                               CGDisplayIDToOpenGLDisplayMask(kCGDirectMainDisplay),
                                               0};
  long sync = 1;
  NSOpenGLView * fullScreenView;
  
  pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes: attributes];
  self = [super initWithFrame: frame pixelFormat: pixelFormat];
  fullScreenContext = [[NSOpenGLContext alloc] initWithFormat: pixelFormat shareContext: [self openGLContext]];
  [fullScreenContext setValues: &sync forParameter: NSOpenGLCPSwapInterval];
  
  fullScreenWindow = [[FullScreenWindow alloc] initWithContentRect: [[[self window] screen] frame]
                                                         styleMask: NSBorderlessWindowMask
                                                           backing: NSBackingStoreNonretained
                                                             defer: NO];
  [fullScreenWindow setLevel: CGShieldingWindowLevel()];
  fullScreenView = [[NSOpenGLView alloc] initWithFrame: [fullScreenWindow frame]];
  [fullScreenView setPixelFormat: pixelFormat];
  [fullScreenView setOpenGLContext: fullScreenContext];
  [fullScreenWindow setContentView: fullScreenView];
  [fullScreenWindow setAcceptsMouseMovedEvents: YES];
  
  [pixelFormat release];
  
  fullScreen = NO;
  
  return self;
}

- (void) dealloc {
  [fullScreenWindow release];
  [fullScreenContext release];
  
  [super dealloc];
}

- (void) toggleFullScreen {
  CGError error;
  CGDisplayFadeReservationToken token;
  
  [controller suspend];
  
  error = CGAcquireDisplayFadeReservation(kCGMaxDisplayReservationInterval, &token);
  if (error == kCGErrorSuccess) {
    CGDisplayFade(token, FADE_INTERVAL, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, 1);
  }
  
  if (fullScreen) {
    error = CGDisplayRelease((CGDirectDisplayID) [[[[fullScreenWindow screen] deviceDescription] objectForKey: @"NSScreenNumber"] longValue]);
    
    fullScreen = NO;
    [fullScreenWindow setFrame: NSMakeRect(0, 0, 0, 0) display: YES];
    [[self window] makeKeyAndOrderFront: self];
    [fullScreenWindow orderOut: self];
    [fullScreenContext clearDrawable];
    [[self openGLContext] setView: self];
    [[self openGLContext] makeCurrentContext];
    [self setUpOpenGL];
  } else {
    error = CGDisplayCapture((CGDirectDisplayID) [[[[[self window] screen] deviceDescription] objectForKey: @"NSScreenNumber"] longValue]);
    
    fullScreen = YES;
    [fullScreenWindow makeKeyAndOrderFront: self];
    [[self window] orderOut: self];
    [[self openGLContext] clearDrawable];
    [fullScreenWindow setFrame: [[[self window] screen] frame] display: YES];
    [fullScreenContext setView: [fullScreenWindow contentView]];
    [fullScreenContext makeCurrentContext];
    [self setUpOpenGL];
  }
  
  if (error == kCGErrorSuccess) {
    CGDisplayFade(token, FADE_INTERVAL, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, 0);
    CGReleaseDisplayFadeReservation(token);
  }
  
  [controller resume];
}

- (void) drawScene {
  // Draw stuff...
  
  if (fullScreen) {
    glFinish();
    [fullScreenContext flushBuffer];
  } else {
    [[self openGLContext] flushBuffer];
  }
}

- (void) drawRect: (NSRect) rect {
  static BOOL first = YES;
  
  if (first) {
    // Set up stuff...
    first = NO;
  }
  [self drawScene];
}

- (void) setNeedsDisplay: (BOOL) needsDisplay {
  if (fullScreen) {
    if (needsDisplay) [self drawScene];
  } else {
    [super setNeedsDisplay: needsDisplay];
  }
}

Then, to make the save panel visible on top of it, simply:

Code:
[savePanel setLevel: CGShieldingWindowLevel()];

I hope I included all the relevant code. Let me know if I forgot anything.
Quote this message in a reply
Sage
Posts: 1,403
Joined: 2005.07
Post: #3
Thanks very much, im sure I can get it running from your description.
Just out of intrest do you have any sort of figures related to what the difference in speed is?

Sir, e^iπ + 1 = 0, hence God exists; reply!
Quote this message in a reply
Moderator
Posts: 1,560
Joined: 2003.10
Post: #4
I don't have actual figures, but here's a test application: http://www.sacredsoftware.net/temp/FullS...edTest.tgz

Random geometry (1000 triangles in immediate mode) is drawn as fast as possible. Command-1 toggles in and out of borderless-window-at-CGShieldingWindowLevel full-screen mode. Command-2 toggles in and out of setFullScreen full-screen mode. FPS is printed to stdout at 1-second intervals.

On the computers I tested it on, some were as fast in mode 1 as in mode 2, and some were as much as... maybe 1.5 times as fast in mode 2 (having trouble remembering). If anyone wants to help try this out on a bunch of different graphics hardware so I/we could get some hard data, that would be great!
Quote this message in a reply
Sage
Posts: 1,403
Joined: 2005.07
Post: #5
on a mac pro I get 66 fps for fullscreen1 and 70 fps for fullscreen2

Sir, e^iπ + 1 = 0, hence God exists; reply!
Quote this message in a reply
Oldtimer
Posts: 834
Joined: 2002.09
Post: #6
The sneaky way to do it would be to run in "true" fullscreen until you need to bring out the save panel. Then just clear the screen to black, fade to gamma quickly, and put a windowed fullscreen up and then display it. Then reverse.
Quote this message in a reply
Moderator
Posts: 1,560
Joined: 2003.10
Post: #7
For future projects where I actually need the additional speed from setFullScreen, I'll probably see if I can find a way to do something like that... I suspect that it would be nearly as jarring as switching to windowed, though, so maybe not worth the effort. Perhaps with a bit of trickery, you could somehow switch without even having to fade to black. I'll have to look into it.
Quote this message in a reply
Member
Posts: 87
Joined: 2006.08
Post: #8
Turn on blending, and the performance differences should grow much larger.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Creating directories for save games xiotex 3 2,849 Sep 18, 2010 01:46 AM
Last Post: xiotex
  Open/Save As versus Import/Export? WhatMeWorry 1 3,367 Jan 15, 2006 09:33 PM
Last Post: OneSadCookie