/************************************************************************* * * * 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 #include #include "texturepath.h" #include "bunny_geom.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif #define DEGTORAD 0.01745329251994329577f //!< PI / 180.0, convert degrees to radians int g_allow_trimesh; // Our heightfield geom dGeomID gheight; // Heightfield dimensions #define HFIELD_WSTEP 15 // Vertex count along edge >= 2 #define HFIELD_DSTEP 31 #define HFIELD_WIDTH REAL( 4.0 ) #define HFIELD_DEPTH REAL( 8.0 ) #define HFIELD_WSAMP ( HFIELD_WIDTH / ( HFIELD_WSTEP-1 ) ) #define HFIELD_DSAMP ( HFIELD_DEPTH / ( HFIELD_DSTEP-1 ) ) //<---- Convex Object dReal planes[]= // planes for a cube { 1.0f ,0.0f ,0.0f ,0.25f, 0.0f ,1.0f ,0.0f ,0.25f, 0.0f ,0.0f ,1.0f ,0.25f, 0.0f ,0.0f ,-1.0f,0.25f, 0.0f ,-1.0f,0.0f ,0.25f, -1.0f,0.0f ,0.0f ,0.25f /* 1.0f ,0.0f ,0.0f ,2.0f, 0.0f ,1.0f ,0.0f ,1.0f, 0.0f ,0.0f ,1.0f ,1.0f, 0.0f ,0.0f ,-1.0f,1.0f, 0.0f ,-1.0f,0.0f ,1.0f, -1.0f,0.0f ,0.0f ,0.0f */ }; const unsigned int planecount=6; dReal points[]= // points for a cube { 0.25f,0.25f,0.25f, // point 0 -0.25f,0.25f,0.25f, // point 1 0.25f,-0.25f,0.25f, // point 2 -0.25f,-0.25f,0.25f,// point 3 0.25f,0.25f,-0.25f, // point 4 -0.25f,0.25f,-0.25f,// point 5 0.25f,-0.25f,-0.25f,// point 6 -0.25f,-0.25f,-0.25f,// point 7 }; const unsigned int pointcount=8; unsigned int polygons[] = //Polygons for a cube (6 squares) { 4,0,2,6,4, // positive X 4,1,0,4,5, // positive Y 4,0,1,3,2, // positive Z 4,3,1,5,7, // negative X 4,2,3,7,6, // negative Y 4,5,4,6,7, // negative Z }; //----> Convex Object // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawSphere dsDrawSphereD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCapsule dsDrawCapsuleD #define dsDrawConvex dsDrawConvexD #define dsDrawTriangle dsDrawTriangleD #endif // some constants #define NUM 100 // max number of objects #define DENSITY (5.0) // density of all objects #define GPB 3 // maximum number of geometries per body #define MAX_CONTACTS 64 // maximum number of contact points per body // dynamics and collision objects struct MyObject { dBodyID body; // the body dGeomID geom[GPB]; // geometries representing this body // Trimesh only - double buffered matrices for 'last transform' setup dReal matrix_dblbuff[ 16 * 2 ]; int last_matrix_index; }; static int num=0; // number of objects in simulation static int nextobj=0; // next object to recycle if num==NUM static dWorldID world; static dSpaceID space; static MyObject obj[NUM]; static dJointGroupID contactgroup; static int selected = -1; // selected object static int show_aabb = 0; // show geom AABBs? static int show_contacts = 0; // show contact points? static int random_pos = 1; // drop objects from random position? static int write_world = 0; //============================ dGeomID TriMesh1; dGeomID TriMesh2; //static dTriMeshDataID TriData1, TriData2; // reusable static trimesh data //============================ dReal heightfield_callback( void*, int x, int z ) { dReal fx = ( ((dReal)x) - ( HFIELD_WSTEP-1 )/2 ) / (dReal)( HFIELD_WSTEP-1 ); dReal fz = ( ((dReal)z) - ( HFIELD_DSTEP-1 )/2 ) / (dReal)( HFIELD_DSTEP-1 ); // Create an interesting 'hump' shape dReal h = REAL( 1.0 ) + ( REAL( -16.0 ) * ( fx*fx*fx + fz*fz*fz ) ); return h; } // this is called by dSpaceCollide when two objects in space are // potentially colliding. static void nearCallback (void *, dGeomID o1, dGeomID o2) { int i; // if (o1->body && o2->body) return; // exit without doing anything if the two bodies are connected by a joint dBodyID b1 = dGeomGetBody(o1); dBodyID b2 = dGeomGetBody(o2); if (b1 && b2 && dAreConnectedExcluding(b1,b2,dJointTypeContact)) return; dContact contact[MAX_CONTACTS]; // up to MAX_CONTACTS contacts per box-box for (i=0; i= 'A' && c <= 'Z') return c - ('a'-'A'); else return c; } // called when a key pressed static void command(int cmd) { dsizeint i; int j,k; dReal sides[3]; dMass m; bool setBody = false; cmd = locase (cmd); // // Geom Creation // if ( cmd == 'b' || cmd == 's' || cmd == 'c' || ( cmd == 'm' && g_allow_trimesh ) || cmd == 'x' || cmd == 'y' || cmd == 'v' ) { if ( num < NUM ) { i = num; num++; } else { i = nextobj++; nextobj %= num; // destroy the body and geoms for slot i dBodyDestroy(obj[i].body); obj[i].body = 0; for (k=0; k < GPB; k++) if (obj[i].geom[k]) { dGeomDestroy(obj[i].geom[k]); obj[i].geom[k] = 0; } } obj[i].body = dBodyCreate(world); for (k=0; k<3; k++) sides[k] = dRandReal()*0.5+0.1; dMatrix3 R; if (random_pos) { dBodySetPosition(obj[i].body, (dRandReal()-0.5)*HFIELD_WIDTH*0.75, (dRandReal()-0.5)*HFIELD_DEPTH*0.75, dRandReal() + 2 ); dRFromAxisAndAngle(R,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0, dRandReal()*2.0-1.0,dRandReal()*10.0-5.0); } else { dReal maxheight = 0; for (k=0; k maxheight) maxheight = pos[2]; } dBodySetPosition(obj[i].body, 0,maxheight+1,0); dRFromAxisAndAngle(R,0,0,1,dRandReal()*10.0-5.0); } dBodySetRotation(obj[i].body,R); if (cmd == 'b') { dMassSetBox(&m,DENSITY,sides[0],sides[1],sides[2]); obj[i].geom[0] = dCreateBox(space,sides[0],sides[1],sides[2]); } else if (cmd == 'c') { sides[0] *= 0.5; dMassSetCapsule(&m,DENSITY,3,sides[0],sides[1]); obj[i].geom[0] = dCreateCapsule(space,sides[0],sides[1]); } else if (cmd == 'v') { dMassSetBox (&m,DENSITY,0.25,0.25,0.25); obj[i].geom[0] = dCreateConvex(space, planes, planecount, points, pointcount, polygons); } else if (cmd == 'y') { dMassSetCylinder(&m,DENSITY,3,sides[0],sides[1]); obj[i].geom[0] = dCreateCylinder(space,sides[0],sides[1]); } else if (cmd == 's') { sides[0] *= 0.5; dMassSetSphere(&m,DENSITY,sides[0]); obj[i].geom[0] = dCreateSphere(space,sides[0]); } else if (cmd == 'm' && g_allow_trimesh) { dTriMeshDataID new_tmdata = dGeomTriMeshDataCreate(); dGeomTriMeshDataBuildSingle(new_tmdata, &Vertices[0], 3 * sizeof(float), VertexCount, &Indices[0], IndexCount, 3 * sizeof(dTriIndex)); dGeomTriMeshDataPreprocess2(new_tmdata, (1U << dTRIDATAPREPROCESS_BUILD_FACE_ANGLES), NULL); obj[i].geom[0] = dCreateTriMesh(space, new_tmdata, 0, 0, 0); dMassSetTrimesh( &m, DENSITY, obj[i].geom[0] ); printf("mass at %f %f %f\n", m.c[0], m.c[1], m.c[2]); dGeomSetPosition(obj[i].geom[0], -m.c[0], -m.c[1], -m.c[2]); dMassTranslate(&m, -m.c[0], -m.c[1], -m.c[2]); } else if (cmd == 'x') { setBody = 1; // start accumulating masses for the composite geometries dMass m2; dMassSetZero (&m); dReal dpos[GPB][3]; // delta-positions for composite geometries dMatrix3 drot[GPB]; // set random delta positions for (j=0; j= num) selected = 0; if (selected < -1) selected = 0; } else if (cmd == 'd' && selected >= 0 && selected < num) { dBodyDisable(obj[selected].body); } else if (cmd == 'e' && selected >= 0 && selected < num) { dBodyEnable(obj[selected].body); } else if (cmd == 'a') { show_aabb = !show_aabb; } else if (cmd == 't') { show_contacts = !show_contacts; } else if (cmd == 'r') { random_pos = !random_pos; } else if (cmd == '1') { write_world = 1; } } // draw a geom void drawGeom (dGeomID g, const dReal *pos, const dReal *R, int show_aabb) { if (!g) return; if (!pos) pos = dGeomGetPosition(g); if (!R) R = dGeomGetRotation(g); int type = dGeomGetClass(g); if (type == dBoxClass) { dVector3 sides; dGeomBoxGetLengths(g,sides); dsDrawBox(pos,R,sides); } else if (type == dSphereClass) { dsDrawSphere(pos,R,dGeomSphereGetRadius(g)); } else if (type == dCapsuleClass) { dReal radius,length; dGeomCapsuleGetParams(g,&radius,&length); dsDrawCapsule(pos,R,length,radius); } else if (type == dConvexClass) { //dVector3 sides={0.50,0.50,0.50}; dsDrawConvex(pos,R,planes, planecount, points, pointcount, polygons); } else if (type == dCylinderClass) { dReal radius,length; dGeomCylinderGetParams(g,&radius,&length); dsDrawCylinder(pos,R,length,radius); } else if (type == dTriMeshClass) { dTriIndex* Indices = (dTriIndex*)::Indices; // assume all trimeshes are drawn as bunnies for (int ii = 0; ii < IndexCount / 3; ii++) { const dReal v[9] = { // explicit conversion from float to dReal Vertices[Indices[ii * 3 + 0] * 3 + 0], Vertices[Indices[ii * 3 + 0] * 3 + 1], Vertices[Indices[ii * 3 + 0] * 3 + 2], Vertices[Indices[ii * 3 + 1] * 3 + 0], Vertices[Indices[ii * 3 + 1] * 3 + 1], Vertices[Indices[ii * 3 + 1] * 3 + 2], Vertices[Indices[ii * 3 + 2] * 3 + 0], Vertices[Indices[ii * 3 + 2] * 3 + 1], Vertices[Indices[ii * 3 + 2] * 3 + 2] }; dsDrawTriangle(pos, R, &v[0], &v[3], &v[6], 1); } } else if (type == dHeightfieldClass) { // Set ox and oz to zero for DHEIGHTFIELD_CORNER_ORIGIN mode. int ox = (int) ( -HFIELD_WIDTH/2 ); int oz = (int) ( -HFIELD_DEPTH/2 ); // for ( int tx = -1; tx < 2; ++tx ) // for ( int tz = -1; tz < 2; ++tz ) dsSetColorAlpha (0.5,1,0.5,0.5); dsSetTexture( DS_WOOD ); for ( int i = 0; i < HFIELD_WSTEP - 1; ++i ) for ( int j = 0; j < HFIELD_DSTEP - 1; ++j ) { dReal a[3], b[3], c[3], d[3]; a[ 0 ] = ox + ( i ) * HFIELD_WSAMP; a[ 1 ] = heightfield_callback( NULL, i, j ); a[ 2 ] = oz + ( j ) * HFIELD_DSAMP; b[ 0 ] = ox + ( i + 1 ) * HFIELD_WSAMP; b[ 1 ] = heightfield_callback( NULL, i + 1, j ); b[ 2 ] = oz + ( j ) * HFIELD_DSAMP; c[ 0 ] = ox + ( i ) * HFIELD_WSAMP; c[ 1 ] = heightfield_callback( NULL, i, j + 1 ); c[ 2 ] = oz + ( j + 1 ) * HFIELD_DSAMP; d[ 0 ] = ox + ( i + 1 ) * HFIELD_WSAMP; d[ 1 ] = heightfield_callback( NULL, i + 1, j + 1 ); d[ 2 ] = oz + ( j + 1 ) * HFIELD_DSAMP; dsDrawTriangle( pos, R, a, c, b, 1 ); dsDrawTriangle( pos, R, b, c, d, 1 ); } } if (show_aabb) { // draw the bounding box for this geom dReal aabb[6]; dGeomGetAABB(g,aabb); dVector3 bbpos; for (int i=0; i<3; i++) bbpos[i] = 0.5*(aabb[i*2] + aabb[i*2+1]); dVector3 bbsides; for (int i=0; i<3; i++) bbsides[i] = aabb[i*2+1] - aabb[i*2]; dMatrix3 RI; dRSetIdentity(RI); dsSetColorAlpha(1,0,0,0.5); dsDrawBox(bbpos,RI,bbsides); } } // simulation loop static void simLoop (int pause) { int i,j; dSpaceCollide(space,0,&nearCallback); if (!pause) dWorldQuickStep(world,0.05); if (write_world) { FILE *f = fopen ("state.dif","wt"); if (f) { dWorldExportDIF(world,f,"X"); fclose (f); } write_world = 0; } // remove all contact joints dJointGroupEmpty(contactgroup); // // Draw Heightfield // drawGeom(gheight, 0, 0, 0); dsSetColor (1,1,0); dsSetTexture (DS_WOOD); for (i=0; i