Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/ode/ode-0.9/drawstuff/src/osx.cpp @ 216

Last change on this file since 216 was 216, checked in by mathiask, 17 years ago

[Physik] add ode-0.9

File size: 16.3 KB
Line 
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}
Note: See TracBrowser for help on using the repository browser.