demo_heightfield.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  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*, 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 *, 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))
  137. return;
  138. dContact contact[MAX_CONTACTS]; // up to MAX_CONTACTS contacts per box-box
  139. for (i=0; i<MAX_CONTACTS; i++) {
  140. contact[i].surface.mode = dContactBounce | dContactSoftCFM;
  141. contact[i].surface.mu = dInfinity;
  142. contact[i].surface.mu2 = 0;
  143. contact[i].surface.bounce = 0.1;
  144. contact[i].surface.bounce_vel = 0.1;
  145. contact[i].surface.soft_cfm = 0.01;
  146. }
  147. if (int numc = dCollide(o1,o2,MAX_CONTACTS,&contact[0].geom,
  148. sizeof(dContact))) {
  149. dMatrix3 RI;
  150. dRSetIdentity(RI);
  151. const dReal ss[3] = {0.02,0.02,0.02};
  152. for (i=0; i<numc; i++) {
  153. dJointID c = dJointCreateContact(world,contactgroup,contact+i);
  154. dJointAttach(c,b1,b2);
  155. if (show_contacts) {
  156. dsSetColor(0,0,1);
  157. dsDrawBox(contact[i].geom.pos,RI,ss);
  158. }
  159. }
  160. }
  161. }
  162. // start simulation - set viewpoint
  163. static void start()
  164. {
  165. dAllocateODEDataForThread(dAllocateMaskAll);
  166. static float xyz[3] = {2.1640f,-1.3079f,1.7600f};
  167. static float hpr[3] = {125.5000f,-17.0000f,0.0000f};
  168. dsSetViewpoint (xyz,hpr);
  169. printf("To drop another object, press:\n");
  170. printf(" b for box.\n");
  171. printf(" s for sphere.\n");
  172. printf(" c for capsule.\n");
  173. printf(" y for cylinder.\n");
  174. printf(" v for a convex object.\n");
  175. printf(" x for a composite object.\n");
  176. if ( g_allow_trimesh )
  177. printf(" m for a trimesh.\n");
  178. printf("To select an object, press space.\n");
  179. printf("To disable the selected object, press d.\n");
  180. printf("To enable the selected object, press e.\n");
  181. printf("To toggle showing the geom AABBs, press a.\n");
  182. printf("To toggle showing the contact points, press t.\n");
  183. printf("To toggle dropping from random position/orientation, press r.\n");
  184. printf("To save the current state to 'state.dif', press 1.\n");
  185. }
  186. char locase(char c)
  187. {
  188. if (c >= 'A' && c <= 'Z') return c - ('a'-'A');
  189. else return c;
  190. }
  191. // called when a key pressed
  192. static void command(int cmd)
  193. {
  194. size_t i;
  195. int j,k;
  196. dReal sides[3];
  197. dMass m;
  198. bool setBody = false;
  199. cmd = locase (cmd);
  200. //
  201. // Geom Creation
  202. //
  203. if ( cmd == 'b' || cmd == 's' || cmd == 'c' || ( cmd == 'm' && g_allow_trimesh ) ||
  204. cmd == 'x' || cmd == 'y' || cmd == 'v' ) {
  205. if ( num < NUM ) {
  206. i = num;
  207. num++;
  208. } else {
  209. i = nextobj++;
  210. nextobj %= num;
  211. // destroy the body and geoms for slot i
  212. dBodyDestroy(obj[i].body);
  213. obj[i].body = 0;
  214. for (k=0; k < GPB; k++)
  215. if (obj[i].geom[k]) {
  216. dGeomDestroy(obj[i].geom[k]);
  217. obj[i].geom[k] = 0;
  218. }
  219. }
  220. obj[i].body = dBodyCreate(world);
  221. for (k=0; k<3; k++)
  222. 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. } else {
  232. dReal maxheight = 0;
  233. for (k=0; k<num; k++) {
  234. const dReal *pos = dBodyGetPosition(obj[k].body);
  235. if (pos[2] > maxheight)
  236. 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. if (cmd == 'b') {
  243. dMassSetBox(&m,DENSITY,sides[0],sides[1],sides[2]);
  244. obj[i].geom[0] = dCreateBox(space,sides[0],sides[1],sides[2]);
  245. } else if (cmd == 'c') {
  246. sides[0] *= 0.5;
  247. dMassSetCapsule(&m,DENSITY,3,sides[0],sides[1]);
  248. obj[i].geom[0] = dCreateCapsule(space,sides[0],sides[1]);
  249. } else if (cmd == 'v') {
  250. dMassSetBox (&m,DENSITY,0.25,0.25,0.25);
  251. obj[i].geom[0] = dCreateConvex(space,
  252. planes,
  253. planecount,
  254. points,
  255. pointcount,
  256. polygons);
  257. } else if (cmd == 'y') {
  258. dMassSetCylinder(&m,DENSITY,3,sides[0],sides[1]);
  259. obj[i].geom[0] = dCreateCylinder(space,sides[0],sides[1]);
  260. } else if (cmd == 's') {
  261. sides[0] *= 0.5;
  262. dMassSetSphere(&m,DENSITY,sides[0]);
  263. obj[i].geom[0] = dCreateSphere(space,sides[0]);
  264. } else if (cmd == 'm' && g_allow_trimesh) {
  265. dTriMeshDataID new_tmdata = dGeomTriMeshDataCreate();
  266. dGeomTriMeshDataBuildSingle(new_tmdata, &Vertices[0], 3 * sizeof(float), VertexCount,
  267. &Indices[0], IndexCount, 3 * sizeof(dTriIndex));
  268. dGeomTriMeshDataPreprocess2(new_tmdata, (1U << dTRIDATAPREPROCESS_BUILD_FACE_ANGLES), NULL);
  269. obj[i].geom[0] = dCreateTriMesh(space, new_tmdata, 0, 0, 0);
  270. dMassSetTrimesh( &m, DENSITY, obj[i].geom[0] );
  271. printf("mass at %f %f %f\n", m.c[0], m.c[1], m.c[2]);
  272. dGeomSetPosition(obj[i].geom[0], -m.c[0], -m.c[1], -m.c[2]);
  273. dMassTranslate(&m, -m.c[0], -m.c[1], -m.c[2]);
  274. } else if (cmd == 'x') {
  275. setBody = 1;
  276. // start accumulating masses for the composite geometries
  277. dMass m2;
  278. dMassSetZero (&m);
  279. dReal dpos[GPB][3]; // delta-positions for composite geometries
  280. dMatrix3 drot[GPB];
  281. // set random delta positions
  282. for (j=0; j<GPB; j++)
  283. for (k=0; k<3; k++)
  284. dpos[j][k] = dRandReal()*0.3-0.15;
  285. for (k=0; k<GPB; k++) {
  286. if (k==0) {
  287. dReal radius = dRandReal()*0.25+0.05;
  288. obj[i].geom[k] = dCreateSphere (space,radius);
  289. dMassSetSphere (&m2,DENSITY,radius);
  290. }
  291. else if (k==1) {
  292. obj[i].geom[k] = dCreateBox(space,sides[0],sides[1],sides[2]);
  293. dMassSetBox(&m2,DENSITY,sides[0],sides[1],sides[2]);
  294. } else {
  295. dReal radius = dRandReal()*0.1+0.05;
  296. dReal length = dRandReal()*1.0+0.1;
  297. obj[i].geom[k] = dCreateCapsule(space,radius,length);
  298. dMassSetCapsule(&m2,DENSITY,3,radius,length);
  299. }
  300. dRFromAxisAndAngle(drot[k],dRandReal()*2.0-1.0,dRandReal()*2.0-1.0,
  301. dRandReal()*2.0-1.0,dRandReal()*10.0-5.0);
  302. dMassRotate(&m2,drot[k]);
  303. dMassTranslate(&m2,dpos[k][0],dpos[k][1],dpos[k][2]);
  304. // add to the total mass
  305. dMassAdd(&m,&m2);
  306. }
  307. for (k=0; k<GPB; k++) {
  308. dGeomSetBody(obj[i].geom[k],obj[i].body);
  309. dGeomSetOffsetPosition(obj[i].geom[k],
  310. dpos[k][0]-m.c[0],
  311. dpos[k][1]-m.c[1],
  312. dpos[k][2]-m.c[2]);
  313. dGeomSetOffsetRotation(obj[i].geom[k], drot[k]);
  314. }
  315. dMassTranslate(&m,-m.c[0],-m.c[1],-m.c[2]);
  316. dBodySetMass(obj[i].body,&m);
  317. }
  318. if (!setBody) { // avoid calling for composite geometries
  319. for (k=0; k < GPB; k++)
  320. if (obj[i].geom[k])
  321. dGeomSetBody(obj[i].geom[k],obj[i].body);
  322. dBodySetMass(obj[i].body,&m);
  323. }
  324. }
  325. //
  326. // Control Commands
  327. //
  328. if (cmd == ' ') {
  329. selected++;
  330. if (selected >= num)
  331. selected = 0;
  332. if (selected < -1)
  333. selected = 0;
  334. } else if (cmd == 'd' && selected >= 0 && selected < num) {
  335. dBodyDisable(obj[selected].body);
  336. } else if (cmd == 'e' && selected >= 0 && selected < num) {
  337. dBodyEnable(obj[selected].body);
  338. } else if (cmd == 'a') {
  339. show_aabb = !show_aabb;
  340. } else if (cmd == 't') {
  341. show_contacts = !show_contacts;
  342. } else if (cmd == 'r') {
  343. random_pos = !random_pos;
  344. } else if (cmd == '1') {
  345. write_world = 1;
  346. }
  347. }
  348. // draw a geom
  349. void drawGeom (dGeomID g, const dReal *pos, const dReal *R, int show_aabb)
  350. {
  351. if (!g)
  352. return;
  353. if (!pos)
  354. pos = dGeomGetPosition(g);
  355. if (!R)
  356. R = dGeomGetRotation(g);
  357. int type = dGeomGetClass(g);
  358. if (type == dBoxClass) {
  359. dVector3 sides;
  360. dGeomBoxGetLengths(g,sides);
  361. dsDrawBox(pos,R,sides);
  362. } else if (type == dSphereClass) {
  363. dsDrawSphere(pos,R,dGeomSphereGetRadius(g));
  364. } else if (type == dCapsuleClass) {
  365. dReal radius,length;
  366. dGeomCapsuleGetParams(g,&radius,&length);
  367. dsDrawCapsule(pos,R,length,radius);
  368. } else if (type == dConvexClass) {
  369. //dVector3 sides={0.50,0.50,0.50};
  370. dsDrawConvex(pos,R,planes,
  371. planecount,
  372. points,
  373. pointcount,
  374. polygons);
  375. } else if (type == dCylinderClass) {
  376. dReal radius,length;
  377. dGeomCylinderGetParams(g,&radius,&length);
  378. dsDrawCylinder(pos,R,length,radius);
  379. } else if (type == dTriMeshClass) {
  380. dTriIndex* Indices = (dTriIndex*)::Indices;
  381. // assume all trimeshes are drawn as bunnies
  382. for (int ii = 0; ii < IndexCount / 3; ii++) {
  383. const dReal v[9] = { // explicit conversion from float to dReal
  384. Vertices[Indices[ii * 3 + 0] * 3 + 0],
  385. Vertices[Indices[ii * 3 + 0] * 3 + 1],
  386. Vertices[Indices[ii * 3 + 0] * 3 + 2],
  387. Vertices[Indices[ii * 3 + 1] * 3 + 0],
  388. Vertices[Indices[ii * 3 + 1] * 3 + 1],
  389. Vertices[Indices[ii * 3 + 1] * 3 + 2],
  390. Vertices[Indices[ii * 3 + 2] * 3 + 0],
  391. Vertices[Indices[ii * 3 + 2] * 3 + 1],
  392. Vertices[Indices[ii * 3 + 2] * 3 + 2]
  393. };
  394. dsDrawTriangle(pos, R, &v[0], &v[3], &v[6], 1);
  395. }
  396. } else if (type == dHeightfieldClass) {
  397. // Set ox and oz to zero for DHEIGHTFIELD_CORNER_ORIGIN mode.
  398. int ox = (int) ( -HFIELD_WIDTH/2 );
  399. int oz = (int) ( -HFIELD_DEPTH/2 );
  400. // for ( int tx = -1; tx < 2; ++tx )
  401. // for ( int tz = -1; tz < 2; ++tz )
  402. dsSetColorAlpha (0.5,1,0.5,0.5);
  403. dsSetTexture( DS_WOOD );
  404. for ( int i = 0; i < HFIELD_WSTEP - 1; ++i )
  405. for ( int j = 0; j < HFIELD_DSTEP - 1; ++j ) {
  406. dReal a[3], b[3], c[3], d[3];
  407. a[ 0 ] = ox + ( i ) * HFIELD_WSAMP;
  408. a[ 1 ] = heightfield_callback( NULL, i, j );
  409. a[ 2 ] = oz + ( j ) * HFIELD_DSAMP;
  410. b[ 0 ] = ox + ( i + 1 ) * HFIELD_WSAMP;
  411. b[ 1 ] = heightfield_callback( NULL, i + 1, j );
  412. b[ 2 ] = oz + ( j ) * HFIELD_DSAMP;
  413. c[ 0 ] = ox + ( i ) * HFIELD_WSAMP;
  414. c[ 1 ] = heightfield_callback( NULL, i, j + 1 );
  415. c[ 2 ] = oz + ( j + 1 ) * HFIELD_DSAMP;
  416. d[ 0 ] = ox + ( i + 1 ) * HFIELD_WSAMP;
  417. d[ 1 ] = heightfield_callback( NULL, i + 1, j + 1 );
  418. d[ 2 ] = oz + ( j + 1 ) * HFIELD_DSAMP;
  419. dsDrawTriangle( pos, R, a, c, b, 1 );
  420. dsDrawTriangle( pos, R, b, c, d, 1 );
  421. }
  422. }
  423. if (show_aabb) {
  424. // draw the bounding box for this geom
  425. dReal aabb[6];
  426. dGeomGetAABB(g,aabb);
  427. dVector3 bbpos;
  428. for (int i=0; i<3; i++)
  429. bbpos[i] = 0.5*(aabb[i*2] + aabb[i*2+1]);
  430. dVector3 bbsides;
  431. for (int i=0; i<3; i++)
  432. bbsides[i] = aabb[i*2+1] - aabb[i*2];
  433. dMatrix3 RI;
  434. dRSetIdentity(RI);
  435. dsSetColorAlpha(1,0,0,0.5);
  436. dsDrawBox(bbpos,RI,bbsides);
  437. }
  438. }
  439. // simulation loop
  440. static void simLoop (int pause)
  441. {
  442. int i,j;
  443. dSpaceCollide(space,0,&nearCallback);
  444. if (!pause)
  445. dWorldQuickStep(world,0.05);
  446. if (write_world) {
  447. FILE *f = fopen ("state.dif","wt");
  448. if (f) {
  449. dWorldExportDIF(world,f,"X");
  450. fclose (f);
  451. }
  452. write_world = 0;
  453. }
  454. // remove all contact joints
  455. dJointGroupEmpty(contactgroup);
  456. //
  457. // Draw Heightfield
  458. //
  459. drawGeom(gheight, 0, 0, 0);
  460. dsSetColor (1,1,0);
  461. dsSetTexture (DS_WOOD);
  462. for (i=0; i<num; i++) {
  463. for (j=0; j < GPB; j++) {
  464. if (i==selected) {
  465. dsSetColor (0,0.7,1);
  466. } else if (! dBodyIsEnabled (obj[i].body)) {
  467. dsSetColor (1,0.8,0);
  468. } else {
  469. dsSetColor (1,1,0);
  470. }
  471. drawGeom (obj[i].geom[j],0,0,show_aabb);
  472. }
  473. }
  474. }
  475. int main (int argc, char **argv)
  476. {
  477. printf("ODE configuration: %s\n", dGetConfiguration());
  478. // Is trimesh support built into this ODE?
  479. g_allow_trimesh = dCheckConfiguration( "ODE_EXT_trimesh" );
  480. // setup pointers to drawstuff callback functions
  481. dsFunctions fn;
  482. fn.version = DS_VERSION;
  483. fn.start = &start;
  484. fn.step = &simLoop;
  485. fn.command = &command;
  486. fn.stop = 0;
  487. fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
  488. // create world
  489. dInitODE2(0);
  490. world = dWorldCreate();
  491. space = dHashSpaceCreate (0);
  492. contactgroup = dJointGroupCreate (0);
  493. dWorldSetGravity(world,0,0,-0.05);
  494. dWorldSetCFM(world,1e-5);
  495. dWorldSetAutoDisableFlag(world,1);
  496. dWorldSetContactMaxCorrectingVel(world,0.1);
  497. dWorldSetContactSurfaceLayer(world,0.001);
  498. memset(obj,0,sizeof(obj));
  499. dWorldSetAutoDisableAverageSamplesCount( world, 1 );
  500. // base plane to catch overspill
  501. dCreatePlane( space, 0, 0, 1, 0 );
  502. // our heightfield floor
  503. dHeightfieldDataID heightid = dGeomHeightfieldDataCreate();
  504. // Create an finite heightfield.
  505. dGeomHeightfieldDataBuildCallback( heightid, NULL, heightfield_callback,
  506. HFIELD_WIDTH, HFIELD_DEPTH, HFIELD_WSTEP, HFIELD_DSTEP,
  507. REAL( 1.0 ), REAL( 0.0 ), REAL( 0.0 ), 0 );
  508. // Give some very bounds which, while conservative,
  509. // makes AABB computation more accurate than +/-INF.
  510. dGeomHeightfieldDataSetBounds( heightid, REAL( -4.0 ), REAL( +6.0 ) );
  511. gheight = dCreateHeightfield( space, heightid, 1 );
  512. dVector3 pos;
  513. pos[ 0 ] = 0;
  514. pos[ 1 ] = 0;
  515. pos[ 2 ] = 0;
  516. // Rotate so Z is up, not Y (which is the default orientation)
  517. dMatrix3 R;
  518. dRSetIdentity( R );
  519. dRFromAxisAndAngle( R, 1, 0, 0, DEGTORAD * 90 );
  520. // Place it.
  521. dGeomSetRotation( gheight, R );
  522. dGeomSetPosition( gheight, pos[0], pos[1], pos[2] );
  523. dThreadingImplementationID threading = dThreadingAllocateMultiThreadedImplementation();
  524. dThreadingThreadPoolID pool = dThreadingAllocateThreadPool(4, 0, dAllocateFlagBasicData, NULL);
  525. dThreadingThreadPoolServeMultiThreadedImplementation(pool, threading);
  526. // dWorldSetStepIslandsProcessingMaxThreadCount(world, 1);
  527. dWorldSetStepThreadingImplementation(world, dThreadingImplementationGetFunctions(threading), threading);
  528. // run simulation
  529. dsSimulationLoop (argc,argv,352,288,&fn);
  530. dThreadingImplementationShutdownProcessing(threading);
  531. dThreadingFreeThreadPool(pool);
  532. dWorldSetStepThreadingImplementation(world, NULL, NULL);
  533. dThreadingFreeImplementation(threading);
  534. dJointGroupDestroy (contactgroup);
  535. dSpaceDestroy (space);
  536. dWorldDestroy (world);
  537. // destroy heightfield data, because _we_ own it not ODE
  538. dGeomHeightfieldDataDestroy( heightid );
  539. dCloseODE();
  540. }