SFML logo
  • Main Page
  • Namespaces
  • Classes
  • Files
  • File List

GLKit.mm

00001 
00002 //
00003 // SFML - Simple and Fast Multimedia Library
00004 // Copyright (C) 2007-2009 Lucas Soltic (ceylow@gmail.com) and Laurent Gomila (laurent.gom@gmail.com)
00005 //
00006 // This software is provided 'as-is', without any express or implied warranty.
00007 // In no event will the authors be held liable for any damages arising from the use of this software.
00008 //
00009 // Permission is granted to anyone to use this software for any purpose,
00010 // including commercial applications, and to alter it and redistribute it freely,
00011 // subject to the following restrictions:
00012 //
00013 // 1. The origin of this software must not be misrepresented;
00014 //    you must not claim that you wrote the original software.
00015 //    If you use this software in a product, an acknowledgment
00016 //    in the product documentation would be appreciated but is not required.
00017 //
00018 // 2. Altered source versions must be plainly marked as such,
00019 //    and must not be misrepresented as being the original software.
00020 //
00021 // 3. This notice may not be removed or altered from any source distribution.
00022 //
00024 
00026 // Headers
00028 #import <SFML/Window/Cocoa/GLKit.h>
00029 #import <SFML/Window/Cocoa/AppController.h>
00030 #import <SFML/Window/VideoMode.hpp>
00031 #import <SFML/Window/WindowStyle.hpp>
00032 #import <SFML/System/Sleep.hpp>
00033 #import <OpenGL/gl.h>
00034 #import <iostream>
00035 
00036 
00040 @implementation GLContext
00041 
00042 static GLContext *sharedCtx = nil;
00043 
00047 + (id)sharedContext
00048 {
00049     if (sharedCtx == nil)
00050     {
00051         // Make a new context with the default parameters
00052         sf::WindowSettings params(0, 0, 0);
00053         sharedCtx = [[GLContext alloc] initWithAttributes:params sharedContext:nil];
00054     }
00055     
00056     return sharedCtx;
00057 }
00058 
00059 - (void)dealloc
00060 {
00061     [mySharedContext release];
00062     [super dealloc];
00063 }
00064 
00069 - (id)initWithAttributes:(sf::WindowSettings&)attribs sharedContext:(GLContext *)context
00070 {
00071     // Note about antialiasing and other context attributes :
00072     // OpenGL context sharing does not allow the shared contexts to use different attributes.
00073     // The point is that the default shared global OpenGL context uses default parameters.
00074     // That means that all the other context *should* use the same paramaters.
00075     // Fortunately some values parameters for some parameters are compatible, but some are not
00076     // among which : the antialising level.
00077     //
00078     // I've no way to fix this for now.
00079     
00080     if (attribs.AntialiasingLevel)
00081         std::cerr << "Warning: antialiasing settings are inhibited under Mac OS X for technical reasons" << std::endl;
00082     
00083     NSOpenGLPixelFormat *myPixelFormat = nil;
00084     unsigned idx = 0;
00085     
00086     // Attributes list
00087     NSOpenGLPixelFormatAttribute ctxtAttribs[15] = {(NSOpenGLPixelFormatAttribute) 0};
00088     
00089     // Accelerated, double buffered
00090     ctxtAttribs[idx++] = NSOpenGLPFAClosestPolicy;
00091     ctxtAttribs[idx++] = NSOpenGLPFADoubleBuffer;
00092     ctxtAttribs[idx++] = NSOpenGLPFAAccelerated;
00093     
00094     // windowed context (even fullscreen mode uses a window)
00095     ctxtAttribs[idx++] = NSOpenGLPFAWindow;
00096     
00097     // Color size ; usually 32 bits per pixel
00098     ctxtAttribs[idx++] = NSOpenGLPFAColorSize;
00099     ctxtAttribs[idx++] = (NSOpenGLPixelFormatAttribute) sf::VideoMode::GetDesktopMode().BitsPerPixel;
00100     
00101     // Z-buffer size
00102     ctxtAttribs[idx++] = NSOpenGLPFADepthSize;
00103     ctxtAttribs[idx++] = (NSOpenGLPixelFormatAttribute) attribs.DepthBits;
00104     
00105     // Stencil bits (I don't really know what's that...)
00106     ctxtAttribs[idx++] = NSOpenGLPFAStencilSize;
00107     ctxtAttribs[idx++] = (NSOpenGLPixelFormatAttribute) attribs.StencilBits;
00108     
00109     myPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:ctxtAttribs];
00110     
00111     if (myPixelFormat) {
00112         self = [super initWithFormat:myPixelFormat
00113                                     shareContext:context];
00114         
00115         mySharedContext = [context retain];
00116         
00117         // Get the effective properties from our OpenGL context
00118         GLint tmpDepthSize = 0, tmpStencilBits = 0, tmpAntialiasingLevel = 0;
00119         
00120         if (self) {
00121             [myPixelFormat getValues:&tmpDepthSize
00122                     forAttribute:NSOpenGLPFADepthSize
00123                 forVirtualScreen:[self currentVirtualScreen]];
00124             
00125             [myPixelFormat getValues:&tmpStencilBits
00126                     forAttribute:NSOpenGLPFAStencilSize
00127                 forVirtualScreen:[self currentVirtualScreen]];
00128             
00129             [myPixelFormat getValues:&tmpAntialiasingLevel
00130                     forAttribute:NSOpenGLPFASamples
00131                 forVirtualScreen:[self currentVirtualScreen]];
00132         }
00133         
00134         
00135         attribs.DepthBits = (unsigned) tmpDepthSize;
00136         attribs.StencilBits = (unsigned) tmpStencilBits;
00137         attribs.AntialiasingLevel = (unsigned) tmpAntialiasingLevel;
00138         
00139         [myPixelFormat release];
00140     }
00141     
00142     return self;
00143 }
00144 
00145 @end
00146 
00147 
00151 @implementation GLView
00152 
00159 - (id)initWithFrame:(NSRect)frame
00160                mode:(const sf::VideoMode&)mode
00161            settings:(sf::WindowSettings&)settings
00162            delegate:(sf::priv::WindowImplCocoa *)delegate
00163 {
00164     assert(delegate != NULL);
00165     
00166     // make the view
00167     self = [super initWithFrame:frame pixelFormat:nil];
00168     
00169     if (self)
00170     {
00171         // enabled auto-resizing
00172         [self setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
00173         
00174         // make the OpenGL context
00175         myGLContext = [[GLContext alloc] initWithAttributes:settings sharedContext:sharedCtx];
00176         
00177         // We need to update the OpenGL view when it's resized
00178         NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
00179         [nc addObserver:self
00180                selector:@selector(viewFrameDidChange:)
00181                    name:NSViewFrameDidChangeNotification
00182                  object:self];
00183         
00184         // Save the delegate
00185         myDelegate = delegate;
00186     }
00187     
00188     return self;
00189 }
00190 
00191 
00195 - (void)dealloc
00196 {
00197     // Remove the observer and release the OpenGL context
00198     [[NSNotificationCenter defaultCenter] removeObserver:self];
00199     [myGLContext release];
00200     
00201     [super dealloc];
00202 }
00203 
00204 
00208 - (void)finishInitialization
00209 {
00210     assert([self superview] != nil);
00211     assert(myGLContext != nil);
00212     
00213     // Attach the OpenGL context to our view
00214     [self clearGLContext];
00215     [self setOpenGLContext:myGLContext];
00216     [myGLContext setView:self];
00217     
00218     // Make our view the first responder
00219     [[self window] makeFirstResponder:self];
00220 }
00221 
00222 
00226 - (void)enableVerticalSync:(bool)flag
00227 {
00228     GLint enable = (flag) ? 1 : 0;
00229     [[self openGLContext] setValues:&enable forParameter:NSOpenGLCPSwapInterval];
00230 }
00231 
00232 
00236 - (void)setActive:(bool)flag
00237 {
00238     if (flag) {
00239         if ([NSOpenGLContext currentContext] != [self openGLContext])
00240             [[self openGLContext] makeCurrentContext];
00241     } else {
00242         if ([NSOpenGLContext currentContext] == [self openGLContext])
00243             [NSOpenGLContext clearCurrentContext];
00244     }
00245 }
00246 
00247 
00251 - (void)flushBuffer
00252 {
00253     [[self openGLContext] flushBuffer];
00254 }
00255 
00256 
00260 - (void)pushEvent:(sf::Event)sfEvent
00261 {
00262     assert(myDelegate != NULL);
00263     myDelegate->HandleNotifiedEvent(sfEvent);
00264 }
00265 
00266 
00270 - (void)viewFrameDidChange:(NSNotification *)notification
00271 {
00272     [self update];
00273     
00274     sf::Event ev;
00275     ev.Type = sf::Event::Resized;
00276     ev.Size.Width = (unsigned) [self frame].size.width;
00277     ev.Size.Height = (unsigned) [self frame].size.height;
00278     
00279     [self pushEvent:ev];
00280 }
00281 
00282 
00286 - (void)keyDown:(NSEvent *)theEvent
00287 {
00288     assert(myDelegate != NULL);
00289     
00290     NSText *field = [[self window] fieldEditor:YES forObject:nil];
00291     [field interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
00292     [field setString:@""];
00293     
00294     myDelegate->HandleKeyDown(theEvent);
00295 }
00296 
00297 
00301 - (void)keyUp:(NSEvent *)theEvent
00302 {
00303     assert(myDelegate != NULL);
00304     myDelegate->HandleKeyUp(theEvent);
00305 }
00306 
00307 
00311 - (void)flagsChanged:(NSEvent *)theEvent
00312 {
00313     assert(myDelegate != NULL);
00314     myDelegate->HandleModifierKey(theEvent);
00315 }
00316 
00317 
00321 - (void)scrollWheel:(NSEvent *)theEvent
00322 {
00323     assert(myDelegate != NULL);
00324     myDelegate->HandleMouseWheel(theEvent);
00325 }
00326 
00327 
00331 - (void)mouseDown:(NSEvent *)theEvent
00332 {
00333     assert(myDelegate != NULL);
00334     myDelegate->HandleMouseDown(theEvent);
00335 }
00336 
00337 
00341 - (void)rightMouseDown:(NSEvent *)theEvent
00342 {
00343     assert(myDelegate != NULL);
00344     myDelegate->HandleMouseDown(theEvent);
00345 }
00346 
00347 
00351 - (void)mouseUp:(NSEvent *)theEvent
00352 {
00353     assert(myDelegate != NULL);
00354     myDelegate->HandleMouseUp(theEvent);
00355 }
00356 
00357 
00361 - (void)rightMouseUp:(NSEvent *)theEvent
00362 {
00363     assert(myDelegate != NULL);
00364     myDelegate->HandleMouseUp(theEvent);
00365 }
00366 
00367 
00371 - (void)mouseMoved:(NSEvent *)theEvent
00372 {
00373     assert(myDelegate != NULL);
00374     myDelegate->HandleMouseMove(theEvent);
00375 }
00376 
00380 - (void)mouseDragged:(NSEvent *)theEvent
00381 {
00382     assert(myDelegate != NULL);
00383     myDelegate->HandleMouseMove(theEvent);
00384 }
00385 
00389 - (void)rightMouseDragged:(NSEvent *)theEvent
00390 {
00391     assert(myDelegate != NULL);
00392     myDelegate->HandleMouseMove(theEvent);
00393 }
00394 
00395 
00399 - (BOOL)acceptsFirstResponder
00400 {
00401     return YES;
00402 }
00403 
00404 
00408 - (BOOL)canBecomeKeyView
00409 {
00410     return YES;
00411 }
00412 
00413 @end
00414 
00415 
00420 @implementation GLWindow
00421 
00422 - (BOOL)canBecomeKeyWindow
00423 {
00424     return YES;
00425 }
00426 
00427 - (BOOL)canBecomeMainWindow
00428 {
00429     return YES;
00430 }
00431 
00432 @end
00433 
00434 
00438 @implementation WindowWrapper
00439 
00445 - (id)initWithSettings:(sf::WindowSettings&)params
00446              videoMode:(sf::VideoMode&)mode
00447                  style:(unsigned long)style
00448                  title:(NSString *)title
00449               delegate:(sf::priv::WindowImplCocoa *)delegate
00450 {
00451     return [self initWithWindow:nil
00452                        settings:params
00453                       videoMode:mode
00454                           style:style
00455                           title:title
00456                        delegate:delegate];
00457 }
00458 
00459 
00466 - (id)initWithWindow:(NSWindow *)window
00467             settings:(sf::WindowSettings&)params
00468             delegate:(sf::priv::WindowImplCocoa *)delegate
00469 {
00470     sf::VideoMode mode([[myWindow contentView] frame].size.width, [[myWindow contentView] frame].size.height);
00471     return [self initWithWindow:window
00472                        settings:params
00473                       videoMode:mode
00474                           style:0
00475                           title:nil
00476                        delegate:delegate];
00477 }
00478 
00479 
00487 - (id)initWithWindow:(NSWindow *)window
00488             settings:(sf::WindowSettings&)params
00489            videoMode:(sf::VideoMode&)mode
00490                style:(unsigned long)style
00491                title:(NSString *)title
00492             delegate:(sf::priv::WindowImplCocoa *)delegate
00493 {
00494     assert(delegate != NULL);
00495     
00496     self = [super init];
00497     
00498     if (self)
00499     {
00500         if (window) {
00501             myWindow = (GLWindow *)[window retain];
00502         } else {
00503             assert(title != nil);
00504             
00505             NSRect frame = NSMakeRect (0.0f, 0.0f, (float) mode.Width, (float) mode.Height);
00506             unsigned int mask = 0;
00507             
00508             if (style & sf::Style::Fullscreen) {
00509                 myIsFullscreen = true;
00510                 
00511                 // Check display mode and put new values in 'mode' if needed
00512                 boolean_t exact = true;
00513                 
00514                 CFDictionaryRef properties = CGDisplayBestModeForParameters(kCGDirectMainDisplay, mode.BitsPerPixel,
00515                                                                             mode.Width, mode.Height, &exact);
00516                 
00517                 if (!properties) {
00518                     std::cerr << "Unable to get a display mode with the given parameters" << std::endl;
00519                     [self autorelease];
00520                     return nil;
00521                 }
00522                 
00523                 if (exact == false) {
00524                     CFNumberGetValue((CFNumberRef) CFDictionaryGetValue(properties, kCGDisplayWidth),
00525                                      kCFNumberIntType, &mode.Width);
00526                     
00527                     CFNumberGetValue((CFNumberRef) CFDictionaryGetValue(properties, kCGDisplayHeight),
00528                                      kCFNumberIntType, &mode.Height);
00529                     
00530                     CFNumberGetValue((CFNumberRef) CFDictionaryGetValue(properties, kCGDisplayBitsPerPixel),
00531                                      kCFNumberIntType, &mode.BitsPerPixel);
00532                     
00533                 }
00534             }
00535             
00536             // We grab options from WindowStyle and add them to our window mask
00537             if (style & sf::Style::None || style & sf::Style::Fullscreen) {
00538                 mask |= NSBorderlessWindowMask;
00539                 
00540                 
00541                 
00542             } else {
00543                 if (style & sf::Style::Titlebar) {
00544                     mask |= NSTitledWindowMask;
00545                     mask |= NSMiniaturizableWindowMask;
00546                 }
00547                 
00548                 if (style & sf::Style::Resize) {
00549                     mask |= NSTitledWindowMask;
00550                     mask |= NSMiniaturizableWindowMask;
00551                     mask |= NSResizableWindowMask;
00552                 }
00553                 
00554                 if (style & sf::Style::Close) {
00555                     mask |= NSTitledWindowMask;
00556                     mask |= NSClosableWindowMask;
00557                     mask |= NSMiniaturizableWindowMask;
00558                 }
00559             }
00560             
00561             // Now we make the window with the values we got
00562             // Note: defer flag set to NO to be able to use OpenGL in our window
00563             myWindow = [[GLWindow alloc] initWithContentRect:frame
00564                                                    styleMask:mask
00565                                                      backing:NSBackingStoreBuffered
00566                                                        defer:NO];
00567             
00568             if (myWindow) {
00569                 // We set title and window position
00570                 [myWindow setTitle:title];
00571                 [myWindow center];
00572             } else {
00573                 std::cerr << "Unable to create the Cocoa window" << std::endl;
00574                 [self autorelease];
00575                 return nil;
00576             }
00577         }
00578         
00579         // Make the OpenGL view
00580         myView = [[GLView alloc] initWithFrame:[[myWindow contentView] frame]
00581                                           mode:mode
00582                                       settings:params
00583                                       delegate:delegate];
00584         
00585         if (myView) {
00586             // Finish setting up the view and window
00587             // Add the view to our window and tell it to the view
00588             [[myWindow contentView] addSubview:myView];
00589             [myView finishInitialization];
00590             
00591             NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
00592             
00593             // We want to know when our window got the focus
00594             [nc addObserver:self
00595                    selector:@selector(windowDidBecomeMain:)
00596                        name:NSWindowDidBecomeMainNotification
00597                      object:myWindow];
00598             
00599             // We want to know when our window lost the focus
00600             [nc addObserver:self
00601                    selector:@selector(windowDidResignMain:)
00602                        name:NSWindowDidResignMainNotification
00603                      object:myWindow];
00604             
00605             // We want to know when the user closes the window
00606             [nc addObserver:self
00607                    selector:@selector(windowWillClose:)
00608                        name:NSWindowWillCloseNotification
00609                      object:myWindow];
00610             
00611             // I want to re-center the window if it's a full screen one and moved by Spaces
00612             [nc addObserver:self
00613                    selector:@selector(windowDidMove:)
00614                        name:NSWindowDidMoveNotification
00615                      object:myWindow];
00616             
00617             // Needed not to make application crash when releasing the window in our destructor
00618             // (I prefer to take control of everything :P)
00619             [myWindow setReleasedWhenClosed:NO];
00620             [myWindow setAcceptsMouseMovedEvents:YES];
00621             
00622         } else {
00623             std::cerr << "Unable to create the OpenGL view" << std::endl;
00624             [self autorelease];
00625             return nil;
00626         }
00627         
00628         if (myIsFullscreen) {
00629             myFullscreenMode = mode;
00630             
00631             // Using this because full screen window was not always
00632             // in front of the other application windows when unhiding app
00633             [myWindow setLevel:NSFloatingWindowLevel];
00634         }
00635     }
00636     
00637     return self;
00638 }
00639 
00640 
00644 - (void)dealloc
00645 {
00646     
00647     // Remove the notification observer
00648     [[NSNotificationCenter defaultCenter] removeObserver:self];
00649     
00650     // Close the window
00651     [self show:false];
00652     
00653     // Release the window and view
00654     [myView release];
00655     [myWindow release];
00656     
00657     [super dealloc];
00658 }
00659 
00660 
00664 - (NSWindow *)window
00665 {
00666     return myWindow;
00667 }
00668 
00669 
00673 - (GLView *)glView
00674 {
00675     return myView;
00676 }
00677 
00678 
00682 - (void)setPosition:(NSPoint)pos
00683 {
00684     assert(myWindow != nil);
00685     
00686     if (!myIsFullscreen) {
00687         // Flip Y and set window position
00688         pos.y = [[myWindow screen] frame].size.height - pos.y;
00689         [myWindow setFrameTopLeftPoint:pos];
00690     }
00691 }
00692 
00693 
00697 - (void)setSize:(NSSize)size
00698 {
00699     assert(myWindow != nil);
00700     
00701     if (!myIsFullscreen) {
00702         [myWindow setFrame:NSMakeRect([myWindow frame].origin.x,
00703                                       [myWindow frame].origin.y,
00704                                       size.width, size.height)
00705                    display:YES];
00706     }
00707 }
00708 
00709 
00713 - (NSPoint)mouseLocation
00714 {
00715     assert(myWindow != nil);
00716     
00717     NSPoint relativeLocation = [myWindow convertScreenToBase:[NSEvent mouseLocation]];
00718     relativeLocation.y = [[self glView] frame].size.height - relativeLocation.y;
00719     return relativeLocation;
00720 }
00721 
00722 
00726 - (BOOL)mouseInside
00727 {
00728     assert(myWindow != nil);
00729     assert(myView != nil);
00730     
00731     BOOL flag = NO;
00732     
00733     if ([myWindow isVisible]) {
00734         NSPoint relativeToWindow = [myWindow mouseLocationOutsideOfEventStream];
00735         NSPoint relativeToView = [myView convertPoint:relativeToWindow fromView:nil];
00736         
00737         if (NSPointInRect (relativeToView, [myView bounds]))
00738         {
00739             flag = YES;
00740         }
00741     }
00742     
00743     return flag;
00744 }
00745 
00746 
00750 - (void)show:(bool)flag
00751 {
00752     assert(myWindow != nil);
00753     
00754     if (flag && ![myWindow isVisible]) {
00755         // Wanna open the closed window
00756         
00757         if (myIsFullscreen) {
00758             [SharedAppController setFullscreenWindow:self mode:&myFullscreenMode];
00759         } else {
00760             // Show the window
00761             [myWindow makeKeyAndOrderFront:nil];
00762         }
00763     } else if (!flag && [myWindow isVisible]) {
00764         // Wanna close the opened window
00765         
00766         if (myIsFullscreen) {
00767             [SharedAppController setFullscreenWindow:nil mode:NULL];
00768         } else {
00769             // Close the window
00770             [myWindow close];
00771         }
00772     }   
00773 }
00774 
00775 
00779 - (void)enableVerticalSync:(bool)flag
00780 {
00781     assert(myView != nil);
00782     [myView enableVerticalSync:flag];
00783 }
00784 
00785 
00789 - (void)setActive:(bool)flag
00790 {
00791     assert(myView != nil);
00792     [myView setActive:flag];
00793 }
00794 
00795 
00799 - (void)flushBuffer
00800 {
00801     assert(myView != nil);
00802     [myView flushBuffer];
00803 }
00804 
00805 
00809 - (void)windowDidBecomeMain:(NSNotification *)notification
00810 {
00811     sf::Event ev;
00812     ev.Type = sf::Event::GainedFocus;
00813     
00814     [myView pushEvent:ev];
00815 }
00816 
00817 
00821 - (void)windowDidResignMain:(NSNotification *)notification
00822 {
00823     sf::Event ev;
00824     ev.Type = sf::Event::LostFocus;
00825     
00826     [myView pushEvent:ev];
00827 }
00828 
00829 
00833 - (void)windowWillClose:(NSNotification *)notification
00834 {
00835     sf::Event ev;
00836     ev.Type = sf::Event::Closed;
00837     
00838     [myView pushEvent:ev];
00839 }
00840 
00841 
00845 - (void)windowDidMove:(NSNotification *)notification
00846 {
00847     NSWindow *sender = [notification object];
00848     
00849     if (!([sender styleMask] & NSTitledWindowMask))
00850         [sender center];
00851 }
00852 
00853 @end
00854 

 ::  Copyright © 2007-2008 Laurent Gomila, all rights reserved  ::  Documentation generated by doxygen 1.5.2  ::