2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
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:
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.
16 ///September 2006: VehicleDemo is work in progress, this file is mostly just a placeholder
17 ///This VehicleDemo file is very early in development, please check it later
18 ///@todo is a basic engine model:
19 ///A function that maps user input (throttle) into torque/force applied on the wheels
21 #include "btBulletDynamicsCommon.h"
22 #include "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h"
23 #include "GLDebugFont.h"
26 #define M_PI 3.14159265358979323846
30 #define M_PI_2 1.57079632679489661923
34 #define M_PI_4 0.785398163397448309616
37 //#define LIFT_EPS 0.0000001f
39 // By default, Bullet Vehicle uses Y as up axis.
40 // You can override the up axis, for example Z-axis up. Enable this define to see how to:
41 //#define FORCE_ZAXIS_UP 1
48 btVector3 wheelDirectionCS0(0,0,-1);
49 btVector3 wheelAxleCS(1,0,0);
54 btVector3 wheelDirectionCS0(0,-1,0);
55 btVector3 wheelAxleCS(-1,0,0);
58 #include "GLDebugDrawer.h"
59 #include <stdio.h> //printf debugging
61 #include "GL_ShapeDrawer.h"
63 #include "GlutStuff.h"
64 #include "ForkLiftDemo.h"
67 const int maxProxies = 32766;
68 const int maxOverlap = 65535;
70 ///btRaycastVehicle is the interface for the constraint that implements the raycast vehicle
71 ///notice that for higher-quality slow-moving vehicles, another approach might be better
72 ///implementing explicit hinged-wheel constraints with cylinder collision, rather then raycasts
73 float gEngineForce = 0.f;
75 float defaultBreakingForce = 10.f;
76 float gBreakingForce = 100.f;
78 float maxEngineForce = 1000.f;//this should be engine/velocity dependent
79 float maxBreakingForce = 100.f;
81 float gVehicleSteering = 0.f;
82 float steeringIncrement = 0.04f;
83 float steeringClamp = 0.3f;
84 float wheelRadius = 0.5f;
85 float wheelWidth = 0.4f;
86 float wheelFriction = 1000;//BT_LARGE_FLOAT;
87 float suspensionStiffness = 20.f;
88 float suspensionDamping = 2.3f;
89 float suspensionCompression = 4.4f;
90 float rollInfluence = 0.1f;//1.0f;
93 btScalar suspensionRestLength(0.6);
95 #define CUBE_HALF_EXTENTS 1
99 ////////////////////////////////////
104 ForkLiftDemo::ForkLiftDemo()
111 m_minCameraDistance(3.f),
112 m_maxCameraDistance(10.f),
113 m_indexVertexArrays(0),
118 m_cameraPosition = btVector3(30,30,30);
119 m_useDefaultCamera = false;
126 void ForkLiftDemo::termPhysics()
128 //cleanup in the reverse order of creation/initialization
130 //remove the rigidbodies from the dynamics world and delete them
132 for (i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
134 btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
135 btRigidBody* body = btRigidBody::upcast(obj);
136 if (body && body->getMotionState())
139 while (body->getNumConstraintRefs())
141 btTypedConstraint* constraint = body->getConstraintRef(0);
142 m_dynamicsWorld->removeConstraint(constraint);
145 delete body->getMotionState();
146 m_dynamicsWorld->removeRigidBody(body);
149 m_dynamicsWorld->removeCollisionObject( obj );
154 //delete collision shapes
155 for (int j=0;j<m_collisionShapes.size();j++)
157 btCollisionShape* shape = m_collisionShapes[j];
161 delete m_indexVertexArrays;
164 //delete dynamics world
165 delete m_dynamicsWorld;
167 delete m_vehicleRayCaster;
174 delete m_constraintSolver;
177 delete m_overlappingPairCache;
182 delete m_collisionConfiguration;
186 ForkLiftDemo::~ForkLiftDemo()
191 void ForkLiftDemo::initPhysics()
194 #ifdef FORCE_ZAXIS_UP
195 m_cameraUp = btVector3(0,0,1);
199 btCollisionShape* groundShape = new btBoxShape(btVector3(50,3,50));
200 m_collisionShapes.push_back(groundShape);
201 m_collisionConfiguration = new btDefaultCollisionConfiguration();
202 m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
203 btVector3 worldMin(-1000,-1000,-1000);
204 btVector3 worldMax(1000,1000,1000);
205 m_overlappingPairCache = new btAxisSweep3(worldMin,worldMax);
206 m_constraintSolver = new btSequentialImpulseConstraintSolver();
207 m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_overlappingPairCache,m_constraintSolver,m_collisionConfiguration);
208 #ifdef FORCE_ZAXIS_UP
209 m_dynamicsWorld->setGravity(btVector3(0,0,-10));
212 //m_dynamicsWorld->setGravity(btVector3(0,0,0));
215 tr.setOrigin(btVector3(0,-10,0));
217 //either use heightfield or triangle mesh
220 //create ground object
221 localCreateRigidBody(0,tr,groundShape);
223 #ifdef FORCE_ZAXIS_UP
224 // indexRightAxis = 0;
226 // indexForwardAxis = 1;
227 btCollisionShape* chassisShape = new btBoxShape(btVector3(1.f,2.f, 0.5f));
228 btCompoundShape* compound = new btCompoundShape();
229 btTransform localTrans;
230 localTrans.setIdentity();
231 //localTrans effectively shifts the center of mass with respect to the chassis
232 localTrans.setOrigin(btVector3(0,0,1));
234 btCollisionShape* chassisShape = new btBoxShape(btVector3(1.f,0.5f,2.f));
235 m_collisionShapes.push_back(chassisShape);
237 btCompoundShape* compound = new btCompoundShape();
238 m_collisionShapes.push_back(compound);
239 btTransform localTrans;
240 localTrans.setIdentity();
241 //localTrans effectively shifts the center of mass with respect to the chassis
242 localTrans.setOrigin(btVector3(0,1,0));
245 compound->addChildShape(localTrans,chassisShape);
248 btCollisionShape* suppShape = new btBoxShape(btVector3(0.5f,0.1f,0.5f));
249 btTransform suppLocalTrans;
250 suppLocalTrans.setIdentity();
251 //localTrans effectively shifts the center of mass with respect to the chassis
252 suppLocalTrans.setOrigin(btVector3(0,1.0,2.5));
253 compound->addChildShape(suppLocalTrans, suppShape);
256 tr.setOrigin(btVector3(0,0.f,0));
258 m_carChassis = localCreateRigidBody(800,tr,compound);//chassisShape);
259 //m_carChassis->setDamping(0.2,0.2);
261 m_wheelShape = new btCylinderShapeX(btVector3(wheelWidth,wheelRadius,wheelRadius));
264 btCollisionShape* liftShape = new btBoxShape(btVector3(0.5f,2.0f,0.05f));
265 m_collisionShapes.push_back(liftShape);
266 btTransform liftTrans;
267 m_liftStartPos = btVector3(0.0f, 2.5f, 3.05f);
268 liftTrans.setIdentity();
269 liftTrans.setOrigin(m_liftStartPos);
270 m_liftBody = localCreateRigidBody(10,liftTrans, liftShape);
272 btTransform localA, localB;
273 localA.setIdentity();
274 localB.setIdentity();
275 localA.getBasis().setEulerZYX(0, M_PI_2, 0);
276 localA.setOrigin(btVector3(0.0, 1.0, 3.05));
277 localB.getBasis().setEulerZYX(0, M_PI_2, 0);
278 localB.setOrigin(btVector3(0.0, -1.5, -0.05));
279 m_liftHinge = new btHingeConstraint(*m_carChassis,*m_liftBody, localA, localB);
280 // m_liftHinge->setLimit(-LIFT_EPS, LIFT_EPS);
281 m_liftHinge->setLimit(0.0f, 0.0f);
282 m_dynamicsWorld->addConstraint(m_liftHinge, true);
284 btCollisionShape* forkShapeA = new btBoxShape(btVector3(1.0f,0.1f,0.1f));
285 m_collisionShapes.push_back(forkShapeA);
286 btCompoundShape* forkCompound = new btCompoundShape();
287 m_collisionShapes.push_back(forkCompound);
288 btTransform forkLocalTrans;
289 forkLocalTrans.setIdentity();
290 forkCompound->addChildShape(forkLocalTrans, forkShapeA);
292 btCollisionShape* forkShapeB = new btBoxShape(btVector3(0.1f,0.02f,0.6f));
293 m_collisionShapes.push_back(forkShapeB);
294 forkLocalTrans.setIdentity();
295 forkLocalTrans.setOrigin(btVector3(-0.9f, -0.08f, 0.7f));
296 forkCompound->addChildShape(forkLocalTrans, forkShapeB);
298 btCollisionShape* forkShapeC = new btBoxShape(btVector3(0.1f,0.02f,0.6f));
299 m_collisionShapes.push_back(forkShapeC);
300 forkLocalTrans.setIdentity();
301 forkLocalTrans.setOrigin(btVector3(0.9f, -0.08f, 0.7f));
302 forkCompound->addChildShape(forkLocalTrans, forkShapeC);
304 btTransform forkTrans;
305 m_forkStartPos = btVector3(0.0f, 0.6f, 3.2f);
306 forkTrans.setIdentity();
307 forkTrans.setOrigin(m_forkStartPos);
308 m_forkBody = localCreateRigidBody(5, forkTrans, forkCompound);
310 localA.setIdentity();
311 localB.setIdentity();
312 localA.getBasis().setEulerZYX(0, 0, M_PI_2);
313 localA.setOrigin(btVector3(0.0f, -1.9f, 0.05f));
314 localB.getBasis().setEulerZYX(0, 0, M_PI_2);
315 localB.setOrigin(btVector3(0.0, 0.0, -0.1));
316 m_forkSlider = new btSliderConstraint(*m_liftBody, *m_forkBody, localA, localB, true);
317 m_forkSlider->setLowerLinLimit(0.1f);
318 m_forkSlider->setUpperLinLimit(0.1f);
319 // m_forkSlider->setLowerAngLimit(-LIFT_EPS);
320 // m_forkSlider->setUpperAngLimit(LIFT_EPS);
321 m_forkSlider->setLowerAngLimit(0.0f);
322 m_forkSlider->setUpperAngLimit(0.0f);
323 m_dynamicsWorld->addConstraint(m_forkSlider, true);
326 btCompoundShape* loadCompound = new btCompoundShape();
327 m_collisionShapes.push_back(loadCompound);
328 btCollisionShape* loadShapeA = new btBoxShape(btVector3(2.0f,0.5f,0.5f));
329 m_collisionShapes.push_back(loadShapeA);
330 btTransform loadTrans;
331 loadTrans.setIdentity();
332 loadCompound->addChildShape(loadTrans, loadShapeA);
333 btCollisionShape* loadShapeB = new btBoxShape(btVector3(0.1f,1.0f,1.0f));
334 m_collisionShapes.push_back(loadShapeB);
335 loadTrans.setIdentity();
336 loadTrans.setOrigin(btVector3(2.1f, 0.0f, 0.0f));
337 loadCompound->addChildShape(loadTrans, loadShapeB);
338 btCollisionShape* loadShapeC = new btBoxShape(btVector3(0.1f,1.0f,1.0f));
339 m_collisionShapes.push_back(loadShapeC);
340 loadTrans.setIdentity();
341 loadTrans.setOrigin(btVector3(-2.1f, 0.0f, 0.0f));
342 loadCompound->addChildShape(loadTrans, loadShapeC);
343 loadTrans.setIdentity();
344 m_loadStartPos = btVector3(0.0f, -3.5f, 7.0f);
345 loadTrans.setOrigin(m_loadStartPos);
346 m_loadBody = localCreateRigidBody(4, loadTrans, loadCompound);
356 m_vehicleRayCaster = new btDefaultVehicleRaycaster(m_dynamicsWorld);
357 m_vehicle = new btRaycastVehicle(m_tuning,m_carChassis,m_vehicleRayCaster);
359 ///never deactivate the vehicle
360 m_carChassis->setActivationState(DISABLE_DEACTIVATION);
362 m_dynamicsWorld->addVehicle(m_vehicle);
364 float connectionHeight = 1.2f;
367 bool isFrontWheel=true;
369 //choose coordinate system
370 m_vehicle->setCoordinateSystem(rightIndex,upIndex,forwardIndex);
372 #ifdef FORCE_ZAXIS_UP
373 btVector3 connectionPointCS0(CUBE_HALF_EXTENTS-(0.3*wheelWidth),2*CUBE_HALF_EXTENTS-wheelRadius, connectionHeight);
375 btVector3 connectionPointCS0(CUBE_HALF_EXTENTS-(0.3*wheelWidth),connectionHeight,2*CUBE_HALF_EXTENTS-wheelRadius);
378 m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel);
379 #ifdef FORCE_ZAXIS_UP
380 connectionPointCS0 = btVector3(-CUBE_HALF_EXTENTS+(0.3*wheelWidth),2*CUBE_HALF_EXTENTS-wheelRadius, connectionHeight);
382 connectionPointCS0 = btVector3(-CUBE_HALF_EXTENTS+(0.3*wheelWidth),connectionHeight,2*CUBE_HALF_EXTENTS-wheelRadius);
385 m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel);
386 #ifdef FORCE_ZAXIS_UP
387 connectionPointCS0 = btVector3(-CUBE_HALF_EXTENTS+(0.3*wheelWidth),-2*CUBE_HALF_EXTENTS+wheelRadius, connectionHeight);
389 connectionPointCS0 = btVector3(-CUBE_HALF_EXTENTS+(0.3*wheelWidth),connectionHeight,-2*CUBE_HALF_EXTENTS+wheelRadius);
390 #endif //FORCE_ZAXIS_UP
391 isFrontWheel = false;
392 m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel);
393 #ifdef FORCE_ZAXIS_UP
394 connectionPointCS0 = btVector3(CUBE_HALF_EXTENTS-(0.3*wheelWidth),-2*CUBE_HALF_EXTENTS+wheelRadius, connectionHeight);
396 connectionPointCS0 = btVector3(CUBE_HALF_EXTENTS-(0.3*wheelWidth),connectionHeight,-2*CUBE_HALF_EXTENTS+wheelRadius);
398 m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel);
400 for (int i=0;i<m_vehicle->getNumWheels();i++)
402 btWheelInfo& wheel = m_vehicle->getWheelInfo(i);
403 wheel.m_suspensionStiffness = suspensionStiffness;
404 wheel.m_wheelsDampingRelaxation = suspensionDamping;
405 wheel.m_wheelsDampingCompression = suspensionCompression;
406 wheel.m_frictionSlip = wheelFriction;
407 wheel.m_rollInfluence = rollInfluence;
412 setCameraDistance(26.f);
417 //to be implemented by the demo
418 void ForkLiftDemo::renderme()
426 btVector3 wheelColor(1,0,0);
428 btVector3 worldBoundsMin,worldBoundsMax;
429 getDynamicsWorld()->getBroadphase()->getBroadphaseAabb(worldBoundsMin,worldBoundsMax);
433 for (i=0;i<m_vehicle->getNumWheels();i++)
435 //synchronize the wheels with the (interpolated) chassis worldtransform
436 m_vehicle->updateWheelTransform(i,true);
437 //draw wheels (cylinders)
438 m_vehicle->getWheelInfo(i).m_worldTransform.getOpenGLMatrix(m);
439 m_shapeDrawer->drawOpenGL(m,m_wheelShape,wheelColor,getDebugMode(),worldBoundsMin,worldBoundsMax);
444 int xStart = m_glutScreenWidth - lineWidth;
447 if((getDebugMode() & btIDebugDraw::DBG_NoHelpText)==0)
449 setOrthographicProjection();
450 glDisable(GL_LIGHTING);
454 glRasterPos3f(xStart, yStart, 0);
455 sprintf(buf,"SHIFT+Cursor Left/Right - rotate lift");
456 GLDebugDrawString(xStart,20,buf);
458 glRasterPos3f(xStart, yStart, 0);
459 sprintf(buf,"SHIFT+Cursor UP/Down - move fork up/down");
461 GLDebugDrawString(xStart,yStart,buf);
462 glRasterPos3f(xStart, yStart, 0);
463 sprintf(buf,"F5 - toggle camera mode");
465 GLDebugDrawString(xStart,yStart,buf);
466 glRasterPos3f(xStart, yStart, 0);
467 sprintf(buf,"Click inside this window for keyboard focus");
469 GLDebugDrawString(xStart,yStart,buf);
472 resetPerspectiveProjection();
473 glEnable(GL_LIGHTING);
475 DemoApplication::renderme();
478 void ForkLiftDemo::clientMoveAndDisplay()
481 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
486 m_vehicle->applyEngineForce(gEngineForce,wheelIndex);
487 m_vehicle->setBrake(gBreakingForce,wheelIndex);
489 m_vehicle->applyEngineForce(gEngineForce,wheelIndex);
490 m_vehicle->setBrake(gBreakingForce,wheelIndex);
494 m_vehicle->setSteeringValue(gVehicleSteering,wheelIndex);
496 m_vehicle->setSteeringValue(gVehicleSteering,wheelIndex);
501 float dt = getDeltaTimeMicroseconds() * 0.000001f;
505 //during idle mode, just run 1 simulation step maximum
506 int maxSimSubSteps = m_idle ? 1 : 2;
510 int numSimSteps = m_dynamicsWorld->stepSimulation(dt,maxSimSubSteps);
513 //#define VERBOSE_FEEDBACK
514 #ifdef VERBOSE_FEEDBACK
516 printf("Interpolated transforms\n");
519 if (numSimSteps > maxSimSubSteps)
521 //detect dropping frames
522 printf("Dropped (%i) simulation steps out of %i\n",numSimSteps - maxSimSubSteps,numSimSteps);
525 printf("Simulated (%i) steps\n",numSimSteps);
528 #endif //VERBOSE_FEEDBACK
539 btProfiler::beginBlock("render");
540 #endif //USE_QUICKPROF
545 //optional but useful: debug drawing
547 m_dynamicsWorld->debugDrawWorld();
550 btProfiler::endBlock("render");
561 void ForkLiftDemo::displayCallback(void)
563 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
567 //optional but useful: debug drawing
569 m_dynamicsWorld->debugDrawWorld();
577 void ForkLiftDemo::clientResetScene()
579 gVehicleSteering = 0.f;
580 gBreakingForce = defaultBreakingForce;
583 m_carChassis->setCenterOfMassTransform(btTransform::getIdentity());
584 m_carChassis->setLinearVelocity(btVector3(0,0,0));
585 m_carChassis->setAngularVelocity(btVector3(0,0,0));
586 m_dynamicsWorld->getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(m_carChassis->getBroadphaseHandle(),getDynamicsWorld()->getDispatcher());
589 m_vehicle->resetSuspension();
590 for (int i=0;i<m_vehicle->getNumWheels();i++)
592 //synchronize the wheels with the (interpolated) chassis worldtransform
593 m_vehicle->updateWheelTransform(i,true);
596 btTransform liftTrans;
597 liftTrans.setIdentity();
598 liftTrans.setOrigin(m_liftStartPos);
599 m_liftBody->activate();
600 m_liftBody->setCenterOfMassTransform(liftTrans);
601 m_liftBody->setLinearVelocity(btVector3(0,0,0));
602 m_liftBody->setAngularVelocity(btVector3(0,0,0));
604 btTransform forkTrans;
605 forkTrans.setIdentity();
606 forkTrans.setOrigin(m_forkStartPos);
607 m_forkBody->activate();
608 m_forkBody->setCenterOfMassTransform(forkTrans);
609 m_forkBody->setLinearVelocity(btVector3(0,0,0));
610 m_forkBody->setAngularVelocity(btVector3(0,0,0));
612 // m_liftHinge->setLimit(-LIFT_EPS, LIFT_EPS);
613 m_liftHinge->setLimit(0.0f, 0.0f);
614 m_liftHinge->enableAngularMotor(false, 0, 0);
617 m_forkSlider->setLowerLinLimit(0.1f);
618 m_forkSlider->setUpperLinLimit(0.1f);
619 m_forkSlider->setPoweredLinMotor(false);
621 btTransform loadTrans;
622 loadTrans.setIdentity();
623 loadTrans.setOrigin(m_loadStartPos);
624 m_loadBody->activate();
625 m_loadBody->setCenterOfMassTransform(loadTrans);
626 m_loadBody->setLinearVelocity(btVector3(0,0,0));
627 m_loadBody->setAngularVelocity(btVector3(0,0,0));
633 void ForkLiftDemo::specialKeyboardUp(int key, int x, int y)
641 gBreakingForce = defaultBreakingForce;
648 gBreakingForce = defaultBreakingForce;
658 DemoApplication::specialKeyboardUp(key,x,y);
664 void ForkLiftDemo::specialKeyboard(int key, int x, int y)
667 if (key==GLUT_KEY_END)
670 // printf("key = %i x=%i y=%i\n",key,x,y);
673 state=glutGetModifiers();
674 if (state & GLUT_ACTIVE_SHIFT)
681 m_liftHinge->setLimit(-M_PI/16.0f, M_PI/8.0f);
682 m_liftHinge->enableAngularMotor(true, -0.1, 10.0);
685 case GLUT_KEY_RIGHT :
688 m_liftHinge->setLimit(-M_PI/16.0f, M_PI/8.0f);
689 m_liftHinge->enableAngularMotor(true, 0.1, 10.0);
694 m_forkSlider->setLowerLinLimit(0.1f);
695 m_forkSlider->setUpperLinLimit(3.9f);
696 m_forkSlider->setPoweredLinMotor(true);
697 m_forkSlider->setMaxLinMotorForce(10.0);
698 m_forkSlider->setTargetLinMotorVelocity(1.0);
703 m_forkSlider->setLowerLinLimit(0.1f);
704 m_forkSlider->setUpperLinLimit(3.9f);
705 m_forkSlider->setPoweredLinMotor(true);
706 m_forkSlider->setMaxLinMotorForce(10.0);
707 m_forkSlider->setTargetLinMotorVelocity(-1.0);
712 DemoApplication::specialKeyboard(key,x,y);
722 gVehicleSteering += steeringIncrement;
723 if ( gVehicleSteering > steeringClamp)
724 gVehicleSteering = steeringClamp;
728 case GLUT_KEY_RIGHT :
730 gVehicleSteering -= steeringIncrement;
731 if ( gVehicleSteering < -steeringClamp)
732 gVehicleSteering = -steeringClamp;
738 gEngineForce = maxEngineForce;
739 gBreakingForce = 0.f;
744 gEngineForce = -maxEngineForce;
745 gBreakingForce = 0.f;
750 m_useDefaultCamera = !m_useDefaultCamera;
753 DemoApplication::specialKeyboard(key,x,y);
758 // glutPostRedisplay();
763 void ForkLiftDemo::updateCamera()
766 //#define DISABLE_CAMERA 1
767 if(m_useDefaultCamera)
769 DemoApplication::updateCamera();
773 glMatrixMode(GL_PROJECTION);
776 btTransform chassisWorldTrans;
778 //look at the vehicle
779 m_carChassis->getMotionState()->getWorldTransform(chassisWorldTrans);
780 m_cameraTargetPosition = chassisWorldTrans.getOrigin();
782 //interpolate the camera height
783 #ifdef FORCE_ZAXIS_UP
784 m_cameraPosition[2] = (15.0*m_cameraPosition[2] + m_cameraTargetPosition[2] + m_cameraHeight)/16.0;
786 m_cameraPosition[1] = (15.0*m_cameraPosition[1] + m_cameraTargetPosition[1] + m_cameraHeight)/16.0;
789 btVector3 camToObject = m_cameraTargetPosition - m_cameraPosition;
791 //keep distance between min and max distance
792 float cameraDistance = camToObject.length();
793 float correctionFactor = 0.f;
794 if (cameraDistance < m_minCameraDistance)
796 correctionFactor = 0.15*(m_minCameraDistance-cameraDistance)/cameraDistance;
798 if (cameraDistance > m_maxCameraDistance)
800 correctionFactor = 0.15*(m_maxCameraDistance-cameraDistance)/cameraDistance;
802 m_cameraPosition -= correctionFactor*camToObject;
804 //update OpenGL camera settings
805 btScalar aspect = m_glutScreenWidth / (btScalar)m_glutScreenHeight;
806 glFrustum (-aspect, aspect, -1.0, 1.0, 1.0, 10000.0);
808 glMatrixMode(GL_MODELVIEW);
811 gluLookAt(m_cameraPosition[0],m_cameraPosition[1],m_cameraPosition[2],
812 m_cameraTargetPosition[0],m_cameraTargetPosition[1], m_cameraTargetPosition[2],
813 m_cameraUp.getX(),m_cameraUp.getY(),m_cameraUp.getZ());
819 void ForkLiftDemo::lockLiftHinge(void)
821 btScalar hingeAngle = m_liftHinge->getHingeAngle();
822 btScalar lowLim = m_liftHinge->getLowerLimit();
823 btScalar hiLim = m_liftHinge->getUpperLimit();
824 m_liftHinge->enableAngularMotor(false, 0, 0);
825 if(hingeAngle < lowLim)
827 // m_liftHinge->setLimit(lowLim, lowLim + LIFT_EPS);
828 m_liftHinge->setLimit(lowLim, lowLim);
830 else if(hingeAngle > hiLim)
832 // m_liftHinge->setLimit(hiLim - LIFT_EPS, hiLim);
833 m_liftHinge->setLimit(hiLim, hiLim);
837 // m_liftHinge->setLimit(hingeAngle - LIFT_EPS, hingeAngle + LIFT_EPS);
838 m_liftHinge->setLimit(hingeAngle, hingeAngle);
841 } // ForkLiftDemo::lockLiftHinge()
843 void ForkLiftDemo::lockForkSlider(void)
845 btScalar linDepth = m_forkSlider->getLinearPos();
846 btScalar lowLim = m_forkSlider->getLowerLinLimit();
847 btScalar hiLim = m_forkSlider->getUpperLinLimit();
848 m_forkSlider->setPoweredLinMotor(false);
849 if(linDepth <= lowLim)
851 m_forkSlider->setLowerLinLimit(lowLim);
852 m_forkSlider->setUpperLinLimit(lowLim);
854 else if(linDepth > hiLim)
856 m_forkSlider->setLowerLinLimit(hiLim);
857 m_forkSlider->setUpperLinLimit(hiLim);
861 m_forkSlider->setLowerLinLimit(linDepth);
862 m_forkSlider->setUpperLinLimit(linDepth);
865 } // ForkLiftDemo::lockForkSlider()