[ODE] ODE / Mac OS X Crash

Kevin Reid kpreid at attglobal.net
Fri Apr 5 09:54:02 2002


/* ODE/Mac OS X Crash Test

  When compiled and executed on my computer, this program often crashes.
  I believe that this is caused by ODE (specifically running on Mac OS
  X), as most of the code was copied (after careful examination) from
  ODE and GLUT demo programs.
  
  Reducing the global CFM seems to make it survive longer, as does
  reducing the number of bodies.
 
  The simulation consists of NUMBODIES unit cubes or spheres dropped
  onto a fixed xz plane, with gravity in the -y direction and damping to
  produce a terminal velocity effect. The x and z location of the bodies
  does not noticeably affect the crashing behavior.
  
  Graphics display is done using OpenGL/GLUT. The original program which
  exhibited this problem used Cocoa instead of GLUT.
  
  Operating systems: 
    Mac OS X 10.1.x: crashes
    x86 SuSE Linux: stable
 
  My results with different numbers of boxes:
  <= 40: stable
  41-59: depends on how long you let it run
  >= 60: SIGSEGV before all the objects fall
 
  Crash log contains:
  
  Thread 0 Crashed:
   #0   0x0001a028 in dSolveLCP(int, double *, double *, double *, double *, int, double *, double *, int *)
   #1   0x000047b4 in processIslands(dxWorld *, double)
   #2   0x00003bd8 in myGlutIdle
   #3   0x71679f1c in -[GLUTAppDelegate idleFuncDrawHack]
   #4   0x71670dfc in -[GLUTApplication sendEvent:]
   #5   0x70c23488 in -[NSApplication run]
   #6   0x71676aec in glutMainLoop
   #7   0x000044e8 in main
   #8   0x00003608 in _start
   #9   0x00003438 in start
    
  - Kevin Reid, Jan 25 - Mar 28, 2002
*/

#include <stdio.h>
#include <GLUT/glut.h>
#include "ode/ode.h"

#define NUMBODIES 80

#define USE_SPHERE 0
#define USE_HELIX 1
#define USE_TORQUE 1
#define USE_WEIRD_MATRIX_OPS 0

#define CONTACTS 3

dWorldID aWorld;
dSpaceID aSpace;
float cycle = 0, fade;
dJointGroupID aContactGroup;
dBodyID bodies[NUMBODIES];
dGeomID geoms[NUMBODIES];
GLfloat colors[NUMBODIES][4];
unsigned int contactsThisFrame;

void kglTransformByODEGeom(dGeomID geom) {
  const dReal *p = dGeomGetPosition(geom);
  const dReal *R = dGeomGetRotation(geom);
  GLdouble glm[16];

  glm[0]  = R[0]; glm[1]  = R[4]; glm[2]  = R[8]; glm[3]  = 0;
  glm[4]  = R[1]; glm[5]  = R[5]; glm[6]  = R[9]; glm[7]  = 0;
  glm[8]  = R[2]; glm[9]  = R[6]; glm[10] = R[10];glm[11] = 0;
  glm[12] = p[0]; glm[13] = p[1]; glm[14] = p[2]; glm[15] = 1;
   
  glMultMatrixd(glm);
}

static void odeNearCallback(void *data, dGeomID g1, dGeomID g2) {
  dBodyID b1 = dGeomGetBody(g1), 
          b2 = dGeomGetBody(g2);
  dContact contact[CONTACTS];
  int contactsUsed, i;

  if (b1 && b2 && dAreConnected(b1, b2)) return;

  contactsUsed = dCollide(g1, g2, CONTACTS, &contact[0].geom,
    sizeof(dContact));
  if (contactsUsed > CONTACTS) contactsUsed = CONTACTS;

  for (i = 0; i < contactsUsed; i++) {
    contact[i].surface.mode = 0;
    contact[i].surface.mu = 20.0;
    
    dJointAttach(dJointCreateContact(aWorld, aContactGroup,
      &(contact[i])), b1, b2);
    contactsThisFrame++;
  }
}

void myGlutResize(int w, int h) {
  glViewport(0, 0, w, h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(45.0, (GLfloat)w / h, 1.0, 120.0);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glTranslatef(0, -6, -20);
}

void myGlutIdle(void) {
  const float step = 1.0/40;
  int i;
  
  cycle = fmod(cycle + step / 4, 1);
  fade = fabs(cycle * 2 - 1);

  contactsThisFrame = 0;
  dSpaceCollide(aSpace, NULL, &odeNearCallback);
  //printf("%u\n", contactsThisFrame);
  dWorldStep(aWorld, step);
  dJointGroupEmpty(aContactGroup);

  for (i = 0; i < NUMBODIES; i++) {
    const dReal *cvel = dBodyGetLinearVel(bodies[i]);
    dBodyAddForce(bodies[i],
      -cvel[0] * 1.25,
      -cvel[1] * 1.25,
      -cvel[2] * 1.25
    );
  }
  glutPostRedisplay();
}

void myGlutDisplay(void) {
  int i;

  glClearColor(fade * 0.15, 0, 0, 1);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  
  if (USE_WEIRD_MATRIX_OPS) glPushMatrix();
  for (i = 0; i < NUMBODIES; i++) {
    if (!USE_WEIRD_MATRIX_OPS) glPushMatrix();
    kglTransformByODEGeom(geoms[i]);
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, colors[i]);
    glColor3f(fade * 1.5, 0, 0);
#if USE_SPHERE
    glRotatef(90, 1, 0, 0);
    glutSolidSphere(0.5, 9, 6);
    glDisable(GL_LIGHTING);
    glutWireSphere(0.5, 9, 6);
#else
    glutSolidCube(1);
    glDisable(GL_LIGHTING);
    glutWireCube(1);
#endif
    glEnable(GL_LIGHTING);
    if (!USE_WEIRD_MATRIX_OPS) glPopMatrix();
  }
  if (USE_WEIRD_MATRIX_OPS) glPopMatrix();
  
  glutSwapBuffers();
}

int main(int argc, char **argv) {
  printf("Initializing GLUT\n");

  glutInit(&argc, argv);                
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  glutInitWindowSize(400, 300);
  glutInitWindowPosition(100, 100);
  glutCreateWindow("ODE Crash Test");
  
  glutDisplayFunc(myGlutDisplay);
  glutReshapeFunc(myGlutResize);
  glutIdleFunc(myGlutIdle);

  glPolygonOffset(1, 1);
  glDepthFunc(GL_LEQUAL);
  glEnable(GL_POLYGON_OFFSET_FILL);
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_CULL_FACE);
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
  myGlutResize(400, 300);
  
  printf("Creating ODE world\n");
  aWorld = dWorldCreate();
  aSpace = dHashSpaceCreate();
  aContactGroup = dJointGroupCreate(0);
  dCreatePlane(aSpace, 0, 1, 0, 0);
  dWorldSetGravity(aWorld, 0, -9.81, 0);
  dWorldSetERP(aWorld, 0.5);
  dWorldSetCFM(aWorld, 1e-10);
  
  printf("Creating objects\n");
  {
    int i;
    dMass mass;
    
    dMassSetBox(&mass, 1.0, 1, 1, 1);

    for (i = 0; i < NUMBODIES; i++) {
      float fraction = (float)i / NUMBODIES;
    
      bodies[i] = dBodyCreate(aWorld);
      dBodySetMass(bodies[i], &mass);
#if USE_SPHERE
      geoms[i] = dCreateSphere(aSpace, 0.5);
#else
      geoms[i] = dCreateBox(aSpace, 1, 1, 1);
#endif
      dGeomSetBody(geoms[i], bodies[i]);
    
      if (USE_HELIX) {
        float r     = (i % 3 - 1) * (1.5+4*(1 - fraction)),
              theta = (float)i / 4;
        dBodySetPosition(bodies[i],
          sin(theta) * r, 
          (float)i + 1,
          cos(theta) * r
        );
      } else {
        dBodySetPosition(bodies[i], 0, (float)i * 2 + 1, 0);
      }
      if (USE_TORQUE) dBodyAddTorque(bodies[i], fraction*10, fraction*20, fraction*30);
      
      colors[i][0] = fraction;
      colors[i][1] = 1 - fraction;
      colors[i][2] = 1 - fabs(fraction * 2 - 1);
      colors[i][3] = 1;
    }
  }
  
  printf("Starting simulation\n");
  glutMainLoop();
  return 0;
}