diff --git a/Demos/ForkLiftDemo/ForkLiftDemo.cpp b/Demos/ForkLiftDemo/ForkLiftDemo.cpp index 2adc92f2e..4c5a8dc27 100644 --- a/Demos/ForkLiftDemo/ForkLiftDemo.cpp +++ b/Demos/ForkLiftDemo/ForkLiftDemo.cpp @@ -13,13 +13,48 @@ subject to the following restrictions: 3. This notice may not be removed or altered from any source distribution. */ - -/// September 2006: ForkLiftDemo is work in progress, this file is mostly just a placeholder -/// This ForkLiftDemo file is very early in development, please check it later - +/// September 2006: VehicleDemo is work in progress, this file is mostly just a placeholder +/// This VehicleDemo file is very early in development, please check it later +/// One todo is a basic engine model: +/// A function that maps user input (throttle) into torque/force applied on the wheels +/// with gears etc. #include "btBulletDynamicsCommon.h" +#include "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h" +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#ifndef M_PI_2 +#define M_PI_2 1.57079632679489661923 +#endif + +#ifndef M_PI_4 +#define M_PI_4 0.785398163397448309616 +#endif + +#define LIFT_EPS 0.0000001f +// +// By default, Bullet Vehicle uses Y as up axis. +// You can override the up axis, for example Z-axis up. Enable this define to see how to: +//#define FORCE_ZAXIS_UP 1 +// + +#ifdef FORCE_ZAXIS_UP + int rightIndex = 0; + int upIndex = 2; + int forwardIndex = 1; + btVector3 wheelDirectionCS0(0,0,-1); + btVector3 wheelAxleCS(1,0,0); +#else + int rightIndex = 0; + int upIndex = 1; + int forwardIndex = 2; + btVector3 wheelDirectionCS0(0,-1,0); + btVector3 wheelAxleCS(-1,0,0); +#endif + #include "GLDebugDrawer.h" #include //printf debugging @@ -27,26 +62,32 @@ subject to the following restrictions: #include "GlutStuff.h" #include "ForkLiftDemo.h" +#include "BMF_Api.h" const int maxProxies = 32766; const int maxOverlap = 65535; - - +///btRaycastVehicle is the interface for the constraint that implements the raycast vehicle +///notice that for higher-quality slow-moving vehicles, another approach might be better +///implementing explicit hinged-wheel constraints with cylinder collision, rather then raycasts float gEngineForce = 0.f; -float maxEngineForce = 100.f; +float gBreakingForce = 0.f; + +float maxEngineForce = 1000.f;//this should be engine/velocity dependent +float maxBreakingForce = 100.f; + float gVehicleSteering = 0.f; -float steeringIncrement = 0.1f; +float steeringIncrement = 0.04f; float steeringClamp = 0.3f; float wheelRadius = 0.5f; -float wheelWidth = 0.2f; -float wheelFriction = 100.f; -float suspensionStiffness = 10.f; -float suspensionDamping = 1.3f; -float suspensionCompression = 2.4f; -float rollInfluence = 0.1f; -btVector3 wheelDirectionCS0(0,-1,0); -btVector3 wheelAxleCS(1,0,0); +float wheelWidth = 0.4f; +float wheelFriction = 1000;//1e30f; +float suspensionStiffness = 20.f; +float suspensionDamping = 2.3f; +float suspensionCompression = 4.4f; +float rollInfluence = 0.1f;//1.0f; + + btScalar suspensionRestLength(0.6); #define CUBE_HALF_EXTENTS 1 @@ -57,37 +98,104 @@ btScalar suspensionRestLength(0.6); -GLDebugDrawer debugDrawer; - -int main(int argc,char** argv) -{ - - ForkLiftDemo* vehicleDemo = new ForkLiftDemo; - - vehicleDemo->setupPhysics(); - - return glutmain(argc, argv,640,480,"Bullet Vehicle Demo. http://www.continuousphysics.com/Bullet/phpBB2/", vehicleDemo); -} ForkLiftDemo::ForkLiftDemo() : m_carChassis(0), +m_liftBody(0), +m_forkBody(0), +m_loadBody(0), m_cameraHeight(4.f), m_minCameraDistance(3.f), -m_maxCameraDistance(10.f) +m_maxCameraDistance(10.f), +m_indexVertexArrays(0), +m_vertices(0) { + m_vehicle = 0; m_cameraPosition = btVector3(30,30,30); + m_useDefaultCamera = false; } -void ForkLiftDemo::setupPhysics() + +void ForkLiftDemo::termPhysics() { + //cleanup in the reverse order of creation/initialization + //remove the rigidbodies from the dynamics world and delete them + int i; + for (i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--) + { + btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i]; + btRigidBody* body = btRigidBody::upcast(obj); + if (body && body->getMotionState()) + { + delete body->getMotionState(); + } + m_dynamicsWorld->removeCollisionObject( obj ); + delete obj; + } + //delete collision shapes + for (int j=0;jsetGravity(btVector3(0,0,-10)); +#endif + //m_dynamicsWorld->setGravity(btVector3(0,0,0)); +btTransform tr; +tr.setIdentity(); +//either use heightfield or triangle mesh #define USE_TRIMESH_GROUND 1 #ifdef USE_TRIMESH_GROUND int i; @@ -98,13 +206,13 @@ const float TRIANGLE_SIZE=20.f; int vertStride = sizeof(btVector3); int indexStride = 3*sizeof(int); - const int NUM_VERTS_X = 50; - const int NUM_VERTS_Y = 50; + const int NUM_VERTS_X = 20; + const int NUM_VERTS_Y = 20; const int totalVerts = NUM_VERTS_X*NUM_VERTS_Y; const int totalTriangles = 2*(NUM_VERTS_X-1)*(NUM_VERTS_Y-1); - btVector3* gVertices = new btVector3[totalVerts]; + m_vertices = new btVector3[totalVerts]; int* gIndices = new int[totalTriangles*3]; @@ -113,7 +221,23 @@ const float TRIANGLE_SIZE=20.f; { for (int j=0;jsetUseDiamondSubdivision(true); + + btVector3 localScaling(20,20,20); + localScaling[upIndex]=1.f; + groundShape->setLocalScaling(localScaling); + + tr.setOrigin(btVector3(0,-64.5f,0)); + #endif // - btTransform tr; - tr.setIdentity(); - - tr.setOrigin(btVector3(0,-4.5f,0)); + m_collisionShapes.push_back(groundShape); //create ground object localCreateRigidBody(0,tr,groundShape); +#ifdef FORCE_ZAXIS_UP +// indexRightAxis = 0; +// indexUpAxis = 2; +// indexForwardAxis = 1; + btCollisionShape* chassisShape = new btBoxShape(btVector3(1.f,2.f, 0.5f)); + btCompoundShape* compound = new btCompoundShape(); + btTransform localTrans; + localTrans.setIdentity(); + //localTrans effectively shifts the center of mass with respect to the chassis + localTrans.setOrigin(btVector3(0,0,1)); +#else btCollisionShape* chassisShape = new btBoxShape(btVector3(1.f,0.5f,2.f)); + m_collisionShapes.push_back(chassisShape); + + btCompoundShape* compound = new btCompoundShape(); + m_collisionShapes.push_back(compound); + btTransform localTrans; + localTrans.setIdentity(); + //localTrans effectively shifts the center of mass with respect to the chassis + localTrans.setOrigin(btVector3(0,1,0)); +#endif + + compound->addChildShape(localTrans,chassisShape); + + { + btCollisionShape* suppShape = new btBoxShape(btVector3(0.5f,0.1f,0.5f)); + m_collisionShapes.push_back(chassisShape); + btTransform suppLocalTrans; + suppLocalTrans.setIdentity(); + //localTrans effectively shifts the center of mass with respect to the chassis + suppLocalTrans.setOrigin(btVector3(0,1.0,2.5)); + compound->addChildShape(suppLocalTrans, suppShape); + } + tr.setOrigin(btVector3(0,0.f,0)); - m_carChassis = localCreateRigidBody(800,tr,chassisShape); + m_carChassis = localCreateRigidBody(800,tr,compound);//chassisShape); + //m_carChassis->setDamping(0.2,0.2); + + { + btCollisionShape* liftShape = new btBoxShape(btVector3(0.5f,2.0f,0.05f)); + m_collisionShapes.push_back(liftShape); + btTransform liftTrans; + m_liftStartPos = btVector3(0.0f, 2.5f, 3.05f); + liftTrans.setIdentity(); + liftTrans.setOrigin(m_liftStartPos); + m_liftBody = localCreateRigidBody(10,liftTrans, liftShape); + + btTransform localA, localB; + localA.setIdentity(); + localB.setIdentity(); + localA.getBasis().setEulerZYX(0, M_PI_2, 0); + localA.setOrigin(btVector3(0.0, 1.0, 3.05)); + localB.getBasis().setEulerZYX(0, M_PI_2, 0); + localB.setOrigin(btVector3(0.0, -1.5, -0.05)); + m_liftHinge = new btHingeConstraint(*m_carChassis,*m_liftBody, localA, localB); + m_liftHinge->setLimit(-LIFT_EPS, LIFT_EPS); + m_dynamicsWorld->addConstraint(m_liftHinge, true); + + btCollisionShape* forkShapeA = new btBoxShape(btVector3(1.0f,0.1f,0.1f)); + m_collisionShapes.push_back(forkShapeA); + btCompoundShape* forkCompound = new btCompoundShape(); + m_collisionShapes.push_back(forkCompound); + btTransform forkLocalTrans; + forkLocalTrans.setIdentity(); + forkCompound->addChildShape(forkLocalTrans, forkShapeA); + + btCollisionShape* forkShapeB = new btBoxShape(btVector3(0.1f,0.02f,0.6f)); + m_collisionShapes.push_back(forkShapeB); + forkLocalTrans.setIdentity(); + forkLocalTrans.setOrigin(btVector3(-0.9f, -0.08f, 0.7f)); + forkCompound->addChildShape(forkLocalTrans, forkShapeB); + + btCollisionShape* forkShapeC = new btBoxShape(btVector3(0.1f,0.02f,0.6f)); + m_collisionShapes.push_back(forkShapeC); + forkLocalTrans.setIdentity(); + forkLocalTrans.setOrigin(btVector3(0.9f, -0.08f, 0.7f)); + forkCompound->addChildShape(forkLocalTrans, forkShapeC); + + btTransform forkTrans; + m_forkStartPos = btVector3(0.0f, 0.6f, 3.2f); + forkTrans.setIdentity(); + forkTrans.setOrigin(m_forkStartPos); + m_forkBody = localCreateRigidBody(5, forkTrans, forkCompound); + + localA.setIdentity(); + localB.setIdentity(); + localA.getBasis().setEulerZYX(0, 0, M_PI_2); + localA.setOrigin(btVector3(0.0f, -1.9f, 0.05f)); + localB.getBasis().setEulerZYX(0, 0, M_PI_2); + localB.setOrigin(btVector3(0.0, 0.0, -0.1)); + m_forkSlider = new btSliderConstraint(*m_liftBody, *m_forkBody, localA, localB, true); + m_forkSlider->setLowerLinLimit(0.1f); + m_forkSlider->setUpperLinLimit(0.1f); + m_forkSlider->setLowerAngLimit(-LIFT_EPS); + m_forkSlider->setUpperAngLimit(LIFT_EPS); + m_dynamicsWorld->addConstraint(m_forkSlider, true); + + + btCompoundShape* loadCompound = new btCompoundShape(); + m_collisionShapes.push_back(loadCompound); + btCollisionShape* loadShapeA = new btBoxShape(btVector3(2.0f,0.5f,0.5f)); + m_collisionShapes.push_back(loadShapeA); + btTransform loadTrans; + loadTrans.setIdentity(); + loadCompound->addChildShape(loadTrans, loadShapeA); + btCollisionShape* loadShapeB = new btBoxShape(btVector3(0.1f,1.0f,1.0f)); + m_collisionShapes.push_back(loadShapeB); + loadTrans.setIdentity(); + loadTrans.setOrigin(btVector3(2.1f, 0.0f, 0.0f)); + loadCompound->addChildShape(loadTrans, loadShapeB); + btCollisionShape* loadShapeC = new btBoxShape(btVector3(0.1f,1.0f,1.0f)); + m_collisionShapes.push_back(loadShapeC); + loadTrans.setIdentity(); + loadTrans.setOrigin(btVector3(-2.1f, 0.0f, 0.0f)); + loadCompound->addChildShape(loadTrans, loadShapeC); + loadTrans.setIdentity(); + m_loadStartPos = btVector3(0.0f, -3.5f, 7.0f); + loadTrans.setOrigin(m_loadStartPos); + m_loadBody = localCreateRigidBody(4, loadTrans, loadCompound); + } + + + clientResetScene(); /// create vehicle { - ///never deactivate the vehicle - m_carChassis->SetActivationState(DISABLE_DEACTIVATION); - - btVector3 connectionPointCS0(CUBE_HALF_EXTENTS-(0.3*wheelWidth),0,2*CUBE_HALF_EXTENTS-wheelRadius); - // m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel); - connectionPointCS0 = btVector3(-CUBE_HALF_EXTENTS+(0.3*wheelWidth),0,2*CUBE_HALF_EXTENTS-wheelRadius); - // m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel); - connectionPointCS0 = btVector3(-CUBE_HALF_EXTENTS+(0.3*wheelWidth),0,-2*CUBE_HALF_EXTENTS+wheelRadius); - // m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel); - connectionPointCS0 = btVector3(CUBE_HALF_EXTENTS-(0.3*wheelWidth),0,-2*CUBE_HALF_EXTENTS+wheelRadius); - // m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel); + m_vehicleRayCaster = new btDefaultVehicleRaycaster(m_dynamicsWorld); + m_vehicle = new btRaycastVehicle(m_tuning,m_carChassis,m_vehicleRayCaster); + ///never deactivate the vehicle + m_carChassis->setActivationState(DISABLE_DEACTIVATION); + + m_dynamicsWorld->addVehicle(m_vehicle); + + float connectionHeight = 1.2f; + + + bool isFrontWheel=true; + + //choose coordinate system + m_vehicle->setCoordinateSystem(rightIndex,upIndex,forwardIndex); + +#ifdef FORCE_ZAXIS_UP + btVector3 connectionPointCS0(CUBE_HALF_EXTENTS-(0.3*wheelWidth),2*CUBE_HALF_EXTENTS-wheelRadius, connectionHeight); +#else + btVector3 connectionPointCS0(CUBE_HALF_EXTENTS-(0.3*wheelWidth),connectionHeight,2*CUBE_HALF_EXTENTS-wheelRadius); +#endif + + m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel); +#ifdef FORCE_ZAXIS_UP + connectionPointCS0 = btVector3(-CUBE_HALF_EXTENTS+(0.3*wheelWidth),2*CUBE_HALF_EXTENTS-wheelRadius, connectionHeight); +#else + connectionPointCS0 = btVector3(-CUBE_HALF_EXTENTS+(0.3*wheelWidth),connectionHeight,2*CUBE_HALF_EXTENTS-wheelRadius); +#endif + + m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel); +#ifdef FORCE_ZAXIS_UP + connectionPointCS0 = btVector3(-CUBE_HALF_EXTENTS+(0.3*wheelWidth),-2*CUBE_HALF_EXTENTS+wheelRadius, connectionHeight); +#else + connectionPointCS0 = btVector3(-CUBE_HALF_EXTENTS+(0.3*wheelWidth),connectionHeight,-2*CUBE_HALF_EXTENTS+wheelRadius); +#endif //FORCE_ZAXIS_UP + isFrontWheel = false; + m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel); +#ifdef FORCE_ZAXIS_UP + connectionPointCS0 = btVector3(CUBE_HALF_EXTENTS-(0.3*wheelWidth),-2*CUBE_HALF_EXTENTS+wheelRadius, connectionHeight); +#else + connectionPointCS0 = btVector3(CUBE_HALF_EXTENTS-(0.3*wheelWidth),connectionHeight,-2*CUBE_HALF_EXTENTS+wheelRadius); +#endif + m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel); + + for (int i=0;igetNumWheels();i++) + { + btWheelInfo& wheel = m_vehicle->getWheelInfo(i); + wheel.m_suspensionStiffness = suspensionStiffness; + wheel.m_wheelsDampingRelaxation = suspensionDamping; + wheel.m_wheelsDampingCompression = suspensionCompression; + wheel.m_frictionSlip = wheelFriction; + wheel.m_rollInfluence = rollInfluence; + } } @@ -185,12 +517,55 @@ void ForkLiftDemo::renderme() updateCamera(); - debugDrawer.setDebugMode(getDebugMode()); - float m[16]; + btScalar m[16]; int i; - DemoApplication::renderme(); + btCylinderShapeX wheelShape(btVector3(wheelWidth,wheelRadius,wheelRadius)); + btVector3 wheelColor(1,0,0); + btVector3 worldBoundsMin,worldBoundsMax; + getDynamicsWorld()->getBroadphase()->getBroadphaseAabb(worldBoundsMin,worldBoundsMax); + + + + for (i=0;igetNumWheels();i++) + { + //synchronize the wheels with the (interpolated) chassis worldtransform + m_vehicle->updateWheelTransform(i,true); + //draw wheels (cylinders) + m_vehicle->getWheelInfo(i).m_worldTransform.getOpenGLMatrix(m); + m_shapeDrawer.drawOpenGL(m,&wheelShape,wheelColor,getDebugMode(),worldBoundsMin,worldBoundsMax); + } + + if((getDebugMode() & btIDebugDraw::DBG_NoHelpText)==0) + { + setOrthographicProjection(); + glDisable(GL_LIGHTING); + glColor3f(0, 0, 0); + char buf[124]; + glRasterPos3f(400, 20, 0); + sprintf(buf,"PgUp - rotate lift up"); + BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); + glRasterPos3f(400, 40, 0); + sprintf(buf,"PgUp - rotate lift down"); + BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); + glRasterPos3f(400, 60, 0); + sprintf(buf,"Home - move fork up"); + BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); + glRasterPos3f(400, 80, 0); + sprintf(buf,"End - move fork down"); + BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); + glRasterPos3f(400, 100, 0); + sprintf(buf,"Insert - move vehicle back"); + BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); + glRasterPos3f(400, 120, 0); + sprintf(buf,"F5 - toggle camera mode"); + BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); + + resetPerspectiveProjection(); + glEnable(GL_LIGHTING); + } + DemoApplication::renderme(); } void ForkLiftDemo::clientMoveAndDisplay() @@ -198,17 +573,38 @@ void ForkLiftDemo::clientMoveAndDisplay() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - float dt = m_clock.getTimeMilliseconds() * 0.001f; - m_clock.reset(); - + + { + int wheelIndex = 2; + m_vehicle->applyEngineForce(gEngineForce,wheelIndex); + m_vehicle->setBrake(gBreakingForce,wheelIndex); + wheelIndex = 3; + m_vehicle->applyEngineForce(gEngineForce,wheelIndex); + m_vehicle->setBrake(gBreakingForce,wheelIndex); + + + wheelIndex = 0; + m_vehicle->setSteeringValue(gVehicleSteering,wheelIndex); + wheelIndex = 1; + m_vehicle->setSteeringValue(gVehicleSteering,wheelIndex); + + } + + + float dt = getDeltaTimeMicroseconds() * 0.000001f; + if (m_dynamicsWorld) { //during idle mode, just run 1 simulation step maximum - int maxSimSubSteps = m_idle ? 1 : 1; + int maxSimSubSteps = m_idle ? 1 : 2; if (m_idle) dt = 1.0/420.f; int numSimSteps = m_dynamicsWorld->stepSimulation(dt,maxSimSubSteps); + + +//#define VERBOSE_FEEDBACK +#ifdef VERBOSE_FEEDBACK if (!numSimSteps) printf("Interpolated transforms\n"); else @@ -222,10 +618,14 @@ void ForkLiftDemo::clientMoveAndDisplay() printf("Simulated (%i) steps\n",numSimSteps); } } +#endif //VERBOSE_FEEDBACK } + + + #ifdef USE_QUICKPROF @@ -235,6 +635,10 @@ void ForkLiftDemo::clientMoveAndDisplay() renderme(); + //optional but useful: debug drawing + if (m_dynamicsWorld) + m_dynamicsWorld->debugDrawWorld(); + #ifdef USE_QUICKPROF btProfiler::endBlock("render"); #endif @@ -249,18 +653,13 @@ void ForkLiftDemo::clientMoveAndDisplay() void ForkLiftDemo::displayCallback(void) { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - - m_dynamicsWorld->updateAabbs(); - //draw contactpoints - //m_physicsEnvironmentPtr->CallbackTriggers(); - - renderme(); +//optional but useful: debug drawing + if (m_dynamicsWorld) + m_dynamicsWorld->debugDrawWorld(); glFlush(); glutSwapBuffers(); @@ -268,14 +667,92 @@ void ForkLiftDemo::displayCallback(void) +void ForkLiftDemo::clientResetScene() +{ + gVehicleSteering = 0.f; + m_carChassis->setCenterOfMassTransform(btTransform::getIdentity()); + m_carChassis->setLinearVelocity(btVector3(0,0,0)); + m_carChassis->setAngularVelocity(btVector3(0,0,0)); + m_dynamicsWorld->getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(m_carChassis->getBroadphaseHandle(),getDynamicsWorld()->getDispatcher()); + if (m_vehicle) + { + m_vehicle->resetSuspension(); + for (int i=0;igetNumWheels();i++) + { + //synchronize the wheels with the (interpolated) chassis worldtransform + m_vehicle->updateWheelTransform(i,true); + } + } + btTransform liftTrans; + liftTrans.setIdentity(); + liftTrans.setOrigin(m_liftStartPos); + m_liftBody->setCenterOfMassTransform(liftTrans); + m_liftBody->setLinearVelocity(btVector3(0,0,0)); + m_liftBody->setAngularVelocity(btVector3(0,0,0)); + + btTransform forkTrans; + forkTrans.setIdentity(); + forkTrans.setOrigin(m_forkStartPos); + m_forkBody->setCenterOfMassTransform(forkTrans); + m_forkBody->setLinearVelocity(btVector3(0,0,0)); + m_forkBody->setAngularVelocity(btVector3(0,0,0)); + + m_liftHinge->setLimit(-LIFT_EPS, LIFT_EPS); + m_liftHinge->enableAngularMotor(false, 0, 0); + + m_forkSlider->setLowerLinLimit(0.1f); + m_forkSlider->setUpperLinLimit(0.1f); + m_forkSlider->setPoweredLinMotor(false); + + btTransform loadTrans; + loadTrans.setIdentity(); + loadTrans.setOrigin(m_loadStartPos); + m_loadBody->setCenterOfMassTransform(loadTrans); + m_loadBody->setLinearVelocity(btVector3(0,0,0)); + m_loadBody->setAngularVelocity(btVector3(0,0,0)); + +} +void ForkLiftDemo::specialKeyboardUp(int key, int x, int y) +{ + switch (key) + { + case GLUT_KEY_UP : + { + gEngineForce = 0.f; + break; + } + case GLUT_KEY_DOWN : + { + gBreakingForce = 0.f; + break; + } + case GLUT_KEY_PAGE_UP: + lockLiftHinge(); + break; + case GLUT_KEY_PAGE_DOWN: + lockLiftHinge(); + break; + case GLUT_KEY_HOME: + lockForkSlider(); + break; + case GLUT_KEY_END: + lockForkSlider(); + break; + default: + DemoApplication::specialKeyboardUp(key,x,y); + break; + } + +} + void ForkLiftDemo::specialKeyboard(int key, int x, int y) { - printf("key = %i x=%i y=%i\n",key,x,y); +// printf("key = %i x=%i y=%i\n",key,x,y); switch (key) { @@ -297,14 +774,47 @@ void ForkLiftDemo::specialKeyboard(int key, int x, int y) } case GLUT_KEY_UP : { - gEngineForce = -maxEngineForce; + gEngineForce = maxEngineForce; + gBreakingForce = 0.f; break; } case GLUT_KEY_DOWN : { - gEngineForce = maxEngineForce; + gBreakingForce = maxBreakingForce; + gEngineForce = 0.f; break; } + case GLUT_KEY_INSERT : + { + gEngineForce = -maxEngineForce; + gBreakingForce = 0.f; + break; + } + case GLUT_KEY_PAGE_UP: + m_liftHinge->setLimit(-M_PI/16.0f, M_PI/8.0f); + m_liftHinge->enableAngularMotor(true, 0.1, 10.0); + break; + case GLUT_KEY_PAGE_DOWN: + m_liftHinge->setLimit(-M_PI/16.0f, M_PI/8.0f); + m_liftHinge->enableAngularMotor(true, -0.1, 10.0); + break; + case GLUT_KEY_HOME: + m_forkSlider->setLowerLinLimit(0.1f); + m_forkSlider->setUpperLinLimit(3.9f); + m_forkSlider->setPoweredLinMotor(true); + m_forkSlider->setMaxLinMotorForce(10.0); + m_forkSlider->setTargetLinMotorVelocity(1.0); + break; + case GLUT_KEY_END: + m_forkSlider->setLowerLinLimit(0.1f); + m_forkSlider->setUpperLinLimit(3.9f); + m_forkSlider->setPoweredLinMotor(true); + m_forkSlider->setMaxLinMotorForce(10.0); + m_forkSlider->setTargetLinMotorVelocity(-1.0); + break; + case GLUT_KEY_F5: + m_useDefaultCamera = !m_useDefaultCamera; + break; default: DemoApplication::specialKeyboard(key,x,y); break; @@ -315,10 +825,15 @@ void ForkLiftDemo::specialKeyboard(int key, int x, int y) } - - void ForkLiftDemo::updateCamera() { + +//#define DISABLE_CAMERA 1 + if(m_useDefaultCamera) + { + DemoApplication::updateCamera(); + return; + } glMatrixMode(GL_PROJECTION); glLoadIdentity(); @@ -330,7 +845,11 @@ void ForkLiftDemo::updateCamera() m_cameraTargetPosition = chassisWorldTrans.getOrigin(); //interpolate the camera height +#ifdef FORCE_ZAXIS_UP + m_cameraPosition[2] = (15.0*m_cameraPosition[2] + m_cameraTargetPosition[2] + m_cameraHeight)/16.0; +#else m_cameraPosition[1] = (15.0*m_cameraPosition[1] + m_cameraTargetPosition[1] + m_cameraHeight)/16.0; +#endif btVector3 camToObject = m_cameraTargetPosition - m_cameraPosition; @@ -350,11 +869,58 @@ void ForkLiftDemo::updateCamera() //update OpenGL camera settings glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 10000.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + gluLookAt(m_cameraPosition[0],m_cameraPosition[1],m_cameraPosition[2], m_cameraTargetPosition[0],m_cameraTargetPosition[1], m_cameraTargetPosition[2], m_cameraUp.getX(),m_cameraUp.getY(),m_cameraUp.getZ()); - glMatrixMode(GL_MODELVIEW); + } +void ForkLiftDemo::lockLiftHinge(void) +{ + btScalar hingeAngle = m_liftHinge->getHingeAngle(); + btScalar lowLim = m_liftHinge->getLowerLimit(); + btScalar hiLim = m_liftHinge->getUpperLimit(); + m_liftHinge->enableAngularMotor(false, 0, 0); + if(hingeAngle < lowLim) + { + m_liftHinge->setLimit(lowLim, lowLim + LIFT_EPS); + } + else if(hingeAngle > hiLim) + { + m_liftHinge->setLimit(hiLim - LIFT_EPS, hiLim); + } + else + { + m_liftHinge->setLimit(hingeAngle - LIFT_EPS, hingeAngle + LIFT_EPS); + } + return; +} // ForkLiftDemo::lockLiftHinge() + +void ForkLiftDemo::lockForkSlider(void) +{ + btScalar linDepth = m_forkSlider->getLinearPos(); + btScalar lowLim = m_forkSlider->getLowerLinLimit(); + btScalar hiLim = m_forkSlider->getUpperLinLimit(); + m_forkSlider->setPoweredLinMotor(false); + if(linDepth <= lowLim) + { + m_forkSlider->setLowerLinLimit(lowLim); + m_forkSlider->setUpperLinLimit(lowLim); + } + else if(linDepth > hiLim) + { + m_forkSlider->setLowerLinLimit(hiLim); + m_forkSlider->setUpperLinLimit(hiLim); + } + else + { + m_forkSlider->setLowerLinLimit(linDepth); + m_forkSlider->setUpperLinLimit(linDepth); + } + return; +} // ForkLiftDemo::lockForkSlider() diff --git a/Demos/ForkLiftDemo/ForkLiftDemo.h b/Demos/ForkLiftDemo/ForkLiftDemo.h index 9049ca839..4ea08ce28 100644 --- a/Demos/ForkLiftDemo/ForkLiftDemo.h +++ b/Demos/ForkLiftDemo/ForkLiftDemo.h @@ -17,17 +17,59 @@ subject to the following restrictions: class btVehicleTuning; struct btVehicleRaycaster; +class btCollisionShape; + #include "BulletDynamics/Vehicle/btRaycastVehicle.h" +#include "BulletDynamics/ConstraintSolver/btHingeConstraint.h" +#include "BulletDynamics/ConstraintSolver/btSliderConstraint.h" #include "DemoApplication.h" -///ForkLiftDemo shows how to setup and use the built-in raycast vehicle +///VehicleDemo shows how to setup and use the built-in raycast vehicle class ForkLiftDemo : public DemoApplication { public: btRigidBody* m_carChassis; + +//---------------------------- + btRigidBody* m_liftBody; + btVector3 m_liftStartPos; + btHingeConstraint* m_liftHinge; + + btRigidBody* m_forkBody; + btVector3 m_forkStartPos; + btSliderConstraint* m_forkSlider; + + btRigidBody* m_loadBody; + btVector3 m_loadStartPos; + + void lockLiftHinge(void); + void lockForkSlider(void); + + bool m_useDefaultCamera; +//---------------------------- + + + btAlignedObjectArray m_collisionShapes; + + class btBroadphaseInterface* m_overlappingPairCache; + + class btCollisionDispatcher* m_dispatcher; + + class btConstraintSolver* m_constraintSolver; + + class btDefaultCollisionConfiguration* m_collisionConfiguration; + + class btTriangleIndexVertexArray* m_indexVertexArrays; + + btVector3* m_vertices; + + btRaycastVehicle::btVehicleTuning m_tuning; + btVehicleRaycaster* m_vehicleRayCaster; + btRaycastVehicle* m_vehicle; + float m_cameraHeight; float m_minCameraDistance; @@ -36,8 +78,11 @@ class ForkLiftDemo : public DemoApplication ForkLiftDemo(); + virtual ~ForkLiftDemo(); + virtual void clientMoveAndDisplay(); + virtual void clientResetScene(); virtual void displayCallback(); @@ -46,11 +91,22 @@ class ForkLiftDemo : public DemoApplication virtual void specialKeyboard(int key, int x, int y); + virtual void specialKeyboardUp(int key, int x, int y); + void renderme(); - void setupPhysics(); + void initPhysics(); + void termPhysics(); + + static DemoApplication* Create() + { + ForkLiftDemo* demo = new ForkLiftDemo(); + demo->myinit(); + demo->initPhysics(); + return demo; + } }; -#endif //FORKLIFT_DEMO_H +#endif // FORKLIFT_DEMO_H diff --git a/Demos/ForkLiftDemo/main.cpp b/Demos/ForkLiftDemo/main.cpp new file mode 100644 index 000000000..536eeb9e3 --- /dev/null +++ b/Demos/ForkLiftDemo/main.cpp @@ -0,0 +1,15 @@ + +#include "ForkLiftDemo.h" +#include "GlutStuff.h" + + +int main(int argc,char** argv) +{ + + ForkLiftDemo* pForkLiftDemo = new ForkLiftDemo; + + pForkLiftDemo->initPhysics(); + + return glutmain(argc, argv,640,480,"Bullet ForkLift Demo. http://www.continuousphysics.com/Bullet/phpBB2/", pForkLiftDemo); +} +