demo_heightfield.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  1. /*************************************************************************
  2. * *
  3. * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
  4. * All rights reserved. Email: [email protected] 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. #include <ode/ode.h>
  23. #include <drawstuff/drawstuff.h>
  24. #include "texturepath.h"
  25. #include "bunny_geom.h"
  26. #ifdef _MSC_VER
  27. #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
  28. #endif
  29. #define DEGTORAD 0.01745329251994329577f //!< PI / 180.0, convert degrees to radians
  30. int g_allow_trimesh;
  31. // Our heightfield geom
  32. dGeomID gheight;
  33. // Heightfield dimensions
  34. #define HFIELD_WSTEP 15 // Vertex count along edge >= 2
  35. #define HFIELD_DSTEP 31
  36. #define HFIELD_WIDTH REAL( 4.0 )
  37. #define HFIELD_DEPTH REAL( 8.0 )
  38. #define HFIELD_WSAMP ( HFIELD_WIDTH / ( HFIELD_WSTEP-1 ) )
  39. #define HFIELD_DSAMP ( HFIELD_DEPTH / ( HFIELD_DSTEP-1 ) )
  40. //<---- Convex Object
  41. dReal planes[]= // planes for a cube
  42. {
  43. 1.0f ,0.0f ,0.0f ,0.25f,
  44. 0.0f ,1.0f ,0.0f ,0.25f,
  45. 0.0f ,0.0f ,1.0f ,0.25f,
  46. 0.0f ,0.0f ,-1.0f,0.25f,
  47. 0.0f ,-1.0f,0.0f ,0.25f,
  48. -1.0f,0.0f ,0.0f ,0.25f
  49. /*
  50. 1.0f ,0.0f ,0.0f ,2.0f,
  51. 0.0f ,1.0f ,0.0f ,1.0f,
  52. 0.0f ,0.0f ,1.0f ,1.0f,
  53. 0.0f ,0.0f ,-1.0f,1.0f,
  54. 0.0f ,-1.0f,0.0f ,1.0f,
  55. -1.0f,0.0f ,0.0f ,0.0f
  56. */
  57. };
  58. const unsigned int planecount=6;
  59. dReal points[]= // points for a cube
  60. {
  61. 0.25f,0.25f,0.25f, // point 0
  62. -0.25f,0.25f,0.25f, // point 1
  63. 0.25f,-0.25f,0.25f, // point 2
  64. -0.25f,-0.25f,0.25f,// point 3
  65. 0.25f,0.25f,-0.25f, // point 4
  66. -0.25f,0.25f,-0.25f,// point 5
  67. 0.25f,-0.25f,-0.25f,// point 6
  68. -0.25f,-0.25f,-0.25f,// point 7
  69. };
  70. const unsigned int pointcount=8;
  71. unsigned int polygons[] = //Polygons for a cube (6 squares)
  72. {
  73. 4,0,2,6,4, // positive X
  74. 4,1,0,4,5, // positive Y
  75. 4,0,1,3,2, // positive Z
  76. 4,3,1,5,7, // negative X
  77. 4,2,3,7,6, // negative Y
  78. 4,5,4,6,7, // negative Z
  79. };
  80. //----> Convex Object
  81. // select correct drawing functions
  82. #ifdef dDOUBLE
  83. #define dsDrawBox dsDrawBoxD
  84. #define dsDrawSphere dsDrawSphereD
  85. #define dsDrawCylinder dsDrawCylinderD
  86. #define dsDrawCapsule dsDrawCapsuleD
  87. #define dsDrawConvex dsDrawConvexD
  88. #define dsDrawTriangle dsDrawTriangleD
  89. #endif
  90. // some constants
  91. #define NUM 100 // max number of objects
  92. #define DENSITY (5.0) // density of all objects
  93. #define GPB 3 // maximum number of geometries per body
  94. #define MAX_CONTACTS 64 // maximum number of contact points per body
  95. // dynamics and collision objects
  96. struct MyObject {
  97. dBodyID body; // the body
  98. dGeomID geom[GPB]; // geometries representing this body
  99. // Trimesh only - double buffered matrices for 'last transform' setup
  100. dReal matrix_dblbuff[ 16 * 2 ];
  101. int last_matrix_index;
  102. };
  103. static int num=0; // number of objects in simulation
  104. static int nextobj=0; // next object to recycle if num==NUM
  105. static dWorldID world;
  106. static dSpaceID space;
  107. static MyObject obj[NUM];
  108. static dJointGroupID contactgroup;
  109. static int selected = -1; // selected object
  110. static int show_aabb = 0; // show geom AABBs?
  111. static int show_contacts = 0; // show contact points?
  112. static int random_pos = 1; // drop objects from random position?
  113. static int write_world = 0;
  114. //============================
  115. dGeomID TriMesh1;
  116. dGeomID TriMesh2;
  117. //static dTriMeshDataID TriData1, TriData2; // reusable static trimesh data
  118. //============================
  119. dReal heightfield_callback( void* pUserData, int x, int z )
  120. {
  121. dReal fx = ( ((dReal)x) - ( HFIELD_WSTEP-1 )/2 ) / (dReal)( HFIELD_WSTEP-1 );
  122. dReal fz = ( ((dReal)z) - ( HFIELD_DSTEP-1 )/2 ) / (dReal)( HFIELD_DSTEP-1 );
  123. // Create an interesting 'hump' shape
  124. dReal h = REAL( 1.0 ) + ( REAL( -16.0 ) * ( fx*fx*fx + fz*fz*fz ) );
  125. return h;
  126. }
  127. // this is called by dSpaceCollide when two objects in space are
  128. // potentially colliding.
  129. static void nearCallback (void *data, dGeomID o1, dGeomID o2)
  130. {
  131. int i;
  132. // if (o1->body && o2->body) return;
  133. // exit without doing anything if the two bodies are connected by a joint
  134. dBodyID b1 = dGeomGetBody(o1);
  135. dBodyID b2 = dGeomGetBody(o2);
  136. if (b1 && b2 && dAreConnectedExcluding (b1,b2,dJointTypeContact)) return;
  137. dContact contact[MAX_CONTACTS]; // up to MAX_CONTACTS contacts per box-box
  138. for (i=0; i<MAX_CONTACTS; i++) {
  139. contact[i].surface.mode = dContactBounce | dContactSoftCFM;
  140. contact[i].surface.mu = dInfinity;
  141. contact[i].surface.mu2 = 0;
  142. contact[i].surface.bounce = 0.1;
  143. contact[i].surface.bounce_vel = 0.1;
  144. contact[i].surface.soft_cfm = 0.01;
  145. }
  146. if (int numc = dCollide (o1,o2,MAX_CONTACTS,&contact[0].geom,
  147. sizeof(dContact))) {
  148. dMatrix3 RI;
  149. dRSetIdentity (RI);
  150. const dReal ss[3] = {0.02,0.02,0.02};
  151. for (i=0; i<numc; i++) {
  152. dJointID c = dJointCreateContact (world,contactgroup,contact+i);
  153. dJointAttach (c,b1,b2);
  154. if (show_contacts) dsDrawBox (contact[i].geom.pos,RI,ss);
  155. }
  156. }
  157. }
  158. // start simulation - set viewpoint
  159. static void start()
  160. {
  161. dAllocateODEDataForThread(dAllocateMaskAll);
  162. static float xyz[3] = {2.1640f,-1.3079f,1.7600f};
  163. static float hpr[3] = {125.5000f,-17.0000f,0.0000f};
  164. dsSetViewpoint (xyz,hpr);
  165. printf ("To drop another object, press:\n");
  166. printf (" b for box.\n");
  167. printf (" s for sphere.\n");
  168. printf (" c for capsule.\n");
  169. printf (" y for cylinder.\n");
  170. printf (" v for a convex object.\n");
  171. printf (" x for a composite object.\n");
  172. if ( g_allow_trimesh )
  173. printf (" m for a trimesh.\n");
  174. printf ("To select an object, press space.\n");
  175. printf ("To disable the selected object, press d.\n");
  176. printf ("To enable the selected object, press e.\n");
  177. printf ("To toggle showing the geom AABBs, press a.\n");
  178. printf ("To toggle showing the contact points, press t.\n");
  179. printf ("To toggle dropping from random position/orientation, press r.\n");
  180. printf ("To save the current state to 'state.dif', press 1.\n");
  181. }
  182. char locase (char c)
  183. {
  184. if (c >= 'A' && c <= 'Z') return c - ('a'-'A');
  185. else return c;
  186. }
  187. // called when a key pressed
  188. static void command (int cmd)
  189. {
  190. size_t i;
  191. int j,k;
  192. dReal sides[3];
  193. dMass m;
  194. cmd = locase (cmd);
  195. //
  196. // Geom Creation
  197. //
  198. if ( cmd == 'b' || cmd == 's' || cmd == 'c' || ( cmd == 'm' && g_allow_trimesh ) ||
  199. cmd == 'x' || cmd == 'y' || cmd == 'v' )
  200. {
  201. if ( num < NUM )
  202. {
  203. i = num;
  204. num++;
  205. }
  206. else
  207. {
  208. i = nextobj;
  209. nextobj++;
  210. if (nextobj >= num) nextobj = 0;
  211. // destroy the body and geoms for slot i
  212. dBodyDestroy (obj[i].body);
  213. for (k=0; k < GPB; k++)
  214. {
  215. if (obj[i].geom[k]) dGeomDestroy (obj[i].geom[k]);
  216. }
  217. memset (&obj[i],0,sizeof(obj[i]));
  218. }
  219. obj[i].body = dBodyCreate (world);
  220. for (k=0; k<3; k++) sides[k] = dRandReal()*0.5+0.1;
  221. dMatrix3 R;
  222. if (random_pos) {
  223. dBodySetPosition (obj[i].body,
  224. (dRandReal()-0.5)*HFIELD_WIDTH*0.75,
  225. (dRandReal()-0.5)*HFIELD_DEPTH*0.75,
  226. dRandReal() + 2 );
  227. dRFromAxisAndAngle (R,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0,
  228. dRandReal()*2.0-1.0,dRandReal()*10.0-5.0);
  229. }
  230. else {
  231. dReal maxheight = 0;
  232. for (k=0; k<num; k++) {
  233. const dReal *pos = dBodyGetPosition (obj[k].body);
  234. if (pos[2] > maxheight) maxheight = pos[2];
  235. }
  236. dBodySetPosition (obj[i].body, 0,maxheight+1,0);
  237. dRFromAxisAndAngle (R,0,0,1,dRandReal()*10.0-5.0);
  238. }
  239. dBodySetRotation (obj[i].body,R);
  240. dBodySetData (obj[i].body,(void*) i);
  241. if (cmd == 'b')
  242. {
  243. dMassSetBox (&m,DENSITY,sides[0],sides[1],sides[2]);
  244. obj[i].geom[0] = dCreateBox (space,sides[0],sides[1],sides[2]);
  245. }
  246. else if (cmd == 'c')
  247. {
  248. sides[0] *= 0.5;
  249. dMassSetCapsule (&m,DENSITY,3,sides[0],sides[1]);
  250. obj[i].geom[0] = dCreateCapsule (space,sides[0],sides[1]);
  251. }
  252. //<---- Convex Object
  253. else if (cmd == 'v')
  254. {
  255. dMassSetBox (&m,DENSITY,0.25,0.25,0.25);
  256. obj[i].geom[0] = dCreateConvex (space,
  257. planes,
  258. planecount,
  259. points,
  260. pointcount,
  261. polygons);
  262. }
  263. //----> Convex Object
  264. else if (cmd == 'y')
  265. {
  266. dMassSetCylinder (&m,DENSITY,3,sides[0],sides[1]);
  267. obj[i].geom[0] = dCreateCylinder (space,sides[0],sides[1]);
  268. }
  269. else if (cmd == 's')
  270. {
  271. sides[0] *= 0.5;
  272. dMassSetSphere (&m,DENSITY,sides[0]);
  273. obj[i].geom[0] = dCreateSphere (space,sides[0]);
  274. }
  275. else if (cmd == 'm' && g_allow_trimesh)
  276. {
  277. dTriMeshDataID new_tmdata = dGeomTriMeshDataCreate();
  278. dGeomTriMeshDataBuildSingle(new_tmdata, &Vertices[0], 3 * sizeof(float), VertexCount,
  279. &Indices[0], IndexCount, 3 * sizeof(dTriIndex));
  280. obj[i].geom[0] = dCreateTriMesh(space, new_tmdata, 0, 0, 0);
  281. dMassSetTrimesh( &m, DENSITY, obj[i].geom[0] );
  282. printf("mass at %f %f %f\n", m.c[0], m.c[1], m.c[2]);
  283. dGeomSetPosition(obj[i].geom[0], -m.c[0], -m.c[1], -m.c[2]);
  284. dMassTranslate(&m, -m.c[0], -m.c[1], -m.c[2]);
  285. }
  286. else if (cmd == 'x')
  287. {
  288. dGeomID g2[GPB]; // encapsulated geometries
  289. dReal dpos[GPB][3]; // delta-positions for encapsulated geometries
  290. // start accumulating masses for the encapsulated geometries
  291. dMass m2;
  292. dMassSetZero (&m);
  293. // set random delta positions
  294. for (j=0; j<GPB; j++) {
  295. for (k=0; k<3; k++) dpos[j][k] = dRandReal()*0.3-0.15;
  296. }
  297. for (k=0; k<GPB; k++) {
  298. obj[i].geom[k] = dCreateGeomTransform (space);
  299. dGeomTransformSetCleanup (obj[i].geom[k],1);
  300. if (k==0) {
  301. dReal radius = dRandReal()*0.25+0.05;
  302. g2[k] = dCreateSphere (0,radius);
  303. dMassSetSphere (&m2,DENSITY,radius);
  304. }
  305. else if (k==1) {
  306. g2[k] = dCreateBox (0,sides[0],sides[1],sides[2]);
  307. dMassSetBox (&m2,DENSITY,sides[0],sides[1],sides[2]);
  308. }
  309. else {
  310. dReal radius = dRandReal()*0.1+0.05;
  311. dReal length = dRandReal()*1.0+0.1;
  312. g2[k] = dCreateCapsule (0,radius,length);
  313. dMassSetCapsule (&m2,DENSITY,3,radius,length);
  314. }
  315. dGeomTransformSetGeom (obj[i].geom[k],g2[k]);
  316. // set the transformation (adjust the mass too)
  317. dGeomSetPosition (g2[k],dpos[k][0],dpos[k][1],dpos[k][2]);
  318. dMassTranslate (&m2,dpos[k][0],dpos[k][1],dpos[k][2]);
  319. dMatrix3 Rtx;
  320. dRFromAxisAndAngle (Rtx,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0,
  321. dRandReal()*2.0-1.0,dRandReal()*10.0-5.0);
  322. dGeomSetRotation (g2[k],Rtx);
  323. dMassRotate (&m2,Rtx);
  324. // add to the total mass
  325. dMassAdd (&m,&m2);
  326. }
  327. // move all encapsulated objects so that the center of mass is (0,0,0)
  328. for (k=0; k<2; k++) {
  329. dGeomSetPosition (g2[k],
  330. dpos[k][0]-m.c[0],
  331. dpos[k][1]-m.c[1],
  332. dpos[k][2]-m.c[2]);
  333. }
  334. dMassTranslate (&m,-m.c[0],-m.c[1],-m.c[2]);
  335. }
  336. for (k=0; k < GPB; k++)
  337. {
  338. if (obj[i].geom[k]) dGeomSetBody (obj[i].geom[k],obj[i].body);
  339. }
  340. dBodySetMass (obj[i].body,&m);
  341. }
  342. //
  343. // Control Commands
  344. //
  345. if (cmd == ' ') {
  346. selected++;
  347. if (selected >= num) selected = 0;
  348. if (selected < 0) selected = 0;
  349. }
  350. else if (cmd == 'd' && selected >= 0 && selected < num) {
  351. dBodyDisable (obj[selected].body);
  352. }
  353. else if (cmd == 'e' && selected >= 0 && selected < num) {
  354. dBodyEnable (obj[selected].body);
  355. }
  356. else if (cmd == 'a') {
  357. show_aabb ^= 1;
  358. }
  359. else if (cmd == 't') {
  360. show_contacts ^= 1;
  361. }
  362. else if (cmd == 'r') {
  363. random_pos ^= 1;
  364. }
  365. else if (cmd == '1') {
  366. write_world = 1;
  367. }
  368. }
  369. // draw a geom
  370. void drawGeom (dGeomID g, const dReal *pos, const dReal *R, int show_aabb)
  371. {
  372. int i;
  373. if (!g) return;
  374. if (!pos) pos = dGeomGetPosition (g);
  375. if (!R) R = dGeomGetRotation (g);
  376. int type = dGeomGetClass (g);
  377. if (type == dBoxClass) {
  378. dVector3 sides;
  379. dGeomBoxGetLengths (g,sides);
  380. dsDrawBox (pos,R,sides);
  381. }
  382. else if (type == dSphereClass) {
  383. dsDrawSphere (pos,R,dGeomSphereGetRadius (g));
  384. }
  385. else if (type == dCapsuleClass) {
  386. dReal radius,length;
  387. dGeomCapsuleGetParams (g,&radius,&length);
  388. dsDrawCapsule (pos,R,length,radius);
  389. }
  390. //<---- Convex Object
  391. else if (type == dConvexClass)
  392. {
  393. //dVector3 sides={0.50,0.50,0.50};
  394. dsDrawConvex(pos,R,planes,
  395. planecount,
  396. points,
  397. pointcount,
  398. polygons);
  399. }
  400. //----> Convex Object
  401. else if (type == dCylinderClass) {
  402. dReal radius,length;
  403. dGeomCylinderGetParams (g,&radius,&length);
  404. dsDrawCylinder (pos,R,length,radius);
  405. }
  406. else if (type == dGeomTransformClass) {
  407. dGeomID g2 = dGeomTransformGetGeom (g);
  408. const dReal *pos2 = dGeomGetPosition (g2);
  409. const dReal *R2 = dGeomGetRotation (g2);
  410. dVector3 actual_pos;
  411. dMatrix3 actual_R;
  412. dMultiply0_331 (actual_pos,R,pos2);
  413. actual_pos[0] += pos[0];
  414. actual_pos[1] += pos[1];
  415. actual_pos[2] += pos[2];
  416. dMultiply0_333 (actual_R,R,R2);
  417. drawGeom (g2,actual_pos,actual_R,0);
  418. }
  419. if (show_aabb) {
  420. // draw the bounding box for this geom
  421. dReal aabb[6];
  422. dGeomGetAABB (g,aabb);
  423. dVector3 bbpos;
  424. for (i=0; i<3; i++) bbpos[i] = 0.5*(aabb[i*2] + aabb[i*2+1]);
  425. dVector3 bbsides;
  426. for (i=0; i<3; i++) bbsides[i] = aabb[i*2+1] - aabb[i*2];
  427. dMatrix3 RI;
  428. dRSetIdentity (RI);
  429. dsSetColorAlpha (1,0,0,0.5);
  430. dsDrawBox (bbpos,RI,bbsides);
  431. }
  432. }
  433. // simulation loop
  434. static void simLoop (int pause)
  435. {
  436. int i,j;
  437. dsSetColor (0,0,2);
  438. dSpaceCollide (space,0,&nearCallback);
  439. //if (!pause) dWorldStep (world,0.05);
  440. if (!pause) dWorldQuickStep (world,0.05);
  441. if (write_world) {
  442. FILE *f = fopen ("state.dif","wt");
  443. if (f) {
  444. dWorldExportDIF (world,f,"X");
  445. fclose (f);
  446. }
  447. write_world = 0;
  448. }
  449. // remove all contact joints
  450. dJointGroupEmpty (contactgroup);
  451. const dReal* pReal = dGeomGetPosition( gheight );
  452. const dReal* RReal = dGeomGetRotation( gheight );
  453. //
  454. // Draw Heightfield
  455. //
  456. // Set ox and oz to zero for DHEIGHTFIELD_CORNER_ORIGIN mode.
  457. int ox = (int) ( -HFIELD_WIDTH/2 );
  458. int oz = (int) ( -HFIELD_DEPTH/2 );
  459. // for ( int tx = -1; tx < 2; ++tx )
  460. // for ( int tz = -1; tz < 2; ++tz )
  461. {
  462. dsSetColorAlpha (0.5,1,0.5,0.5);
  463. dsSetTexture( DS_WOOD );
  464. for ( int i = 0; i < HFIELD_WSTEP - 1; ++i )
  465. for ( int j = 0; j < HFIELD_DSTEP - 1; ++j )
  466. {
  467. dReal a[3], b[3], c[3], d[3];
  468. a[ 0 ] = ox + ( i ) * HFIELD_WSAMP;
  469. a[ 1 ] = heightfield_callback( NULL, i, j );
  470. a[ 2 ] = oz + ( j ) * HFIELD_DSAMP;
  471. b[ 0 ] = ox + ( i + 1 ) * HFIELD_WSAMP;
  472. b[ 1 ] = heightfield_callback( NULL, i + 1, j );
  473. b[ 2 ] = oz + ( j ) * HFIELD_DSAMP;
  474. c[ 0 ] = ox + ( i ) * HFIELD_WSAMP;
  475. c[ 1 ] = heightfield_callback( NULL, i, j + 1 );
  476. c[ 2 ] = oz + ( j + 1 ) * HFIELD_DSAMP;
  477. d[ 0 ] = ox + ( i + 1 ) * HFIELD_WSAMP;
  478. d[ 1 ] = heightfield_callback( NULL, i + 1, j + 1 );
  479. d[ 2 ] = oz + ( j + 1 ) * HFIELD_DSAMP;
  480. dsDrawTriangle( pReal, RReal, a, c, b, 1 );
  481. dsDrawTriangle( pReal, RReal, b, c, d, 1 );
  482. }
  483. }
  484. dsSetColor (1,1,0);
  485. dsSetTexture (DS_WOOD);
  486. for (i=0; i<num; i++)
  487. {
  488. for (j=0; j < GPB; j++)
  489. {
  490. if (i==selected)
  491. {
  492. dsSetColor (0,0.7,1);
  493. }
  494. else if (! dBodyIsEnabled (obj[i].body))
  495. {
  496. dsSetColor (1,0.8,0);
  497. }
  498. else
  499. {
  500. dsSetColor (1,1,0);
  501. }
  502. if ( obj[i].geom[j] && dGeomGetClass(obj[i].geom[j]) == dTriMeshClass )
  503. {
  504. dTriIndex* Indices = (dTriIndex*)::Indices;
  505. // assume all trimeshes are drawn as bunnies
  506. const dReal* Pos = dGeomGetPosition(obj[i].geom[j]);
  507. const dReal* Rot = dGeomGetRotation(obj[i].geom[j]);
  508. for (int ii = 0; ii < IndexCount / 3; ii++)
  509. {
  510. const dReal v[9] = { // explicit conversion from float to dReal
  511. Vertices[Indices[ii * 3 + 0] * 3 + 0],
  512. Vertices[Indices[ii * 3 + 0] * 3 + 1],
  513. Vertices[Indices[ii * 3 + 0] * 3 + 2],
  514. Vertices[Indices[ii * 3 + 1] * 3 + 0],
  515. Vertices[Indices[ii * 3 + 1] * 3 + 1],
  516. Vertices[Indices[ii * 3 + 1] * 3 + 2],
  517. Vertices[Indices[ii * 3 + 2] * 3 + 0],
  518. Vertices[Indices[ii * 3 + 2] * 3 + 1],
  519. Vertices[Indices[ii * 3 + 2] * 3 + 2]
  520. };
  521. dsDrawTriangle(Pos, Rot, &v[0], &v[3], &v[6], 1);
  522. }
  523. // tell the tri-tri collider the current transform of the trimesh --
  524. // this is fairly important for good results.
  525. // Fill in the (4x4) matrix.
  526. dReal* p_matrix = obj[i].matrix_dblbuff + ( obj[i].last_matrix_index * 16 );
  527. p_matrix[ 0 ] = Rot[ 0 ]; p_matrix[ 1 ] = Rot[ 1 ]; p_matrix[ 2 ] = Rot[ 2 ]; p_matrix[ 3 ] = 0;
  528. p_matrix[ 4 ] = Rot[ 4 ]; p_matrix[ 5 ] = Rot[ 5 ]; p_matrix[ 6 ] = Rot[ 6 ]; p_matrix[ 7 ] = 0;
  529. p_matrix[ 8 ] = Rot[ 8 ]; p_matrix[ 9 ] = Rot[ 9 ]; p_matrix[10 ] = Rot[10 ]; p_matrix[11 ] = 0;
  530. p_matrix[12 ] = Pos[ 0 ]; p_matrix[13 ] = Pos[ 1 ]; p_matrix[14 ] = Pos[ 2 ]; p_matrix[15 ] = 1;
  531. // Flip to other matrix.
  532. obj[i].last_matrix_index = !obj[i].last_matrix_index;
  533. // Apply the 'other' matrix which is the oldest.
  534. dGeomTriMeshSetLastTransform( obj[i].geom[j],
  535. *(dMatrix4*)( obj[i].matrix_dblbuff + ( obj[i].last_matrix_index * 16 ) ) );
  536. }
  537. else
  538. {
  539. drawGeom (obj[i].geom[j],0,0,show_aabb);
  540. }
  541. }
  542. }
  543. if ( show_aabb )
  544. {
  545. // draw the bounding box for this geom
  546. dReal aabb[6];
  547. dGeomGetAABB (gheight,aabb);
  548. dVector3 bbpos;
  549. for (i=0; i<3; i++) bbpos[i] = 0.5*(aabb[i*2] + aabb[i*2+1]);
  550. dVector3 bbsides;
  551. for (i=0; i<3; i++) bbsides[i] = aabb[i*2+1] - aabb[i*2];
  552. dMatrix3 RI;
  553. dRSetIdentity (RI);
  554. dsSetColorAlpha (1,0,0,0.5);
  555. dsDrawBox (bbpos,RI,bbsides);
  556. }
  557. }
  558. int main (int argc, char **argv)
  559. {
  560. printf("ODE configuration: %s\n", dGetConfiguration());
  561. // Is trimesh support built into this ODE?
  562. g_allow_trimesh = dCheckConfiguration( "ODE_EXT_trimesh" );
  563. // setup pointers to drawstuff callback functions
  564. dsFunctions fn;
  565. fn.version = DS_VERSION;
  566. fn.start = &start;
  567. fn.step = &simLoop;
  568. fn.command = &command;
  569. fn.stop = 0;
  570. fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
  571. // create world
  572. dInitODE2(0);
  573. world = dWorldCreate();
  574. space = dHashSpaceCreate (0);
  575. contactgroup = dJointGroupCreate (0);
  576. dWorldSetGravity (world,0,0,-0.05);
  577. dWorldSetCFM (world,1e-5);
  578. dWorldSetAutoDisableFlag (world,1);
  579. dWorldSetContactMaxCorrectingVel (world,0.1);
  580. dWorldSetContactSurfaceLayer (world,0.001);
  581. memset (obj,0,sizeof(obj));
  582. #if 1
  583. dWorldSetAutoDisableAverageSamplesCount( world, 1 );
  584. #endif
  585. // base plane to catch overspill
  586. dCreatePlane( space, 0, 0, 1, 0 );
  587. // our heightfield floor
  588. dHeightfieldDataID heightid = dGeomHeightfieldDataCreate();
  589. // Create an finite heightfield.
  590. dGeomHeightfieldDataBuildCallback( heightid, NULL, heightfield_callback,
  591. HFIELD_WIDTH, HFIELD_DEPTH, HFIELD_WSTEP, HFIELD_DSTEP,
  592. REAL( 1.0 ), REAL( 0.0 ), REAL( 0.0 ), 0 );
  593. // Give some very bounds which, while conservative,
  594. // makes AABB computation more accurate than +/-INF.
  595. dGeomHeightfieldDataSetBounds( heightid, REAL( -4.0 ), REAL( +6.0 ) );
  596. gheight = dCreateHeightfield( space, heightid, 1 );
  597. dVector3 pos;
  598. pos[ 0 ] = 0;
  599. pos[ 1 ] = 0;
  600. pos[ 2 ] = 0;
  601. // Rotate so Z is up, not Y (which is the default orientation)
  602. dMatrix3 R;
  603. dRSetIdentity( R );
  604. dRFromAxisAndAngle( R, 1, 0, 0, DEGTORAD * 90 );
  605. // Place it.
  606. dGeomSetRotation( gheight, R );
  607. dGeomSetPosition( gheight, pos[0], pos[1], pos[2] );
  608. dThreadingImplementationID threading = dThreadingAllocateMultiThreadedImplementation();
  609. dThreadingThreadPoolID pool = dThreadingAllocateThreadPool(4, 0, dAllocateFlagBasicData, NULL);
  610. dThreadingThreadPoolServeMultiThreadedImplementation(pool, threading);
  611. // dWorldSetStepIslandsProcessingMaxThreadCount(world, 1);
  612. dWorldSetStepThreadingImplementation(world, dThreadingImplementationGetFunctions(threading), threading);
  613. // run simulation
  614. dsSimulationLoop (argc,argv,352,288,&fn);
  615. dThreadingImplementationShutdownProcessing(threading);
  616. dThreadingFreeThreadPool(pool);
  617. dWorldSetStepThreadingImplementation(world, NULL, NULL);
  618. dThreadingFreeImplementation(threading);
  619. dJointGroupDestroy (contactgroup);
  620. dSpaceDestroy (space);
  621. dWorldDestroy (world);
  622. // destroy heightfield data, because _we_ own it not ODE
  623. dGeomHeightfieldDataDestroy( heightid );
  624. dCloseODE();
  625. return 0;
  626. }