Imported Upstream version 2.81
[platform/upstream/libbullet.git] / Demos / MultiMaterialDemo / MultiMaterialDemo.cpp
1 /*
2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
4
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the use of this software.
7 Permission is granted to anyone to use this software for any purpose, 
8 including commercial applications, and to alter it and redistribute it freely, 
9 subject to the following restrictions:
10
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.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
14 */
15
16 #include "btBulletDynamicsCommon.h"
17 #include "LinearMath/btIDebugDraw.h"
18 #include "GLDebugDrawer.h"
19 #include "MultiMaterialDemo.h"
20 #include "GL_ShapeDrawer.h"
21 #include "GlutStuff.h"
22
23 #include "BulletCollision/CollisionShapes/btTriangleShape.h"
24 #include "BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.h"
25 #include "BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.h"
26 #include "BulletCollision/CollisionShapes/btMaterial.h"
27 #include "BulletCollision/CollisionDispatch/btCollisionObjectWrapper.h"
28
29 // Create a custom material, just because we can
30 class CustomMaterial : public btMaterial
31 {
32 public:
33     int foo1;
34     int foo2;
35     CustomMaterial(){}
36     CustomMaterial(int a, int b) {foo1 = a; foo2 = b;}
37 };
38
39 // Storage for the vertex data
40 static btVector3*       gVertices = 0;
41 // Storage for the face data
42 static int*     gIndices = 0;
43 // Storage for the material data
44 static CustomMaterial* gMaterials = 0;
45 // Storage for the face -> material index data
46 static int* gFaceMaterialIndices = 0;
47
48 static btBvhTriangleMeshShape* trimeshShape =0;
49 static btRigidBody* staticBody = 0;
50 static float waveheight = 0.f;
51
52 const float TRIANGLE_SIZE=1.f;
53
54
55 ///User can override this material combiner by implementing gContactAddedCallback and setting body0->m_collisionFlags |= btCollisionObject::customMaterialCallback;
56 inline btScalar calculateCombinedFriction(float friction0,float friction1)
57 {
58     btScalar friction = friction0 * friction1;
59
60     const btScalar MAX_FRICTION  = 10.f;
61     if (friction < -MAX_FRICTION)
62         friction = -MAX_FRICTION;
63     if (friction > MAX_FRICTION)
64         friction = MAX_FRICTION;
65     return friction;
66
67 }
68
69 inline btScalar calculateCombinedRestitution(float restitution0,float restitution1)
70 {
71     return restitution0 * restitution1;
72 }
73
74
75
76 static bool CustomMaterialCombinerCallback(btManifoldPoint& cp, const btCollisionObjectWrapper* colObj0Wrap,int partId0,int index0,const btCollisionObjectWrapper* colObj1Wrap,int partId1,int index1)
77 {
78     
79     // Apply material properties
80     if (colObj0Wrap->getCollisionShape()->getShapeType() == TRIANGLE_SHAPE_PROXYTYPE)
81     {
82                 const btCollisionShape* parent0 = colObj0Wrap->getCollisionObject()->getCollisionShape();
83         if(parent0 != 0 && parent0->getShapeType() == MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE)
84         {
85             btMultimaterialTriangleMeshShape* shape = (btMultimaterialTriangleMeshShape*)parent0;
86             const btMaterial * props = shape->getMaterialProperties(partId0, index0);
87             cp.m_combinedFriction = calculateCombinedFriction(props->m_friction, colObj1Wrap->getCollisionObject()->getFriction());
88             cp.m_combinedRestitution = props->m_restitution * colObj1Wrap->getCollisionObject()->getRestitution();
89         }
90     }
91     else if (colObj1Wrap->getCollisionShape()->getShapeType() == TRIANGLE_SHAPE_PROXYTYPE)
92     {
93         const btCollisionShape* parent1 = colObj1Wrap->getCollisionObject()->getCollisionShape();
94         if(parent1 != 0 && parent1->getShapeType() == MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE)
95         {
96             btMultimaterialTriangleMeshShape* shape = (btMultimaterialTriangleMeshShape*)parent1;
97             const btMaterial * props = shape->getMaterialProperties(partId1, index1);
98             cp.m_combinedFriction = calculateCombinedFriction(props->m_friction, colObj0Wrap->getCollisionObject()->getFriction());
99             cp.m_combinedRestitution = props->m_restitution * colObj0Wrap->getCollisionObject()->getRestitution();
100         }
101     }
102
103     //this return value is currently ignored, but to be on the safe side: return false if you don't calculate friction
104     return true;
105 }
106
107 extern ContactAddedCallback             gContactAddedCallback;
108
109 const int NUM_VERTS_X = 20;
110 const int NUM_VERTS_Y = 50;
111 const int totalVerts = NUM_VERTS_X*NUM_VERTS_Y;
112
113 void MultiMaterialDemo::setVertexPositions(float waveheight, float offset)
114 {
115     int i;
116     int j;
117
118     for ( i=0;i<NUM_VERTS_X;i++)
119     {
120         for (j=0;j<NUM_VERTS_Y;j++)
121         {
122             gVertices[i+j*NUM_VERTS_X].setValue((i-NUM_VERTS_X*0.5f)*TRIANGLE_SIZE,
123                 //0.f,
124                 waveheight*sinf((float)i+offset)*cosf((float)j+offset),
125                 (j-NUM_VERTS_Y*0.5f)*TRIANGLE_SIZE);
126         }
127     }
128 }
129
130 void MultiMaterialDemo::keyboardCallback(unsigned char key, int x, int y)
131 {
132     if (key == 'g')
133     {
134         m_animatedMesh = !m_animatedMesh;
135         if (m_animatedMesh)
136         {
137             staticBody->setCollisionFlags( staticBody->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
138             staticBody->setActivationState(DISABLE_DEACTIVATION);
139         } else
140         {
141             staticBody->setCollisionFlags( staticBody->getCollisionFlags() & ~btCollisionObject::CF_KINEMATIC_OBJECT);
142             staticBody->forceActivationState(ACTIVE_TAG);
143         }
144     }
145
146     DemoApplication::keyboardCallback(key,x,y);
147
148 }
149
150 void    MultiMaterialDemo::initPhysics()
151 {
152 #define TRISIZE 50.f
153
154     gContactAddedCallback = CustomMaterialCombinerCallback;
155
156     // The number of triangles
157     const int totalTriangles = 2*(NUM_VERTS_X-1)*(NUM_VERTS_Y-1);
158     // The number of materials
159     const int totalMaterials = 2;
160
161     int vertStride = sizeof(btVector3);
162     int indexStride = 3*sizeof(int);
163  //   int materialStride = sizeof(CustomMaterial);
164    // int triangleMaterialStride = sizeof(int);
165
166     gVertices = new btVector3[totalVerts];
167     gIndices = new int[totalTriangles*3];
168     gMaterials = new CustomMaterial[totalMaterials];
169     gFaceMaterialIndices = new int[totalTriangles];
170
171     // Explicitly set up the materials.  It's a small array so let's do it bit by bit.
172     gMaterials[0].m_friction = 0;
173     gMaterials[0].m_restitution = 0.9;
174     gMaterials[0].foo1 = 5;
175     gMaterials[0].foo2 = 7;
176     gMaterials[1].m_friction = 0.9;
177     gMaterials[1].m_restitution = 0.1;
178     gMaterials[1].foo1 = 53;
179     gMaterials[1].foo2 = 15;
180
181     int i;
182     // Set up the vertex data
183     setVertexPositions(waveheight,0.f);
184     int index=0;
185     // Set up the face data
186     for ( i=0;i<NUM_VERTS_X-1;i++)
187     {
188         for (int j=0;j<NUM_VERTS_Y-1;j++)
189         {
190             gIndices[index++] = j*NUM_VERTS_X+i;
191             gIndices[index++] = j*NUM_VERTS_X+i+1;
192             gIndices[index++] = (j+1)*NUM_VERTS_X+i+1;
193
194             gIndices[index++] = j*NUM_VERTS_X+i;
195             gIndices[index++] = (j+1)*NUM_VERTS_X+i+1;
196             gIndices[index++] = (j+1)*NUM_VERTS_X+i;
197         }
198     }
199
200     // Set up the face->material index data
201     for(int a = 0; a < totalTriangles; a++)
202     {
203         // This will give the first half of the faces low friction and high restitution
204         // and the second half of the faces high friction and low restitution
205         if(a > totalTriangles*0.5f)
206             gFaceMaterialIndices[a] = 0;
207         else
208             gFaceMaterialIndices[a] = 1;
209     }
210
211     // Create the array structure
212     m_indexVertexArrays = new btTriangleIndexVertexMaterialArray(
213         totalTriangles, gIndices, indexStride,
214         totalVerts,(btScalar*) &gVertices[0].x(),vertStride,
215         totalMaterials, (unsigned char *)gMaterials, sizeof(CustomMaterial),
216         gFaceMaterialIndices, sizeof(int));
217
218     bool useQuantizedAabbCompression = true;
219     // Create the multimaterial mesh shape
220     trimeshShape  = new btMultimaterialTriangleMeshShape((btTriangleIndexVertexMaterialArray*)m_indexVertexArrays,useQuantizedAabbCompression);
221     m_collisionShapes.push_back(trimeshShape);
222
223     btCollisionShape* groundShape = trimeshShape;
224
225     m_collisionConfiguration = new btDefaultCollisionConfiguration();
226
227     m_dispatcher = new  btCollisionDispatcher(m_collisionConfiguration);
228
229     btVector3 worldMin(-1000,-1000,-1000);
230     btVector3 worldMax(1000,1000,1000);
231     m_broadphase = new btAxisSweep3(worldMin,worldMax);
232     m_solver = new btSequentialImpulseConstraintSolver();
233     m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration);
234
235     float mass = 0.f;
236     btTransform startTransform;
237     startTransform.setIdentity();
238     startTransform.setOrigin(btVector3(0,-2,0));
239
240     btCollisionShape* colShape = new btBoxShape(btVector3(0.5f,0.5f,0.5f));
241     m_collisionShapes.push_back(colShape);
242
243     {
244         for (int i=0;i<1;i++)
245         {
246             startTransform.setOrigin(btVector3(10,10,-20));
247             btRigidBody* body = localCreateRigidBody(1, startTransform,colShape);
248             body->setCollisionFlags(body->getCollisionFlags()  | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
249             body->setFriction(0.9f);
250             body->setGravity(btVector3(0,-20.f,0));
251             body->applyCentralImpulse(btVector3(-7.7f,0,0));
252         }
253     }
254
255     startTransform.setIdentity();
256     staticBody = localCreateRigidBody(mass, startTransform,groundShape);
257
258     staticBody->setCollisionFlags(staticBody->getCollisionFlags() | btCollisionObject::CF_STATIC_OBJECT);
259
260     //enable custom material callback
261     staticBody->setCollisionFlags(staticBody->getCollisionFlags()  | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
262 }
263
264 void MultiMaterialDemo::clientMoveAndDisplay()
265 {
266     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
267
268     float dt = getDeltaTimeMicroseconds() * 0.000001f;
269
270     if (m_animatedMesh)
271     {
272         static float offset=0.f;
273         offset+=0.01f;
274
275         //      setVertexPositions(waveheight,offset);
276
277         int i;
278         int j;
279         btVector3 aabbMin(BT_LARGE_FLOAT,BT_LARGE_FLOAT,BT_LARGE_FLOAT);
280         btVector3 aabbMax(-BT_LARGE_FLOAT,-BT_LARGE_FLOAT,-BT_LARGE_FLOAT);
281
282         for ( i=NUM_VERTS_X/2-3;i<NUM_VERTS_X/2+2;i++)
283         {
284             for (j=NUM_VERTS_X/2-3;j<NUM_VERTS_Y/2+2;j++)
285             {
286
287                 aabbMax.setMax(gVertices[i+j*NUM_VERTS_X]);
288                 aabbMin.setMin(gVertices[i+j*NUM_VERTS_X]);
289
290                 gVertices[i+j*NUM_VERTS_X].setValue((i-NUM_VERTS_X*0.5f)*TRIANGLE_SIZE,
291                     0.f,
292                     (j-NUM_VERTS_Y*0.5f)*TRIANGLE_SIZE);
293
294                 aabbMin.setMin(gVertices[i+j*NUM_VERTS_X]);
295                 aabbMax.setMax(gVertices[i+j*NUM_VERTS_X]);
296
297             }
298         }
299
300         trimeshShape->partialRefitTree(aabbMin,aabbMax);
301
302         //clear all contact points involving mesh proxy. Note: this is a slow/unoptimized operation.
303         m_dynamicsWorld->getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(staticBody->getBroadphaseHandle(),getDynamicsWorld()->getDispatcher());
304     }
305
306     m_dynamicsWorld->stepSimulation(dt);
307
308     //optional but useful: debug drawing
309     m_dynamicsWorld->debugDrawWorld();
310
311     renderme();
312
313     glFlush();
314     glutSwapBuffers();
315
316 }
317
318
319
320
321 void MultiMaterialDemo::displayCallback(void) {
322
323     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
324
325     renderme();
326
327     glFlush();
328     glutSwapBuffers();
329 }
330
331
332
333 void    MultiMaterialDemo::exitPhysics()
334 {
335
336
337
338     //cleanup in the reverse order of creation/initialization
339
340     //remove the rigidbodies from the dynamics world and delete them
341     int i;
342     for (i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
343     {
344         btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
345         btRigidBody* body = btRigidBody::upcast(obj);
346         if (body && body->getMotionState())
347         {
348             delete body->getMotionState();
349         }
350         m_dynamicsWorld->removeCollisionObject( obj );
351         delete obj;
352     }
353
354     //delete collision shapes
355     for (int j=0;j<m_collisionShapes.size();j++)
356     {
357         btCollisionShape* shape = m_collisionShapes[j];
358         delete shape;
359     }
360
361     //delete dynamics world
362     delete m_dynamicsWorld;
363
364     if (m_indexVertexArrays)
365         delete m_indexVertexArrays;
366
367     //delete solver
368     delete m_solver;
369
370     //delete broadphase
371     delete m_broadphase;
372
373     //delete dispatcher
374     delete m_dispatcher;
375
376     delete m_collisionConfiguration;
377
378
379 }
380
381
382
383