Imported Upstream version 2.81
[platform/upstream/libbullet.git] / Demos / VoronoiFractureDemo / VoronoiFractureDemo.cpp
1 /*\r
2 Bullet Continuous Collision Detection and Physics Library\r
3 Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/\r
4 \r
5 This software is provided 'as-is', without any express or implied warranty.\r
6 In no event will the authors be held liable for any damages arising from the use of this software.\r
7 Permission is granted to anyone to use this software for any purpose, \r
8 including commercial applications, and to alter it and redistribute it freely, \r
9 subject to the following restrictions:\r
10 \r
11 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.\r
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\r
13 3. This notice may not be removed or altered from any source distribution.\r
14 */\r
15 /*\r
16 Voronoi fracture and shatter code and demo copyright (c) 2011 Alain Ducharme\r
17   - Reset scene (press spacebar) to generate new random voronoi shattered cuboids\r
18   - Check console for total time required to: compute and mesh all 3D shards, calculate volumes and centers of mass and create rigid bodies\r
19   - Modify VORONOIPOINTS define below to change number of potential voronoi shards\r
20   - Note that demo's visual cracks between voronoi shards are NOT present in the internally generated voronoi mesh!\r
21 */\r
22 \r
23 //Number of random voronoi points to generate for shattering\r
24 #define VORONOIPOINTS 100\r
25 \r
26 //maximum number of objects (and allow user to shoot additional boxes)\r
27 #define MAX_PROXIES (2048)\r
28 #define BREAKING_THRESHOLD 2\r
29 #define CONVEX_MARGIN 0.04\r
30 \r
31 #include "VoronoiFractureDemo.h"\r
32 #include "GlutStuff.h"\r
33 ///btBulletDynamicsCommon.h is the main Bullet include file, contains most common include files.\r
34 #include "btBulletDynamicsCommon.h"\r
35 \r
36 #include <stdio.h> //printf debugging\r
37 \r
38 #include "GLDebugDrawer.h"\r
39 static GLDebugDrawer sDebugDraw;\r
40 \r
41 void VoronoiFractureDemo::attachFixedConstraints()\r
42 {\r
43         btAlignedObjectArray<btRigidBody*> bodies;\r
44 \r
45         int numManifolds = getDynamicsWorld()->getDispatcher()->getNumManifolds();\r
46 \r
47         for (int i=0;i<numManifolds;i++)\r
48         {\r
49                 btPersistentManifold* manifold = getDynamicsWorld()->getDispatcher()->getManifoldByIndexInternal(i);\r
50                 if (!manifold->getNumContacts())\r
51                         continue;\r
52 \r
53                 btScalar minDist = 1e30f;\r
54                 int minIndex = -1;\r
55                 for (int v=0;v<manifold->getNumContacts();v++)\r
56                 {\r
57                         if (minDist >manifold->getContactPoint(v).getDistance())\r
58                         {\r
59                                 minDist = manifold->getContactPoint(v).getDistance();\r
60                                 minIndex = v;\r
61                         }\r
62                 }\r
63                 if (minDist>0.)\r
64                         continue;\r
65                 \r
66                 btCollisionObject* colObj0 = (btCollisionObject*)manifold->getBody0();\r
67                 btCollisionObject* colObj1 = (btCollisionObject*)manifold->getBody1();\r
68         //      int tag0 = (colObj0)->getIslandTag();\r
69 //              int tag1 = (colObj1)->getIslandTag();\r
70                 btRigidBody* body0 = btRigidBody::upcast(colObj0);\r
71                 btRigidBody* body1 = btRigidBody::upcast(colObj1);\r
72                 if (bodies.findLinearSearch(body0)==bodies.size())\r
73                         bodies.push_back(body0);\r
74                 if (bodies.findLinearSearch(body1)==bodies.size())\r
75                         bodies.push_back(body1);\r
76 \r
77                 if (body0 && body1)\r
78                 {\r
79                         if (!colObj0->isStaticOrKinematicObject() && !colObj1->isStaticOrKinematicObject())\r
80                         {\r
81                                 if (body0->checkCollideWithOverride(body1))\r
82                                 {\r
83                                         {\r
84                                                 btTransform trA,trB;\r
85                                                 trA.setIdentity();\r
86                                                 trB.setIdentity();\r
87                                                 btVector3 contactPosWorld = manifold->getContactPoint(minIndex).m_positionWorldOnA;\r
88                                                 btTransform globalFrame;\r
89                                                 globalFrame.setIdentity();\r
90                                                 globalFrame.setOrigin(contactPosWorld);\r
91 \r
92                                                 trA = body0->getWorldTransform().inverse()*globalFrame;\r
93                                                 trB = body1->getWorldTransform().inverse()*globalFrame;\r
94 \r
95                                                 btGeneric6DofConstraint* dof6 = new btGeneric6DofConstraint(*body0,*body1,trA,trB,true);\r
96                                                 dof6->setOverrideNumSolverIterations(100);\r
97 \r
98                                                 float totalMass = 1.f/body0->getInvMass() + 1.f/body1->getInvMass();\r
99 \r
100                                                 dof6->setBreakingImpulseThreshold(BREAKING_THRESHOLD*totalMass);\r
101 \r
102                                                 for (int i=0;i<6;i++)\r
103                                                         dof6->setLimit(i,0,0);\r
104                                                 getDynamicsWorld()->addConstraint(dof6,true);\r
105                                                         \r
106                                         }\r
107                                 }\r
108                         }\r
109                 }\r
110                         \r
111         } \r
112 \r
113         for (int i=0;i<bodies.size();i++)\r
114         {\r
115                 getDynamicsWorld()->removeRigidBody(bodies[i]);\r
116                 getDynamicsWorld()->addRigidBody(bodies[i]);\r
117         }\r
118 }\r
119 \r
120 void VoronoiFractureDemo::keyboardCallback(unsigned char key, int x, int y)\r
121 {\r
122         if (key == 'g')\r
123         {\r
124                 attachFixedConstraints();\r
125         }else\r
126         {\r
127                 PlatformDemoApplication::keyboardCallback(key,x,y);\r
128         }\r
129 }\r
130 \r
131 \r
132 void VoronoiFractureDemo::getVerticesInsidePlanes(const btAlignedObjectArray<btVector3>& planes, btAlignedObjectArray<btVector3>& verticesOut, std::set<int>& planeIndicesOut)\r
133 {\r
134         // Based on btGeometryUtil.cpp (Gino van den Bergen / Erwin Coumans)\r
135         verticesOut.resize(0);\r
136         planeIndicesOut.clear();\r
137         const int numPlanes = planes.size();\r
138         int i, j, k, l;\r
139         for (i=0;i<numPlanes;i++)\r
140         {\r
141                 const btVector3& N1 = planes[i];\r
142                 for (j=i+1;j<numPlanes;j++)\r
143                 {\r
144                         const btVector3& N2 = planes[j];\r
145                         btVector3 n1n2 = N1.cross(N2);\r
146                         if (n1n2.length2() > btScalar(0.0001))\r
147                         {\r
148                                 for (k=j+1;k<numPlanes;k++)\r
149                                 {\r
150                                         const btVector3& N3 = planes[k];\r
151                                         btVector3 n2n3 = N2.cross(N3);\r
152                                         btVector3 n3n1 = N3.cross(N1);\r
153                                         if ((n2n3.length2() > btScalar(0.0001)) && (n3n1.length2() > btScalar(0.0001) ))\r
154                                         {\r
155                                                 btScalar quotient = (N1.dot(n2n3));\r
156                                                 if (btFabs(quotient) > btScalar(0.0001))\r
157                                                 {\r
158                                                         btVector3 potentialVertex = (n2n3 * N1[3] + n3n1 * N2[3] + n1n2 * N3[3]) * (btScalar(-1.) / quotient);\r
159                                                         for (l=0; l<numPlanes; l++)\r
160                                                         {\r
161                                                                 const btVector3& NP = planes[l];\r
162                                                                 if (btScalar(NP.dot(potentialVertex))+btScalar(NP[3]) > btScalar(0.000001))\r
163                                                                         break;\r
164                                                         }\r
165                                                         if (l == numPlanes)\r
166                                                         {\r
167                                                                 // vertex (three plane intersection) inside all planes\r
168                                                                 verticesOut.push_back(potentialVertex);\r
169                                                                 planeIndicesOut.insert(i);\r
170                                                                 planeIndicesOut.insert(j);\r
171                                                                 planeIndicesOut.insert(k);\r
172                                                         }\r
173                                                 }\r
174                                         }\r
175                                 }\r
176                         }\r
177                 }\r
178         }\r
179 }\r
180 \r
181 static btVector3 curVoronoiPoint; \r
182 \r
183 struct pointCmp\r
184 {\r
185         bool operator()(const btVector3& p1, const btVector3& p2) const\r
186         {\r
187                 float v1 = (p1-curVoronoiPoint).length2();\r
188                 float v2 = (p2-curVoronoiPoint).length2();\r
189                 bool result0 = v1 < v2;\r
190                 //bool result1 = ((btScalar)(p1-curVoronoiPoint).length2()) < ((btScalar)(p2-curVoronoiPoint).length2());\r
191                 //apparently result0 is not always result1, because extended precision used in registered is different from precision when values are stored in memory\r
192                 return result0;\r
193         }\r
194 };\r
195 \r
196 void VoronoiFractureDemo::voronoiBBShatter(const btAlignedObjectArray<btVector3>& points, const btVector3& bbmin, const btVector3& bbmax, const btQuaternion& bbq, const btVector3& bbt, btScalar matDensity) {\r
197         // points define voronoi cells in world space (avoid duplicates)\r
198         // bbmin & bbmax = bounding box min and max in local space\r
199         // bbq & bbt = bounding box quaternion rotation and translation\r
200         // matDensity = Material density for voronoi shard mass calculation\r
201         btVector3 bbvx = quatRotate(bbq, btVector3(1.0, 0.0, 0.0));\r
202         btVector3 bbvy = quatRotate(bbq, btVector3(0.0, 1.0, 0.0));\r
203         btVector3 bbvz = quatRotate(bbq, btVector3(0.0, 0.0, 1.0));\r
204         btQuaternion bbiq = bbq.inverse();\r
205         btConvexHullComputer* convexHC = new btConvexHullComputer();\r
206         btAlignedObjectArray<btVector3> vertices;\r
207         btVector3 rbb, nrbb;\r
208         btScalar nlength, maxDistance, distance;\r
209         btAlignedObjectArray<btVector3> sortedVoronoiPoints;\r
210         sortedVoronoiPoints.copyFromArray(points);\r
211         btVector3 normal, plane;\r
212         btAlignedObjectArray<btVector3> planes;\r
213         std::set<int> planeIndices;\r
214         std::set<int>::iterator planeIndicesIter;\r
215         int numplaneIndices;\r
216         int cellnum = 0;\r
217         int i, j, k;\r
218 \r
219         int numpoints = points.size();\r
220         for (i=0; i < numpoints ;i++) {\r
221                 curVoronoiPoint = points[i];\r
222                 btVector3 icp = quatRotate(bbiq, curVoronoiPoint - bbt);\r
223                 rbb = icp - bbmax;\r
224                 nrbb = bbmin - icp;\r
225                 planes.resize(6);\r
226                 planes[0] = bbvx; planes[0][3] = rbb.x();\r
227                 planes[1] = bbvy; planes[1][3] = rbb.y();\r
228                 planes[2] = bbvz; planes[2][3] = rbb.z();\r
229                 planes[3] = -bbvx; planes[3][3] = nrbb.x();\r
230                 planes[4] = -bbvy; planes[4][3] = nrbb.y();\r
231                 planes[5] = -bbvz; planes[5][3] = nrbb.z();\r
232                 maxDistance = SIMD_INFINITY;\r
233                 sortedVoronoiPoints.heapSort(pointCmp());\r
234                 for (j=1; j < numpoints; j++) {\r
235                         normal = sortedVoronoiPoints[j] - curVoronoiPoint;\r
236                         nlength = normal.length();\r
237                         if (nlength > maxDistance)\r
238                                 break;\r
239                         plane = normal.normalized();\r
240                         plane[3] = -nlength / btScalar(2.);\r
241                         planes.push_back(plane);\r
242                         getVerticesInsidePlanes(planes, vertices, planeIndices);\r
243                         if (vertices.size() == 0)\r
244                                 break;\r
245                         numplaneIndices = planeIndices.size();\r
246                         if (numplaneIndices != planes.size()) {\r
247                                 planeIndicesIter = planeIndices.begin();\r
248                                 for (k=0; k < numplaneIndices; k++) {\r
249                                         if (k != *planeIndicesIter)\r
250                                                 planes[k] = planes[*planeIndicesIter];\r
251                                         planeIndicesIter++;\r
252                                 }\r
253                                 planes.resize(numplaneIndices);\r
254                         }\r
255                         maxDistance = vertices[0].length();\r
256                         for (k=1; k < vertices.size(); k++) {\r
257                                 distance = vertices[k].length();\r
258                                 if (maxDistance < distance)\r
259                                         maxDistance = distance;\r
260                         }\r
261                         maxDistance *= btScalar(2.);\r
262                 }\r
263                 if (vertices.size() == 0)\r
264                         continue;\r
265 \r
266                 // Clean-up voronoi convex shard vertices and generate edges & faces\r
267                 convexHC->compute(&vertices[0].getX(), sizeof(btVector3), vertices.size(),CONVEX_MARGIN,0.0);\r
268 \r
269                 // At this point we have a complete 3D voronoi shard mesh contained in convexHC\r
270 \r
271                 // Calculate volume and center of mass (Stan Melax volume integration)\r
272                 int numFaces = convexHC->faces.size();\r
273                 int v0, v1, v2; // Triangle vertices\r
274                 btScalar volume = btScalar(0.);\r
275                 btVector3 com(0., 0., 0.);\r
276                 for (j=0; j < numFaces; j++) {\r
277                         const btConvexHullComputer::Edge* edge = &convexHC->edges[convexHC->faces[j]];\r
278                         v0 = edge->getSourceVertex();\r
279                         v1 = edge->getTargetVertex();\r
280                         edge = edge->getNextEdgeOfFace();\r
281                         v2 = edge->getTargetVertex();\r
282                         while (v2 != v0) {\r
283                                 // Counter-clockwise triangulated voronoi shard mesh faces (v0-v1-v2) and edges here...\r
284                                 btScalar vol = convexHC->vertices[v0].triple(convexHC->vertices[v1], convexHC->vertices[v2]);\r
285                                 volume += vol;\r
286                                 com += vol * (convexHC->vertices[v0] + convexHC->vertices[v1] + convexHC->vertices[v2]);\r
287                                 edge = edge->getNextEdgeOfFace();\r
288                                 v1 = v2;\r
289                                 v2 = edge->getTargetVertex();\r
290                         }\r
291                 }\r
292                 com /= volume * btScalar(4.);\r
293                 volume /= btScalar(6.);\r
294 \r
295                 // Shift all vertices relative to center of mass\r
296                 int numVerts = convexHC->vertices.size();\r
297                 for (j=0; j < numVerts; j++)\r
298                 {\r
299                         convexHC->vertices[j] -= com;\r
300                 }\r
301 \r
302                 // Note:\r
303                 // At this point convex hulls contained in convexHC should be accurate (line up flush with other pieces, no cracks),\r
304                 // ...however Bullet Physics rigid bodies demo visualizations appear to produce some visible cracks.\r
305                 // Use the mesh in convexHC for visual display or to perform boolean operations with.\r
306 \r
307                 // Create Bullet Physics rigid body shards\r
308                 btCollisionShape* shardShape = new btConvexHullShape(&(convexHC->vertices[0].getX()), convexHC->vertices.size());\r
309                 shardShape->setMargin(CONVEX_MARGIN); // for this demo; note convexHC has optional margin parameter for this\r
310                 m_collisionShapes.push_back(shardShape);\r
311                 btTransform shardTransform;\r
312                 shardTransform.setIdentity();\r
313                 shardTransform.setOrigin(curVoronoiPoint + com); // Shard's adjusted location\r
314                 btDefaultMotionState* shardMotionState = new btDefaultMotionState(shardTransform);\r
315                 btScalar shardMass(volume * matDensity);\r
316                 btVector3 shardInertia(0.,0.,0.);\r
317                 shardShape->calculateLocalInertia(shardMass, shardInertia);\r
318                 btRigidBody::btRigidBodyConstructionInfo shardRBInfo(shardMass, shardMotionState, shardShape, shardInertia);\r
319                 btRigidBody* shardBody = new btRigidBody(shardRBInfo);\r
320                 m_dynamicsWorld->addRigidBody(shardBody);\r
321 \r
322                 cellnum ++;\r
323 \r
324         }\r
325         printf("Generated %d voronoi btRigidBody shards\n", cellnum);\r
326 }\r
327 \r
328 void VoronoiFractureDemo::voronoiConvexHullShatter(const btAlignedObjectArray<btVector3>& points, const btAlignedObjectArray<btVector3>& verts, const btQuaternion& bbq, const btVector3& bbt, btScalar matDensity) {\r
329         // points define voronoi cells in world space (avoid duplicates)\r
330         // verts = source (convex hull) mesh vertices in local space\r
331         // bbq & bbt = source (convex hull) mesh quaternion rotation and translation\r
332         // matDensity = Material density for voronoi shard mass calculation\r
333         btConvexHullComputer* convexHC = new btConvexHullComputer();\r
334         btAlignedObjectArray<btVector3> vertices, chverts;\r
335         btVector3 rbb, nrbb;\r
336         btScalar nlength, maxDistance, distance;\r
337         btAlignedObjectArray<btVector3> sortedVoronoiPoints;\r
338         sortedVoronoiPoints.copyFromArray(points);\r
339         btVector3 normal, plane;\r
340         btAlignedObjectArray<btVector3> planes, convexPlanes;\r
341         std::set<int> planeIndices;\r
342         std::set<int>::iterator planeIndicesIter;\r
343         int numplaneIndices;\r
344         int cellnum = 0;\r
345         int i, j, k;\r
346 \r
347         // Convert verts to world space and get convexPlanes\r
348         int numverts = verts.size();\r
349         chverts.resize(verts.size());\r
350         for (i=0; i < numverts ;i++) {\r
351                 chverts[i] = quatRotate(bbq, verts[i]) + bbt;\r
352         }\r
353         //btGeometryUtil::getPlaneEquationsFromVertices(chverts, convexPlanes);\r
354         // Using convexHullComputer faster than getPlaneEquationsFromVertices for large meshes...\r
355         convexHC->compute(&chverts[0].getX(), sizeof(btVector3), numverts, 0.0, 0.0);\r
356         int numFaces = convexHC->faces.size();\r
357         int v0, v1, v2; // vertices\r
358         for (i=0; i < numFaces; i++) {\r
359                 const btConvexHullComputer::Edge* edge = &convexHC->edges[convexHC->faces[i]];\r
360                 v0 = edge->getSourceVertex();\r
361                 v1 = edge->getTargetVertex();\r
362                 edge = edge->getNextEdgeOfFace();\r
363                 v2 = edge->getTargetVertex();\r
364                 plane = (convexHC->vertices[v1]-convexHC->vertices[v0]).cross(convexHC->vertices[v2]-convexHC->vertices[v0]).normalize();\r
365                 plane[3] = -plane.dot(convexHC->vertices[v0]);\r
366                 convexPlanes.push_back(plane);\r
367         }\r
368         const int numconvexPlanes = convexPlanes.size();\r
369 \r
370         int numpoints = points.size();\r
371         for (i=0; i < numpoints ;i++) {\r
372                 curVoronoiPoint = points[i];\r
373                 planes.copyFromArray(convexPlanes);\r
374                 for (j=0; j < numconvexPlanes ;j++) {\r
375                         planes[j][3] += planes[j].dot(curVoronoiPoint);\r
376                 }\r
377                 maxDistance = SIMD_INFINITY;\r
378                 sortedVoronoiPoints.heapSort(pointCmp());\r
379                 for (j=1; j < numpoints; j++) {\r
380                         normal = sortedVoronoiPoints[j] - curVoronoiPoint;\r
381                         nlength = normal.length();\r
382                         if (nlength > maxDistance)\r
383                                 break;\r
384                         plane = normal.normalized();\r
385                         plane[3] = -nlength / btScalar(2.);\r
386                         planes.push_back(plane);\r
387                         getVerticesInsidePlanes(planes, vertices, planeIndices);\r
388                         if (vertices.size() == 0)\r
389                                 break;\r
390                         numplaneIndices = planeIndices.size();\r
391                         if (numplaneIndices != planes.size()) {\r
392                                 planeIndicesIter = planeIndices.begin();\r
393                                 for (k=0; k < numplaneIndices; k++) {\r
394                                         if (k != *planeIndicesIter)\r
395                                                 planes[k] = planes[*planeIndicesIter];\r
396                                         planeIndicesIter++;\r
397                                 }\r
398                                 planes.resize(numplaneIndices);\r
399                         }\r
400                         maxDistance = vertices[0].length();\r
401                         for (k=1; k < vertices.size(); k++) {\r
402                                 distance = vertices[k].length();\r
403                                 if (maxDistance < distance)\r
404                                         maxDistance = distance;\r
405                         }\r
406                         maxDistance *= btScalar(2.);\r
407                 }\r
408                 if (vertices.size() == 0)\r
409                         continue;\r
410 \r
411                 // Clean-up voronoi convex shard vertices and generate edges & faces\r
412                 convexHC->compute(&vertices[0].getX(), sizeof(btVector3), vertices.size(),0.0,0.0);\r
413 \r
414                 // At this point we have a complete 3D voronoi shard mesh contained in convexHC\r
415 \r
416                 // Calculate volume and center of mass (Stan Melax volume integration)\r
417                 numFaces = convexHC->faces.size();\r
418                 btScalar volume = btScalar(0.);\r
419                 btVector3 com(0., 0., 0.);\r
420                 for (j=0; j < numFaces; j++) {\r
421                         const btConvexHullComputer::Edge* edge = &convexHC->edges[convexHC->faces[j]];\r
422                         v0 = edge->getSourceVertex();\r
423                         v1 = edge->getTargetVertex();\r
424                         edge = edge->getNextEdgeOfFace();\r
425                         v2 = edge->getTargetVertex();\r
426                         while (v2 != v0) {\r
427                                 // Counter-clockwise triangulated voronoi shard mesh faces (v0-v1-v2) and edges here...\r
428                                 btScalar vol = convexHC->vertices[v0].triple(convexHC->vertices[v1], convexHC->vertices[v2]);\r
429                                 volume += vol;\r
430                                 com += vol * (convexHC->vertices[v0] + convexHC->vertices[v1] + convexHC->vertices[v2]);\r
431                                 edge = edge->getNextEdgeOfFace();\r
432                                 v1 = v2;\r
433                                 v2 = edge->getTargetVertex();\r
434                         }\r
435                 }\r
436                 com /= volume * btScalar(4.);\r
437                 volume /= btScalar(6.);\r
438 \r
439                 // Shift all vertices relative to center of mass\r
440                 int numVerts = convexHC->vertices.size();\r
441                 for (j=0; j < numVerts; j++)\r
442                 {\r
443                         convexHC->vertices[j] -= com;\r
444                 }\r
445 \r
446                 // Note:\r
447                 // At this point convex hulls contained in convexHC should be accurate (line up flush with other pieces, no cracks),\r
448                 // ...however Bullet Physics rigid bodies demo visualizations appear to produce some visible cracks.\r
449                 // Use the mesh in convexHC for visual display or to perform boolean operations with.\r
450 \r
451                 // Create Bullet Physics rigid body shards\r
452                 btCollisionShape* shardShape = new btConvexHullShape(&(convexHC->vertices[0].getX()), convexHC->vertices.size());\r
453                 shardShape->setMargin(CONVEX_MARGIN); // for this demo; note convexHC has optional margin parameter for this\r
454                 m_collisionShapes.push_back(shardShape);\r
455                 btTransform shardTransform;\r
456                 shardTransform.setIdentity();\r
457                 shardTransform.setOrigin(curVoronoiPoint + com); // Shard's adjusted location\r
458                 btDefaultMotionState* shardMotionState = new btDefaultMotionState(shardTransform);\r
459                 btScalar shardMass(volume * matDensity);\r
460                 btVector3 shardInertia(0.,0.,0.);\r
461                 shardShape->calculateLocalInertia(shardMass, shardInertia);\r
462                 btRigidBody::btRigidBodyConstructionInfo shardRBInfo(shardMass, shardMotionState, shardShape, shardInertia);\r
463                 btRigidBody* shardBody = new btRigidBody(shardRBInfo);\r
464                 m_dynamicsWorld->addRigidBody(shardBody);\r
465 \r
466                 cellnum ++;\r
467 \r
468         }\r
469         printf("Generated %d voronoi btRigidBody shards\n", cellnum);\r
470 }\r
471 \r
472 void VoronoiFractureDemo::clientMoveAndDisplay()\r
473 {\r
474         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); \r
475 \r
476         //simple dynamics world doesn't handle fixed-time-stepping\r
477         float ms = getDeltaTimeMicroseconds();\r
478         \r
479         ///step the simulation\r
480         if (m_dynamicsWorld)\r
481         {\r
482                 m_dynamicsWorld->stepSimulation(ms / 1000000.f);\r
483                 //optional but useful: debug drawing\r
484                 m_dynamicsWorld->debugDrawWorld();\r
485         }\r
486                 \r
487         renderme(); \r
488 \r
489         glFlush();\r
490 \r
491         swapBuffers();\r
492 }\r
493 \r
494 \r
495 void VoronoiFractureDemo::displayCallback(void) {\r
496 \r
497         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); \r
498         \r
499         renderme();\r
500 \r
501         //optional but useful: debug drawing to detect problems\r
502         if (m_dynamicsWorld)\r
503                 m_dynamicsWorld->debugDrawWorld();\r
504 \r
505         glFlush();\r
506         swapBuffers();\r
507 }\r
508 \r
509 \r
510 void    VoronoiFractureDemo::initPhysics()\r
511 {\r
512         setTexturing(true);\r
513         setShadows(true);\r
514 \r
515         setCameraDistance(btScalar(20.));\r
516 \r
517         ///collision configuration contains default setup for memory, collision setup\r
518         m_collisionConfiguration = new btDefaultCollisionConfiguration();\r
519         //m_collisionConfiguration->setConvexConvexMultipointIterations();\r
520 \r
521         ///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)\r
522         m_dispatcher = new      btCollisionDispatcher(m_collisionConfiguration);\r
523 \r
524         m_broadphase = new btDbvtBroadphase();\r
525 \r
526         ///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded)\r
527         btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver;\r
528         m_solver = sol;\r
529 \r
530         m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration);\r
531         m_dynamicsWorld->getSolverInfo().m_splitImpulse = true;\r
532         m_dynamicsWorld->setDebugDrawer(&sDebugDraw);\r
533         \r
534         m_dynamicsWorld->setGravity(btVector3(0,-10,0));\r
535 \r
536         ///create a few basic rigid bodies\r
537         btCollisionShape* groundShape = new btBoxShape(btVector3(btScalar(50.),btScalar(50.),btScalar(50.)));\r
538 //      btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0,1,0),50);\r
539         \r
540         m_collisionShapes.push_back(groundShape);\r
541 \r
542         btTransform groundTransform;\r
543         groundTransform.setIdentity();\r
544         groundTransform.setOrigin(btVector3(0,-50,0));\r
545 \r
546         //We can also use DemoApplication::localCreateRigidBody, but for clarity it is provided here:\r
547         {\r
548                 btScalar mass(0.);\r
549 \r
550                 //rigidbody is dynamic if and only if mass is non zero, otherwise static\r
551                 bool isDynamic = (mass != 0.f);\r
552 \r
553                 btVector3 localInertia(0,0,0);\r
554                 if (isDynamic)\r
555                         groundShape->calculateLocalInertia(mass,localInertia);\r
556 \r
557                 //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects\r
558                 btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform);\r
559                 btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,groundShape,localInertia);\r
560                 btRigidBody* body = new btRigidBody(rbInfo);\r
561 \r
562                 //add the body to the dynamics world\r
563                 m_dynamicsWorld->addRigidBody(body);\r
564         }\r
565 \r
566         // ==> Voronoi Shatter Basic Demo: Random Cuboid\r
567 \r
568         // Random size cuboid (defined by bounding box max and min)\r
569         btVector3 bbmax(btScalar(rand() / btScalar(RAND_MAX)) * 6. +0.5, btScalar(rand() / btScalar(RAND_MAX)) * 6. +0.5, btScalar(rand() / btScalar(RAND_MAX)) * 6. +0.5);\r
570         btVector3 bbmin = -bbmax;\r
571         // Place it 10 units above ground\r
572         btVector3 bbt(0,10,0);\r
573         // Use an arbitrary material density for shards (should be consitent/relative with/to rest of RBs in world)\r
574         btScalar matDensity = 1;\r
575         // Using random rotation\r
576         btQuaternion bbq(btScalar(rand() / btScalar(RAND_MAX)) * 2. -1.,btScalar(rand() / btScalar(RAND_MAX)) * 2. -1.,btScalar(rand() / btScalar(RAND_MAX)) * 2. -1.,btScalar(rand() / btScalar(RAND_MAX)) * 2. -1.);\r
577         bbq.normalize();\r
578         // Generate random points for voronoi cells\r
579         btAlignedObjectArray<btVector3> points;\r
580         btVector3 point;\r
581         btVector3 diff = bbmax - bbmin;\r
582         for (int i=0; i < VORONOIPOINTS; i++) {\r
583                 // Place points within box area (points are in world coordinates)\r
584                 point = quatRotate(bbq, btVector3(btScalar(rand() / btScalar(RAND_MAX)) * diff.x() -diff.x()/2., btScalar(rand() / btScalar(RAND_MAX)) * diff.y() -diff.y()/2., btScalar(rand() / btScalar(RAND_MAX)) * diff.z() -diff.z()/2.)) + bbt;\r
585                 points.push_back(point);\r
586         }\r
587         m_perfmTimer.reset();\r
588         voronoiBBShatter(points, bbmin, bbmax, bbq, bbt, matDensity);\r
589         printf("Total Time: %f seconds\n", m_perfmTimer.getTimeMilliseconds()/1000.);\r
590         \r
591         for (int i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)\r
592         {\r
593                 btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];\r
594                 obj->getCollisionShape()->setMargin(CONVEX_MARGIN+0.01);\r
595         }\r
596         m_dynamicsWorld->performDiscreteCollisionDetection();\r
597 \r
598         for (int i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)\r
599         {\r
600                 btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];\r
601                 obj->getCollisionShape()->setMargin(CONVEX_MARGIN);\r
602         }\r
603 \r
604         attachFixedConstraints();\r
605 \r
606 }\r
607 void    VoronoiFractureDemo::clientResetScene()\r
608 {\r
609         exitPhysics();\r
610         initPhysics();\r
611 }\r
612         \r
613 \r
614 void    VoronoiFractureDemo::exitPhysics()\r
615 {\r
616 \r
617         //cleanup in the reverse order of creation/initialization\r
618 \r
619         int i;\r
620         //remove all constraints\r
621         for (i=m_dynamicsWorld->getNumConstraints()-1;i>=0;i--)\r
622         {\r
623                 btTypedConstraint* constraint = m_dynamicsWorld->getConstraint(i);\r
624                 m_dynamicsWorld->removeConstraint(constraint);\r
625                 delete constraint;\r
626         }\r
627         \r
628         //remove the rigidbodies from the dynamics world and delete them\r
629         \r
630         for (i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)\r
631         {\r
632                 btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];\r
633                 btRigidBody* body = btRigidBody::upcast(obj);\r
634                 if (body && body->getMotionState())\r
635                 {\r
636                         delete body->getMotionState();\r
637                 }\r
638                 m_dynamicsWorld->removeCollisionObject( obj );\r
639                 delete obj;\r
640         }\r
641 \r
642         //delete collision shapes\r
643         for (int j=0;j<m_collisionShapes.size();j++)\r
644         {\r
645                 btCollisionShape* shape = m_collisionShapes[j];\r
646                 delete shape;\r
647         }\r
648         m_collisionShapes.clear();\r
649 \r
650         delete m_dynamicsWorld;\r
651         \r
652         delete m_solver;\r
653         \r
654         delete m_broadphase;\r
655         \r
656         delete m_dispatcher;\r
657 \r
658         delete m_collisionConfiguration;\r
659 \r
660 }\r