#ifndef COMMON_RIGID_BODY_SETUP_H #define COMMON_RIGID_BODY_SETUP_H //todo: replace this 'btBulletDynamicsCommon.h' header with specific used header files #include "btBulletDynamicsCommon.h" #include "CommonPhysicsSetup.h" struct CommonRigidBodySetup : public CommonPhysicsSetup { //keep the collision shapes, for deletion/cleanup btAlignedObjectArray m_collisionShapes; btBroadphaseInterface* m_broadphase; btCollisionDispatcher* m_dispatcher; btConstraintSolver* m_solver; btDefaultCollisionConfiguration* m_collisionConfiguration; btDiscreteDynamicsWorld* m_dynamicsWorld; //data for picking objects class btRigidBody* m_pickedBody; class btTypedConstraint* m_pickedConstraint; btVector3 m_oldPickingPos; btVector3 m_hitPos; btScalar m_oldPickingDist; CommonRigidBodySetup() :m_broadphase(0), m_dispatcher(0), m_solver(0), m_collisionConfiguration(0), m_dynamicsWorld(0), m_pickedBody(0), m_pickedConstraint(0) { } virtual void createEmptyDynamicsWorld() { ///collision configuration contains default setup for memory, collision setup m_collisionConfiguration = new btDefaultCollisionConfiguration(); //m_collisionConfiguration->setConvexConvexMultipointIterations(); ///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded) m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration); m_broadphase = new btDbvtBroadphase(); ///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded) btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver; m_solver = sol; m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, m_collisionConfiguration); m_dynamicsWorld->setGravity(btVector3(0, -10, 0)); } virtual void stepSimulation(float deltaTime) { if (m_dynamicsWorld) { m_dynamicsWorld->stepSimulation(deltaTime); } } virtual void exitPhysics() { removePickingConstraint(); //cleanup in the reverse order of creation/initialization //remove the rigidbodies from the dynamics world and delete them int i; for (i = m_dynamicsWorld->getNumConstraints() - 1; i >= 0; i--) { m_dynamicsWorld->removeConstraint(m_dynamicsWorld->getConstraint(i)); } if (m_dynamicsWorld) { 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; jdebugDrawWorld(); } } virtual bool pickBody(const btVector3& rayFromWorld, const btVector3& rayToWorld) { if (m_dynamicsWorld==0) return false; btCollisionWorld::ClosestRayResultCallback rayCallback(rayFromWorld, rayToWorld); m_dynamicsWorld->rayTest(rayFromWorld, rayToWorld, rayCallback); if (rayCallback.hasHit()) { btVector3 pickPos = rayCallback.m_hitPointWorld; btRigidBody* body = (btRigidBody*)btRigidBody::upcast(rayCallback.m_collisionObject); if (body) { //other exclusions? if (!(body->isStaticObject() || body->isKinematicObject())) { m_pickedBody = body; m_pickedBody->setActivationState(DISABLE_DEACTIVATION); //printf("pickPos=%f,%f,%f\n",pickPos.getX(),pickPos.getY(),pickPos.getZ()); btVector3 localPivot = body->getCenterOfMassTransform().inverse() * pickPos; btPoint2PointConstraint* p2p = new btPoint2PointConstraint(*body, localPivot); m_dynamicsWorld->addConstraint(p2p, true); m_pickedConstraint = p2p; btScalar mousePickClamping = 30.f; p2p->m_setting.m_impulseClamp = mousePickClamping; //very weak constraint for picking p2p->m_setting.m_tau = 0.001f; } } // pickObject(pickPos, rayCallback.m_collisionObject); m_oldPickingPos = rayToWorld; m_hitPos = pickPos; m_oldPickingDist = (pickPos - rayFromWorld).length(); // printf("hit !\n"); //add p2p } return false; } virtual bool movePickedBody(const btVector3& rayFromWorld, const btVector3& rayToWorld) { if (m_pickedBody && m_pickedConstraint) { btPoint2PointConstraint* pickCon = static_cast(m_pickedConstraint); if (pickCon) { //keep it at the same picking distance btVector3 newPivotB; btVector3 dir = rayToWorld - rayFromWorld; dir.normalize(); dir *= m_oldPickingDist; newPivotB = rayFromWorld + dir; pickCon->setPivotB(newPivotB); return true; } } return false; } virtual void removePickingConstraint() { if (m_pickedConstraint) { m_dynamicsWorld->removeConstraint(m_pickedConstraint); delete m_pickedConstraint; m_pickedConstraint = 0; m_pickedBody = 0; } } btBoxShape* createBoxShape(const btVector3& halfExtents) { btBoxShape* box = new btBoxShape(halfExtents); m_collisionShapes.push_back(box); return box; } btRigidBody* createRigidBody(float mass, const btTransform& startTransform, btCollisionShape* shape, const btVector4& color = btVector4(1, 0, 0, 1)) { btAssert((!shape || shape->getShapeType() != INVALID_SHAPE_PROXYTYPE)); //rigidbody is dynamic if and only if mass is non zero, otherwise static bool isDynamic = (mass != 0.f); btVector3 localInertia(0, 0, 0); if (isDynamic) shape->calculateLocalInertia(mass, localInertia); //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects #define USE_MOTIONSTATE 1 #ifdef USE_MOTIONSTATE btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform); btRigidBody::btRigidBodyConstructionInfo cInfo(mass, myMotionState, shape, localInertia); btRigidBody* body = new btRigidBody(cInfo); //body->setContactProcessingThreshold(m_defaultContactProcessingThreshold); #else btRigidBody* body = new btRigidBody(mass, 0, shape, localInertia); body->setWorldTransform(startTransform); #endif// body->setUserIndex(-1); m_dynamicsWorld->addRigidBody(body); return body; } }; #endif //COMMON_RIGID_BODY_SETUP_H