1 2 #ifndef COMMON_RIGID_BODY_BASE_H 3 #define COMMON_RIGID_BODY_BASE_H 4 5 #include "btBulletDynamicsCommon.h" 6 #include "CommonExampleInterface.h" 7 #include "CommonGUIHelperInterface.h" 8 #include "CommonRenderInterface.h" 9 #include "CommonCameraInterface.h" 10 #include "CommonGraphicsAppInterface.h" 11 #include "CommonWindowInterface.h" 12 #include "BulletCollision/NarrowPhaseCollision/btRaycastCallback.h" 13 14 struct CommonRigidBodyBase : public CommonExampleInterface 15 { 16 //keep the collision shapes, for deletion/cleanup 17 btAlignedObjectArray<btCollisionShape*> m_collisionShapes; 18 btBroadphaseInterface* m_broadphase; 19 btCollisionDispatcher* m_dispatcher; 20 btConstraintSolver* m_solver; 21 btDefaultCollisionConfiguration* m_collisionConfiguration; 22 btDiscreteDynamicsWorld* m_dynamicsWorld; 23 24 //data for picking objects 25 class btRigidBody* m_pickedBody; 26 class btTypedConstraint* m_pickedConstraint; 27 int m_savedState; 28 btVector3 m_oldPickingPos; 29 btVector3 m_hitPos; 30 btScalar m_oldPickingDist; 31 struct GUIHelperInterface* m_guiHelper; 32 CommonRigidBodyBaseCommonRigidBodyBase33 CommonRigidBodyBase(struct GUIHelperInterface* helper) 34 : m_broadphase(0), 35 m_dispatcher(0), 36 m_solver(0), 37 m_collisionConfiguration(0), 38 m_dynamicsWorld(0), 39 m_pickedBody(0), 40 m_pickedConstraint(0), 41 m_guiHelper(helper) 42 { 43 } ~CommonRigidBodyBaseCommonRigidBodyBase44 virtual ~CommonRigidBodyBase() 45 { 46 } 47 getDynamicsWorldCommonRigidBodyBase48 btDiscreteDynamicsWorld* getDynamicsWorld() 49 { 50 return m_dynamicsWorld; 51 } 52 createEmptyDynamicsWorldCommonRigidBodyBase53 virtual void createEmptyDynamicsWorld() 54 { 55 ///collision configuration contains default setup for memory, collision setup 56 m_collisionConfiguration = new btDefaultCollisionConfiguration(); 57 //m_collisionConfiguration->setConvexConvexMultipointIterations(); 58 59 ///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded) 60 m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration); 61 62 m_broadphase = new btDbvtBroadphase(); 63 64 ///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded) 65 btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver; 66 m_solver = sol; 67 68 m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, m_collisionConfiguration); 69 70 m_dynamicsWorld->setGravity(btVector3(0, -10, 0)); 71 } 72 stepSimulationCommonRigidBodyBase73 virtual void stepSimulation(float deltaTime) 74 { 75 if (m_dynamicsWorld) 76 { 77 m_dynamicsWorld->stepSimulation(deltaTime); 78 } 79 } 80 physicsDebugDrawCommonRigidBodyBase81 virtual void physicsDebugDraw(int debugFlags) 82 { 83 if (m_dynamicsWorld && m_dynamicsWorld->getDebugDrawer()) 84 { 85 m_dynamicsWorld->getDebugDrawer()->setDebugMode(debugFlags); 86 m_dynamicsWorld->debugDrawWorld(); 87 } 88 } 89 exitPhysicsCommonRigidBodyBase90 virtual void exitPhysics() 91 { 92 removePickingConstraint(); 93 //cleanup in the reverse order of creation/initialization 94 95 //remove the rigidbodies from the dynamics world and delete them 96 97 if (m_dynamicsWorld) 98 { 99 int i; 100 for (i = m_dynamicsWorld->getNumConstraints() - 1; i >= 0; i--) 101 { 102 m_dynamicsWorld->removeConstraint(m_dynamicsWorld->getConstraint(i)); 103 } 104 for (i = m_dynamicsWorld->getNumCollisionObjects() - 1; i >= 0; i--) 105 { 106 btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i]; 107 btRigidBody* body = btRigidBody::upcast(obj); 108 if (body && body->getMotionState()) 109 { 110 delete body->getMotionState(); 111 } 112 m_dynamicsWorld->removeCollisionObject(obj); 113 delete obj; 114 } 115 } 116 //delete collision shapes 117 for (int j = 0; j < m_collisionShapes.size(); j++) 118 { 119 btCollisionShape* shape = m_collisionShapes[j]; 120 delete shape; 121 } 122 m_collisionShapes.clear(); 123 124 delete m_dynamicsWorld; 125 m_dynamicsWorld = 0; 126 127 delete m_solver; 128 m_solver = 0; 129 130 delete m_broadphase; 131 m_broadphase = 0; 132 133 delete m_dispatcher; 134 m_dispatcher = 0; 135 136 delete m_collisionConfiguration; 137 m_collisionConfiguration = 0; 138 } 139 debugDrawCommonRigidBodyBase140 virtual void debugDraw(int debugDrawFlags) 141 { 142 if (m_dynamicsWorld) 143 { 144 if (m_dynamicsWorld->getDebugDrawer()) 145 { 146 m_dynamicsWorld->getDebugDrawer()->setDebugMode(debugDrawFlags); 147 } 148 m_dynamicsWorld->debugDrawWorld(); 149 } 150 } 151 keyboardCallbackCommonRigidBodyBase152 virtual bool keyboardCallback(int key, int state) 153 { 154 if ((key == B3G_F3) && state && m_dynamicsWorld) 155 { 156 btDefaultSerializer* serializer = new btDefaultSerializer(); 157 m_dynamicsWorld->serialize(serializer); 158 159 FILE* file = fopen("testFile.bullet", "wb"); 160 fwrite(serializer->getBufferPointer(), serializer->getCurrentBufferSize(), 1, file); 161 fclose(file); 162 //b3Printf("btDefaultSerializer wrote testFile.bullet"); 163 delete serializer; 164 return true; 165 } 166 return false; //don't handle this key 167 } 168 getRayToCommonRigidBodyBase169 btVector3 getRayTo(int x, int y) 170 { 171 CommonRenderInterface* renderer = m_guiHelper->getRenderInterface(); 172 173 if (!renderer) 174 { 175 btAssert(0); 176 return btVector3(0, 0, 0); 177 } 178 179 float top = 1.f; 180 float bottom = -1.f; 181 float nearPlane = 1.f; 182 float tanFov = (top - bottom) * 0.5f / nearPlane; 183 float fov = btScalar(2.0) * btAtan(tanFov); 184 185 btVector3 camPos, camTarget; 186 187 renderer->getActiveCamera()->getCameraPosition(camPos); 188 renderer->getActiveCamera()->getCameraTargetPosition(camTarget); 189 190 btVector3 rayFrom = camPos; 191 btVector3 rayForward = (camTarget - camPos); 192 rayForward.normalize(); 193 float farPlane = 10000.f; 194 rayForward *= farPlane; 195 196 btVector3 rightOffset; 197 btVector3 cameraUp = btVector3(0, 0, 0); 198 cameraUp[m_guiHelper->getAppInterface()->getUpAxis()] = 1; 199 200 btVector3 vertical = cameraUp; 201 202 btVector3 hor; 203 hor = rayForward.cross(vertical); 204 hor.safeNormalize(); 205 vertical = hor.cross(rayForward); 206 vertical.safeNormalize(); 207 208 float tanfov = tanf(0.5f * fov); 209 210 hor *= 2.f * farPlane * tanfov; 211 vertical *= 2.f * farPlane * tanfov; 212 213 btScalar aspect; 214 float width = float(renderer->getScreenWidth()); 215 float height = float(renderer->getScreenHeight()); 216 217 aspect = width / height; 218 219 hor *= aspect; 220 221 btVector3 rayToCenter = rayFrom + rayForward; 222 btVector3 dHor = hor * 1.f / width; 223 btVector3 dVert = vertical * 1.f / height; 224 225 btVector3 rayTo = rayToCenter - 0.5f * hor + 0.5f * vertical; 226 rayTo += btScalar(x) * dHor; 227 rayTo -= btScalar(y) * dVert; 228 return rayTo; 229 } 230 mouseMoveCallbackCommonRigidBodyBase231 virtual bool mouseMoveCallback(float x, float y) 232 { 233 CommonRenderInterface* renderer = m_guiHelper->getRenderInterface(); 234 235 if (!renderer) 236 { 237 btAssert(0); 238 return false; 239 } 240 241 btVector3 rayTo = getRayTo(int(x), int(y)); 242 btVector3 rayFrom; 243 renderer->getActiveCamera()->getCameraPosition(rayFrom); 244 movePickedBody(rayFrom, rayTo); 245 246 return false; 247 } 248 mouseButtonCallbackCommonRigidBodyBase249 virtual bool mouseButtonCallback(int button, int state, float x, float y) 250 { 251 CommonRenderInterface* renderer = m_guiHelper->getRenderInterface(); 252 253 if (!renderer) 254 { 255 btAssert(0); 256 return false; 257 } 258 259 CommonWindowInterface* window = m_guiHelper->getAppInterface()->m_window; 260 261 #if 0 262 if (window->isModifierKeyPressed(B3G_ALT)) 263 { 264 printf("ALT pressed\n"); 265 } else 266 { 267 printf("NO ALT pressed\n"); 268 } 269 270 if (window->isModifierKeyPressed(B3G_SHIFT)) 271 { 272 printf("SHIFT pressed\n"); 273 } else 274 { 275 printf("NO SHIFT pressed\n"); 276 } 277 278 if (window->isModifierKeyPressed(B3G_CONTROL)) 279 { 280 printf("CONTROL pressed\n"); 281 } else 282 { 283 printf("NO CONTROL pressed\n"); 284 } 285 #endif 286 287 if (state == 1) 288 { 289 if (button == 0 && (!window->isModifierKeyPressed(B3G_ALT) && !window->isModifierKeyPressed(B3G_CONTROL))) 290 { 291 btVector3 camPos; 292 renderer->getActiveCamera()->getCameraPosition(camPos); 293 294 btVector3 rayFrom = camPos; 295 btVector3 rayTo = getRayTo(int(x), int(y)); 296 297 pickBody(rayFrom, rayTo); 298 } 299 } 300 else 301 { 302 if (button == 0) 303 { 304 removePickingConstraint(); 305 //remove p2p 306 } 307 } 308 309 //printf("button=%d, state=%d\n",button,state); 310 return false; 311 } 312 pickBodyCommonRigidBodyBase313 virtual bool pickBody(const btVector3& rayFromWorld, const btVector3& rayToWorld) 314 { 315 if (m_dynamicsWorld == 0) 316 return false; 317 318 btCollisionWorld::ClosestRayResultCallback rayCallback(rayFromWorld, rayToWorld); 319 320 rayCallback.m_flags |= btTriangleRaycastCallback::kF_UseGjkConvexCastRaytest; 321 m_dynamicsWorld->rayTest(rayFromWorld, rayToWorld, rayCallback); 322 if (rayCallback.hasHit()) 323 { 324 btVector3 pickPos = rayCallback.m_hitPointWorld; 325 btRigidBody* body = (btRigidBody*)btRigidBody::upcast(rayCallback.m_collisionObject); 326 if (body) 327 { 328 //other exclusions? 329 if (!(body->isStaticObject() || body->isKinematicObject())) 330 { 331 m_pickedBody = body; 332 m_savedState = m_pickedBody->getActivationState(); 333 m_pickedBody->setActivationState(DISABLE_DEACTIVATION); 334 //printf("pickPos=%f,%f,%f\n",pickPos.getX(),pickPos.getY(),pickPos.getZ()); 335 btVector3 localPivot = body->getCenterOfMassTransform().inverse() * pickPos; 336 btPoint2PointConstraint* p2p = new btPoint2PointConstraint(*body, localPivot); 337 m_dynamicsWorld->addConstraint(p2p, true); 338 m_pickedConstraint = p2p; 339 btScalar mousePickClamping = 30.f; 340 p2p->m_setting.m_impulseClamp = mousePickClamping; 341 //very weak constraint for picking 342 p2p->m_setting.m_tau = 0.001f; 343 } 344 } 345 346 // pickObject(pickPos, rayCallback.m_collisionObject); 347 m_oldPickingPos = rayToWorld; 348 m_hitPos = pickPos; 349 m_oldPickingDist = (pickPos - rayFromWorld).length(); 350 // printf("hit !\n"); 351 //add p2p 352 } 353 return false; 354 } movePickedBodyCommonRigidBodyBase355 virtual bool movePickedBody(const btVector3& rayFromWorld, const btVector3& rayToWorld) 356 { 357 if (m_pickedBody && m_pickedConstraint) 358 { 359 btPoint2PointConstraint* pickCon = static_cast<btPoint2PointConstraint*>(m_pickedConstraint); 360 if (pickCon) 361 { 362 //keep it at the same picking distance 363 364 btVector3 newPivotB; 365 366 btVector3 dir = rayToWorld - rayFromWorld; 367 dir.normalize(); 368 dir *= m_oldPickingDist; 369 370 newPivotB = rayFromWorld + dir; 371 pickCon->setPivotB(newPivotB); 372 return true; 373 } 374 } 375 return false; 376 } removePickingConstraintCommonRigidBodyBase377 virtual void removePickingConstraint() 378 { 379 if (m_pickedConstraint) 380 { 381 m_pickedBody->forceActivationState(m_savedState); 382 m_pickedBody->activate(); 383 m_dynamicsWorld->removeConstraint(m_pickedConstraint); 384 delete m_pickedConstraint; 385 m_pickedConstraint = 0; 386 m_pickedBody = 0; 387 } 388 } 389 createBoxShapeCommonRigidBodyBase390 btBoxShape* createBoxShape(const btVector3& halfExtents) 391 { 392 btBoxShape* box = new btBoxShape(halfExtents); 393 return box; 394 } 395 deleteRigidBodyCommonRigidBodyBase396 void deleteRigidBody(btRigidBody* body) 397 { 398 int graphicsUid = body->getUserIndex(); 399 m_guiHelper->removeGraphicsInstance(graphicsUid); 400 401 m_dynamicsWorld->removeRigidBody(body); 402 btMotionState* ms = body->getMotionState(); 403 delete body; 404 delete ms; 405 } 406 407 btRigidBody* createRigidBody(float mass, const btTransform& startTransform, btCollisionShape* shape, const btVector4& color = btVector4(1, 0, 0, 1)) 408 { 409 btAssert((!shape || shape->getShapeType() != INVALID_SHAPE_PROXYTYPE)); 410 411 //rigidbody is dynamic if and only if mass is non zero, otherwise static 412 bool isDynamic = (mass != 0.f); 413 414 btVector3 localInertia(0, 0, 0); 415 if (isDynamic) 416 shape->calculateLocalInertia(mass, localInertia); 417 418 //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects 419 420 #define USE_MOTIONSTATE 1 421 #ifdef USE_MOTIONSTATE 422 btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform); 423 424 btRigidBody::btRigidBodyConstructionInfo cInfo(mass, myMotionState, shape, localInertia); 425 426 btRigidBody* body = new btRigidBody(cInfo); 427 //body->setContactProcessingThreshold(m_defaultContactProcessingThreshold); 428 429 #else 430 btRigidBody* body = new btRigidBody(mass, 0, shape, localInertia); 431 body->setWorldTransform(startTransform); 432 #endif // 433 434 body->setUserIndex(-1); 435 m_dynamicsWorld->addRigidBody(body); 436 return body; 437 } 438 renderSceneCommonRigidBodyBase439 virtual void renderScene() 440 { 441 if (m_dynamicsWorld) 442 { 443 { 444 m_guiHelper->syncPhysicsToGraphics(m_dynamicsWorld); 445 } 446 447 { 448 m_guiHelper->render(m_dynamicsWorld); 449 } 450 } 451 } 452 }; 453 454 #endif //COMMON_RIGID_BODY_SETUP_H 455