#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 ];
|
|
|
|
//NSPoint eventLocation = [NSEvent mouseLocation]; //[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];
|
|
}
|
|
|