demo_space_stress.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  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 (" y for cylinder.\n");
  104. printf ("To select an object, press space.\n");
  105. printf ("To disable the selected object, press d.\n");
  106. printf ("To enable the selected object, press e.\n");
  107. printf ("To toggle showing the geom AABBs, press a.\n");
  108. printf ("To toggle showing the contact points, press t.\n");
  109. printf ("To toggle dropping from random position/orientation, press r.\n");
  110. }
  111. char locase(char c)
  112. {
  113. if (c >= 'A' && c <= 'Z') return c - ('a'-'A');
  114. else return c;
  115. }
  116. // called when a key pressed
  117. static void command (int cmd)
  118. {
  119. int i,j,k;
  120. dReal sides[3];
  121. dMass m;
  122. bool setBody = false;
  123. cmd = locase(cmd);
  124. if (cmd == 'b' || cmd == 's' || cmd == 'c' || cmd == 'x' || cmd == 'y') {
  125. if (num < NUM) {
  126. // new object to be created
  127. i = num;
  128. num++;
  129. } else {
  130. // recycle existing object
  131. i = nextobj++;
  132. nextobj %= num; // wrap-around if needed
  133. // destroy the body and geoms for slot i
  134. dBodyDestroy (obj[i].body);
  135. obj[i].body = 0;
  136. for (k=0; k < GPB; k++)
  137. if (obj[i].geom[k]) {
  138. dGeomDestroy(obj[i].geom[k]);
  139. obj[i].geom[k] = 0;
  140. }
  141. }
  142. obj[i].body = dBodyCreate(world);
  143. for (k=0; k<3; k++)
  144. sides[k] = dRandReal()*0.5+0.1;
  145. dMatrix3 R;
  146. if (random_pos) {
  147. dBodySetPosition(obj[i].body,
  148. dRandReal()*2-1,dRandReal()*2-1,dRandReal()+2);
  149. dRFromAxisAndAngle(R,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0,
  150. dRandReal()*2.0-1.0,dRandReal()*10.0-5.0);
  151. } else {
  152. // higher than highest body position
  153. dReal maxheight = 0;
  154. for (k=0; k<num; k++) {
  155. const dReal *pos = dBodyGetPosition(obj[k].body);
  156. if (pos[2] > maxheight)
  157. maxheight = pos[2];
  158. }
  159. dBodySetPosition(obj[i].body, 0,0,maxheight+1);
  160. dRSetIdentity(R);
  161. //dRFromAxisAndAngle (R,0,0,1,/*dRandReal()*10.0-5.0*/0);
  162. }
  163. dBodySetRotation(obj[i].body,R);
  164. if (cmd == 'b') {
  165. dMassSetBox(&m,DENSITY,sides[0],sides[1],sides[2]);
  166. obj[i].geom[0] = dCreateBox(space,sides[0],sides[1],sides[2]);
  167. } else if (cmd == 'c') {
  168. sides[0] *= 0.5;
  169. dMassSetCapsule(&m,DENSITY,3,sides[0],sides[1]);
  170. obj[i].geom[0] = dCreateCapsule (space,sides[0],sides[1]);
  171. } else if (cmd == 'y') {
  172. dMassSetCylinder(&m,DENSITY,3,sides[0],sides[1]);
  173. obj[i].geom[0] = dCreateCylinder(space,sides[0],sides[1]);
  174. } else if (cmd == 's') {
  175. sides[0] *= 0.5;
  176. dMassSetSphere (&m,DENSITY,sides[0]);
  177. obj[i].geom[0] = dCreateSphere (space,sides[0]);
  178. } else if (cmd == 'x') {
  179. setBody = true;
  180. // start accumulating masses for the composite geometries
  181. dMass m2;
  182. dMassSetZero (&m);
  183. dReal dpos[GPB][3]; // delta-positions for composite geometries
  184. dMatrix3 drot[GPB];
  185. // set random delta positions
  186. for (j=0; j<GPB; j++)
  187. for (k=0; k<3; k++)
  188. dpos[j][k] = dRandReal()*0.3-0.15;
  189. for (k=0; k<GPB; k++) {
  190. if (k==0) {
  191. dReal radius = dRandReal()*0.25+0.05;
  192. obj[i].geom[k] = dCreateSphere (space,radius);
  193. dMassSetSphere (&m2,DENSITY,radius);
  194. } else if (k==1) {
  195. obj[i].geom[k] = dCreateBox(space,sides[0],sides[1],sides[2]);
  196. dMassSetBox(&m2,DENSITY,sides[0],sides[1],sides[2]);
  197. } else {
  198. dReal radius = dRandReal()*0.1+0.05;
  199. dReal length = dRandReal()*1.0+0.1;
  200. obj[i].geom[k] = dCreateCapsule(space,radius,length);
  201. dMassSetCapsule(&m2,DENSITY,3,radius,length);
  202. }
  203. dRFromAxisAndAngle(drot[k],dRandReal()*2.0-1.0,dRandReal()*2.0-1.0,
  204. dRandReal()*2.0-1.0,dRandReal()*10.0-5.0);
  205. dMassRotate(&m2,drot[k]);
  206. dMassTranslate(&m2,dpos[k][0],dpos[k][1],dpos[k][2]);
  207. // add to the total mass
  208. dMassAdd(&m,&m2);
  209. }
  210. for (k=0; k<GPB; k++) {
  211. dGeomSetBody(obj[i].geom[k],obj[i].body);
  212. dGeomSetOffsetPosition(obj[i].geom[k],
  213. dpos[k][0]-m.c[0],
  214. dpos[k][1]-m.c[1],
  215. dpos[k][2]-m.c[2]);
  216. dGeomSetOffsetRotation(obj[i].geom[k], drot[k]);
  217. }
  218. dMassTranslate(&m,-m.c[0],-m.c[1],-m.c[2]);
  219. dBodySetMass(obj[i].body,&m);
  220. }
  221. if (!setBody) { // avoid calling for composite geometries
  222. for (k=0; k < GPB; k++)
  223. if (obj[i].geom[k])
  224. dGeomSetBody(obj[i].geom[k],obj[i].body);
  225. dBodySetMass(obj[i].body,&m);
  226. }
  227. }
  228. if (cmd == ' ') {
  229. selected++;
  230. if (selected >= num) selected = 0;
  231. if (selected < 0) selected = 0;
  232. }
  233. else if (cmd == 'd' && selected >= 0 && selected < num) {
  234. dBodyDisable (obj[selected].body);
  235. }
  236. else if (cmd == 'e' && selected >= 0 && selected < num) {
  237. dBodyEnable (obj[selected].body);
  238. }
  239. else if (cmd == 'a') {
  240. show_aabb ^= 1;
  241. }
  242. else if (cmd == 't') {
  243. show_contacts ^= 1;
  244. }
  245. else if (cmd == 'r') {
  246. random_pos ^= 1;
  247. }
  248. else if (cmd == 'o') {
  249. draw_geom ^= 1;
  250. }
  251. }
  252. // draw a geom
  253. void drawGeom (dGeomID g, const dReal *pos, const dReal *R, int show_aabb)
  254. {
  255. if (!draw_geom){
  256. return;
  257. }
  258. if (!g) return;
  259. if (!pos) pos = dGeomGetPosition(g);
  260. if (!R) R = dGeomGetRotation(g);
  261. int type = dGeomGetClass (g);
  262. if (type == dBoxClass) {
  263. dVector3 sides;
  264. dGeomBoxGetLengths(g,sides);
  265. dsDrawBox(pos,R,sides);
  266. }
  267. else if (type == dSphereClass) {
  268. dsDrawSphere(pos,R,dGeomSphereGetRadius (g));
  269. }
  270. else if (type == dCapsuleClass) {
  271. dReal radius,length;
  272. dGeomCapsuleGetParams(g,&radius,&length);
  273. dsDrawCapsule (pos,R,length,radius);
  274. } else if (type == dCylinderClass) {
  275. dReal radius,length;
  276. dGeomCylinderGetParams(g,&radius,&length);
  277. dsDrawCylinder(pos,R,length,radius);
  278. }
  279. if (show_aabb) {
  280. // draw the bounding box for this geom
  281. dReal aabb[6];
  282. dGeomGetAABB(g,aabb);
  283. dVector3 bbpos;
  284. for (int i=0; i<3; i++)
  285. bbpos[i] = 0.5*(aabb[i*2] + aabb[i*2+1]);
  286. dVector3 bbsides;
  287. for (int j=0; j<3; j++)
  288. bbsides[j] = aabb[j*2+1] - aabb[j*2];
  289. dMatrix3 RI;
  290. dRSetIdentity(RI);
  291. dsSetColorAlpha(1,0,0,0.5);
  292. dsDrawBox(bbpos,RI,bbsides);
  293. }
  294. }
  295. // simulation loop
  296. static void simLoop (int pause)
  297. {
  298. dsSetColor (0,0,2);
  299. dSpaceCollide (space,0,&nearCallback);
  300. //if (!pause) dWorldStep (world,0.05);
  301. if (!pause) dWorldQuickStep (world,0.05);
  302. //if (!pause) dWorldStepFast (world,0.05, 1);
  303. // remove all contact joints
  304. dJointGroupEmpty (contactgroup);
  305. dsSetColor (1,1,0);
  306. dsSetTexture (DS_WOOD);
  307. for (int i=0; i<num; i++) {
  308. for (int j=0; j < GPB; j++) {
  309. if (i==selected) {
  310. dsSetColor (0,0.7,1);
  311. }
  312. else if (! dBodyIsEnabled (obj[i].body)) {
  313. dsSetColor (1,0,0);
  314. }
  315. else {
  316. dsSetColor (1,1,0);
  317. }
  318. drawGeom (obj[i].geom[j],0,0,show_aabb);
  319. }
  320. }
  321. }
  322. int main (int argc, char **argv)
  323. {
  324. // setup pointers to drawstuff callback functions
  325. dsFunctions fn;
  326. fn.version = DS_VERSION;
  327. fn.start = &start;
  328. fn.step = &simLoop;
  329. fn.command = &command;
  330. fn.stop = 0;
  331. fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
  332. dsSetSphereQuality(0);
  333. // create world
  334. dInitODE2(0);
  335. world = dWorldCreate();
  336. for (int i=1; i<argc; ++i) {
  337. if (argv[i] == std::string("quad")) {
  338. dVector3 Center = {0, 0, 0, 0};
  339. dVector3 Extents = {WORLD_SIZE * 0.55, WORLD_SIZE * 0.55, WORLD_SIZE * 0.55, 0};
  340. puts(":::: Using dQuadTreeSpace");
  341. space = dQuadTreeSpaceCreate (0, Center, Extents, 6);
  342. } else if (argv[i] == std::string("hash")) {
  343. puts(":::: Using dHashSpace");
  344. space = dHashSpaceCreate (0);
  345. } else if (argv[i] == std::string("sap")) {
  346. puts(":::: Using dSweepAndPruneSpace");
  347. space = dSweepAndPruneSpaceCreate (0, dSAP_AXES_XYZ);
  348. } else if (argv[i] == std::string("simple")) {
  349. puts(":::: Using dSimpleSpace");
  350. space = dSimpleSpaceCreate(0);
  351. }
  352. }
  353. if (!space) {
  354. puts(":::: You can specify 'quad', 'hash', 'sap' or 'simple' in the");
  355. puts(":::: command line to specify the type of space.");
  356. puts(":::: Using SAP space by default.");
  357. space = dSweepAndPruneSpaceCreate (0, dSAP_AXES_XYZ);
  358. }
  359. contactgroup = dJointGroupCreate (0);
  360. dWorldSetGravity (world,0,0,-0.5);
  361. dWorldSetCFM (world,1e-5);
  362. dCreatePlane (space,0,0,1,0);
  363. memset (obj,0,sizeof(obj));
  364. for (int i = 0; i < NUM; i++){
  365. command('s');
  366. }
  367. // run simulation
  368. dsSimulationLoop (argc,argv,352,288,&fn);
  369. dJointGroupDestroy (contactgroup);
  370. dSpaceDestroy (space);
  371. dWorldDestroy (world);
  372. dCloseODE();
  373. return 0;
  374. }