| #include "MacOpenGLWindow.h" |
| |
| #define GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED |
| #import <Cocoa/Cocoa.h> |
| #include "OpenGLInclude.h" |
| |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <stddef.h> |
| #include <string.h> |
| |
| |
| enum |
| { |
| MY_MAC_ALTKEY=1, |
| MY_MAC_SHIFTKEY=2, |
| MY_MAC_CONTROL_KEY=4 |
| }; |
| |
| /* report GL errors, if any, to stderr */ |
| static void checkError(const char *functionName) |
| { |
| GLenum error; |
| while (( error = glGetError() ) != GL_NO_ERROR) |
| { |
| fprintf (stderr, "GL error 0x%X detected in %s\n", error, functionName); |
| } |
| } |
| |
| void dumpInfo(void) |
| { |
| printf ("Vendor: %s\n", glGetString (GL_VENDOR)); |
| printf ("Renderer: %s\n", glGetString (GL_RENDERER)); |
| printf ("Version: %s\n", glGetString (GL_VERSION)); |
| printf ("GLSL: %s\n", glGetString (GL_SHADING_LANGUAGE_VERSION)); |
| checkError ("dumpInfo"); |
| } |
| |
| |
| |
| |
| // -------------------- View ------------------------ |
| |
| @interface TestView : NSView |
| { |
| NSOpenGLContext* m_context; |
| int m_lastWidth; |
| int m_lastHeight; |
| bool m_requestClose; |
| b3ResizeCallback m_resizeCallback; |
| |
| } |
| -(void)drawRect:(NSRect)rect; |
| -(void) MakeContext:(int) openglVersion; |
| -(void) MakeCurrent; |
| -(float) GetWindowWidth; |
| -(float) GetWindowHeight; |
| -(BOOL) GetRequestClose; |
| - (BOOL)windowShouldClose:(id)sender; |
| -(void) setResizeCallback:(b3ResizeCallback) callback; |
| -(b3ResizeCallback) getResizeCallback; |
| -(NSOpenGLContext*) getContext; |
| @end |
| |
| float loop; |
| |
| #define Pi 3.1415 |
| |
| @implementation TestView |
| |
| - (BOOL)windowShouldClose:(id)sender |
| { |
| m_requestClose = true; |
| return false; |
| } |
| -(BOOL) GetRequestClose |
| { |
| return m_requestClose; |
| } |
| -(float) GetWindowWidth |
| { |
| return m_lastWidth; |
| } |
| -(float) GetWindowHeight |
| { |
| return m_lastHeight; |
| } |
| |
| -(b3ResizeCallback) getResizeCallback |
| { |
| return m_resizeCallback; |
| } |
| |
| -(NSOpenGLContext*) getContext |
| { |
| return m_context; |
| } |
| -(void)setResizeCallback:(b3ResizeCallback)callback |
| { |
| m_resizeCallback = callback; |
| } |
| -(void)drawRect:(NSRect)rect |
| { |
| if (([self frame].size.width != m_lastWidth) || ([self frame].size.height != m_lastHeight)) |
| { |
| m_lastWidth = [self frame].size.width; |
| m_lastHeight = [self frame].size.height; |
| |
| // Only needed on resize: |
| [m_context clearDrawable]; |
| |
| // reshape([self frame].size.width, [self frame].size.height); |
| float width = [self frame].size.width; |
| float height = [self frame].size.height; |
| |
| |
| // Get view dimensions in pixels |
| // glViewport(0,0,10,10); |
| |
| if (m_resizeCallback) |
| { |
| (*m_resizeCallback)(width,height); |
| } |
| #ifndef NO_OPENGL3 |
| NSRect backingBounds = [self convertRectToBacking:[self bounds]]; |
| GLsizei backingPixelWidth = (GLsizei)(backingBounds.size.width), |
| backingPixelHeight = (GLsizei)(backingBounds.size.height); |
| |
| // Set viewport |
| glViewport(0, 0, backingPixelWidth, backingPixelHeight); |
| #else |
| glViewport(0,0,(GLsizei)width,(GLsizei)height); |
| #endif |
| } |
| |
| [m_context setView: self]; |
| [m_context makeCurrentContext]; |
| |
| // Draw |
| //display(); |
| |
| [m_context flushBuffer]; |
| [NSOpenGLContext clearCurrentContext]; |
| |
| loop = loop + 0.1; |
| } |
| |
| -(void) MakeContext :(int) openglVersion |
| { |
| // NSWindow *w; |
| NSOpenGLPixelFormat *fmt; |
| |
| m_requestClose = false; |
| |
| |
| |
| #ifndef NO_OPENGL3 |
| if (openglVersion==3) |
| { |
| NSOpenGLPixelFormatAttribute attrs[] = |
| { |
| NSOpenGLPFAOpenGLProfile, |
| NSOpenGLProfileVersion3_2Core, |
| NSOpenGLPFADoubleBuffer, |
| NSOpenGLPFADepthSize, 32, |
| NSOpenGLPFAStencilSize, (NSOpenGLPixelFormatAttribute)8, |
| (NSOpenGLPixelFormatAttribute)0 |
| }; |
| |
| // Init GL context |
| fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes: (NSOpenGLPixelFormatAttribute*)attrs]; |
| } else |
| #endif |
| { |
| NSOpenGLPixelFormatAttribute attrs[] = |
| { |
| NSOpenGLPFADoubleBuffer, |
| NSOpenGLPFADepthSize, 32, |
| NSOpenGLPFAStencilSize, (NSOpenGLPixelFormatAttribute)8, |
| (NSOpenGLPixelFormatAttribute)0 |
| }; |
| // Init GL context |
| fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes: (NSOpenGLPixelFormatAttribute*)attrs]; |
| |
| } |
| m_context = [[NSOpenGLContext alloc] initWithFormat: fmt shareContext: nil]; |
| [fmt release]; |
| [m_context makeCurrentContext]; |
| |
| checkError("makeCurrentContext"); |
| } |
| |
| -(void) MakeCurrent |
| { |
| [m_context makeCurrentContext]; |
| } |
| -(void)windowWillClose:(NSNotification *)note |
| { |
| [[NSApplication sharedApplication] terminate:self]; |
| } |
| @end |
| |
| struct MacOpenGLWindowInternalData |
| { |
| MacOpenGLWindowInternalData() |
| { |
| m_myApp = 0; |
| m_myview = 0; |
| m_pool = 0; |
| m_window = 0; |
| m_width = -1; |
| m_height = -1; |
| m_exitRequested = false; |
| } |
| NSApplication* m_myApp; |
| TestView* m_myview; |
| NSAutoreleasePool* m_pool; |
| NSWindow* m_window; |
| int m_width; |
| int m_height; |
| bool m_exitRequested; |
| |
| }; |
| |
| MacOpenGLWindow::MacOpenGLWindow() |
| :m_internalData(0), |
| m_mouseX(0), |
| m_mouseY(0), |
| m_modifierFlags(0), |
| m_mouseMoveCallback(0), |
| m_mouseButtonCallback(0), |
| m_wheelCallback(0), |
| m_keyboardCallback(0), |
| m_retinaScaleFactor(1), |
| m_allowRetina(true) |
| { |
| } |
| |
| MacOpenGLWindow::~MacOpenGLWindow() |
| { |
| if (m_internalData) |
| closeWindow(); |
| } |
| |
| |
| bool MacOpenGLWindow::isModifierKeyPressed(int key) |
| { |
| bool isPressed = false; |
| |
| switch (key) |
| { |
| case B3G_ALT: |
| { |
| isPressed = ((m_modifierFlags & MY_MAC_ALTKEY)!=0); |
| break; |
| }; |
| case B3G_SHIFT: |
| { |
| isPressed = ((m_modifierFlags & MY_MAC_SHIFTKEY)!=0); |
| break; |
| }; |
| case B3G_CONTROL: |
| { |
| isPressed = ((m_modifierFlags & MY_MAC_CONTROL_KEY )!=0); |
| break; |
| }; |
| |
| default: |
| { |
| } |
| }; |
| return isPressed; |
| } |
| |
| float MacOpenGLWindow::getTimeInSeconds() |
| { |
| return 0.f; |
| } |
| |
| |
| void MacOpenGLWindow::setRenderCallback( b3RenderCallback renderCallback) |
| { |
| m_renderCallback = renderCallback; |
| } |
| |
| void MacOpenGLWindow::setWindowTitle(const char* windowTitle) |
| { |
| [m_internalData->m_window setTitle:[NSString stringWithCString:windowTitle encoding:NSISOLatin1StringEncoding]] ; |
| } |
| |
| void MacOpenGLWindow::createWindow(const b3gWindowConstructionInfo& ci) |
| { |
| if (m_internalData) |
| closeWindow(); |
| |
| int width = ci.m_width; |
| int height = ci.m_height; |
| const char* windowTitle = ci.m_title; |
| |
| |
| |
| NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
| |
| m_internalData = new MacOpenGLWindowInternalData; |
| m_internalData->m_width = width; |
| m_internalData->m_height = height; |
| |
| m_internalData->m_pool = [NSAutoreleasePool new]; |
| m_internalData->m_myApp = [NSApplication sharedApplication]; |
| //myApp = [MyApp sharedApplication]; |
| //home(); |
| |
| [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; |
| |
| id menubar = [[NSMenu new] autorelease]; |
| id appMenuItem = [[NSMenuItem new] autorelease]; |
| [menubar addItem:appMenuItem]; |
| [NSApp setMainMenu:menubar]; |
| |
| id appMenu = [[NSMenu new] autorelease]; |
| id appName = [[NSProcessInfo processInfo] processName]; |
| id quitTitle = [@"Quit " stringByAppendingString:appName]; |
| id quitMenuItem = [[[NSMenuItem alloc] initWithTitle:quitTitle |
| action:@selector(terminate:) keyEquivalent:@"q"] autorelease]; |
| |
| [appMenu addItem:quitMenuItem]; |
| [appMenuItem setSubmenu:appMenu]; |
| |
| NSMenuItem *fileMenuItem = [[NSMenuItem new] autorelease]; |
| NSMenu *fileMenu = [[NSMenu alloc] initWithTitle:@"File"]; |
| [fileMenuItem setSubmenu: fileMenu]; // was setMenu: |
| |
| NSMenuItem *newMenu = [[NSMenuItem alloc] initWithTitle:@"New" action:NULL keyEquivalent:@""]; |
| NSMenuItem *openMenu = [[NSMenuItem alloc] initWithTitle:@"Open" action:NULL keyEquivalent:@""]; |
| NSMenuItem *saveMenu = [[NSMenuItem alloc] initWithTitle:@"Save" action:NULL keyEquivalent:@""]; |
| |
| [fileMenu addItem: newMenu]; |
| [fileMenu addItem: openMenu]; |
| [fileMenu addItem: saveMenu]; |
| [menubar addItem: fileMenuItem]; |
| |
| |
| // add Edit menu |
| NSMenuItem *editMenuItem = [[NSMenuItem new] autorelease]; |
| NSMenu *menu = [[NSMenu allocWithZone:[NSMenu menuZone]]initWithTitle:@"Edit"]; |
| [editMenuItem setSubmenu: menu]; |
| |
| NSMenuItem *copyItem = [[NSMenuItem allocWithZone:[NSMenu menuZone]]initWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"c"]; |
| |
| [menu addItem:copyItem]; |
| [menubar addItem:editMenuItem]; |
| |
| // [mainMenu setSubmenu:menu forItem:menuItem]; |
| |
| |
| //NSMenuItem *fileMenuItem = [[NSMenuItem alloc] initWithTitle: @"File"]; |
| /*[fileMenuItem setSubmenu: fileMenu]; // was setMenu: |
| [fileMenuItem release]; |
| */ |
| |
| /*NSMenu *newMenu; |
| NSMenuItem *newItem; |
| |
| // Add the submenu |
| newItem = [[NSMenuItem allocWithZone:[NSMenu menuZone]] |
| initWithTitle:@"Flashy" action:NULL keyEquivalent:@""]; |
| newMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] |
| initWithTitle:@"Flashy"]; |
| [newItem setSubmenu:newMenu]; |
| [newMenu release]; |
| [[NSApp mainMenu] addItem:newItem]; |
| [newItem release]; |
| */ |
| |
| NSRect frame = NSMakeRect(0., 0., width, height); |
| |
| m_internalData->m_window = [NSWindow alloc]; |
| [m_internalData->m_window initWithContentRect:frame |
| styleMask:NSTitledWindowMask |NSResizableWindowMask| NSClosableWindowMask | NSMiniaturizableWindowMask |
| backing:NSBackingStoreBuffered |
| defer:false]; |
| |
| |
| [m_internalData->m_window setTitle:[NSString stringWithCString:windowTitle encoding:NSISOLatin1StringEncoding]] ; |
| |
| m_internalData->m_myview = [TestView alloc]; |
| |
| [m_internalData->m_myview setResizeCallback:0]; |
| ///ci.m_resizeCallback]; |
| |
| [m_internalData->m_myview initWithFrame: frame]; |
| |
| // OpenGL init! |
| [m_internalData->m_myview MakeContext : ci.m_openglVersion]; |
| |
| // https://developer.apple.com/library/mac/#documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/CapturingScreenContents/CapturingScreenContents.html#//apple_ref/doc/uid/TP40012302-CH10-SW1 |
| //support HighResolutionOSX for Retina Macbook |
| if (ci.m_openglVersion>=3) |
| { |
| if (m_allowRetina) |
| { |
| [m_internalData->m_myview setWantsBestResolutionOpenGLSurface:YES]; |
| } |
| } |
| NSSize sz; |
| sz.width = 1; |
| sz.height = 1; |
| |
| // float newBackingScaleFactor = [m_internalData->m_window backingScaleFactor]; |
| |
| dumpInfo(); |
| |
| |
| |
| |
| [m_internalData->m_window setContentView: m_internalData->m_myview]; |
| |
| |
| |
| [m_internalData->m_window setDelegate:(id) m_internalData->m_myview]; |
| |
| [m_internalData->m_window makeKeyAndOrderFront: nil]; |
| |
| [m_internalData->m_myview MakeCurrent]; |
| m_internalData->m_width = m_internalData->m_myview.GetWindowWidth; |
| m_internalData->m_height = m_internalData->m_myview.GetWindowHeight; |
| |
| |
| [NSApp activateIgnoringOtherApps:YES]; |
| |
| |
| //[m_internalData->m_window setLevel:NSMainMenuWindowLevel]; |
| |
| // [NSEvent addGlobalMonitorForEventsMatchingMask:NSMouseMovedMask]; |
| |
| // [NSEvent addGlobalMonitorForEventsMatchingMask:NSMouseMovedMask handler:^(NSEvent *event) |
| // { |
| //[window setFrameOrigin:[NSEvent mouseLocation]]; |
| // NSPoint eventLocation = [m_internalData->m_window mouseLocationOutsideOfEventStream]; |
| |
| // NSPoint eventLocation = [event locationInWindow]; |
| //NSPoint center = [m_internalData->m_myview convertPoint:eventLocation fromView:nil]; |
| // m_mouseX = center.x; |
| // m_mouseY = [m_internalData->m_myview GetWindowHeight] - center.y; |
| |
| |
| // printf("mouse coord = %f, %f\n",m_mouseX,m_mouseY); |
| // if (m_mouseMoveCallback) |
| // (*m_mouseMoveCallback)(m_mouseX,m_mouseY); |
| |
| // }]; |
| |
| //see http://stackoverflow.com/questions/8238473/cant-get-nsmousemoved-events-from-nexteventmatchingmask-with-an-nsopenglview |
| /* ProcessSerialNumber psn; |
| GetCurrentProcess(&psn); |
| TransformProcessType(&psn, kProcessTransformToForegroundApplication); |
| SetFrontProcess(&psn); |
| */ |
| #ifndef NO_OPENGL3 |
| m_retinaScaleFactor = [m_internalData->m_myview convertSizeToBacking:sz].width; |
| #else |
| m_retinaScaleFactor=1.f; |
| #endif |
| |
| [m_internalData->m_myApp finishLaunching]; |
| [pool release]; |
| |
| } |
| |
| void MacOpenGLWindow::runMainLoop() |
| { |
| NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
| // FILE* dump = fopen ("/Users/erwincoumans/yes.txt","wb"); |
| // fclose(dump); |
| |
| |
| |
| |
| [pool release]; |
| |
| } |
| |
| void MacOpenGLWindow::closeWindow() |
| { |
| |
| delete m_internalData; |
| m_internalData = 0; |
| |
| } |
| extern float m_azi; |
| extern float m_ele; |
| extern float m_cameraDistance; |
| |
| |
| /* |
| * Summary: |
| * Virtual keycodes |
| * |
| * Discussion: |
| * These constants are the virtual keycodes defined originally in |
| * Inside Mac Volume V, pg. V-191. They identify physical keys on a |
| * keyboard. Those constants with "ANSI" in the name are labeled |
| * according to the key position on an ANSI-standard US keyboard. |
| * For example, kVK_ANSI_A indicates the virtual keycode for the key |
| * with the letter 'A' in the US keyboard layout. Other keyboard |
| * layouts may have the 'A' key label on a different physical key; |
| * in this case, pressing 'A' will generate a different virtual |
| * keycode. |
| */ |
| enum { |
| kVK_ANSI_A = 0x00, |
| kVK_ANSI_S = 0x01, |
| kVK_ANSI_D = 0x02, |
| kVK_ANSI_F = 0x03, |
| kVK_ANSI_H = 0x04, |
| kVK_ANSI_G = 0x05, |
| kVK_ANSI_Z = 0x06, |
| kVK_ANSI_X = 0x07, |
| kVK_ANSI_C = 0x08, |
| kVK_ANSI_V = 0x09, |
| kVK_ANSI_B = 0x0B, |
| kVK_ANSI_Q = 0x0C, |
| kVK_ANSI_W = 0x0D, |
| kVK_ANSI_E = 0x0E, |
| kVK_ANSI_R = 0x0F, |
| kVK_ANSI_Y = 0x10, |
| kVK_ANSI_T = 0x11, |
| kVK_ANSI_1 = 0x12, |
| kVK_ANSI_2 = 0x13, |
| kVK_ANSI_3 = 0x14, |
| kVK_ANSI_4 = 0x15, |
| kVK_ANSI_6 = 0x16, |
| kVK_ANSI_5 = 0x17, |
| kVK_ANSI_Equal = 0x18, |
| kVK_ANSI_9 = 0x19, |
| kVK_ANSI_7 = 0x1A, |
| kVK_ANSI_Minus = 0x1B, |
| kVK_ANSI_8 = 0x1C, |
| kVK_ANSI_0 = 0x1D, |
| kVK_ANSI_RightBracket = 0x1E, |
| kVK_ANSI_O = 0x1F, |
| kVK_ANSI_U = 0x20, |
| kVK_ANSI_LeftBracket = 0x21, |
| kVK_ANSI_I = 0x22, |
| kVK_ANSI_P = 0x23, |
| kVK_ANSI_L = 0x25, |
| kVK_ANSI_J = 0x26, |
| kVK_ANSI_Quote = 0x27, |
| kVK_ANSI_K = 0x28, |
| kVK_ANSI_Semicolon = 0x29, |
| kVK_ANSI_Backslash = 0x2A, |
| kVK_ANSI_Comma = 0x2B, |
| kVK_ANSI_Slash = 0x2C, |
| kVK_ANSI_N = 0x2D, |
| kVK_ANSI_M = 0x2E, |
| kVK_ANSI_Period = 0x2F, |
| kVK_ANSI_Grave = 0x32, |
| kVK_ANSI_KeypadDecimal = 0x41, |
| kVK_ANSI_KeypadMultiply = 0x43, |
| kVK_ANSI_KeypadPlus = 0x45, |
| kVK_ANSI_KeypadClear = 0x47, |
| kVK_ANSI_KeypadDivide = 0x4B, |
| kVK_ANSI_KeypadEnter = 0x4C, |
| kVK_ANSI_KeypadMinus = 0x4E, |
| kVK_ANSI_KeypadEquals = 0x51, |
| kVK_ANSI_Keypad0 = 0x52, |
| kVK_ANSI_Keypad1 = 0x53, |
| kVK_ANSI_Keypad2 = 0x54, |
| kVK_ANSI_Keypad3 = 0x55, |
| kVK_ANSI_Keypad4 = 0x56, |
| kVK_ANSI_Keypad5 = 0x57, |
| kVK_ANSI_Keypad6 = 0x58, |
| kVK_ANSI_Keypad7 = 0x59, |
| kVK_ANSI_Keypad8 = 0x5B, |
| kVK_ANSI_Keypad9 = 0x5C |
| }; |
| |
| /* keycodes for keys that are independent of keyboard layout*/ |
| enum { |
| kVK_Return = 0x24, |
| kVK_Tab = 0x30, |
| kVK_Space = 0x31, |
| kVK_Delete = 0x33, |
| kVK_Escape = 0x35, |
| kVK_Command = 0x37, |
| kVK_Shift = 0x38, |
| kVK_CapsLock = 0x39, |
| kVK_Option = 0x3A, |
| kVK_Control = 0x3B, |
| kVK_RightShift = 0x3C, |
| kVK_RightOption = 0x3D, |
| kVK_RightControl = 0x3E, |
| kVK_Function = 0x3F, |
| kVK_F17 = 0x40, |
| kVK_VolumeUp = 0x48, |
| kVK_VolumeDown = 0x49, |
| kVK_Mute = 0x4A, |
| kVK_F18 = 0x4F, |
| kVK_F19 = 0x50, |
| kVK_F20 = 0x5A, |
| kVK_F5 = 0x60, |
| kVK_F6 = 0x61, |
| kVK_F7 = 0x62, |
| kVK_F3 = 0x63, |
| kVK_F8 = 0x64, |
| kVK_F9 = 0x65, |
| kVK_F11 = 0x67, |
| kVK_F13 = 0x69, |
| kVK_F16 = 0x6A, |
| kVK_F14 = 0x6B, |
| kVK_F10 = 0x6D, |
| kVK_F12 = 0x6F, |
| kVK_F15 = 0x71, |
| kVK_Help = 0x72, |
| kVK_Home = 0x73, |
| kVK_PageUp = 0x74, |
| kVK_ForwardDelete = 0x75, |
| kVK_F4 = 0x76, |
| kVK_End = 0x77, |
| kVK_F2 = 0x78, |
| kVK_PageDown = 0x79, |
| kVK_F1 = 0x7A, |
| kVK_LeftArrow = 0x7B, |
| kVK_RightArrow = 0x7C, |
| kVK_DownArrow = 0x7D, |
| kVK_UpArrow = 0x7E |
| }; |
| |
| /* ISO keyboards only*/ |
| enum { |
| kVK_ISO_Section = 0x0A |
| }; |
| |
| /* JIS keyboards only*/ |
| enum { |
| kVK_JIS_Yen = 0x5D, |
| kVK_JIS_Underscore = 0x5E, |
| kVK_JIS_KeypadComma = 0x5F, |
| kVK_JIS_Eisu = 0x66, |
| kVK_JIS_Kana = 0x68 |
| }; |
| |
| int getAsciiCodeFromVirtualKeycode(int virtualKeyCode) |
| { |
| int keycode = 0xffffffff; |
| |
| switch (virtualKeyCode) |
| { |
| |
| case kVK_ANSI_A : {keycode = 'a'; break;} |
| case kVK_ANSI_B : {keycode = 'b'; break;} |
| case kVK_ANSI_C : {keycode = 'c'; break;} |
| case kVK_ANSI_D : {keycode = 'd';break;} |
| case kVK_ANSI_E : {keycode = 'e'; break;} |
| case kVK_ANSI_F : {keycode = 'f'; break;} |
| case kVK_ANSI_G : {keycode = 'g'; break;} |
| case kVK_ANSI_H : {keycode = 'h'; break;} |
| case kVK_ANSI_I : {keycode = 'i'; break;} |
| case kVK_ANSI_J : {keycode = 'j'; break;} |
| case kVK_ANSI_K : {keycode = 'k'; break;} |
| case kVK_ANSI_L : {keycode = 'l'; break;} |
| case kVK_ANSI_M : {keycode = 'm'; break;} |
| case kVK_ANSI_N : {keycode = 'n'; break;} |
| case kVK_ANSI_O : {keycode = 'o'; break;} |
| case kVK_ANSI_P : {keycode = 'p'; break;} |
| case kVK_ANSI_Q : {keycode = 'q'; break;} |
| case kVK_ANSI_R : {keycode = 'r'; break;} |
| case kVK_ANSI_S : {keycode = 's';break;} |
| case kVK_ANSI_T : {keycode = 't'; break;} |
| case kVK_ANSI_U : {keycode = 'u'; break;} |
| case kVK_ANSI_V : {keycode = 'v'; break;} |
| case kVK_ANSI_W : {keycode = 'w'; break;} |
| case kVK_ANSI_X : {keycode = 'x'; break;} |
| case kVK_ANSI_Y : {keycode = 'y'; break;} |
| case kVK_ANSI_Z : {keycode = 'z'; break;} |
| |
| case kVK_ANSI_1 : {keycode = '1'; break;} |
| case kVK_ANSI_2 : {keycode = '2'; break;} |
| case kVK_ANSI_3 : {keycode = '3'; break;} |
| case kVK_ANSI_4 : {keycode = '4'; break;} |
| case kVK_ANSI_5 : {keycode = '5'; break;} |
| case kVK_ANSI_6 : {keycode = '6'; break;} |
| case kVK_ANSI_7 : {keycode = '7'; break;} |
| case kVK_ANSI_8 : {keycode = '8'; break;} |
| case kVK_ANSI_9 : {keycode = '9'; break;} |
| case kVK_ANSI_0 : {keycode = '0'; break;} |
| case kVK_ANSI_Equal : {keycode = '='; break;} |
| case kVK_ANSI_Minus : {keycode = '-'; break;} |
| |
| case kVK_Tab: {keycode = 9; break;} |
| case kVK_Space: {keycode=' '; break;} |
| case kVK_Escape: {keycode=27; break;} |
| case kVK_Delete: {keycode=8; break;} |
| case kVK_ForwardDelete: {keycode=B3G_INSERT; break;} |
| |
| |
| case kVK_F1: {keycode = B3G_F1; break;} |
| case kVK_F2: {keycode = B3G_F2; break;} |
| case kVK_F3: {keycode = B3G_F3; break;} |
| case kVK_F4: {keycode = B3G_F4; break;} |
| case kVK_F5: {keycode = B3G_F5; break;} |
| case kVK_F6: {keycode = B3G_F6; break;} |
| case kVK_F7: {keycode = B3G_F7; break;} |
| case kVK_F8: {keycode = B3G_F8; break;} |
| case kVK_F9: {keycode = B3G_F9; break;} |
| case kVK_F10: {keycode = B3G_F10; break;} |
| case kVK_F11: {keycode = B3G_F11; break;} |
| case kVK_F12: {keycode = B3G_F12; break;} |
| case kVK_F13: {keycode = B3G_F13; break;} |
| case kVK_F14: {keycode = B3G_F14; break;} |
| case kVK_F15: {keycode = B3G_F15; break;} |
| |
| case kVK_LeftArrow: {keycode = B3G_LEFT_ARROW;break;} |
| case kVK_RightArrow: {keycode = B3G_RIGHT_ARROW;break;} |
| case kVK_UpArrow: {keycode = B3G_UP_ARROW;break;} |
| case kVK_DownArrow: {keycode = B3G_DOWN_ARROW;break;} |
| |
| case kVK_PageUp :{keycode = B3G_PAGE_UP;break;} |
| case kVK_PageDown :{keycode = B3G_PAGE_DOWN;break;} |
| case kVK_End :{keycode = B3G_END;break;} |
| case kVK_Home :{keycode = B3G_HOME;break;} |
| case kVK_Control: {keycode = B3G_CONTROL;break;} |
| case kVK_Option: {keycode = B3G_ALT;break;} |
| |
| case kVK_ANSI_RightBracket : {keycode = ']'; break;} |
| case kVK_ANSI_LeftBracket : {keycode = '['; break;} |
| case kVK_ANSI_Quote : {keycode = '\''; break;} |
| case kVK_ANSI_Semicolon : {keycode = ';'; break;} |
| case kVK_ANSI_Backslash : {keycode = '\\'; break;} |
| case kVK_ANSI_Comma : {keycode = ','; break;} |
| case kVK_ANSI_Slash : {keycode = '/'; break;} |
| case kVK_ANSI_Period : {keycode = '.'; break;} |
| case kVK_ANSI_Grave : {keycode = '`'; break;} |
| case kVK_ANSI_KeypadDecimal : {keycode = '.'; break;} |
| case kVK_ANSI_KeypadMultiply : {keycode = '*'; break;} |
| case kVK_ANSI_KeypadPlus : {keycode = '+'; break;} |
| case kVK_ANSI_KeypadClear : {keycode = '?'; break;} |
| case kVK_ANSI_KeypadDivide : {keycode = '/'; break;} |
| case kVK_ANSI_KeypadEnter : {keycode = B3G_RETURN; break;} |
| case kVK_ANSI_KeypadMinus : {keycode = '-'; break;} |
| case kVK_ANSI_KeypadEquals : {keycode = '='; break;} |
| case kVK_ANSI_Keypad0 : {keycode = '0'; break;} |
| case kVK_ANSI_Keypad1 : {keycode = '1'; break;} |
| case kVK_ANSI_Keypad2 : {keycode = '2'; break;} |
| case kVK_ANSI_Keypad3 : {keycode = '3'; break;} |
| case kVK_ANSI_Keypad4 : {keycode = '4'; break;} |
| case kVK_ANSI_Keypad5 : {keycode = '5'; break;} |
| case kVK_ANSI_Keypad6 : {keycode = '6'; break;} |
| case kVK_ANSI_Keypad7 : {keycode = '7'; break;} |
| case kVK_ANSI_Keypad8 : {keycode = '8'; break;} |
| case kVK_ANSI_Keypad9 : {keycode = '9'; break;} |
| case kVK_Return: |
| { |
| keycode = B3G_RETURN; break; |
| } |
| |
| default: |
| { |
| |
| printf("unknown keycode\n"); |
| } |
| } |
| return keycode; |
| } |
| |
| |
| void MacOpenGLWindow::startRendering() |
| { |
| NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
| |
| |
| GLint err = glGetError(); |
| assert(err==GL_NO_ERROR); |
| |
| |
| NSEvent *event = nil; |
| bool handledEvent = false; |
| |
| do |
| { |
| [pool release]; |
| pool = [[NSAutoreleasePool alloc] init]; |
| event = [m_internalData->m_myApp |
| nextEventMatchingMask:NSAnyEventMask |
| untilDate:[NSDate distantPast] |
| inMode:NSDefaultRunLoopMode |
| // inMode:NSEventTrackingRunLoopMode |
| dequeue:YES]; |
| |
| //NSShiftKeyMask = 1 << 17, |
| //NSControlKeyMask |
| |
| if ([event type] == NSFlagsChanged) |
| { |
| int modifiers = [event modifierFlags]; |
| if (m_keyboardCallback) |
| { |
| if ((modifiers & NSShiftKeyMask)) |
| { |
| m_keyboardCallback(B3G_SHIFT,1); |
| m_modifierFlags |= MY_MAC_SHIFTKEY; |
| }else |
| { |
| if (m_modifierFlags& MY_MAC_SHIFTKEY) |
| { |
| m_keyboardCallback(B3G_SHIFT,0); |
| m_modifierFlags &= ~MY_MAC_SHIFTKEY; |
| } |
| } |
| if (modifiers & NSControlKeyMask) |
| { |
| m_keyboardCallback(B3G_CONTROL,1); |
| m_modifierFlags |= MY_MAC_CONTROL_KEY; |
| } else |
| { |
| if (m_modifierFlags&MY_MAC_CONTROL_KEY) |
| { |
| m_keyboardCallback(B3G_CONTROL,0); |
| m_modifierFlags &= ~MY_MAC_CONTROL_KEY; |
| } |
| } |
| if (modifiers & NSAlternateKeyMask) |
| { |
| m_keyboardCallback(B3G_ALT,1); |
| m_modifierFlags |= MY_MAC_ALTKEY; |
| } else |
| { |
| if (m_modifierFlags&MY_MAC_ALTKEY) |
| { |
| m_keyboardCallback(B3G_ALT,0); |
| m_modifierFlags &= ~MY_MAC_ALTKEY; |
| |
| } |
| } |
| //handle NSCommandKeyMask |
| |
| } |
| } |
| if ([event type] == NSKeyUp) |
| { |
| handledEvent = true; |
| |
| uint32 virtualKeycode = [event keyCode]; |
| |
| int keycode = getAsciiCodeFromVirtualKeycode(virtualKeycode); |
| // printf("keycode = %d\n", keycode); |
| |
| if (m_keyboardCallback) |
| { |
| int state = 0; |
| m_keyboardCallback(keycode,state); |
| } |
| } |
| if ([event type] == NSKeyDown) |
| { |
| handledEvent = true; |
| |
| if (![event isARepeat]) |
| { |
| uint32 virtualKeycode = [event keyCode]; |
| |
| int keycode = getAsciiCodeFromVirtualKeycode(virtualKeycode); |
| //printf("keycode = %d\n", keycode); |
| |
| if (m_keyboardCallback) |
| { |
| int state = 1; |
| m_keyboardCallback(keycode,state); |
| } |
| } |
| } |
| |
| |
| if (([event type]== NSRightMouseDown) || ([ event type]==NSLeftMouseDown)||([event type]==NSOtherMouseDown)) |
| { |
| // printf("right mouse!"); |
| // float mouseX,mouseY; |
| |
| NSPoint eventLocation = [event locationInWindow]; |
| NSPoint center = [m_internalData->m_myview convertPoint:eventLocation fromView:nil]; |
| m_mouseX = center.x; |
| m_mouseY = [m_internalData->m_myview GetWindowHeight] - center.y; |
| int button=0; |
| switch ([event type]) |
| { |
| case NSLeftMouseDown: |
| { |
| button=0; |
| break; |
| } |
| case NSOtherMouseDown: |
| { |
| button=1; |
| break; |
| } |
| case NSRightMouseDown: |
| { |
| button=2; |
| break; |
| } |
| default: |
| { |
| |
| } |
| }; |
| // printf("mouse coord = %f, %f\n",mouseX,mouseY); |
| if (m_mouseButtonCallback) |
| { |
| //handledEvent = true; |
| (*m_mouseButtonCallback)(button,1,m_mouseX,m_mouseY); |
| } |
| } |
| |
| |
| if (([event type]== NSRightMouseUp) || ([ event type]==NSLeftMouseUp)||([event type]==NSOtherMouseUp)) |
| { |
| // printf("right mouse!"); |
| // float mouseX,mouseY; |
| |
| NSPoint eventLocation = [event locationInWindow]; |
| NSPoint center = [m_internalData->m_myview convertPoint:eventLocation fromView:nil]; |
| m_mouseX = center.x; |
| m_mouseY = [m_internalData->m_myview GetWindowHeight] - center.y; |
| |
| int button=0; |
| switch ([event type]) |
| { |
| case NSLeftMouseUp: |
| { |
| button=0; |
| break; |
| } |
| case NSOtherMouseUp: |
| { |
| button=1; |
| break; |
| } |
| case NSRightMouseUp: |
| { |
| button=2; |
| break; |
| } |
| default: |
| { |
| |
| } |
| }; |
| |
| // printf("mouse coord = %f, %f\n",mouseX,mouseY); |
| if (m_mouseButtonCallback) |
| (*m_mouseButtonCallback)(button,0,m_mouseX,m_mouseY); |
| |
| } |
| |
| |
| if ([event type] == NSMouseMoved) |
| { |
| |
| // http://stackoverflow.com/questions/4630509/how-to-find-if-the-mouse-is-over-a-view |
| NSPoint globalLocation = [ NSEvent mouseLocation ]; |
| NSPoint windowLocation = [ [m_internalData->m_myview window] convertScreenToBase:globalLocation ]; |
| NSPoint viewLocation = [ m_internalData->m_myview convertPoint:windowLocation fromView: nil ]; |
| //printf("global = %f, %f\n", globalLocation.x, globalLocation.y); |
| //printf("window = %f, %f\n", windowLocation.x, windowLocation.y); |
| //printf("view = %f, %f\n", viewLocation.x, viewLocation.y); |
| |
| //NSPoint eventLocation = [event locationInWindow]; |
| //NSPoint center = [m_internalData->m_myview convertPoint:eventLocation fromView:nil]; |
| NSPoint center = viewLocation; |
| m_mouseX = center.x; |
| m_mouseY = [m_internalData->m_myview GetWindowHeight] - center.y; |
| |
| // printf("mouse coord = %f, %f\n",m_mouseX,m_mouseY); |
| if (m_mouseMoveCallback) |
| { |
| //handledEvent = true; |
| (*m_mouseMoveCallback)(m_mouseX,m_mouseY); |
| } |
| } |
| |
| if (([event type] == NSLeftMouseDragged) || ([event type] == NSRightMouseDragged) || ([event type] == NSOtherMouseDragged)) |
| { |
| int dx1, dy1; |
| CGGetLastMouseDelta (&dx1, &dy1); |
| |
| NSPoint eventLocation = [event locationInWindow]; |
| NSPoint center = [m_internalData->m_myview convertPoint:eventLocation fromView:nil]; |
| m_mouseX = center.x; |
| m_mouseY = [m_internalData->m_myview GetWindowHeight] - center.y; |
| |
| if (m_mouseMoveCallback) |
| { |
| //handledEvent = true; |
| (*m_mouseMoveCallback)(m_mouseX,m_mouseY); |
| } |
| |
| // printf("mouse coord = %f, %f\n",m_mouseX,m_mouseY); |
| } |
| |
| if ([event type] == NSScrollWheel) |
| { |
| float dy, dx; |
| dy = [ event deltaY ]; |
| dx = [ event deltaX ]; |
| |
| if (m_wheelCallback) |
| { |
| handledEvent = true; |
| (*m_wheelCallback)(dx,dy); |
| } |
| // m_cameraDistance -= dy*0.1; |
| // m_azi -= dx*0.1; |
| |
| } |
| |
| if (!handledEvent) |
| [m_internalData->m_myApp sendEvent:event]; |
| |
| [m_internalData->m_myApp updateWindows]; |
| } while (event); |
| |
| err = glGetError(); |
| assert(err==GL_NO_ERROR); |
| |
| [m_internalData->m_myview MakeCurrent]; |
| err = glGetError(); |
| assert(err==GL_NO_ERROR); |
| |
| |
| // glClearColor(1,1,1,1); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); //clear buffers |
| |
| err = glGetError(); |
| assert(err==GL_NO_ERROR); |
| |
| //glCullFace(GL_BACK); |
| //glFrontFace(GL_CCW); |
| glEnable(GL_DEPTH_TEST); |
| err = glGetError(); |
| assert(err==GL_NO_ERROR); |
| |
| float aspect; |
| //b3Vector3 extents; |
| |
| if (m_internalData->m_width > m_internalData->m_height) |
| { |
| aspect = (float)m_internalData->m_width / (float)m_internalData->m_height; |
| //extents.setValue(aspect * 1.0f, 1.0f,0); |
| } else |
| { |
| aspect = (float)m_internalData->m_height / (float)m_internalData->m_width; |
| //extents.setValue(1.0f, aspect*1.f,0); |
| } |
| |
| err = glGetError(); |
| assert(err==GL_NO_ERROR); |
| [pool release]; |
| |
| } |
| |
| void MacOpenGLWindow::endRendering() |
| { |
| [m_internalData->m_myview MakeCurrent]; |
| //#ifndef NO_OPENGL3 |
| // glSwapAPPLE(); |
| //#else |
| [[m_internalData->m_myview getContext] flushBuffer]; |
| // #endif |
| |
| } |
| |
| bool MacOpenGLWindow::requestedExit() const |
| { |
| bool closeme = m_internalData->m_myview.GetRequestClose; |
| return m_internalData->m_exitRequested || closeme; |
| } |
| |
| void MacOpenGLWindow::setRequestExit() |
| { |
| m_internalData->m_exitRequested = true; |
| } |
| |
| #include <string.h> |
| int MacOpenGLWindow::fileOpenDialog(char* filename, int maxNameLength) |
| { |
| //save/restore the OpenGL context, NSOpenPanel can mess it up |
| //http://stackoverflow.com/questions/13987148/nsopenpanel-breaks-my-sdl-opengl-app |
| |
| NSOpenGLContext *foo = [NSOpenGLContext currentContext]; |
| // get the url of a .txt file |
| NSOpenPanel * zOpenPanel = [NSOpenPanel openPanel]; |
| NSArray * zAryOfExtensions = [NSArray arrayWithObjects:@"urdf",@"bullet",@"obj",@"sdf",nil]; |
| [zOpenPanel setAllowedFileTypes:zAryOfExtensions]; |
| NSInteger zIntResult = [zOpenPanel runModal]; |
| |
| [foo makeCurrentContext]; |
| |
| if (zIntResult == NSFileHandlingPanelCancelButton) { |
| NSLog(@"readUsingOpenPanel cancelled"); |
| return 0; |
| } |
| NSURL *zUrl = [zOpenPanel URL]; |
| if (zUrl) |
| { |
| //without the file:// |
| NSString *myString = [zUrl absoluteString]; |
| int slen = [myString length]; |
| if (slen < maxNameLength) |
| { |
| const char *cfilename=[myString UTF8String]; |
| //expect file:// at start of URL |
| const char* p = strstr(cfilename, "file://"); |
| if (p==cfilename) |
| { |
| int actualLen = strlen(cfilename)-7; |
| memcpy(filename, cfilename+7,actualLen); |
| filename[actualLen]=0; |
| return actualLen; |
| } |
| } |
| } |
| |
| return 0; |
| } |
| |
| |
| |
| void MacOpenGLWindow::getMouseCoordinates(int& x, int& y) |
| { |
| |
| NSPoint pt = [m_internalData->m_window mouseLocationOutsideOfEventStream]; |
| m_mouseX = pt.x; |
| m_mouseY = pt.y; |
| |
| x = m_mouseX; |
| //our convention is x,y is upper left hand side |
| y = [m_internalData->m_myview GetWindowHeight]-m_mouseY; |
| |
| |
| } |
| |
| int MacOpenGLWindow::getWidth() const |
| { |
| if (m_internalData && m_internalData->m_myview && m_internalData->m_myview.GetWindowWidth) |
| return m_internalData->m_myview.GetWindowWidth; |
| return 0; |
| } |
| |
| int MacOpenGLWindow::getHeight() const |
| { |
| if (m_internalData && m_internalData->m_myview && m_internalData->m_myview.GetWindowHeight) |
| return m_internalData->m_myview.GetWindowHeight; |
| return 0; |
| } |
| |
| |
| void MacOpenGLWindow::setResizeCallback(b3ResizeCallback resizeCallback) |
| { |
| [m_internalData->m_myview setResizeCallback:resizeCallback]; |
| if (resizeCallback) |
| { |
| (resizeCallback)(m_internalData->m_width,m_internalData->m_height); |
| } |
| } |
| |
| b3ResizeCallback MacOpenGLWindow::getResizeCallback() |
| { |
| return [m_internalData->m_myview getResizeCallback]; |
| } |
| |