demo_space_stress.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. /*************************************************************************
  2. * *
  3. * Open Dynamics Engine, Copyright (C) 2001-2003 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 <string>
  23. #include <ode/ode.h>
  24. #include <drawstuff/drawstuff.h>
  25. #include "texturepath.h"
  26. #ifdef _MSC_VER
  27. #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
  28. #endif
  29. // select correct drawing functions
  30. #ifdef dDOUBLE
  31. #define dsDrawBox dsDrawBoxD
  32. #define dsDrawSphere dsDrawSphereD
  33. #define dsDrawCylinder dsDrawCylinderD
  34. #define dsDrawCapsule dsDrawCapsuleD
  35. #endif
  36. // some constants
  37. #define NUM 10000 // max number of objects
  38. #define DENSITY (5.0) // density of all objects
  39. #define GPB 3 // maximum number of geometries per body
  40. #define MAX_CONTACTS 4 // maximum number of contact points per body
  41. #define WORLD_SIZE 20
  42. #define WORLD_HEIGHT 20
  43. // dynamics and collision objects
  44. struct MyObject {
  45. dBodyID body; // the body
  46. dGeomID geom[GPB]; // geometries representing this body
  47. };
  48. static int num=0; // number of objects in simulation
  49. static int nextobj=0; // next object to recycle if num==NUM
  50. static dWorldID world;
  51. static dSpaceID space = NULL;
  52. static MyObject obj[NUM];
  53. static dJointGroupID contactgroup;
  54. static int selected = -1; // selected object
  55. static int show_aabb = 0; // show geom AABBs?
  56. static int show_contacts = 0; // show contact points?
  57. static int random_pos = 1; // drop objects from random position?
  58. static int draw_geom = 1;
  59. // this is called by dSpaceCollide when two objects in space are
  60. // potentially colliding.
  61. static void nearCallback (void *, dGeomID o1, dGeomID o2)
  62. {
  63. int i;
  64. // if (o1->body && o2->body) return;
  65. // exit without doing anything if the two bodies are connected by a joint
  66. dBodyID b1 = dGeomGetBody(o1);
  67. dBodyID b2 = dGeomGetBody(o2);
  68. if (b1 && b2 && dAreConnectedExcluding (b1,b2,dJointTypeContact)) return;
  69. dContact contact[MAX_CONTACTS]; // up to MAX_CONTACTS contacts per box-box
  70. for (i=0; i<MAX_CONTACTS; i++) {
  71. contact[i].surface.mode = dContactBounce | dContactSoftCFM;
  72. contact[i].surface.mu = dInfinity;
  73. contact[i].surface.mu2 = 0;
  74. contact[i].surface.bounce = 0.1;
  75. contact[i].surface.bounce_vel = 0.1;
  76. contact[i].surface.soft_cfm = 0.01;
  77. }
  78. if (int numc = dCollide (o1,o2,MAX_CONTACTS,&contact[0].geom,
  79. sizeof(dContact))) {
  80. dMatrix3 RI;
  81. dRSetIdentity (RI);
  82. const dReal ss[3] = {0.02,0.02,0.02};
  83. for (i=0; i<numc; i++) {
  84. dJointID c = dJointCreateContact (world,contactgroup,contact+i);
  85. dJointAttach (c,b1,b2);
  86. if (show_contacts) dsDrawBox (contact[i].geom.pos,RI,ss);
  87. }
  88. }
  89. }
  90. // start simulation - set viewpoint
  91. static void start()
  92. {
  93. dAllocateODEDataForThread(dAllocateMaskAll);
  94. static float xyz[3] = {2.1640f,-1.3079f,3.7600f};
  95. static float hpr[3] = {125.5000f,-17.0000f,0.0000f};
  96. dsSetViewpoint (xyz,hpr);
  97. printf ("To drop another object, press:\n");
  98. printf (" o to disable rendering.\n");
  99. printf (" b for box.\n");
  100. printf (" s for sphere.\n");
  101. printf (" c for cylinder.\n");
  102. printf (" x for a composite object.\n");
  103. printf ("To select an object, press space.\n");
  104. printf ("To disable the selected object, press d.\n");
  105. printf ("To enable the selected object, press e.\n");
  106. printf ("To toggle showing the geom AABBs, press a.\n");
  107. printf ("To toggle showing the contact points, press t.\n");
  108. printf ("To toggle dropping from random position/orientation, press r.\n");
  109. }
  110. char locase (char c)
  111. {
  112. if (c >= 'A' && c <= 'Z') return c - ('a'-'A');
  113. else return c;
  114. }
  115. // called when a key pressed
  116. static void command (int cmd)
  117. {
  118. int i,j,k;
  119. dReal sides[3];
  120. dMass m;
  121. cmd = locase (cmd);
  122. if (cmd == 'b' || cmd == 's' || cmd == 'c' || cmd == 'x'
  123. /* || cmd == 'l' */) {
  124. if (num < NUM) {
  125. i = num;
  126. num++;
  127. }
  128. else {
  129. i = nextobj;
  130. nextobj++;
  131. if (nextobj >= num) nextobj = 0;
  132. // destroy the body and geoms for slot i
  133. dBodyDestroy (obj[i].body);
  134. for (k=0; k < GPB; k++) {
  135. if (obj[i].geom[k]) dGeomDestroy (obj[i].geom[k]);
  136. }
  137. memset (&obj[i],0,sizeof(obj[i]));
  138. }
  139. obj[i].body = dBodyCreate (world);
  140. for (k=0; k<3; k++) sides[k] = dRandReal()*0.5+0.1;
  141. dMatrix3 R;
  142. if (random_pos) {
  143. dBodySetPosition (obj[i].body,
  144. dRandReal()*WORLD_SIZE-(WORLD_SIZE/2),
  145. dRandReal()*WORLD_SIZE-(WORLD_SIZE/2),
  146. dRandReal()*WORLD_HEIGHT+1);
  147. dRFromAxisAndAngle (R,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0,
  148. dRandReal()*2.0-1.0,dRandReal()*10.0-5.0);
  149. }
  150. else {
  151. dReal maxheight = 0;
  152. for (k=0; k<num; k++) {
  153. const dReal *pos = dBodyGetPosition (obj[k].body);
  154. if (pos[2] > maxheight) maxheight = pos[2];
  155. }
  156. dBodySetPosition (obj[i].body, 0,0,maxheight+1);
  157. dRFromAxisAndAngle (R,0,0,1,dRandReal()*10.0-5.0);
  158. }
  159. dBodySetRotation (obj[i].body,R);
  160. dBodySetData (obj[i].body,(void*)(size_t)i);
  161. if (cmd == 'b') {
  162. dMassSetBox (&m,DENSITY,sides[0],sides[1],sides[2]);
  163. obj[i].geom[0] = dCreateBox (space,sides[0],sides[1],sides[2]);
  164. }
  165. else if (cmd == 'c') {
  166. sides[0] *= 0.5;
  167. dMassSetCapsule (&m,DENSITY,3,sides[0],sides[1]);
  168. obj[i].geom[0] = dCreateCapsule (space,sides[0],sides[1]);
  169. }
  170. /*
  171. // cylinder option not yet implemented
  172. else if (cmd == 'l') {
  173. sides[1] *= 0.5;
  174. dMassSetCapsule (&m,DENSITY,3,sides[0],sides[1]);
  175. obj[i].geom[0] = dCreateCylinder (space,sides[0],sides[1]);
  176. }
  177. */
  178. else if (cmd == 's') {
  179. sides[0] *= 0.5;
  180. dMassSetSphere (&m,DENSITY,sides[0]);
  181. obj[i].geom[0] = dCreateSphere (space,sides[0]);
  182. }
  183. else if (cmd == 'x') {
  184. dGeomID g2[GPB]; // encapsulated geometries
  185. dReal dpos[GPB][3]; // delta-positions for encapsulated geometries
  186. // start accumulating masses for the encapsulated geometries
  187. dMass m2;
  188. dMassSetZero (&m);
  189. // set random delta positions
  190. for (j=0; j<GPB; j++) {
  191. for (k=0; k<3; k++) dpos[j][k] = dRandReal()*0.3-0.15;
  192. }
  193. for (k=0; k<GPB; k++) {
  194. obj[i].geom[k] = dCreateGeomTransform (space);
  195. dGeomTransformSetCleanup (obj[i].geom[k],1);
  196. if (k==0) {
  197. dReal radius = dRandReal()*0.25+0.05;
  198. g2[k] = dCreateSphere (0,radius);
  199. dMassSetSphere (&m2,DENSITY,radius);
  200. }
  201. else if (k==1) {
  202. g2[k] = dCreateBox (0,sides[0],sides[1],sides[2]);
  203. dMassSetBox (&m2,DENSITY,sides[0],sides[1],sides[2]);
  204. }
  205. else {
  206. dReal radius = dRandReal()*0.1+0.05;
  207. dReal length = dRandReal()*1.0+0.1;
  208. g2[k] = dCreateCapsule (0,radius,length);
  209. dMassSetCapsule (&m2,DENSITY,3,radius,length);
  210. }
  211. dGeomTransformSetGeom (obj[i].geom[k],g2[k]);
  212. // set the transformation (adjust the mass too)
  213. dGeomSetPosition (g2[k],dpos[k][0],dpos[k][1],dpos[k][2]);
  214. dMassTranslate (&m2,dpos[k][0],dpos[k][1],dpos[k][2]);
  215. dMatrix3 Rtx;
  216. dRFromAxisAndAngle (Rtx,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0,
  217. dRandReal()*2.0-1.0,dRandReal()*10.0-5.0);
  218. dGeomSetRotation (g2[k],Rtx);
  219. dMassRotate (&m2,Rtx);
  220. // add to the total mass
  221. dMassAdd (&m,&m2);
  222. }
  223. // move all encapsulated objects so that the center of mass is (0,0,0)
  224. for (k=0; k<2; k++) {
  225. dGeomSetPosition (g2[k],
  226. dpos[k][0]-m.c[0],
  227. dpos[k][1]-m.c[1],
  228. dpos[k][2]-m.c[2]);
  229. }
  230. dMassTranslate (&m,-m.c[0],-m.c[1],-m.c[2]);
  231. }
  232. for (k=0; k < GPB; k++) {
  233. if (obj[i].geom[k]) dGeomSetBody (obj[i].geom[k],obj[i].body);
  234. }
  235. dBodySetMass (obj[i].body,&m);
  236. }
  237. if (cmd == ' ') {
  238. selected++;
  239. if (selected >= num) selected = 0;
  240. if (selected < 0) selected = 0;
  241. }
  242. else if (cmd == 'd' && selected >= 0 && selected < num) {
  243. dBodyDisable (obj[selected].body);
  244. }
  245. else if (cmd == 'e' && selected >= 0 && selected < num) {
  246. dBodyEnable (obj[selected].body);
  247. }
  248. else if (cmd == 'a') {
  249. show_aabb ^= 1;
  250. }
  251. else if (cmd == 't') {
  252. show_contacts ^= 1;
  253. }
  254. else if (cmd == 'r') {
  255. random_pos ^= 1;
  256. }
  257. else if (cmd == 'o') {
  258. draw_geom ^= 1;
  259. }
  260. }
  261. // draw a geom
  262. void drawGeom (dGeomID g, const dReal *pos, const dReal *R, int show_aabb)
  263. {
  264. if (!draw_geom){
  265. return;
  266. }
  267. if (!g) return;
  268. if (!pos) pos = dGeomGetPosition (g);
  269. if (!R) R = dGeomGetRotation (g);
  270. int type = dGeomGetClass (g);
  271. if (type == dBoxClass) {
  272. dVector3 sides;
  273. dGeomBoxGetLengths (g,sides);
  274. dsDrawBox (pos,R,sides);
  275. }
  276. else if (type == dSphereClass) {
  277. dsDrawSphere (pos,R,dGeomSphereGetRadius (g));
  278. }
  279. else if (type == dCapsuleClass) {
  280. dReal radius,length;
  281. dGeomCapsuleGetParams (g,&radius,&length);
  282. dsDrawCapsule (pos,R,length,radius);
  283. }
  284. /*
  285. // cylinder option not yet implemented
  286. else if (type == dCylinderClass) {
  287. dReal radius,length;
  288. dGeomCylinderGetParams (g,&radius,&length);
  289. dsDrawCylinder (pos,R,length,radius);
  290. }
  291. */
  292. else if (type == dGeomTransformClass) {
  293. dGeomID g2 = dGeomTransformGetGeom (g);
  294. const dReal *pos2 = dGeomGetPosition (g2);
  295. const dReal *R2 = dGeomGetRotation (g2);
  296. dVector3 actual_pos;
  297. dMatrix3 actual_R;
  298. dMultiply0_331 (actual_pos,R,pos2);
  299. actual_pos[0] += pos[0];
  300. actual_pos[1] += pos[1];
  301. actual_pos[2] += pos[2];
  302. dMultiply0_333 (actual_R,R,R2);
  303. drawGeom (g2,actual_pos,actual_R,0);
  304. }
  305. if (show_aabb) {
  306. // draw the bounding box for this geom
  307. dReal aabb[6];
  308. dGeomGetAABB (g,aabb);
  309. dVector3 bbpos;
  310. for (int i=0; i<3; i++) bbpos[i] = 0.5*(aabb[i*2] + aabb[i*2+1]);
  311. dVector3 bbsides;
  312. for (int j=0; j<3; j++) bbsides[j] = aabb[j*2+1] - aabb[j*2];
  313. dMatrix3 RI;
  314. dRSetIdentity (RI);
  315. dsSetColorAlpha (1,0,0,0.5);
  316. dsDrawBox (bbpos,RI,bbsides);
  317. }
  318. }
  319. // simulation loop
  320. static void simLoop (int pause)
  321. {
  322. dsSetColor (0,0,2);
  323. dSpaceCollide (space,0,&nearCallback);
  324. //if (!pause) dWorldStep (world,0.05);
  325. if (!pause) dWorldQuickStep (world,0.05);
  326. //if (!pause) dWorldStepFast (world,0.05, 1);
  327. // remove all contact joints
  328. dJointGroupEmpty (contactgroup);
  329. dsSetColor (1,1,0);
  330. dsSetTexture (DS_WOOD);
  331. for (int i=0; i<num; i++) {
  332. for (int j=0; j < GPB; j++) {
  333. if (i==selected) {
  334. dsSetColor (0,0.7,1);
  335. }
  336. else if (! dBodyIsEnabled (obj[i].body)) {
  337. dsSetColor (1,0,0);
  338. }
  339. else {
  340. dsSetColor (1,1,0);
  341. }
  342. drawGeom (obj[i].geom[j],0,0,show_aabb);
  343. }
  344. }
  345. }
  346. int main (int argc, char **argv)
  347. {
  348. // setup pointers to drawstuff callback functions
  349. dsFunctions fn;
  350. fn.version = DS_VERSION;
  351. fn.start = &start;
  352. fn.step = &simLoop;
  353. fn.command = &command;
  354. fn.stop = 0;
  355. fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
  356. dsSetSphereQuality(0);
  357. // create world
  358. dInitODE2(0);
  359. world = dWorldCreate();
  360. for (int i=1; i<argc; ++i) {
  361. if (argv[i] == std::string("quad")) {
  362. dVector3 Center = {0, 0, 0, 0};
  363. dVector3 Extents = {WORLD_SIZE * 0.55, WORLD_SIZE * 0.55, WORLD_SIZE * 0.55, 0};
  364. puts(":::: Using dQuadTreeSpace");
  365. space = dQuadTreeSpaceCreate (0, Center, Extents, 6);
  366. } else if (argv[i] == std::string("hash")) {
  367. puts(":::: Using dHashSpace");
  368. space = dHashSpaceCreate (0);
  369. } else if (argv[i] == std::string("sap")) {
  370. puts(":::: Using dSweepAndPruneSpace");
  371. space = dSweepAndPruneSpaceCreate (0, dSAP_AXES_XYZ);
  372. } else if (argv[i] == std::string("simple")) {
  373. puts(":::: Using dSimpleSpace");
  374. space = dSimpleSpaceCreate(0);
  375. }
  376. }
  377. if (!space) {
  378. puts(":::: You can specify 'quad', 'hash', 'sap' or 'simple' in the");
  379. puts(":::: command line to specify the type of space.");
  380. puts(":::: Using SAP space by default.");
  381. space = dSweepAndPruneSpaceCreate (0, dSAP_AXES_XYZ);
  382. }
  383. contactgroup = dJointGroupCreate (0);
  384. dWorldSetGravity (world,0,0,-0.5);
  385. dWorldSetCFM (world,1e-5);
  386. dCreatePlane (space,0,0,1,0);
  387. memset (obj,0,sizeof(obj));
  388. for (int i = 0; i < NUM; i++){
  389. command('s');
  390. }
  391. // run simulation
  392. dsSimulationLoop (argc,argv,352,288,&fn);
  393. dJointGroupDestroy (contactgroup);
  394. dSpaceDestroy (space);
  395. dWorldDestroy (world);
  396. dCloseODE();
  397. return 0;
  398. }