Imported Upstream version 2.81
[platform/upstream/libbullet.git] / Demos / CharacterDemo / CharacterDemo.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 "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h"
18 #include "BulletCollision/CollisionDispatch/btGhostObject.h"
19
20 #include "GLDebugDrawer.h"
21 #include <stdio.h> //printf debugging
22
23 #include "GL_ShapeDrawer.h"
24
25 #include "GlutStuff.h"
26 #include "CharacterDemo.h"
27 #ifdef DYNAMIC_CHARACTER_CONTROLLER
28 #include "DynamicCharacterController.h"
29 #else
30 #include "BulletDynamics/Character/btKinematicCharacterController.h"
31 #endif
32
33 const int maxProxies = 32766;
34 const int maxOverlap = 65535;
35
36 static int gForward = 0;
37 static int gBackward = 0;
38 static int gLeft = 0;
39 static int gRight = 0;
40 static int gJump = 0;
41
42
43
44
45 CharacterDemo::CharacterDemo()
46 :
47 m_indexVertexArrays(0),
48 m_vertices(0),
49 m_cameraHeight(4.f),
50 m_minCameraDistance(3.f),
51 m_maxCameraDistance(10.f)
52 {
53         m_character = 0;
54         m_cameraPosition = btVector3(30,30,30);
55 }
56
57
58 void CharacterDemo::initPhysics()
59 {
60         btCollisionShape* groundShape = new btBoxShape(btVector3(50,3,50));
61         m_collisionShapes.push_back(groundShape);
62         m_collisionConfiguration = new btDefaultCollisionConfiguration();
63         m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
64         btVector3 worldMin(-1000,-1000,-1000);
65         btVector3 worldMax(1000,1000,1000);
66         btAxisSweep3* sweepBP = new btAxisSweep3(worldMin,worldMax);
67         m_overlappingPairCache = sweepBP;
68
69         m_constraintSolver = new btSequentialImpulseConstraintSolver();
70         m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_overlappingPairCache,m_constraintSolver,m_collisionConfiguration);
71         m_dynamicsWorld->getDispatchInfo().m_allowedCcdPenetration=0.0001f;
72         
73 #ifdef DYNAMIC_CHARACTER_CONTROLLER
74         m_character = new DynamicCharacterController ();
75 #else
76         
77         btTransform startTransform;
78         startTransform.setIdentity ();
79         //startTransform.setOrigin (btVector3(0.0, 4.0, 0.0));
80         startTransform.setOrigin (btVector3(10.210098,-1.6433364,16.453260));
81
82
83         m_ghostObject = new btPairCachingGhostObject();
84         m_ghostObject->setWorldTransform(startTransform);
85         sweepBP->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback());
86         btScalar characterHeight=1.75;
87         btScalar characterWidth =1.75;
88         btConvexShape* capsule = new btCapsuleShape(characterWidth,characterHeight);
89         m_ghostObject->setCollisionShape (capsule);
90         m_ghostObject->setCollisionFlags (btCollisionObject::CF_CHARACTER_OBJECT);
91
92         btScalar stepHeight = btScalar(0.35);
93         m_character = new btKinematicCharacterController (m_ghostObject,capsule,stepHeight);
94 #endif
95
96         ////////////////
97
98         /// Create some basic environment from a Quake level
99
100         //m_dynamicsWorld->setGravity(btVector3(0,0,0));
101         btTransform tr;
102         tr.setIdentity();
103
104         const char* bspfilename = "BspDemo.bsp";
105         void* memoryBuffer = 0;
106
107         FILE* file = fopen(bspfilename,"r");
108         if (!file)
109         {
110                 //cmake generated visual studio projects need 4 levels back
111                 bspfilename = "../../../../BspDemo.bsp";
112                 file = fopen(bspfilename,"r");
113         }
114         if (!file)
115         {
116                 //visual studio leaves the current working directory in the projectfiles folder
117                 bspfilename = "../../BspDemo.bsp";
118                 file = fopen(bspfilename,"r");
119         }
120         if (!file)
121         {
122                 //visual studio leaves the current working directory in the projectfiles folder
123                 bspfilename = "BspDemo.bsp";
124                 file = fopen(bspfilename,"r");
125         }
126
127         if (file)
128         {
129                 BspLoader bspLoader;
130                 int size=0;
131                 if (fseek(file, 0, SEEK_END) || (size = ftell(file)) == EOF || fseek(file, 0, SEEK_SET)) {        /* File operations denied? ok, just close and return failure */
132                         printf("Error: cannot get filesize from %s\n", bspfilename);
133                 } else
134                 {
135                         //how to detect file size?
136                         memoryBuffer = malloc(size+1);
137                         fread(memoryBuffer,1,size,file);
138                         bspLoader.loadBSPFile( memoryBuffer);
139
140                         BspToBulletConverter bsp2bullet(this);
141                         float bspScaling = 0.1f;
142                         bsp2bullet.convertBsp(bspLoader,bspScaling);
143
144                 }
145                 fclose(file);
146         }
147
148         ///only collide with static for now (no interaction with dynamic objects)
149         m_dynamicsWorld->addCollisionObject(m_ghostObject,btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::StaticFilter|btBroadphaseProxy::DefaultFilter);
150
151         m_dynamicsWorld->addAction(m_character);
152
153
154         ///////////////
155
156         clientResetScene();
157
158         setCameraDistance(56.f);
159
160 }
161
162
163 //to be implemented by the demo
164 void CharacterDemo::renderme()
165 {
166         updateCamera();
167
168         DemoApplication::renderme();
169 }
170
171
172
173 void    CharacterDemo::debugDrawContacts()
174 {
175 //      printf("numPairs = %d\n",m_customPairCallback->getOverlappingPairArray().size());
176         {
177                 btManifoldArray manifoldArray;
178                 btBroadphasePairArray& pairArray = m_ghostObject->getOverlappingPairCache()->getOverlappingPairArray();
179                 int numPairs = pairArray.size();
180
181                 for (int i=0;i<numPairs;i++)
182                 {
183                         manifoldArray.clear();
184
185                         const btBroadphasePair& pair = pairArray[i];
186                         
187                         btBroadphasePair* collisionPair = m_overlappingPairCache->getOverlappingPairCache()->findPair(pair.m_pProxy0,pair.m_pProxy1);
188                         if (!collisionPair)
189                                 continue;
190
191                         if (collisionPair->m_algorithm)
192                                 collisionPair->m_algorithm->getAllContactManifolds(manifoldArray);
193
194                         for (int j=0;j<manifoldArray.size();j++)
195                         {
196                                 btPersistentManifold* manifold = manifoldArray[j];
197                                 for (int p=0;p<manifold->getNumContacts();p++)
198                                 {
199                                         const btManifoldPoint&pt = manifold->getContactPoint(p);
200
201                                         btVector3 color(255,255,255);
202                                         m_dynamicsWorld->getDebugDrawer()->drawContactPoint(pt.getPositionWorldOnB(),pt.m_normalWorldOnB,pt.getDistance(),pt.getLifeTime(),color);
203                                 }
204                         }
205                 }
206         }
207
208 }
209
210 void CharacterDemo::clientMoveAndDisplay()
211 {
212
213         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
214
215         float dt = getDeltaTimeMicroseconds() * 0.000001f;
216
217         /* Character stuff &*/
218         if (m_character)
219         {
220                 
221         }
222
223         debugDrawContacts();
224
225
226         if (m_dynamicsWorld)
227         {
228                 //during idle mode, just run 1 simulation step maximum
229                 int maxSimSubSteps = m_idle ? 1 : 2;
230                 if (m_idle)
231                         dt = 1.0/420.f;
232
233                 ///set walkDirection for our character
234                 btTransform xform;
235                 xform = m_ghostObject->getWorldTransform ();
236
237                 btVector3 forwardDir = xform.getBasis()[2];
238         //      printf("forwardDir=%f,%f,%f\n",forwardDir[0],forwardDir[1],forwardDir[2]);
239                 btVector3 upDir = xform.getBasis()[1];
240                 btVector3 strafeDir = xform.getBasis()[0];
241                 forwardDir.normalize ();
242                 upDir.normalize ();
243                 strafeDir.normalize ();
244
245                 btVector3 walkDirection = btVector3(0.0, 0.0, 0.0);
246                 btScalar walkVelocity = btScalar(1.1) * 4.0; // 4 km/h -> 1.1 m/s
247                 btScalar walkSpeed = walkVelocity * dt;
248
249                 //rotate view
250                 if (gLeft)
251                 {
252                         btMatrix3x3 orn = m_ghostObject->getWorldTransform().getBasis();
253                         orn *= btMatrix3x3(btQuaternion(btVector3(0,1,0),0.01));
254                         m_ghostObject->getWorldTransform ().setBasis(orn);
255                 }
256
257                 if (gRight)
258                 {
259                         btMatrix3x3 orn = m_ghostObject->getWorldTransform().getBasis();
260                         orn *= btMatrix3x3(btQuaternion(btVector3(0,1,0),-0.01));
261                         m_ghostObject->getWorldTransform ().setBasis(orn);
262                 }
263
264                 if (gForward)
265                         walkDirection += forwardDir;
266
267                 if (gBackward)
268                         walkDirection -= forwardDir;    
269
270
271                 m_character->setWalkDirection(walkDirection*walkSpeed);
272
273
274                 int numSimSteps = m_dynamicsWorld->stepSimulation(dt,maxSimSubSteps);
275
276                 //optional but useful: debug drawing
277                 if (m_dynamicsWorld)
278                         m_dynamicsWorld->debugDrawWorld();
279
280 //#define VERBOSE_FEEDBACK
281 #ifdef VERBOSE_FEEDBACK
282                 if (!numSimSteps)
283                         printf("Interpolated transforms\n");
284                 else
285                 {
286                         if (numSimSteps > maxSimSubSteps)
287                         {
288                                 //detect dropping frames
289                                 printf("Dropped (%i) simulation steps out of %i\n",numSimSteps - maxSimSubSteps,numSimSteps);
290                         } else
291                         {
292                                 printf("Simulated (%i) steps\n",numSimSteps);
293                         }
294                 }
295 #endif //VERBOSE_FEEDBACK
296
297         }
298
299
300
301
302
303
304
305 #ifdef USE_QUICKPROF
306         btProfiler::beginBlock("render");
307 #endif //USE_QUICKPROF
308
309
310         renderme();
311
312 #ifdef USE_QUICKPROF
313         btProfiler::endBlock("render");
314 #endif
315
316
317         glFlush();
318         glutSwapBuffers();
319
320 }
321
322
323
324 void CharacterDemo::displayCallback(void)
325 {
326         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
327
328         renderme();
329
330         //optional but useful: debug drawing
331         if (m_dynamicsWorld)
332                 m_dynamicsWorld->debugDrawWorld();
333
334         debugDrawContacts();
335
336         glFlush();
337         glutSwapBuffers();
338 }
339
340 void CharacterDemo::clientResetScene()
341 {
342         m_dynamicsWorld->getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(m_ghostObject->getBroadphaseHandle(),getDynamicsWorld()->getDispatcher());
343
344         m_character->reset ();
345         ///WTF
346         m_character->warp (btVector3(10.210001,-2.0306311,16.576973));
347         
348 }
349
350 void CharacterDemo::specialKeyboardUp(int key, int x, int y)
351 {
352    switch (key)
353     {
354     case GLUT_KEY_UP:
355         {
356                 gForward = 0;
357         }
358         break;
359         case GLUT_KEY_DOWN:
360         {
361                 gBackward = 0;
362         }
363         break;
364         case GLUT_KEY_LEFT:
365         {
366                 gLeft = 0;
367         }
368         break;
369         case GLUT_KEY_RIGHT:
370         {
371                 gRight = 0;
372         }
373         break;
374         default:
375                 DemoApplication::specialKeyboardUp(key,x,y);
376         break;
377     }
378 }
379
380
381 void CharacterDemo::specialKeyboard(int key, int x, int y)
382 {
383
384 //      printf("key = %i x=%i y=%i\n",key,x,y);
385
386     switch (key)
387     {
388     case GLUT_KEY_UP:
389         {
390                 gForward = 1;
391         }
392         break;
393         case GLUT_KEY_DOWN:
394         {
395                 gBackward = 1;
396         }
397         break;
398         case GLUT_KEY_LEFT:
399         {
400                 gLeft = 1;
401         }
402         break;
403         case GLUT_KEY_RIGHT:
404         {
405                 gRight = 1;
406         }
407         break;
408         case GLUT_KEY_F1:
409         {
410                 if (m_character && m_character->canJump())
411                         gJump = 1;
412         }
413         break;
414         default:
415                 DemoApplication::specialKeyboard(key,x,y);
416         break;
417     }
418
419 //      glutPostRedisplay();
420
421
422 }
423
424 void    CharacterDemo::updateCamera()
425 {
426
427 //#define DISABLE_CAMERA 1
428 #ifdef DISABLE_CAMERA
429         DemoApplication::updateCamera();
430         return;
431 #endif //DISABLE_CAMERA
432
433         glMatrixMode(GL_PROJECTION);
434         glLoadIdentity();
435
436         btTransform characterWorldTrans;
437
438         //look at the vehicle
439         characterWorldTrans = m_ghostObject->getWorldTransform();
440         btVector3 up = characterWorldTrans.getBasis()[1];
441         btVector3 backward = -characterWorldTrans.getBasis()[2];
442         up.normalize ();
443         backward.normalize ();
444
445         m_cameraTargetPosition = characterWorldTrans.getOrigin();
446         m_cameraPosition = m_cameraTargetPosition + up * 10.0 + backward * 12.0;
447         
448         //use the convex sweep test to find a safe position for the camera (not blocked by static geometry)
449         btSphereShape cameraSphere(0.2f);
450         btTransform cameraFrom,cameraTo;
451         cameraFrom.setIdentity();
452         cameraFrom.setOrigin(characterWorldTrans.getOrigin());
453         cameraTo.setIdentity();
454         cameraTo.setOrigin(m_cameraPosition);
455         
456         btCollisionWorld::ClosestConvexResultCallback cb( characterWorldTrans.getOrigin(), cameraTo.getOrigin() );
457         cb.m_collisionFilterMask = btBroadphaseProxy::StaticFilter;
458                 
459         m_dynamicsWorld->convexSweepTest(&cameraSphere,cameraFrom,cameraTo,cb);
460         if (cb.hasHit())
461         {
462
463                 btScalar minFraction  = cb.m_closestHitFraction;//btMax(btScalar(0.3),cb.m_closestHitFraction);
464                 m_cameraPosition.setInterpolate3(cameraFrom.getOrigin(),cameraTo.getOrigin(),minFraction);
465         }
466
467
468
469
470         //update OpenGL camera settings
471     glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 10000.0);
472
473         glMatrixMode(GL_MODELVIEW);
474         glLoadIdentity();
475
476     gluLookAt(m_cameraPosition[0],m_cameraPosition[1],m_cameraPosition[2],
477                       m_cameraTargetPosition[0],m_cameraTargetPosition[1], m_cameraTargetPosition[2],
478                           m_cameraUp.getX(),m_cameraUp.getY(),m_cameraUp.getZ());
479
480
481
482 }
483
484
485 CharacterDemo::~CharacterDemo()
486 {
487         //cleanup in the reverse order of creation/initialization
488         if (m_character)
489         {
490                 m_dynamicsWorld->removeCollisionObject(m_ghostObject);
491         }
492         //remove the rigidbodies from the dynamics world and delete them
493         int i;
494         for (i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
495         {
496                 btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
497                 btRigidBody* body = btRigidBody::upcast(obj);
498                 if (body && body->getMotionState())
499                 {
500                         delete body->getMotionState();
501                 }
502                 m_dynamicsWorld->removeCollisionObject( obj );
503                 delete obj;
504         }
505
506         //delete collision shapes
507         for (int j=0;j<m_collisionShapes.size();j++)
508         {
509                 btCollisionShape* shape = m_collisionShapes[j];
510                 delete shape;
511         }
512
513         delete m_indexVertexArrays;
514         delete m_vertices;
515
516         //delete dynamics world
517         delete m_dynamicsWorld;
518
519         //delete solver
520         delete m_constraintSolver;
521
522         //delete broadphase
523         delete m_overlappingPairCache;
524
525         //delete dispatcher
526         delete m_dispatcher;
527
528         delete m_collisionConfiguration;
529
530 }
531