/** OpenGL Display for MacOS X by Glenn Fiedler I place this code is in the public domain, please use it however you wish! **/ #ifndef OPENGL_DISPLAY_H #define OPENGL_DISPLAY_H #include #include #include #include #include #ifndef FULLSCREEN #include #endif static pascal OSErr quitEventHandler( const AppleEvent *appleEvt, AppleEvent *reply, SInt32 refcon ) { exit( 0 ); return false; } #define QZ_ESCAPE 0x35 #define QZ_PAGEUP 0x74 #define QZ_PAGEDOWN 0x79 #define QZ_RETURN 0x24 #define QZ_UP 0x7E #define QZ_SPACE 0x31 #define QZ_LEFT 0x7B #define QZ_DOWN 0x7D #define QZ_RIGHT 0x7C #define QZ_W 0x0D #define QZ_A 0x00 #define QZ_S 0x01 #define QZ_D 0x02 #define QZ_ONE 0x12 #define QZ_TWO 0x13 #define QZ_THREE 0x14 #define QZ_FOUR 0x15 #define QZ_FIVE 0x17 #define QZ_SIX 0x16 #define QZ_SEVEN 0x1A #define QZ_EIGHT 0x1C #define QZ_NINE 0x19 #define QZ_ZERO 0x1D static bool spaceKeyDown = false; static bool enterKeyDown = false; static bool escapeKeyDown = false; static bool pageUpKeyDown = false; static bool pageDownKeyDown = false; static bool upKeyDown = false; static bool downKeyDown = false; static bool leftKeyDown = false; static bool rightKeyDown = false; static bool wKeyDown = false; static bool aKeyDown = false; static bool sKeyDown = false; static bool dKeyDown = false; static bool oneKeyDown = false; static bool twoKeyDown = false; static bool threeKeyDown = false; static bool fourKeyDown = false; static bool fiveKeyDown = false; static bool sixKeyDown = false; static bool sevenKeyDown = false; static bool eightKeyDown = false; static bool nineKeyDown = false; static bool zeroKeyDown = false; pascal OSStatus keyboardEventHandler( EventHandlerCallRef nextHandler, EventRef event, void * userData ) { UInt32 eventClass = GetEventClass( event ); UInt32 eventKind = GetEventKind( event ); if ( eventClass == kEventClassKeyboard ) { char macCharCodes; UInt32 macKeyCode; UInt32 macKeyModifiers; GetEventParameter( event, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(macCharCodes), NULL, &macCharCodes ); GetEventParameter( event, kEventParamKeyCode, typeUInt32, NULL, sizeof(macKeyCode), NULL, &macKeyCode ); GetEventParameter( event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(macKeyModifiers), NULL, &macKeyModifiers ); if ( eventKind == kEventRawKeyDown ) { switch ( macKeyCode ) { case QZ_SPACE: spaceKeyDown = true; break; case QZ_RETURN: enterKeyDown = true; break; case QZ_ESCAPE: escapeKeyDown = true; break; case QZ_PAGEUP: pageUpKeyDown = true; break; case QZ_PAGEDOWN: pageDownKeyDown = true; break; case QZ_UP: upKeyDown = true; break; case QZ_DOWN: downKeyDown = true; break; case QZ_LEFT: leftKeyDown = true; break; case QZ_RIGHT: rightKeyDown = true; break; case QZ_W: wKeyDown = true; break; case QZ_A: aKeyDown = true; break; case QZ_S: sKeyDown = true; break; case QZ_D: dKeyDown = true; break; case QZ_ONE: oneKeyDown = true; break; case QZ_TWO: twoKeyDown = true; break; case QZ_THREE: threeKeyDown = true; break; case QZ_FOUR: fourKeyDown = true; break; case QZ_FIVE: fiveKeyDown = true; break; case QZ_SIX: sixKeyDown = true; break; case QZ_SEVEN: sevenKeyDown = true; break; case QZ_EIGHT: eightKeyDown = true; break; case QZ_NINE: nineKeyDown = true; break; case QZ_ZERO: zeroKeyDown = true; break; default: { // note: for "discovering" keycodes for new keys :) /* char title[] = "Message"; char text[64]; sprintf( text, "key=%x", (int) macKeyCode ); Str255 msg_title; Str255 msg_text; c2pstrcpy( msg_title, title ); c2pstrcpy( msg_text, text ); StandardAlert( kAlertStopAlert, (ConstStr255Param) msg_title, (ConstStr255Param) msg_text, NULL, NULL); */ return eventNotHandledErr; } } } else if ( eventKind == kEventRawKeyUp ) { switch ( macKeyCode ) { case QZ_SPACE: spaceKeyDown = false; break; case QZ_RETURN: enterKeyDown = false; break; case QZ_ESCAPE: escapeKeyDown = false; break; case QZ_PAGEUP: pageUpKeyDown = false; break; case QZ_PAGEDOWN: pageDownKeyDown = false; break; case QZ_UP: upKeyDown = false; break; case QZ_DOWN: downKeyDown = false; break; case QZ_LEFT: leftKeyDown = false; break; case QZ_RIGHT: rightKeyDown = false; break; case QZ_W: wKeyDown = false; break; case QZ_A: aKeyDown = false; break; case QZ_S: sKeyDown = false; break; case QZ_D: dKeyDown = false; break; case QZ_ONE: oneKeyDown = false; break; case QZ_TWO: twoKeyDown = false; break; case QZ_THREE: threeKeyDown = false; break; case QZ_FOUR: fourKeyDown = false; break; case QZ_FIVE: fiveKeyDown = false; break; case QZ_SIX: sixKeyDown = false; break; case QZ_SEVEN: sevenKeyDown = false; break; case QZ_EIGHT: eightKeyDown = false; break; case QZ_NINE: nineKeyDown = false; break; case QZ_ZERO: zeroKeyDown = false; break; default: return eventNotHandledErr; } } } return noErr; } #ifndef FULLSCREEN static AGLContext setupAGL( WindowRef window, int width, int height ) { if ( (Ptr) kUnresolvedCFragSymbolAddress == (Ptr) aglChoosePixelFormat ) return 0; GLint attributes[] = { AGL_RGBA, AGL_DOUBLEBUFFER, AGL_DEPTH_SIZE, 32, AGL_NO_RECOVERY, AGL_NONE, AGL_NONE }; AGLPixelFormat format = NULL; format = aglChoosePixelFormat( NULL, 0, attributes ); if ( !format ) return 0; AGLContext context = aglCreateContext( format, 0 ); if ( !context ) return 0; aglDestroyPixelFormat( format ); aglSetWindowRef( context, window ); aglSetCurrentContext( context ); return context; } static void cleanupAGL( AGLContext context ) { aglDestroyContext( context ); } WindowRef window; AGLContext context; #else CGLContextObj contextObj; #endif int GetDisplayWidth() { return CGDisplayPixelsWide( kCGDirectMainDisplay ); } int GetDisplayHeight() { return CGDisplayPixelsHigh( kCGDirectMainDisplay ); } void HideMouseCursor() { CGDisplayHideCursor( kCGNullDirectDisplay ); CGAssociateMouseAndMouseCursorPosition( false ); CGDisplayMoveCursorToPoint( kCGDirectMainDisplay, CGPointZero ); } void ShowMouseCursor() { CGAssociateMouseAndMouseCursorPosition( true ); CGDisplayShowCursor( kCGNullDirectDisplay ); } bool OpenDisplay( const char title[], int width, int height ) { #ifndef FULLSCREEN int screenWidth = GetDisplayWidth(); int screenHeight = GetDisplayHeight(); Rect rect; rect.left = ( screenWidth - width ) / 2; rect.top = ( screenHeight - height ) / 2; rect.right = rect.left + width; rect.bottom = rect.top + height; OSErr result = CreateNewWindow( kDocumentWindowClass, ( kWindowStandardDocumentAttributes | // kWindowNoTitleBarAttribute | kWindowStandardHandlerAttribute ) & ~kWindowResizableAttribute, &rect, &window ); if ( result != noErr ) return false; SetWindowTitleWithCFString( window, CFStringCreateWithCString( 0, title, CFStringGetSystemEncoding() ) ); context = setupAGL( window, width, height ); if ( !context ) return false; ShowWindow( window ); SelectWindow( window ); // install standard event handlers InstallStandardEventHandler( GetWindowEventTarget( window ) ); #endif // install keyboard handler EventTypeSpec eventTypes[2]; eventTypes[0].eventClass = kEventClassKeyboard; eventTypes[0].eventKind = kEventRawKeyDown; eventTypes[1].eventClass = kEventClassKeyboard; eventTypes[1].eventKind = kEventRawKeyUp; EventHandlerUPP handlerUPP = NewEventHandlerUPP( keyboardEventHandler ); InstallApplicationEventHandler( handlerUPP, 2, eventTypes, NULL, NULL ); #ifdef FULLSCREEN // initialize fullscreen CGL CGDisplayCapture( kCGDirectMainDisplay ); CGLPixelFormatAttribute attribs[] = { kCGLPFANoRecovery, kCGLPFADoubleBuffer, kCGLPFAFullScreen, kCGLPFAStencilSize, ( CGLPixelFormatAttribute ) 8, kCGLPFADisplayMask, ( CGLPixelFormatAttribute ) CGDisplayIDToOpenGLDisplayMask( kCGDirectMainDisplay ), ( CGLPixelFormatAttribute ) NULL }; CGLPixelFormatObj pixelFormatObj; GLint numPixelFormats; CGLChoosePixelFormat( attribs, &pixelFormatObj, &numPixelFormats ); CGLCreateContext( pixelFormatObj, NULL, &contextObj ); CGLDestroyPixelFormat( pixelFormatObj ); CGLSetCurrentContext( contextObj ); CGLSetFullScreen( contextObj ); #endif // install quit handler (via apple events) AEInstallEventHandler( kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP(quitEventHandler), 0, false ); return true; } void UpdateDisplay( int interval = 1 ) { #ifdef FULLSCREEN CGLSetParameter( contextObj, kCGLCPSwapInterval, &interval ); CGLFlushDrawable( contextObj ); #else GLint swapInterval = interval; aglSetInteger( context, AGL_SWAP_INTERVAL, &swapInterval ); aglSwapBuffers( context ); #endif // process events EventRef event = 0; OSStatus status = ReceiveNextEvent( 0, NULL, 0.0f, kEventRemoveFromQueue, &event ); if ( status == noErr && event ) { bool sendEvent = true; #ifndef FULLSCREEN // note: required for menu bar to work properly if ( GetEventClass( event ) == kEventClassMouse && GetEventKind( event ) == kEventMouseDown ) { WindowRef window; Point location; GetEventParameter( event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &location ); if ( MacFindWindow( location, &window ) == inMenuBar ) { sendEvent = false; MenuSelect( location ); } } #endif if ( sendEvent ) SendEventToEventTarget( event, GetEventDispatcherTarget() ); ReleaseEvent( event ); } } void CloseDisplay() { #ifdef FULLSCREEN CGLSetCurrentContext( NULL ); CGLClearDrawable( contextObj ); CGLDestroyContext( contextObj ); CGReleaseAllDisplays(); #else cleanupAGL( context ); context = 0; DisposeWindow( (WindowPtr) window ); window = 0; #endif } // basic keyboard input struct Input { static Input Sample() { Input input; input.left = leftKeyDown; input.right = rightKeyDown; input.up = upKeyDown; input.down = downKeyDown; input.space = spaceKeyDown; input.escape = escapeKeyDown; input.enter = enterKeyDown; input.pageUp = pageUpKeyDown; input.pageDown = pageDownKeyDown; input.w = wKeyDown; input.a = aKeyDown; input.s = sKeyDown; input.d = dKeyDown; input.one = oneKeyDown; input.two = twoKeyDown; input.three = threeKeyDown; input.four = fourKeyDown; input.five = fiveKeyDown; input.six = sixKeyDown; input.seven = sevenKeyDown; input.eight = eightKeyDown; input.nine = nineKeyDown; input.zero = zeroKeyDown; return input; } Input() { left = false; right = false; up = false; down = false; space = false; escape = false; enter = false; pageUp = false; pageDown = false; w = false; a = false; s = false; d = false; one = false; two = false; three = false; four = false; five = false; six = false; seven = false; eight = false; nine = false; zero = false; } bool left; bool right; bool up; bool down; bool space; bool escape; bool enter; bool pageUp; bool pageDown; bool w; bool a; bool s; bool d; bool one; bool two; bool three; bool four; bool five; bool six; bool seven; bool eight; bool nine; bool zero; }; #endif