[ODE] Stability in ODE

Timothy J. Wood tjw at omnigroup.com
Thu Jul 25 19:58:02 2002


--Apple-Mail-1--47056944
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	charset=US-ASCII;
	format=flowed




   Well, I'm still trying to write some basic code of my own -- I just 
wrote the stability test since I saw some weird glitches in the box 
dropping example.

   As far as the native Mac OS X port, here is what I have so far (as a 
diff against the head of CVS).  This doesn't handle mouse input, for 
example -- if any of the examples actually use that, I could certainly 
add it, though.

First there is a new file in drawstuff/src


--Apple-Mail-1--47056944
Content-Disposition: attachment;
	filename=macosx.mm
Content-Transfer-Encoding: 7bit
Content-Type: application/octet-stream;
	x-unix-mode=0664;
	name="macosx.mm"

/*************************************************************************
 *                                                                       *
 * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith.       *
 * All rights reserved.  Email: russ@q12.org   Web: www.q12.org          *
 *                                                                       *
 * This library is free software; you can redistribute it and/or         *
 * modify it under the terms of EITHER:                                  *
 *   (1) The GNU Lesser General Public License as published by the Free  *
 *       Software Foundation; either version 2.1 of the License, or (at  *
 *       your option) any later version. The text of the GNU Lesser      *
 *       General Public License is included with this library in the     *
 *       file LICENSE.TXT.                                               *
 *   (2) The BSD-style license that is included with this library in     *
 *       the file LICENSE-BSD.TXT.                                       *
 *                                                                       *
 * This library is distributed in the hope that it will be useful,       *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files    *
 * LICENSE.TXT and LICENSE-BSD.TXT for more details.                     *
 *                                                                       *
 *************************************************************************/

#include <ode/config.h>
#include "internal.h"

#import <Cocoa/Cocoa.h>
#import <AppKit/NSOpenGL.h>
#import <OpenGL/gl.h>
#import <pthread.h>

//***************************************************************************
// application globals

@interface SimWindow : NSWindow
@end
static SimWindow *window;

//***************************************************************************
// error and message handling

static void errorBox (char *title, char *msg, va_list ap)
{
    NSString *formatString, *msgString;

    formatString = [[NSString alloc] initWithCString: msg];
    msgString = [[NSString alloc] initWithFormat: formatString arguments: ap];
    [formatString release];

#warning TJW: Run a sheet relative to our window
    NSLog(@"msg=%@", msgString);

    [msgString release];
}


static void dsWarning (char *msg, ...)
{
  va_list ap;
  va_start (ap,msg);
  errorBox ("Warning",msg,ap);
}


extern "C" void dsError (char *msg, ...)
{
  va_list ap;
  va_start (ap,msg);
  errorBox ("Error",msg,ap);
  exit (1);
}


extern "C" void dsDebug (char *msg, ...)
{
  va_list ap;
  va_start (ap,msg);
  errorBox ("INTERNAL ERROR",msg,ap);
  // *((char *)0) = 0;	 ... commit SEGVicide ?
  abort();
  exit (1);	  // should never get here, but just in case...
}


extern "C" void dsPrint (char *msg, ...)
{
  va_list ap;
  va_start (ap,msg);
  vprintf (msg,ap);
}

//***************************************************************************
// rendering thread

// globals used to communicate with rendering thread

static volatile int renderer_run = 1;
static volatile int renderer_pause = 0;	  // 0=run, 1=pause
static volatile int renderer_ss = 0;	  // single step command
static volatile int renderer_width = 1;
static volatile int renderer_height = 1;
static dsFunctions *renderer_fn = 0;
static volatile NSOpenGLPixelFormat *renderer_pixelFormat = nil;
static volatile int keybuffer[16];	  // fifo ring buffer for keypresses
static volatile int keybuffer_head = 0;	  // index of next key to put in (modified by GUI)
static volatile int keybuffer_tail = 0;	  // index of next key to take out (modified by renderer)


static void setupRendererGlobals()
{
  renderer_run = 1;
  renderer_pause = 0;
  renderer_ss = 0;
  renderer_width = 1;
  renderer_height = 1;
  renderer_fn = 0;
  renderer_pixelFormat = nil;
  keybuffer[16];
  keybuffer_head = 0;
  keybuffer_tail = 0;
}


static void *renderingThread (void *arg)
{
    // create openGL context and make it current
    NSOpenGLContext *glc;

    glc = [[NSOpenGLContext alloc] initWithFormat: renderer_pixelFormat shareContext:nil];
    if (glc==NULL) dsError ("could not create OpenGL context");

    [glc setView: [window contentView]];
    [glc makeCurrentContext];
    if ([NSOpenGLContext currentContext] != glc)
        dsError ("could not make OpenGL context current");

    // test openGL capabilities
    GLint maxtsize=0;
    glGetIntegerv (GL_MAX_TEXTURE_SIZE,&maxtsize);
    if (maxtsize < 128) dsWarning ("max texture size too small (%dx%d)",
                                   maxtsize,maxtsize);

    dsStartGraphics (renderer_width,renderer_height,renderer_fn);
    if (renderer_fn->start) renderer_fn->start();

    while (renderer_run) {
        // need to make local copy of renderer_ss to help prevent races
        int ss = renderer_ss;
        dsDrawFrame (renderer_width,renderer_height,renderer_fn,
                     renderer_pause && !ss);
        if (ss) renderer_ss = 0;

        // read keys out of ring buffer and feed them to the command function
        while (keybuffer_head != keybuffer_tail) {
            if (renderer_fn->command) renderer_fn->command (keybuffer[keybuffer_tail]);
            keybuffer_tail = (keybuffer_tail+1) & 15;
        }

        // swap buffers
        [glc flushBuffer];
    }

    if (renderer_fn->stop) renderer_fn->stop();
    dsStopGraphics();

    // delete openGL context
    [NSOpenGLContext clearCurrentContext];
    [glc release];

    return arg;
}

//***************************************************************************
// window handling

// callback function for the main window

@implementation SimWindow
- (void) mouseDown: (NSEvent *) event;
{
    NSLog(@"event = %@", event);
    NSLog(@"key = %d", [window isKeyWindow]);
    NSLog(@"main = %d", [window isMainWindow]);
}
- (void) keyDown: (NSEvent *) event;
{
    NSString *characters;
    unsigned int characterIndex, characterCount;
    unichar c;

    NSLog(@"event = %@", event);
    
    characters = [event charactersIgnoringModifiers];
    characterCount = [characters length];
    for (characterIndex = 0; characterIndex < characterCount; characterIndex++) {
        c = [characters characterAtIndex: characterIndex];
        if (c < ' ' || c > 126)
            continue;
        int nexth = (keybuffer_head+1) & 15;
        if (nexth != keybuffer_tail) {
            keybuffer[keybuffer_head] = c;
            keybuffer_head = nexth;
        }
    }
}
@end

#if 0
static LRESULT CALLBACK mainWndProc (HWND hWnd, UINT msg, WPARAM wParam,
				     LPARAM lParam)
{
  static int button=0,lastx=0,lasty=0;
  int ctrl = wParam & MK_CONTROL;

  switch (msg) {
  case WM_LBUTTONDOWN:
  case WM_MBUTTONDOWN:
  case WM_RBUTTONDOWN:
    if (msg==WM_LBUTTONDOWN) button |= 1;
    else if (msg==WM_MBUTTONDOWN) button |= 2;
    else button |= 4;
    lastx = SHORT(LOWORD(lParam));
    lasty = SHORT(HIWORD(lParam));
    SetCapture (hWnd);
    break;

  case WM_LBUTTONUP:
  case WM_MBUTTONUP:
  case WM_RBUTTONUP:
    if (msg==WM_LBUTTONUP) button &= ~1;
    else if (msg==WM_MBUTTONUP) button &= ~2;
    else button &= ~4;
    if (button==0) ReleaseCapture();
    break;

  case WM_MOUSEMOVE: {
    int x = SHORT(LOWORD(lParam));
    int y = SHORT(HIWORD(lParam));
    if (button) dsMotion (button,x-lastx,y-lasty);
    lastx = x;
    lasty = y;
    break;
  }

  case WM_CHAR: {
    if (wParam >= ' ' && wParam <= 126) {
      int nexth = (keybuffer_head+1) & 15;
      if (nexth != keybuffer_tail) {
	keybuffer[keybuffer_head] = wParam;
	keybuffer_head = nexth;
      }
    }
    break;
  }

  case WM_SIZE:
    // lParam will contain the size of the *client* area!
    renderer_width = LOWORD(lParam);
    renderer_height = HIWORD(lParam);
    break;

  case WM_COMMAND:
    switch (wParam & 0xffff) {
    case IDM_ABOUT:
      DialogBox (ghInstance,MAKEINTRESOURCE(IDD_ABOUT),hWnd,
	(DLGPROC) AboutDlgProc);
      break;
    case IDM_PAUSE: {
      renderer_pause ^= 1;
      CheckMenuItem (GetMenu(hWnd),IDM_PAUSE,
		     renderer_pause ? MF_CHECKED : MF_UNCHECKED);
      if (renderer_pause) renderer_ss = 0;
      break;
    }
    case IDM_SINGLE_STEP: {
      renderer_ss = 1;
      break;
    }
    case IDM_PERF_MONITOR: {
      dsWarning ("Performance monitor not yet implemented.");
      break;
    }
    case IDM_TEXTURES: {
      static int tex = 1;
      tex ^= 1;
      CheckMenuItem (GetMenu(hWnd),IDM_TEXTURES,
		     tex ? MF_CHECKED : MF_UNCHECKED);
      dsSetTextures (tex);
      break;
    }
    case IDM_SHADOWS: {
      static int shadows = 1;
      shadows ^= 1;
      CheckMenuItem (GetMenu(hWnd),IDM_SHADOWS,
		     shadows ? MF_CHECKED : MF_UNCHECKED);
      dsSetShadows (shadows);
      break;
    }
    case IDM_SAVE_SETTINGS: {
      dsWarning ("\"Save Settings\" not yet implemented.");
      break;
    }
    case IDM_EXIT:
      PostQuitMessage (0);
      break;
    }
    break;

  case WM_CLOSE:
    PostQuitMessage (0);
    break;

  default:
    return (DefWindowProc (hWnd, msg, wParam, lParam));
  }

  return 0;
}
#endif

#if 0
// this comes from an MSDN example. believe it or not, this is the recommended
// way to get the console window handle.

static HWND GetConsoleHwnd()
{
  // the console window title to a "unique" value, then find the window
  // that has this title.
  char title[1024];
  wsprintf (title,"DrawStuff:%d/%d",GetTickCount(),GetCurrentProcessId());
  SetConsoleTitle (title);
  Sleep(40);			// ensure window title has been updated
  return FindWindow (NULL,title);
}
#endif

static void drawStuffStartup()
{
  static int startup_called = 0;
  if (startup_called) return;
  startup_called = 1;
  NSAutoreleasePool *pool;
  pool = [[NSAutoreleasePool alloc] init];
  [NSApplication sharedApplication];
  [pool release];
}


void dsPlatformSimLoop (int window_width, int window_height,
			dsFunctions *fn, int initial_pause)
{
    NSAutoreleasePool *pool;
    pool = [[NSAutoreleasePool alloc] init];
    
  drawStuffStartup();
  setupRendererGlobals();
  renderer_pause = initial_pause;

  // create window - but first get window size for desired size of client area.
  // if this adjustment isn't made then the openGL area will be shifted into
  // the nonclient area and determining the frame buffer coordinate from the
  // client area coordinate will be hard.
  NSRect frame;

  frame.origin.x    = 50;
  frame.origin.y    = 80;
  frame.size.width  = window_width;
  frame.size.height = window_height;

  window = [[SimWindow alloc] initWithContentRect:frame
                                        styleMask:NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask
                                          backing:NSBackingStoreBuffered
                                            defer:NO];

  NSString *title;
  title = [[NSString alloc] initWithFormat: @"Simulation test environment v%d.%02d", DS_VERSION >> 8,DS_VERSION & 0xff];
  [window setTitle: title];
  [title release];
  
  if (!window) dsError ("could not create main window");
  [window makeKeyAndOrderFront:nil];
  [window setAcceptsMouseMovedEvents: YES];
  [window makeKeyWindow];

  NSLog(@"can key = %d", [window canBecomeKeyWindow]);
  NSLog(@"can main = %d", [window canBecomeMainWindow]);
  NSLog(@"key = %d", [window isKeyWindow]);
  NSLog(@"main = %d", [window isMainWindow]);
  
  // Set up pixel format
  NSOpenGLPixelFormatAttribute attributes[] = {
      NSOpenGLPFADoubleBuffer,
      NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute)24,
      NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)24,
      (NSOpenGLPixelFormatAttribute)0
  };
  renderer_pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes: attributes];
  if (!renderer_pixelFormat)
    dsError ("could not find a good OpenGL pixel format");

  // **********
  // start the rendering thread

  // set renderer globals
  renderer_width = window_width;
  renderer_height = window_height;
  renderer_fn = fn;

  pthread_t thread = NULL;
  int rc;
  rc = pthread_create(&thread, NULL, renderingThread, NULL);
  if (rc || thread==NULL) dsError ("Could not create rendering thread");

  // **********
  // start GUI message processing
  [pool release];
  [NSApp run];

#if 0
  // terminate rendering thread
  renderer_run = 0;
  DWORD ret = WaitForSingleObject (hThread,2000);
  if (ret==WAIT_TIMEOUT) dsWarning ("Could not kill rendering thread (1)");
  DWORD exitcode=0;
  if (!(GetExitCodeThread (hThread,&exitcode) && exitcode == 123))
    dsWarning ("Could not kill rendering thread (2)");
  CloseHandle (hThread);	     // dont need thread handle anymore

  // destroy window
  DestroyWindow (main_window);
#endif
}


extern "C" void dsStop()
{
#warning TJW: Finish me
    abort();
#if 0
  // just calling PostQuitMessage() here wont work, as this function is
  // typically called from the rendering thread, not the GUI thread.
  // instead we must post the message to the GUI window explicitly.

  if (main_window) PostMessage (main_window,WM_QUIT,0,0);
#endif
}

#if 0
//***************************************************************************
// windows entry point
//
// NOTE: WinMain is not guaranteed to be called with MinGW, because MinGW
// always calls main if it is defined and most users of this library will
// define their own main. So the startup functionality is kept in
// zDriverStartup(), which is also called when dsSimulationLoop() is called.

extern "C" int main (int argc, char **argv);


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
		   LPSTR lpCmdLine, int nCmdShow)
{
  drawStuffStartup();
  return main (0,0);	// @@@ should really pass cmd line arguments
}
#endif

--Apple-Mail-1--47056944
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	charset=US-ASCII;
	format=flowed



Then some diffs:


--Apple-Mail-1--47056944
Content-Disposition: attachment;
	filename=macosx.patch
Content-Transfer-Encoding: 7bit
Content-Type: application/octet-stream;
	x-unix-mode=0664;
	name="macosx.patch"

Index: Makefile
===================================================================
RCS file: /cvsroot/ode/Makefile,v
retrieving revision 1.7
diff -c -r1.7 Makefile
*** Makefile	2002/06/25 23:46:13	1.7
--- Makefile	2002/07/26 02:56:22
***************
*** 71,77 ****
  ifeq ($(WINDOWS),1)
  DRAWSTUFF_SRC = drawstuff/src/drawstuff.cpp drawstuff/src/windows.cpp
  RESOURCE_FILE=lib/resources.RES
! else
  DRAWSTUFF_SRC = drawstuff/src/drawstuff.cpp drawstuff/src/x11.cpp
  endif
  
--- 71,84 ----
  ifeq ($(WINDOWS),1)
  DRAWSTUFF_SRC = drawstuff/src/drawstuff.cpp drawstuff/src/windows.cpp
  RESOURCE_FILE=lib/resources.RES
! endif
! 
! ifeq ($(MACOSX),1)
! DRAWSTUFF_SRC    = drawstuff/src/drawstuff.cpp
! DRAWSTUFF_SRC_MM = drawstuff/src/macosx.mm
! endif
! 
! ifndef DRAWSTUFF_SRC
  DRAWSTUFF_SRC = drawstuff/src/drawstuff.cpp drawstuff/src/x11.cpp
  endif
  
***************
*** 118,124 ****
  # object file names
  ODE_PREGEN_OBJECTS=$(ODE_PREGEN_SRC:%.c=%$(OBJ))
  ODE_OBJECTS=$(ODE_SRC:%.cpp=%$(OBJ)) $(ODE_PREGEN_OBJECTS)
! DRAWSTUFF_OBJECTS=$(DRAWSTUFF_SRC:%.cpp=%$(OBJ)) $(RESOURCE_FILE)
  
  # side-effect variables causing creation of files containing lists of
  # filenames to be linked, to work around command-line-length limitations
--- 125,134 ----
  # object file names
  ODE_PREGEN_OBJECTS=$(ODE_PREGEN_SRC:%.c=%$(OBJ))
  ODE_OBJECTS=$(ODE_SRC:%.cpp=%$(OBJ)) $(ODE_PREGEN_OBJECTS)
! ifeq ($(MACOSX),1)
!   DRAWSTUFF_OBJECTS_MM = $(DRAWSTUFF_SRC_MM:%.mm=%$(OBJ))
! endif
! DRAWSTUFF_OBJECTS=$(DRAWSTUFF_SRC:%.cpp=%$(OBJ)) $(RESOURCE_FILE) $(DRAWSTUFF_OBJECTS_MM)
  
  # side-effect variables causing creation of files containing lists of
  # filenames to be linked, to work around command-line-length limitations
Index: config/makefile.osx
===================================================================
RCS file: /cvsroot/ode/config/makefile.osx,v
retrieving revision 1.1
diff -c -r1.1 makefile.osx
*** config/makefile.osx	2001/12/25 06:22:48	1.1
--- config/makefile.osx	2002/07/26 02:56:22
***************
*** 2,19 ****
  DEL_CMD=rm -f
  CC=cc
  OBJ=.o
! C_FLAGS=-c -Wall -fno-rtti -fno-exceptions -Wall
  C_INC=-I
  C_OUT=-o 
  C_EXEOUT=-o 
  C_DEF=-D
  C_OPT=-O
  AR=ar rc 
! RANLIB=
  LIB_PREFIX=lib
  LIB_SUFFIX=.a
! LINK_OPENGL=-L/usr/X11R6/lib -L/usr/X11/lib -L/usr/lib/X11R6 -L/usr/lib/X11 -lX11 -lGL -lGLU
! LINK_MATH=-lm
  
  ifeq ($(BUILD),release)
  OPT=2
--- 2,20 ----
  DEL_CMD=rm -f
  CC=cc
  OBJ=.o
! C_FLAGS=-c -Wall -fno-rtti -fno-exceptions -Wall -DMACOSX
  C_INC=-I
  C_OUT=-o 
  C_EXEOUT=-o 
  C_DEF=-D
  C_OPT=-O
  AR=ar rc 
! RANLIB=ranlib
  LIB_PREFIX=lib
  LIB_SUFFIX=.a
! LINK_OPENGL=-framework Cocoa -framework OpenGL -lstdc++
! LINK_MATH=
! MACOSX=1
  
  ifeq ($(BUILD),release)
  OPT=2
***************
*** 24,26 ****
--- 25,30 ----
  OPT=0
  C_FLAGS+=-g
  endif
+ 
+ %$(OBJ): %.mm
+ 	$(CC) $(C_FLAGS) $(C_INC)$(INCPATH) $(DEFINES) $(C_OPT)$(OPT) $(C_OUT)$@ $<
Index: drawstuff/src/drawstuff.cpp
===================================================================
RCS file: /cvsroot/ode/drawstuff/src/drawstuff.cpp,v
retrieving revision 1.20
diff -c -r1.20 drawstuff.cpp
*** drawstuff/src/drawstuff.cpp	2002/06/25 23:46:14	1.20
--- drawstuff/src/drawstuff.cpp	2002/07/26 02:56:22
***************
*** 41,48 ****
--- 41,53 ----
  #endif
  
  #include <ode/config.h>
+ #ifdef MACOSX
+ #include <OpenGL/gl.h>
+ #include <OpenGL/glu.h>
+ #else
  #include <GL/gl.h>
  #include <GL/glu.h>
+ #endif
  
  #include "drawstuff/drawstuff.h"
  #include "internal.h"

--Apple-Mail-1--47056944
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	charset=US-ASCII;
	format=flowed




-tim


On Thursday, July 25, 2002, at 07:00  PM, maddocks@metservice.com wrote:

> How did you get on with this?
>
> You say that you have drawstuff running natively. Would you care to 
> share your port?
>
> Henry

--Apple-Mail-1--47056944--