demo_boxstack.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  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. #ifdef _MSC_VER
  26. #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
  27. #endif
  28. #include "icosahedron_geom.h"
  29. //<---- Convex Object
  30. dReal planes[]= // planes for a cube, these should coincide with the face array
  31. {
  32. 1.0f ,0.0f ,0.0f ,0.25f,
  33. 0.0f ,1.0f ,0.0f ,0.25f,
  34. 0.0f ,0.0f ,1.0f ,0.25f,
  35. -1.0f,0.0f ,0.0f ,0.25f,
  36. 0.0f ,-1.0f,0.0f ,0.25f,
  37. 0.0f ,0.0f ,-1.0f,0.25f
  38. /*
  39. 1.0f ,0.0f ,0.0f ,2.0f,
  40. 0.0f ,1.0f ,0.0f ,1.0f,
  41. 0.0f ,0.0f ,1.0f ,1.0f,
  42. 0.0f ,0.0f ,-1.0f,1.0f,
  43. 0.0f ,-1.0f,0.0f ,1.0f,
  44. -1.0f,0.0f ,0.0f ,0.0f
  45. */
  46. };
  47. const unsigned int planecount=6;
  48. dReal points[]= // points for a cube
  49. {
  50. 0.25f,0.25f,0.25f, // point 0
  51. -0.25f,0.25f,0.25f, // point 1
  52. 0.25f,-0.25f,0.25f, // point 2
  53. -0.25f,-0.25f,0.25f,// point 3
  54. 0.25f,0.25f,-0.25f, // point 4
  55. -0.25f,0.25f,-0.25f,// point 5
  56. 0.25f,-0.25f,-0.25f,// point 6
  57. -0.25f,-0.25f,-0.25f,// point 7
  58. };
  59. const unsigned int pointcount=8;
  60. unsigned int polygons[] = //Polygons for a cube (6 squares)
  61. {
  62. 4,0,2,6,4, // positive X
  63. 4,1,0,4,5, // positive Y
  64. 4,0,1,3,2, // positive Z
  65. 4,3,1,5,7, // negative X
  66. 4,2,3,7,6, // negative Y
  67. 4,5,4,6,7, // negative Z
  68. };
  69. //----> Convex Object
  70. // select correct drawing functions
  71. #ifdef dDOUBLE
  72. #define dsDrawBox dsDrawBoxD
  73. #define dsDrawSphere dsDrawSphereD
  74. #define dsDrawCylinder dsDrawCylinderD
  75. #define dsDrawCapsule dsDrawCapsuleD
  76. #define dsDrawConvex dsDrawConvexD
  77. #endif
  78. // some constants
  79. #define NUM 100 // max number of objects
  80. #define DENSITY (5.0) // density of all objects
  81. #define GPB 3 // maximum number of geometries per body
  82. #define MAX_CONTACTS 8 // maximum number of contact points per body
  83. #define MAX_FEEDBACKNUM 20
  84. #define GRAVITY REAL(0.5)
  85. // dynamics and collision objects
  86. struct MyObject {
  87. dBodyID body; // the body
  88. dGeomID geom[GPB]; // geometries representing this body
  89. };
  90. static int num=0; // number of objects in simulation
  91. static int nextobj=0; // next object to recycle if num==NUM
  92. static dWorldID world;
  93. static dSpaceID space;
  94. static MyObject obj[NUM];
  95. static dJointGroupID contactgroup;
  96. static int selected = -1; // selected object
  97. static int show_aabb = 0; // show geom AABBs?
  98. static int show_contacts = 0; // show contact points?
  99. static int random_pos = 1; // drop objects from random position?
  100. static int write_world = 0;
  101. static int show_body = 0;
  102. struct MyFeedback {
  103. dJointFeedback fb;
  104. bool first;
  105. };
  106. static int doFeedback=0;
  107. static MyFeedback feedbacks[MAX_FEEDBACKNUM];
  108. static int fbnum=0;
  109. // this is called by dSpaceCollide when two objects in space are
  110. // potentially colliding.
  111. static void nearCallback (void *, dGeomID o1, dGeomID o2)
  112. {
  113. int i;
  114. // if (o1->body && o2->body) return;
  115. // exit without doing anything if the two bodies are connected by a joint
  116. dBodyID b1 = dGeomGetBody(o1);
  117. dBodyID b2 = dGeomGetBody(o2);
  118. if (b1 && b2 && dAreConnectedExcluding(b1,b2,dJointTypeContact))
  119. return;
  120. dContact contact[MAX_CONTACTS]; // up to MAX_CONTACTS contacts per box-box
  121. for (i=0; i<MAX_CONTACTS; i++) {
  122. contact[i].surface.mode = dContactBounce | dContactSoftCFM;
  123. contact[i].surface.mu = dInfinity;
  124. contact[i].surface.mu2 = 0;
  125. contact[i].surface.bounce = 0.1;
  126. contact[i].surface.bounce_vel = 0.1;
  127. contact[i].surface.soft_cfm = 0.01;
  128. }
  129. if (int numc = dCollide(o1,o2,MAX_CONTACTS,&contact[0].geom,
  130. sizeof(dContact))) {
  131. dMatrix3 RI;
  132. dRSetIdentity (RI);
  133. const dReal ss[3] = {0.02,0.02,0.02};
  134. for (i=0; i<numc; i++) {
  135. dJointID c = dJointCreateContact (world,contactgroup,contact+i);
  136. dJointAttach (c,b1,b2);
  137. if (show_contacts) {
  138. dsSetColor(0,0,1);
  139. dsDrawBox(contact[i].geom.pos,RI,ss);
  140. }
  141. if (doFeedback && (b1==obj[selected].body || b2==obj[selected].body)) {
  142. if (fbnum<MAX_FEEDBACKNUM) {
  143. feedbacks[fbnum].first = b1==obj[selected].body;
  144. dJointSetFeedback(c,&feedbacks[fbnum++].fb);
  145. }
  146. else fbnum++;
  147. }
  148. }
  149. }
  150. }
  151. // start simulation - set viewpoint
  152. static void start()
  153. {
  154. dAllocateODEDataForThread(dAllocateMaskAll);
  155. float xyz[3] = {2.1640f,-1.3079f,1.7600f};
  156. float hpr[3] = {125.5000f,-17.0000f,0.0000f};
  157. dsSetViewpoint (xyz,hpr);
  158. printf ("To drop another object, press:\n");
  159. printf (" b for box.\n");
  160. printf (" s for sphere.\n");
  161. printf (" c for capsule.\n");
  162. printf (" y for cylinder.\n");
  163. printf (" v for a convex object.\n");
  164. printf (" x for a composite object.\n");
  165. printf ("To select an object, press space.\n");
  166. printf ("To disable the selected object, press d.\n");
  167. printf ("To enable the selected object, press e.\n");
  168. printf ("To dump transformation data for the selected object, press p.\n");
  169. printf ("To toggle showing the geom AABBs, press a.\n");
  170. printf ("To toggle showing the contact points, press t.\n");
  171. printf ("To toggle dropping from random position/orientation, press r.\n");
  172. printf ("To save the current state to 'state.dif', press 1.\n");
  173. printf ("To show joint feedbacks of selected object, press f.\n");
  174. }
  175. static char locase(char c)
  176. {
  177. if (c >= 'A' && c <= 'Z') return c - ('a'-'A');
  178. else return c;
  179. }
  180. // called when a key pressed
  181. static void command(int cmd)
  182. {
  183. dsizeint i;
  184. int j,k;
  185. dReal sides[3];
  186. dMass m;
  187. bool setBody = false;
  188. cmd = locase(cmd);
  189. if (cmd == 'b' || cmd == 's' || cmd == 'c' || cmd == 'x' || cmd == 'y' || cmd == 'v') {
  190. if (num < NUM) {
  191. // new object to be created
  192. i = num;
  193. num++;
  194. } else {
  195. // recycle existing object
  196. i = nextobj++;
  197. nextobj %= num; // wrap-around if needed
  198. // destroy the body and geoms for slot i
  199. dBodyDestroy (obj[i].body);
  200. obj[i].body = 0;
  201. for (k=0; k < GPB; k++)
  202. if (obj[i].geom[k]) {
  203. dGeomDestroy(obj[i].geom[k]);
  204. obj[i].geom[k] = 0;
  205. }
  206. }
  207. obj[i].body = dBodyCreate(world);
  208. for (k=0; k<3; k++)
  209. sides[k] = dRandReal()*0.5+0.1;
  210. dMatrix3 R;
  211. if (random_pos) {
  212. dBodySetPosition(obj[i].body,
  213. dRandReal()*2-1,dRandReal()*2-1,dRandReal()+2);
  214. dRFromAxisAndAngle(R,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0,
  215. dRandReal()*2.0-1.0,dRandReal()*10.0-5.0);
  216. } else {
  217. // higher than highest body position
  218. dReal maxheight = 0;
  219. for (k=0; k<num; k++) {
  220. const dReal *pos = dBodyGetPosition(obj[k].body);
  221. if (pos[2] > maxheight)
  222. maxheight = pos[2];
  223. }
  224. dBodySetPosition(obj[i].body, 0,0,maxheight+1);
  225. dRSetIdentity(R);
  226. //dRFromAxisAndAngle (R,0,0,1,/*dRandReal()*10.0-5.0*/0);
  227. }
  228. dBodySetRotation(obj[i].body,R);
  229. if (cmd == 'b') {
  230. dMassSetBox(&m,DENSITY,sides[0],sides[1],sides[2]);
  231. obj[i].geom[0] = dCreateBox(space,sides[0],sides[1],sides[2]);
  232. } else if (cmd == 'c') {
  233. sides[0] *= 0.5;
  234. dMassSetCapsule(&m,DENSITY,3,sides[0],sides[1]);
  235. obj[i].geom[0] = dCreateCapsule (space,sides[0],sides[1]);
  236. } else if (cmd == 'v') {
  237. dMassSetBox(&m,DENSITY,0.25,0.25,0.25);
  238. #if 0
  239. obj[i].geom[0] = dCreateConvex(space,
  240. planes,
  241. planecount,
  242. points,
  243. pointcount,
  244. polygons);
  245. #else
  246. obj[i].geom[0] = dCreateConvex(space,
  247. Sphere_planes,
  248. Sphere_planecount,
  249. Sphere_points,
  250. Sphere_pointcount,
  251. Sphere_polygons);
  252. #endif
  253. } else if (cmd == 'y') {
  254. dMassSetCylinder(&m,DENSITY,3,sides[0],sides[1]);
  255. obj[i].geom[0] = dCreateCylinder(space,sides[0],sides[1]);
  256. } else if (cmd == 's') {
  257. sides[0] *= 0.5;
  258. dMassSetSphere (&m,DENSITY,sides[0]);
  259. obj[i].geom[0] = dCreateSphere (space,sides[0]);
  260. } else if (cmd == 'x') {
  261. setBody = true;
  262. // start accumulating masses for the composite geometries
  263. dMass m2;
  264. dMassSetZero (&m);
  265. dReal dpos[GPB][3]; // delta-positions for composite geometries
  266. dMatrix3 drot[GPB];
  267. // set random delta positions
  268. for (j=0; j<GPB; j++)
  269. for (k=0; k<3; k++)
  270. dpos[j][k] = dRandReal()*0.3-0.15;
  271. for (k=0; k<GPB; k++) {
  272. if (k==0) {
  273. dReal radius = dRandReal()*0.25+0.05;
  274. obj[i].geom[k] = dCreateSphere (space,radius);
  275. dMassSetSphere (&m2,DENSITY,radius);
  276. } else if (k==1) {
  277. obj[i].geom[k] = dCreateBox(space,sides[0],sides[1],sides[2]);
  278. dMassSetBox(&m2,DENSITY,sides[0],sides[1],sides[2]);
  279. } else {
  280. dReal radius = dRandReal()*0.1+0.05;
  281. dReal length = dRandReal()*1.0+0.1;
  282. obj[i].geom[k] = dCreateCapsule(space,radius,length);
  283. dMassSetCapsule(&m2,DENSITY,3,radius,length);
  284. }
  285. dRFromAxisAndAngle(drot[k],dRandReal()*2.0-1.0,dRandReal()*2.0-1.0,
  286. dRandReal()*2.0-1.0,dRandReal()*10.0-5.0);
  287. dMassRotate(&m2,drot[k]);
  288. dMassTranslate(&m2,dpos[k][0],dpos[k][1],dpos[k][2]);
  289. // add to the total mass
  290. dMassAdd(&m,&m2);
  291. }
  292. for (k=0; k<GPB; k++) {
  293. dGeomSetBody(obj[i].geom[k],obj[i].body);
  294. dGeomSetOffsetPosition(obj[i].geom[k],
  295. dpos[k][0]-m.c[0],
  296. dpos[k][1]-m.c[1],
  297. dpos[k][2]-m.c[2]);
  298. dGeomSetOffsetRotation(obj[i].geom[k], drot[k]);
  299. }
  300. dMassTranslate(&m,-m.c[0],-m.c[1],-m.c[2]);
  301. dBodySetMass(obj[i].body,&m);
  302. }
  303. if (!setBody) { // avoid calling for composite geometries
  304. for (k=0; k < GPB; k++)
  305. if (obj[i].geom[k])
  306. dGeomSetBody(obj[i].geom[k],obj[i].body);
  307. dBodySetMass(obj[i].body,&m);
  308. }
  309. }
  310. if (cmd == ' ') {
  311. selected++;
  312. if (selected >= num)
  313. selected = 0;
  314. if (selected == -1)
  315. selected = 0;
  316. } else if (cmd == 'd' && selected >= 0 && selected < num) {
  317. dBodyDisable(obj[selected].body);
  318. } else if (cmd == 'e' && selected >= 0 && selected < num) {
  319. dBodyEnable(obj[selected].body);
  320. } else if (cmd == 'a') {
  321. show_aabb = !show_aabb;
  322. } else if (cmd == 't') {
  323. show_contacts = !show_contacts;
  324. } else if (cmd == 'r') {
  325. random_pos = !random_pos;
  326. } else if (cmd == '1') {
  327. write_world = 1;
  328. } else if (cmd == 'p'&& selected >= 0) {
  329. const dReal* pos = dGeomGetPosition(obj[selected].geom[0]);
  330. const dReal* rot = dGeomGetRotation(obj[selected].geom[0]);
  331. printf("POSITION:\n\t[%f,%f,%f]\n\n",pos[0],pos[1],pos[2]);
  332. printf("ROTATION:\n\t[%f,%f,%f,%f]\n\t[%f,%f,%f,%f]\n\t[%f,%f,%f,%f]\n\n",
  333. rot[0],rot[1],rot[2],rot[3],
  334. rot[4],rot[5],rot[6],rot[7],
  335. rot[8],rot[9],rot[10],rot[11]);
  336. } else if (cmd == 'f' && selected >= 0 && selected < num) {
  337. if (dBodyIsEnabled(obj[selected].body))
  338. doFeedback = 1;
  339. }
  340. }
  341. // draw a geom
  342. void drawGeom(dGeomID g, const dReal *pos, const dReal *R, int show_aabb)
  343. {
  344. int i;
  345. if (!g)
  346. return;
  347. if (!pos)
  348. pos = dGeomGetPosition(g);
  349. if (!R)
  350. R = dGeomGetRotation(g);
  351. int type = dGeomGetClass(g);
  352. if (type == dBoxClass) {
  353. dVector3 sides;
  354. dGeomBoxGetLengths (g,sides);
  355. dsDrawBox(pos,R,sides);
  356. } else if (type == dSphereClass) {
  357. dsDrawSphere(pos,R,dGeomSphereGetRadius(g));
  358. } else if (type == dCapsuleClass) {
  359. dReal radius,length;
  360. dGeomCapsuleGetParams(g,&radius,&length);
  361. dsDrawCapsule(pos,R,length,radius);
  362. } else if (type == dConvexClass) {
  363. #if 0
  364. dsDrawConvex(pos,R,planes,
  365. planecount,
  366. points,
  367. pointcount,
  368. polygons);
  369. #else
  370. dsDrawConvex(pos,R,
  371. Sphere_planes,
  372. Sphere_planecount,
  373. Sphere_points,
  374. Sphere_pointcount,
  375. Sphere_polygons);
  376. #endif
  377. } else if (type == dCylinderClass) {
  378. dReal radius,length;
  379. dGeomCylinderGetParams(g,&radius,&length);
  380. dsDrawCylinder(pos,R,length,radius);
  381. }
  382. if (show_body) {
  383. dBodyID body = dGeomGetBody(g);
  384. if (body) {
  385. const dReal *bodypos = dBodyGetPosition(body);
  386. const dReal *bodyr = dBodyGetRotation(body);
  387. dReal bodySides[3] = { 0.1, 0.1, 0.1 };
  388. dsSetColorAlpha(0,1,0,1);
  389. dsDrawBox(bodypos,bodyr,bodySides);
  390. }
  391. }
  392. if (show_aabb) {
  393. // draw the bounding box for this geom
  394. dReal aabb[6];
  395. dGeomGetAABB(g,aabb);
  396. dVector3 bbpos;
  397. for (i=0; i<3; i++)
  398. bbpos[i] = 0.5*(aabb[i*2] + aabb[i*2+1]);
  399. dVector3 bbsides;
  400. for (i=0; i<3; i++)
  401. bbsides[i] = aabb[i*2+1] - aabb[i*2];
  402. dMatrix3 RI;
  403. dRSetIdentity (RI);
  404. dsSetColorAlpha(1,0,0,0.5);
  405. dsDrawBox(bbpos,RI,bbsides);
  406. }
  407. }
  408. // simulation loop
  409. static void simLoop(int pause)
  410. {
  411. dSpaceCollide(space, 0, &nearCallback);
  412. if (!pause)
  413. dWorldQuickStep(world, 0.02);
  414. if (write_world) {
  415. FILE *f = fopen("state.dif","wt");
  416. if (f) {
  417. dWorldExportDIF(world,f,"X");
  418. fclose (f);
  419. }
  420. write_world = 0;
  421. }
  422. if (doFeedback) {
  423. if (fbnum>MAX_FEEDBACKNUM)
  424. printf("joint feedback buffer overflow!\n");
  425. else {
  426. dVector3 sum = {0, 0, 0};
  427. printf("\n");
  428. for (int i=0; i<fbnum; i++) {
  429. dReal* f = feedbacks[i].first?feedbacks[i].fb.f1:feedbacks[i].fb.f2;
  430. printf("%f %f %f\n", f[0], f[1], f[2]);
  431. sum[0] += f[0];
  432. sum[1] += f[1];
  433. sum[2] += f[2];
  434. }
  435. printf("Sum: %f %f %f\n", sum[0], sum[1], sum[2]);
  436. dMass m;
  437. dBodyGetMass(obj[selected].body, &m);
  438. printf("Object G=%f\n", GRAVITY*m.mass);
  439. }
  440. doFeedback = 0;
  441. fbnum = 0;
  442. }
  443. // remove all contact joints
  444. dJointGroupEmpty(contactgroup);
  445. dsSetTexture(DS_WOOD);
  446. for (int i=0; i<num; i++) {
  447. for (int j=0; j < GPB; j++) {
  448. if (i==selected) {
  449. dsSetColor(0,0.7,1);
  450. } else if (!dBodyIsEnabled(obj[i].body)) {
  451. dsSetColor(1,0.8,0);
  452. } else {
  453. dsSetColor(1,1,0);
  454. }
  455. drawGeom(obj[i].geom[j],0,0,show_aabb);
  456. }
  457. }
  458. }
  459. int main (int argc, char **argv)
  460. {
  461. // setup pointers to drawstuff callback functions
  462. dsFunctions fn;
  463. fn.version = DS_VERSION;
  464. fn.start = &start;
  465. fn.step = &simLoop;
  466. fn.command = &command;
  467. fn.stop = 0;
  468. fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
  469. // create world
  470. dInitODE2(0);
  471. world = dWorldCreate();
  472. space = dHashSpaceCreate(0);
  473. contactgroup = dJointGroupCreate(0);
  474. dWorldSetGravity(world,0,0,-GRAVITY);
  475. dWorldSetCFM(world,1e-5);
  476. dWorldSetAutoDisableFlag(world,1);
  477. #if 1
  478. dWorldSetAutoDisableAverageSamplesCount( world, 10 );
  479. #endif
  480. dWorldSetLinearDamping(world, 0.00001);
  481. dWorldSetAngularDamping(world, 0.005);
  482. dWorldSetMaxAngularSpeed(world, 200);
  483. dWorldSetContactMaxCorrectingVel(world,0.1);
  484. dWorldSetContactSurfaceLayer(world,0.001);
  485. dCreatePlane(space,0,0,1,0);
  486. memset(obj,0,sizeof(obj));
  487. dThreadingImplementationID threading = dThreadingAllocateMultiThreadedImplementation();
  488. dThreadingThreadPoolID pool = dThreadingAllocateThreadPool(4, 0, dAllocateFlagBasicData, NULL);
  489. dThreadingThreadPoolServeMultiThreadedImplementation(pool, threading);
  490. // dWorldSetStepIslandsProcessingMaxThreadCount(world, 1);
  491. dWorldSetStepThreadingImplementation(world, dThreadingImplementationGetFunctions(threading), threading);
  492. // run simulation
  493. dsSimulationLoop(argc, argv, DS_SIMULATION_DEFAULT_WIDTH, DS_SIMULATION_DEFAULT_HEIGHT, &fn);
  494. dThreadingImplementationShutdownProcessing(threading);
  495. dThreadingFreeThreadPool(pool);
  496. dWorldSetStepThreadingImplementation(world, NULL, NULL);
  497. dThreadingFreeImplementation(threading);
  498. dJointGroupDestroy(contactgroup);
  499. dSpaceDestroy(space);
  500. dWorldDestroy(world);
  501. dCloseODE();
  502. }