aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/ode-0.9/drawstuff/src/osx.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/ode-0.9/drawstuff/src/osx.cpp')
-rw-r--r--libraries/ode-0.9/drawstuff/src/osx.cpp542
1 files changed, 542 insertions, 0 deletions
diff --git a/libraries/ode-0.9/drawstuff/src/osx.cpp b/libraries/ode-0.9/drawstuff/src/osx.cpp
new file mode 100644
index 0000000..fcecba9
--- /dev/null
+++ b/libraries/ode-0.9/drawstuff/src/osx.cpp
@@ -0,0 +1,542 @@
1/*************************************************************************
2 * *
3 * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
4 * All rights reserved. Email: russ@q12.org Web: www.q12.org *
5 * *
6 * This library is free software; you can redistribute it and/or *
7 * modify it under the terms of EITHER: *
8 * (1) The GNU Lesser General Public License as published by the Free *
9 * Software Foundation; either version 2.1 of the License, or (at *
10 * your option) any later version. The text of the GNU Lesser *
11 * General Public License is included with this library in the *
12 * file LICENSE.TXT. *
13 * (2) The BSD-style license that is included with this library in *
14 * the file LICENSE-BSD.TXT. *
15 * *
16 * This library is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
19 * LICENSE.TXT and LICENSE-BSD.TXT for more details. *
20 * *
21 *************************************************************************/
22
23// Platform-specific code for Mac OS X using Carbon+AGL
24//
25// Created using x11.cpp and the window-initialization -routines from GLFW
26// as reference.
27// Not thoroughly tested and is certain to contain deficiencies and bugs
28
29#include <ode/config.h>
30#include <stdlib.h>
31#include <string.h>
32#include <stdarg.h>
33
34#ifdef HAVE_SYS_TIME_H
35#include <sys/time.h>
36#endif
37
38#include <drawstuff/drawstuff.h>
39#include <drawstuff/version.h>
40#include "internal.h"
41
42#include <Carbon/Carbon.h>
43#include <AGL/agl.h>
44
45// Global variables
46
47static bool running = true; // 1 if simulation running
48static bool paused = false; // 1 if in `pause' mode
49static bool singlestep = false; // 1 if single step key pressed
50static bool writeframes = false; // 1 if frame files to be written
51
52static int windowWidth = -1;
53static int windowHeight = -1;
54static UInt32 modifierMask = 0;
55static int mouseButtonMode = 0;
56static bool mouseWithOption = false; // Set if dragging the mouse with alt pressed
57static bool mouseWithControl = false; // Set if dragging the mouse with ctrl pressed
58
59static dsFunctions* functions = NULL;
60static WindowRef windowReference;
61static AGLContext aglContext;
62
63static EventHandlerUPP mouseUPP = NULL;
64static EventHandlerUPP keyboardUPP = NULL;
65static EventHandlerUPP windowUPP = NULL;
66
67// Describes the window-events we are interested in
68EventTypeSpec OSX_WINDOW_EVENT_TYPES[] = {
69 { kEventClassWindow, kEventWindowBoundsChanged },
70 { kEventClassWindow, kEventWindowClose },
71 { kEventClassWindow, kEventWindowDrawContent }
72};
73
74// Describes the mouse-events we are interested in
75EventTypeSpec OSX_MOUSE_EVENT_TYPES[] = {
76 { kEventClassMouse, kEventMouseDown },
77 { kEventClassMouse, kEventMouseUp },
78 { kEventClassMouse, kEventMouseMoved },
79 { kEventClassMouse, kEventMouseDragged }
80};
81
82// Describes the key-events we are interested in
83EventTypeSpec OSX_KEY_EVENT_TYPES[] = {
84 { kEventClassKeyboard, kEventRawKeyDown },
85// { kEventClassKeyboard, kEventRawKeyUp },
86 { kEventClassKeyboard, kEventRawKeyModifiersChanged }
87};
88
89//***************************************************************************
90// error handling for unix
91
92static void printMessage (char *msg1, char *msg2, va_list ap)
93{
94 fflush (stderr);
95 fflush (stdout);
96 fprintf (stderr,"\n%s: ",msg1);
97 vfprintf (stderr,msg2,ap);
98 fprintf (stderr,"\n");
99 fflush (stderr);
100}
101
102extern "C" void dsError (char *msg, ...)
103{
104 va_list ap;
105 va_start (ap,msg);
106 printMessage ("Error",msg,ap);
107 exit (1);
108}
109
110
111extern "C" void dsDebug (char *msg, ...)
112{
113 va_list ap;
114 va_start (ap,msg);
115 printMessage ("INTERNAL ERROR",msg,ap);
116 // *((char *)0) = 0; ... commit SEGVicide ?
117 abort();
118}
119
120extern "C" void dsPrint (char *msg, ...)
121{
122 va_list ap;
123 va_start (ap,msg);
124 vprintf (msg,ap);
125}
126
127static void captureFrame( int num ){
128
129 fprintf( stderr,"\rcapturing frame %04d", num );
130 unsigned char buffer[windowWidth*windowHeight][3];
131 glReadPixels( 0, 0, windowWidth, windowHeight, GL_RGB, GL_UNSIGNED_BYTE, &buffer );
132 char s[100];
133 sprintf (s,"frame%04d.ppm",num);
134 FILE *f = fopen (s,"wb");
135 if( !f ){
136 dsError( "can't open \"%s\" for writing", s );
137 }
138 fprintf( f,"P6\n%d %d\n255\n", windowWidth, windowHeight );
139 for( int y=windowHeight-1; y>-1; y-- ){
140 fwrite( buffer[y*windowWidth], 3*windowWidth, 1, f );
141 }
142 fclose (f);
143}
144
145extern "C" void dsStop(){
146
147 running = false;
148}
149
150extern "C" double dsElapsedTime()
151{
152#if HAVE_GETTIMEOFDAY
153 static double prev=0.0;
154 timeval tv ;
155
156 gettimeofday(&tv, 0);
157 double curr = tv.tv_sec + (double) tv.tv_usec / 1000000.0 ;
158 if (!prev)
159 prev=curr;
160 double retval = curr-prev;
161 prev=curr;
162 if (retval>1.0) retval=1.0;
163 if (retval<dEpsilon) retval=dEpsilon;
164 return retval;
165#else
166 return 0.01666; // Assume 60 fps
167#endif
168}
169
170OSStatus osxKeyEventHandler( EventHandlerCallRef handlerCallRef, EventRef event, void *userData ){
171
172 UInt32 keyCode;
173 UInt32 state = 0;
174 void* KCHR = NULL;
175 char charCode = 0;
176 char uppercase = 0;
177
178 switch( GetEventKind( event ) ){
179 case kEventRawKeyDown:
180 if( GetEventParameter( event, kEventParamKeyCode, typeUInt32, NULL, sizeof( UInt32 ), NULL, &keyCode ) != noErr ){
181 break;
182 }
183 KCHR = (void *)GetScriptVariable( smCurrentScript, smKCHRCache );
184 charCode = (char)KeyTranslate( KCHR, keyCode, &state );
185 uppercase = charCode;
186 UppercaseText( &uppercase, 1, smSystemScript );
187 //printf( "Character %d [%c] [%c] modifiers [%d]\n", charCode, charCode, uppercase, modifierMask );
188
189 if( modifierMask == 0 ){
190 if( charCode >= ' ' && charCode <= 126 && functions -> command ){
191 functions -> command( charCode );
192 }
193 }
194 else if( ( modifierMask & controlKey ) ){
195 // ctrl+key was pressed
196 switch(uppercase ){
197 case 'T':
198 dsSetTextures( !dsGetTextures() );
199 break;
200 case 'S':
201 dsSetShadows( !dsGetShadows() );
202 break;
203 case 'X':
204 running = false;
205 break;
206 case 'P':
207 paused = !paused;
208 singlestep = false;
209 break;
210 case 'O':
211 if( paused ){
212 singlestep = true;
213 }
214 break;
215 case 'V': {
216 float xyz[3],hpr[3];
217 dsGetViewpoint( xyz,hpr );
218 printf( "Viewpoint = (%.4f,%.4f,%.4f,%.4f,%.4f,%.4f)\n", xyz[0], xyz[1], xyz[2], hpr[0], hpr[1], hpr[2] );
219 break;
220 }
221 case 'W':
222 writeframes = !writeframes;
223 if( writeframes ){
224 printf( "Now writing frames to PPM files\n" );
225 }
226 break;
227 }
228
229 }
230 return noErr;
231 case kEventRawKeyModifiersChanged:
232 if( GetEventParameter( event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof( UInt32 ), NULL, &modifierMask ) == noErr ){
233 if( ( mouseWithOption && !( modifierMask & optionKey ) ) || ( mouseWithControl && !( modifierMask & controlKey ) ) ){
234 // The mouse was being dragged using either the command-key or the option-key modifier to emulate
235 // the right button or both left + right.
236 // Now the modifier-key has been released so the mouseButtonMode must be changed accordingly
237 // The following releases the right-button.
238 mouseButtonMode &= (~4);
239 mouseWithOption = false;
240 mouseWithControl = false;
241 }
242 return noErr;
243 }
244 break;
245 }
246 return eventNotHandledErr;
247}
248
249OSStatus osxMouseEventHandler( EventHandlerCallRef handlerCallRef, EventRef event, void *userData ){
250
251 bool buttonDown = false;
252 HIPoint mouseLocation;
253
254 switch( GetEventKind( event ) ){
255
256 case kEventMouseDown:
257 buttonDown = true;
258 case kEventMouseUp:
259 if( GetEventParameter( event, kEventParamWindowMouseLocation, typeHIPoint, NULL, sizeof( HIPoint ), NULL, &mouseLocation ) != noErr ){
260 break;
261 }
262 EventMouseButton button;
263 if( GetEventParameter( event, kEventParamMouseButton, typeMouseButton, NULL, sizeof( EventMouseButton ), NULL, &button ) == noErr ){
264
265 if( button == kEventMouseButtonPrimary ){
266 if( modifierMask & controlKey ){
267 // Ctrl+button == right
268 button = kEventMouseButtonSecondary;
269 mouseWithControl = true;
270 }
271 else if( modifierMask & optionKey ){
272 // Alt+button == left+right
273 mouseButtonMode = 5;
274 mouseWithOption = true;
275 return noErr;
276 }
277 }
278 if( buttonDown ){
279 if( button == kEventMouseButtonPrimary ) mouseButtonMode |= 1; // Left
280 if( button == kEventMouseButtonTertiary ) mouseButtonMode |= 2; // Middle
281 if( button == kEventMouseButtonSecondary ) mouseButtonMode |= 4; // Right
282 }
283 else{
284 if( button == kEventMouseButtonPrimary ) mouseButtonMode &= (~1); // Left
285 if( button == kEventMouseButtonTertiary ) mouseButtonMode &= (~2); // Middle
286 if( button == kEventMouseButtonSecondary ) mouseButtonMode &= (~4);// Right
287 }
288 return noErr;
289 }
290 break;
291 case kEventMouseMoved:
292 // NO-OP
293 return noErr;
294 case kEventMouseDragged:
295 // Carbon provides mouse-position deltas, so we don't have to store the old state ourselves
296 if( GetEventParameter( event, kEventParamMouseDelta, typeHIPoint, NULL, sizeof( HIPoint ), NULL, &mouseLocation ) == noErr ){
297 //printf( "Mode %d\n", mouseButtonMode );
298 dsMotion( mouseButtonMode, (int)mouseLocation.x, (int)mouseLocation.y );
299 return noErr;
300 }
301 break;
302 case kEventMouseWheelMoved:
303 // NO-OP
304 break;
305 }
306 return eventNotHandledErr;
307}
308
309static void osxCloseMainWindow(){
310
311 if( windowUPP != NULL ){
312 DisposeEventHandlerUPP( windowUPP );
313 windowUPP = NULL;
314 }
315
316 if( aglContext != NULL ){
317 aglSetCurrentContext( NULL );
318 aglSetDrawable( aglContext, NULL );
319 aglDestroyContext( aglContext );
320 aglContext = NULL;
321 }
322
323 if( windowReference != NULL ){
324 ReleaseWindow( windowReference );
325 windowReference = NULL;
326 }
327}
328
329OSStatus osxWindowEventHandler( EventHandlerCallRef handlerCallRef, EventRef event, void *userData ){
330
331 //printf( "WindowEvent\n" );
332 switch( GetEventKind(event) ){
333 case kEventWindowBoundsChanged:
334 WindowRef window;
335 GetEventParameter( event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &window );
336 Rect rect;
337 GetWindowPortBounds( window, &rect );
338 windowWidth = rect.right;
339 windowHeight = rect.bottom;
340 aglUpdateContext( aglContext );
341 break;
342 case kEventWindowClose:
343 osxCloseMainWindow();
344 exit( 0 );
345 return noErr;
346 case kEventWindowDrawContent:
347 // NO-OP
348 break;
349 }
350
351 return eventNotHandledErr;
352}
353
354static void osxCreateMainWindow( int width, int height ){
355
356 int redbits = 4;
357 int greenbits = 4;
358 int bluebits = 4;
359 int alphabits = 4;
360 int depthbits = 16;
361
362 OSStatus error;
363
364 // create pixel format attribute list
365
366 GLint pixelFormatAttributes[256];
367 int numAttrs = 0;
368
369 pixelFormatAttributes[numAttrs++] = AGL_RGBA;
370 pixelFormatAttributes[numAttrs++] = AGL_DOUBLEBUFFER;
371
372 pixelFormatAttributes[numAttrs++] = AGL_RED_SIZE;
373 pixelFormatAttributes[numAttrs++] = redbits;
374 pixelFormatAttributes[numAttrs++] = AGL_GREEN_SIZE;
375 pixelFormatAttributes[numAttrs++] = greenbits;
376 pixelFormatAttributes[numAttrs++] = AGL_BLUE_SIZE;
377 pixelFormatAttributes[numAttrs++] = bluebits;
378 pixelFormatAttributes[numAttrs++] = AGL_ALPHA_SIZE;
379 pixelFormatAttributes[numAttrs++] = alphabits;
380 pixelFormatAttributes[numAttrs++] = AGL_DEPTH_SIZE;
381 pixelFormatAttributes[numAttrs++] = depthbits;
382
383 pixelFormatAttributes[numAttrs++] = AGL_NONE;
384
385 // create pixel format.
386
387 AGLDevice mainMonitor = GetMainDevice();
388 AGLPixelFormat pixelFormat = aglChoosePixelFormat( &mainMonitor, 1, pixelFormatAttributes );
389 if( pixelFormat == NULL ){
390 return;
391 }
392
393 aglContext = aglCreateContext( pixelFormat, NULL );
394
395 aglDestroyPixelFormat( pixelFormat );
396
397 if( aglContext == NULL ){
398 osxCloseMainWindow();
399 return;
400 }
401
402 Rect windowContentBounds;
403 windowContentBounds.left = 0;
404 windowContentBounds.top = 0;
405 windowContentBounds.right = width;
406 windowContentBounds.bottom = height;
407
408 int windowAttributes = kWindowCloseBoxAttribute
409 | kWindowFullZoomAttribute
410 | kWindowCollapseBoxAttribute
411 | kWindowResizableAttribute
412 | kWindowStandardHandlerAttribute
413 | kWindowLiveResizeAttribute;
414
415 error = CreateNewWindow( kDocumentWindowClass, windowAttributes, &windowContentBounds, &windowReference );
416 if( ( error != noErr ) || ( windowReference == NULL ) ){
417 osxCloseMainWindow();
418 return;
419 }
420
421 windowUPP = NewEventHandlerUPP( osxWindowEventHandler );
422
423 error = InstallWindowEventHandler( windowReference, windowUPP,GetEventTypeCount( OSX_WINDOW_EVENT_TYPES ), OSX_WINDOW_EVENT_TYPES, NULL, NULL );
424 if( error != noErr ){
425 osxCloseMainWindow();
426 return;
427 }
428
429 // The process-type must be changed for a ForegroundApplication
430 // Unless it is a foreground-process, the application will not show in the dock or expose and the window
431 // will not behave properly.
432 ProcessSerialNumber currentProcess;
433 GetCurrentProcess( &currentProcess );
434 TransformProcessType( &currentProcess, kProcessTransformToForegroundApplication );
435 SetFrontProcess( &currentProcess );
436
437 SetWindowTitleWithCFString( windowReference, CFSTR( "ODE - Drawstuff" ) );
438 RepositionWindow( windowReference, NULL, kWindowCenterOnMainScreen );
439
440 ShowWindow( windowReference );
441
442 if( !aglSetDrawable( aglContext, GetWindowPort( windowReference ) ) ){
443 osxCloseMainWindow();
444 return;
445 }
446
447 if( !aglSetCurrentContext( aglContext ) ){
448 osxCloseMainWindow();
449 }
450
451 windowWidth = width;
452 windowHeight = height;
453}
454
455int osxInstallEventHandlers(){
456
457 OSStatus error;
458
459 mouseUPP = NewEventHandlerUPP( osxMouseEventHandler );
460
461 error = InstallEventHandler( GetApplicationEventTarget(), mouseUPP, GetEventTypeCount( OSX_MOUSE_EVENT_TYPES ), OSX_MOUSE_EVENT_TYPES, NULL, NULL );
462 if( error != noErr ){
463 return GL_FALSE;
464 }
465
466 keyboardUPP = NewEventHandlerUPP( osxKeyEventHandler );
467
468 error = InstallEventHandler( GetApplicationEventTarget(), keyboardUPP, GetEventTypeCount( OSX_KEY_EVENT_TYPES ), OSX_KEY_EVENT_TYPES, NULL, NULL );
469 if( error != noErr ){
470 return GL_FALSE;
471 }
472
473 return GL_TRUE;
474}
475
476extern void dsPlatformSimLoop( int givenWindowWidth, int givenWindowHeight, dsFunctions *fn, int givenPause ){
477
478 functions = fn;
479
480 paused = givenPause;
481
482 osxCreateMainWindow( givenWindowWidth, givenWindowHeight );
483 osxInstallEventHandlers();
484
485 dsStartGraphics( windowWidth, windowHeight, fn );
486
487 static bool firsttime=true;
488 if( firsttime )
489 {
490 fprintf
491 (
492 stderr,
493 "\n"
494 "Simulation test environment v%d.%02d\n"
495 " Ctrl-P : pause / unpause (or say `-pause' on command line).\n"
496 " Ctrl-O : single step when paused.\n"
497 " Ctrl-T : toggle textures (or say `-notex' on command line).\n"
498 " Ctrl-S : toggle shadows (or say `-noshadow' on command line).\n"
499 " Ctrl-V : print current viewpoint coordinates (x,y,z,h,p,r).\n"
500 " Ctrl-W : write frames to ppm files: frame/frameNNN.ppm\n"
501 " Ctrl-X : exit.\n"
502 "\n"
503 "Change the camera position by clicking + dragging in the window.\n"
504 " Left button - pan and tilt.\n"
505 " Right button (or Ctrl + button) - forward and sideways.\n"
506 " Left + Right button (or middle button, or Alt + button) - sideways and up.\n"
507 "\n",DS_VERSION >> 8,DS_VERSION & 0xff
508 );
509 firsttime = false;
510 }
511
512 if( fn -> start ) fn->start();
513
514 int frame = 1;
515 running = true;
516 while( running ){
517 // read in and process all pending events for the main window
518 EventRef event;
519 EventTargetRef eventDispatcher = GetEventDispatcherTarget();
520 while( ReceiveNextEvent( 0, NULL, 0.0, TRUE, &event ) == noErr ){
521 SendEventToEventTarget( event, eventDispatcher );
522 ReleaseEvent( event );
523 }
524
525 dsDrawFrame( windowWidth, windowHeight, fn, paused && !singlestep );
526 singlestep = false;
527
528 glFlush();
529 aglSwapBuffers( aglContext );
530
531 // capture frames if necessary
532 if( !paused && writeframes ){
533 captureFrame( frame );
534 frame++;
535 }
536 }
537
538 if( fn->stop ) fn->stop();
539 dsStopGraphics();
540
541 osxCloseMainWindow();
542}