demo_heightfield.cpp 21 KB

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