Panda3D
|
00001 // Filename: bulletWorld.cxx 00002 // Created by: enn0x (23Jan10) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "bulletWorld.h" 00016 #include "bulletPersistentManifold.h" 00017 #include "bulletShape.h" 00018 #include "bulletSoftBodyWorldInfo.h" 00019 00020 #include "collideMask.h" 00021 00022 #define clamp(x, x_min, x_max) max(min(x, x_max), x_min) 00023 00024 TypeHandle BulletWorld::_type_handle; 00025 00026 PStatCollector BulletWorld::_pstat_physics("App:Bullet:DoPhysics"); 00027 PStatCollector BulletWorld::_pstat_simulation("App:Bullet:DoPhysics:Simulation"); 00028 PStatCollector BulletWorld::_pstat_debug("App:Bullet:DoPhysics:Debug"); 00029 PStatCollector BulletWorld::_pstat_p2b("App:Bullet:DoPhysics:SyncP2B"); 00030 PStatCollector BulletWorld::_pstat_b2p("App:Bullet:DoPhysics:SyncB2P"); 00031 00032 //////////////////////////////////////////////////////////////////// 00033 // Function: BulletWorld::Constructor 00034 // Access: Published 00035 // Description: 00036 //////////////////////////////////////////////////////////////////// 00037 BulletWorld:: 00038 BulletWorld() { 00039 00040 // Init groups filter matrix 00041 for (int i=0; i<32; i++) { 00042 _filter_cb2._collide[i].clear(); 00043 _filter_cb2._collide[i].set_bit(i); 00044 } 00045 00046 // Broadphase 00047 btScalar dx(bullet_sap_extents); 00048 btVector3 extents(dx, dx, dx); 00049 00050 switch (bullet_broadphase_algorithm) { 00051 case BA_sweep_and_prune: 00052 _broadphase = new btAxisSweep3(extents, extents, 1024); 00053 break; 00054 case BA_dynamic_aabb_tree: 00055 _broadphase = new btDbvtBroadphase(); 00056 break; 00057 default: 00058 bullet_cat.error() << "no proper broadphase algorithm!" << endl; 00059 } 00060 00061 // Configuration 00062 _configuration = new btSoftBodyRigidBodyCollisionConfiguration(); 00063 00064 // Dispatcher 00065 _dispatcher = new btCollisionDispatcher(_configuration); 00066 00067 // Solver 00068 _solver = new btSequentialImpulseConstraintSolver; 00069 00070 // World 00071 _world = new btSoftRigidDynamicsWorld(_dispatcher, _broadphase, _solver, _configuration); 00072 _world->setGravity(btVector3(0.0f, 0.0f, 0.0f)); 00073 00074 // Ghost-pair callback 00075 _world->getPairCache()->setInternalGhostPairCallback(&_ghost_cb); 00076 00077 // Filter callback 00078 switch (bullet_filter_algorithm) { 00079 case FA_mask: 00080 _world->getPairCache()->setOverlapFilterCallback(&_filter_cb1); 00081 break; 00082 case FA_groups_mask: 00083 _world->getPairCache()->setOverlapFilterCallback(&_filter_cb2); 00084 break; 00085 default: 00086 bullet_cat.error() << "no proper filter algorithm!" << endl; 00087 } 00088 00089 // SoftBodyWorldInfo 00090 _info.m_dispatcher = _dispatcher; 00091 _info.m_broadphase = _broadphase; 00092 _info.m_gravity = _world->getGravity(); 00093 _info.m_sparsesdf.Initialize(); 00094 00095 // Register GIMPACT algorithm 00096 btGImpactCollisionAlgorithm::registerAlgorithm(_dispatcher); 00097 00098 // Some prefered settings 00099 _world->getDispatchInfo().m_enableSPU = true; // default: true 00100 _world->getDispatchInfo().m_useContinuous = true; // default: true 00101 _world->getSolverInfo().m_splitImpulse = false; // default: false 00102 _world->getSolverInfo().m_numIterations = bullet_solver_iterations; 00103 } 00104 00105 //////////////////////////////////////////////////////////////////// 00106 // Function: BulletWorld::get_world_info 00107 // Access: Published 00108 // Description: 00109 //////////////////////////////////////////////////////////////////// 00110 BulletSoftBodyWorldInfo BulletWorld:: 00111 get_world_info() { 00112 00113 return BulletSoftBodyWorldInfo(_info); 00114 } 00115 00116 //////////////////////////////////////////////////////////////////// 00117 // Function: BulletWorld::set_gravity 00118 // Access: Published 00119 // Description: 00120 //////////////////////////////////////////////////////////////////// 00121 void BulletWorld:: 00122 set_gravity(const LVector3 &gravity) { 00123 00124 _world->setGravity(LVecBase3_to_btVector3(gravity)); 00125 _info.m_gravity = _world->getGravity(); 00126 } 00127 00128 //////////////////////////////////////////////////////////////////// 00129 // Function: BulletWorld::set_gravity 00130 // Access: Published 00131 // Description: 00132 //////////////////////////////////////////////////////////////////// 00133 void BulletWorld:: 00134 set_gravity(PN_stdfloat gx, PN_stdfloat gy, PN_stdfloat gz) { 00135 00136 _world->setGravity(btVector3((btScalar)gx, (btScalar)gy, (btScalar)gz)); 00137 _info.m_gravity = _world->getGravity(); 00138 } 00139 00140 //////////////////////////////////////////////////////////////////// 00141 // Function: BulletWorld::get_gravity 00142 // Access: Published 00143 // Description: 00144 //////////////////////////////////////////////////////////////////// 00145 const LVector3 BulletWorld:: 00146 get_gravity() const { 00147 00148 return btVector3_to_LVector3(_world->getGravity()); 00149 } 00150 00151 //////////////////////////////////////////////////////////////////// 00152 // Function: BulletWorld::do_physics 00153 // Access: Published 00154 // Description: 00155 //////////////////////////////////////////////////////////////////// 00156 int BulletWorld:: 00157 do_physics(PN_stdfloat dt, int max_substeps, PN_stdfloat stepsize) { 00158 00159 _pstat_physics.start(); 00160 00161 int num_substeps = clamp(int(dt / stepsize), 1, max_substeps); 00162 00163 // Synchronize Panda to Bullet 00164 _pstat_p2b.start(); 00165 sync_p2b(dt, num_substeps); 00166 _pstat_p2b.stop(); 00167 00168 // Simulation 00169 _pstat_simulation.start(); 00170 int n = _world->stepSimulation((btScalar)dt, max_substeps, (btScalar)stepsize); 00171 _pstat_simulation.stop(); 00172 00173 // Synchronize Bullet to Panda 00174 _pstat_b2p.start(); 00175 sync_b2p(); 00176 _info.m_sparsesdf.GarbageCollect(bullet_gc_lifetime); 00177 _pstat_b2p.stop(); 00178 00179 // Render debug 00180 if (_debug) { 00181 _pstat_debug.start(); 00182 _debug->sync_b2p(_world); 00183 _pstat_debug.stop(); 00184 } 00185 00186 _pstat_physics.stop(); 00187 00188 return n; 00189 } 00190 00191 //////////////////////////////////////////////////////////////////// 00192 // Function: BulletWorld::sync_p2b 00193 // Access: Private 00194 // Description: 00195 //////////////////////////////////////////////////////////////////// 00196 void BulletWorld:: 00197 sync_p2b(PN_stdfloat dt, int num_substeps) { 00198 00199 for (int i=0; i < get_num_rigid_bodies(); i++) { 00200 get_rigid_body(i)->sync_p2b(); 00201 } 00202 00203 for (int i=0; i < get_num_soft_bodies(); i++) { 00204 get_soft_body(i)->sync_p2b(); 00205 } 00206 00207 for (int i=0; i < get_num_ghosts(); i++) { 00208 get_ghost(i)->sync_p2b(); 00209 } 00210 00211 for (int i=0; i < get_num_characters(); i++) { 00212 get_character(i)->sync_p2b(dt, num_substeps); 00213 } 00214 } 00215 00216 //////////////////////////////////////////////////////////////////// 00217 // Function: BulletWorld::sync_b2p 00218 // Access: Private 00219 // Description: 00220 //////////////////////////////////////////////////////////////////// 00221 void BulletWorld:: 00222 sync_b2p() { 00223 00224 for (int i=0; i < get_num_vehicles(); i++) { 00225 get_vehicle(i)->sync_b2p(); 00226 } 00227 00228 for (int i=0; i < get_num_rigid_bodies(); i++) { 00229 get_rigid_body(i)->sync_b2p(); 00230 } 00231 00232 for (int i=0; i < get_num_soft_bodies(); i++) { 00233 get_soft_body(i)->sync_b2p(); 00234 } 00235 00236 for (int i=0; i < get_num_ghosts(); i++) { 00237 get_ghost(i)->sync_b2p(); 00238 } 00239 00240 for (int i=0; i < get_num_characters(); i++) { 00241 get_character(i)->sync_b2p(); 00242 } 00243 } 00244 00245 //////////////////////////////////////////////////////////////////// 00246 // Function: BulletWorld::set_debug_node 00247 // Access: Published 00248 // Description: 00249 //////////////////////////////////////////////////////////////////// 00250 void BulletWorld:: 00251 set_debug_node(BulletDebugNode *node) { 00252 00253 nassertv(node); 00254 00255 _debug = node; 00256 _world->setDebugDrawer(&(_debug->_drawer)); 00257 } 00258 00259 //////////////////////////////////////////////////////////////////// 00260 // Function: BulletWorld::clear_debug_node 00261 // Access: Published 00262 // Description: 00263 //////////////////////////////////////////////////////////////////// 00264 void BulletWorld:: 00265 clear_debug_node() { 00266 00267 _debug = NULL; 00268 _world->setDebugDrawer(NULL); 00269 } 00270 00271 //////////////////////////////////////////////////////////////////// 00272 // Function: BulletWorld::attach_rigid_body 00273 // Access: Published 00274 // Description: 00275 //////////////////////////////////////////////////////////////////// 00276 void BulletWorld:: 00277 attach_rigid_body(BulletRigidBodyNode *node) { 00278 00279 nassertv(node); 00280 00281 btRigidBody *ptr = btRigidBody::upcast(node->get_object()); 00282 00283 BulletRigidBodies::iterator found; 00284 PT(BulletRigidBodyNode) ptnode = node; 00285 found = find(_bodies.begin(), _bodies.end(), ptnode); 00286 00287 if (found == _bodies.end()) { 00288 _bodies.push_back(node); 00289 _world->addRigidBody(ptr); 00290 } 00291 else { 00292 bullet_cat.warning() << "rigid body already attached" << endl; 00293 } 00294 } 00295 00296 //////////////////////////////////////////////////////////////////// 00297 // Function: BulletWorld::remove_rigid_body 00298 // Access: Published 00299 // Description: 00300 //////////////////////////////////////////////////////////////////// 00301 void BulletWorld:: 00302 remove_rigid_body(BulletRigidBodyNode *node) { 00303 00304 nassertv(node); 00305 00306 btRigidBody *ptr = btRigidBody::upcast(node->get_object()); 00307 00308 BulletRigidBodies::iterator found; 00309 PT(BulletRigidBodyNode) ptnode = node; 00310 found = find(_bodies.begin(), _bodies.end(), ptnode); 00311 00312 if (found == _bodies.end()) { 00313 bullet_cat.warning() << "rigid body not attached" << endl; 00314 } 00315 else { 00316 _bodies.erase(found); 00317 _world->removeRigidBody(ptr); 00318 } 00319 } 00320 00321 //////////////////////////////////////////////////////////////////// 00322 // Function: BulletWorld::attach_soft_body 00323 // Access: Published 00324 // Description: 00325 //////////////////////////////////////////////////////////////////// 00326 void BulletWorld:: 00327 attach_soft_body(BulletSoftBodyNode *node) { 00328 00329 nassertv(node); 00330 00331 btSoftBody *ptr = btSoftBody::upcast(node->get_object()); 00332 00333 // TODO: group/filter settings (see ghost objects too) 00334 short group = btBroadphaseProxy::DefaultFilter; 00335 short mask = btBroadphaseProxy::AllFilter; 00336 00337 BulletSoftBodies::iterator found; 00338 PT(BulletSoftBodyNode) ptnode = node; 00339 found = find(_softbodies.begin(), _softbodies.end(), ptnode); 00340 00341 if (found == _softbodies.end()) { 00342 _softbodies.push_back(node); 00343 _world->addSoftBody(ptr, group, mask); 00344 } 00345 else { 00346 bullet_cat.warning() << "soft body already attached" << endl; 00347 } 00348 } 00349 00350 //////////////////////////////////////////////////////////////////// 00351 // Function: BulletWorld::remove_soft_body 00352 // Access: Published 00353 // Description: 00354 //////////////////////////////////////////////////////////////////// 00355 void BulletWorld:: 00356 remove_soft_body(BulletSoftBodyNode *node) { 00357 00358 nassertv(node); 00359 00360 btSoftBody *ptr = btSoftBody::upcast(node->get_object()); 00361 00362 BulletSoftBodies::iterator found; 00363 PT(BulletSoftBodyNode) ptnode = node; 00364 found = find(_softbodies.begin(), _softbodies.end(), ptnode); 00365 00366 if (found == _softbodies.end()) { 00367 bullet_cat.warning() << "soft body not attached" << endl; 00368 } 00369 else { 00370 _softbodies.erase(found); 00371 _world->removeSoftBody(ptr); 00372 } 00373 } 00374 00375 //////////////////////////////////////////////////////////////////// 00376 // Function: BulletWorld::attach_ghost 00377 // Access: Published 00378 // Description: 00379 //////////////////////////////////////////////////////////////////// 00380 void BulletWorld:: 00381 attach_ghost(BulletGhostNode *node) { 00382 00383 nassertv(node); 00384 00385 // TODO group/filter settings... 00386 /* 00387 enum CollisionFilterGroups { 00388 DefaultFilter = 1, 00389 StaticFilter = 2, 00390 KinematicFilter = 4, 00391 DebrisFilter = 8, 00392 SensorTrigger = 16, 00393 CharacterFilter = 32, 00394 AllFilter = -1 00395 } 00396 */ 00397 00398 short group = btBroadphaseProxy::SensorTrigger; 00399 short mask = btBroadphaseProxy::AllFilter 00400 & ~btBroadphaseProxy::StaticFilter 00401 & ~btBroadphaseProxy::SensorTrigger; 00402 00403 btGhostObject *ptr = btGhostObject::upcast(node->get_object()); 00404 00405 BulletGhosts::iterator found; 00406 PT(BulletGhostNode) ptnode = node; 00407 found = find(_ghosts.begin(), _ghosts.end(), ptnode); 00408 00409 if (found == _ghosts.end()) { 00410 _ghosts.push_back(node); 00411 _world->addCollisionObject(ptr, group, mask); 00412 } 00413 else { 00414 bullet_cat.warning() << "ghost already attached" << endl; 00415 } 00416 } 00417 00418 //////////////////////////////////////////////////////////////////// 00419 // Function: BulletWorld::remove_ghost 00420 // Access: Published 00421 // Description: 00422 //////////////////////////////////////////////////////////////////// 00423 void BulletWorld:: 00424 remove_ghost(BulletGhostNode *node) { 00425 00426 nassertv(node); 00427 00428 btGhostObject *ptr = btGhostObject::upcast(node->get_object()); 00429 00430 BulletGhosts::iterator found; 00431 PT(BulletGhostNode) ptnode = node; 00432 found = find(_ghosts.begin(), _ghosts.end(), ptnode); 00433 00434 if (found == _ghosts.end()) { 00435 bullet_cat.warning() << "ghost not attached" << endl; 00436 } 00437 else { 00438 _ghosts.erase(found); 00439 _world->removeCollisionObject(ptr); 00440 } 00441 } 00442 00443 //////////////////////////////////////////////////////////////////// 00444 // Function: BulletWorld::attach_character 00445 // Access: Published 00446 // Description: 00447 //////////////////////////////////////////////////////////////////// 00448 void BulletWorld:: 00449 attach_character(BulletBaseCharacterControllerNode *node) { 00450 00451 nassertv(node); 00452 00453 BulletCharacterControllers::iterator found; 00454 PT(BulletBaseCharacterControllerNode) ptnode = node; 00455 found = find(_characters.begin(), _characters.end(), ptnode); 00456 00457 if (found == _characters.end()) { 00458 _characters.push_back(node); 00459 00460 _world->addCollisionObject(node->get_ghost(), 00461 btBroadphaseProxy::CharacterFilter, 00462 btBroadphaseProxy::StaticFilter|btBroadphaseProxy::DefaultFilter); 00463 00464 _world->addCharacter(node->get_character()); 00465 } 00466 else { 00467 bullet_cat.warning() << "character already attached" << endl; 00468 } 00469 } 00470 00471 //////////////////////////////////////////////////////////////////// 00472 // Function: BulletWorld::remove_character 00473 // Access: Published 00474 // Description: 00475 //////////////////////////////////////////////////////////////////// 00476 void BulletWorld:: 00477 remove_character(BulletBaseCharacterControllerNode *node) { 00478 00479 nassertv(node); 00480 00481 BulletCharacterControllers::iterator found; 00482 PT(BulletBaseCharacterControllerNode) ptnode = node; 00483 found = find(_characters.begin(), _characters.end(), ptnode); 00484 00485 if (found == _characters.end()) { 00486 bullet_cat.warning() << "character not attached" << endl; 00487 } 00488 else { 00489 _characters.erase(found); 00490 _world->removeCollisionObject(node->get_ghost()); 00491 _world->removeCharacter(node->get_character()); 00492 } 00493 } 00494 00495 //////////////////////////////////////////////////////////////////// 00496 // Function: BulletWorld::attach_vehicle 00497 // Access: Published 00498 // Description: 00499 //////////////////////////////////////////////////////////////////// 00500 void BulletWorld:: 00501 attach_vehicle(BulletVehicle *vehicle) { 00502 00503 nassertv(vehicle); 00504 00505 BulletVehicles::iterator found; 00506 PT(BulletVehicle) ptvehicle = vehicle; 00507 found = find(_vehicles.begin(), _vehicles.end(), ptvehicle); 00508 00509 if (found == _vehicles.end()) { 00510 _vehicles.push_back(vehicle); 00511 _world->addVehicle(vehicle->get_vehicle()); 00512 } 00513 else { 00514 bullet_cat.warning() << "vehicle already attached" << endl; 00515 } 00516 } 00517 00518 //////////////////////////////////////////////////////////////////// 00519 // Function: BulletWorld::remove_vehicle 00520 // Access: Published 00521 // Description: 00522 //////////////////////////////////////////////////////////////////// 00523 void BulletWorld:: 00524 remove_vehicle(BulletVehicle *vehicle) { 00525 00526 nassertv(vehicle); 00527 00528 remove_rigid_body(vehicle->get_chassis()); 00529 00530 BulletVehicles::iterator found; 00531 PT(BulletVehicle) ptvehicle = vehicle; 00532 found = find(_vehicles.begin(), _vehicles.end(), ptvehicle); 00533 00534 if (found == _vehicles.end()) { 00535 bullet_cat.warning() << "vehicle not attached" << endl; 00536 } 00537 else { 00538 _vehicles.erase(found); 00539 _world->removeVehicle(vehicle->get_vehicle()); 00540 } 00541 } 00542 00543 //////////////////////////////////////////////////////////////////// 00544 // Function: BulletWorld::attach_constraint 00545 // Access: Published 00546 // Description: 00547 //////////////////////////////////////////////////////////////////// 00548 void BulletWorld:: 00549 attach_constraint(BulletConstraint *constraint) { 00550 00551 nassertv(constraint); 00552 00553 BulletConstraints::iterator found; 00554 PT(BulletConstraint) ptconstraint = constraint; 00555 found = find(_constraints.begin(), _constraints.end(), ptconstraint); 00556 00557 if (found == _constraints.end()) { 00558 _constraints.push_back(constraint); 00559 _world->addConstraint(constraint->ptr()); 00560 } 00561 else { 00562 bullet_cat.warning() << "constraint already attached" << endl; 00563 } 00564 } 00565 00566 //////////////////////////////////////////////////////////////////// 00567 // Function: BulletWorld::remove_constraint 00568 // Access: Published 00569 // Description: 00570 //////////////////////////////////////////////////////////////////// 00571 void BulletWorld:: 00572 remove_constraint(BulletConstraint *constraint) { 00573 00574 nassertv(constraint); 00575 00576 BulletConstraints::iterator found; 00577 PT(BulletConstraint) ptconstraint = constraint; 00578 found = find(_constraints.begin(), _constraints.end(), ptconstraint); 00579 00580 if (found == _constraints.end()) { 00581 bullet_cat.warning() << "constraint not attached" << endl; 00582 } 00583 else { 00584 _constraints.erase(found); 00585 _world->removeConstraint(constraint->ptr()); 00586 } 00587 } 00588 00589 //////////////////////////////////////////////////////////////////// 00590 // Function: BulletWorld::ray_test_closest 00591 // Access: Published 00592 // Description: 00593 //////////////////////////////////////////////////////////////////// 00594 BulletClosestHitRayResult BulletWorld:: 00595 ray_test_closest(const LPoint3 &from_pos, const LPoint3 &to_pos, const CollideMask &mask) const { 00596 00597 nassertr(!from_pos.is_nan(), BulletClosestHitRayResult::empty()); 00598 nassertr(!to_pos.is_nan(), BulletClosestHitRayResult::empty()); 00599 00600 const btVector3 from = LVecBase3_to_btVector3(from_pos); 00601 const btVector3 to = LVecBase3_to_btVector3(to_pos); 00602 00603 BulletClosestHitRayResult cb(from, to, mask); 00604 _world->rayTest(from, to, cb); 00605 return cb; 00606 } 00607 00608 //////////////////////////////////////////////////////////////////// 00609 // Function: BulletWorld::ray_test_all 00610 // Access: Published 00611 // Description: 00612 //////////////////////////////////////////////////////////////////// 00613 BulletAllHitsRayResult BulletWorld:: 00614 ray_test_all(const LPoint3 &from_pos, const LPoint3 &to_pos, const CollideMask &mask) const { 00615 00616 nassertr(!from_pos.is_nan(), BulletAllHitsRayResult::empty()); 00617 nassertr(!to_pos.is_nan(), BulletAllHitsRayResult::empty()); 00618 00619 const btVector3 from = LVecBase3_to_btVector3(from_pos); 00620 const btVector3 to = LVecBase3_to_btVector3(to_pos); 00621 00622 BulletAllHitsRayResult cb(from, to, mask); 00623 _world->rayTest(from, to, cb); 00624 return cb; 00625 } 00626 00627 //////////////////////////////////////////////////////////////////// 00628 // Function: BulletWorld::sweep_test_closest 00629 // Access: Published 00630 // Description: 00631 //////////////////////////////////////////////////////////////////// 00632 BulletClosestHitSweepResult BulletWorld:: 00633 sweep_test_closest(BulletShape *shape, const TransformState &from_ts, const TransformState &to_ts, const CollideMask &mask, PN_stdfloat penetration) const { 00634 00635 nassertr(shape, BulletClosestHitSweepResult::empty()); 00636 nassertr(shape->is_convex(), BulletClosestHitSweepResult::empty()); 00637 nassertr(!from_ts.is_invalid(), BulletClosestHitSweepResult::empty()); 00638 nassertr(!to_ts.is_invalid(), BulletClosestHitSweepResult::empty()); 00639 00640 const btConvexShape *convex = (const btConvexShape *) shape->ptr(); 00641 const btVector3 from_pos = LVecBase3_to_btVector3(from_ts.get_pos()); 00642 const btVector3 to_pos = LVecBase3_to_btVector3(to_ts.get_pos()); 00643 const btTransform from_trans = LMatrix4_to_btTrans(from_ts.get_mat()); 00644 const btTransform to_trans = LMatrix4_to_btTrans(to_ts.get_mat()); 00645 00646 BulletClosestHitSweepResult cb(from_pos, to_pos, mask); 00647 _world->convexSweepTest(convex, from_trans, to_trans, cb, penetration); 00648 return cb; 00649 } 00650 00651 //////////////////////////////////////////////////////////////////// 00652 // Function: BulletWorld::contact_test 00653 // Access: Published 00654 // Description: 00655 //////////////////////////////////////////////////////////////////// 00656 BulletContactResult BulletWorld:: 00657 contact_test(PandaNode *node) const { 00658 00659 btCollisionObject *obj = get_collision_object(node); 00660 00661 BulletContactResult cb; 00662 00663 if (obj) { 00664 _world->contactTest(obj, cb); 00665 } 00666 00667 return cb; 00668 } 00669 00670 //////////////////////////////////////////////////////////////////// 00671 // Function: BulletWorld::contact_pair_test 00672 // Access: Published 00673 // Description: 00674 //////////////////////////////////////////////////////////////////// 00675 BulletContactResult BulletWorld:: 00676 contact_test_pair(PandaNode *node0, PandaNode *node1) const { 00677 00678 btCollisionObject *obj0 = get_collision_object(node0); 00679 btCollisionObject *obj1 = get_collision_object(node1); 00680 00681 BulletContactResult cb; 00682 00683 if (obj0 && obj1) { 00684 _world->contactPairTest(obj0, obj1, cb); 00685 } 00686 00687 return cb; 00688 } 00689 00690 //////////////////////////////////////////////////////////////////// 00691 // Function: BulletWorld::get_manifold 00692 // Access: Published 00693 // Description: 00694 //////////////////////////////////////////////////////////////////// 00695 BulletPersistentManifold *BulletWorld:: 00696 get_manifold(int idx) const { 00697 00698 nassertr(idx < get_num_manifolds(), NULL); 00699 00700 btPersistentManifold *ptr = _dispatcher->getManifoldByIndexInternal(idx); 00701 return (ptr) ? new BulletPersistentManifold(ptr) : NULL; 00702 } 00703 00704 //////////////////////////////////////////////////////////////////// 00705 // Function: BulletWorld::get_collision_object 00706 // Access: Public 00707 // Description: 00708 //////////////////////////////////////////////////////////////////// 00709 btCollisionObject *BulletWorld:: 00710 get_collision_object(PandaNode *node) { 00711 00712 if (node->is_of_type(BulletRigidBodyNode::get_class_type())) { 00713 return ((BulletRigidBodyNode *)node)->get_object(); 00714 } 00715 else if (node->is_of_type(BulletGhostNode::get_class_type())) { 00716 return ((BulletGhostNode *)node)->get_object(); 00717 } 00718 else if (node->is_of_type(BulletBaseCharacterControllerNode::get_class_type())) { 00719 return ((BulletBaseCharacterControllerNode *)node)->get_ghost(); 00720 } 00721 else if (node->is_of_type(BulletSoftBodyNode::get_class_type())) { 00722 return ((BulletSoftBodyNode *)node)->get_object(); 00723 } 00724 00725 return NULL; 00726 } 00727 00728 /* 00729 //////////////////////////////////////////////////////////////////// 00730 // Function: BulletWorld::clean_manifolds_for_node 00731 // Access: Public 00732 // Description: 00733 //////////////////////////////////////////////////////////////////// 00734 void BulletWorld:: 00735 clean_manifolds_for_node(PandaNode *node) { 00736 00737 btCollisionObject *object = get_collision_object(node); 00738 if (object) { 00739 btBroadphaseProxy* proxy = object->getBroadphaseHandle(); 00740 if (proxy) { 00741 _world->getPairCache()->cleanProxyFromPairs(proxy, _dispatcher); 00742 } 00743 } 00744 } 00745 */ 00746 00747 //////////////////////////////////////////////////////////////////// 00748 // Function: BulletWorld::get_collision_object 00749 // Access: Public 00750 // Description: 00751 //////////////////////////////////////////////////////////////////// 00752 void BulletWorld:: 00753 set_group_collision_flag(unsigned int group1, unsigned int group2, bool enable) { 00754 00755 if (bullet_filter_algorithm != FA_groups_mask) { 00756 bullet_cat.warning() << "filter algorithm is not 'groups-mask'" << endl; 00757 } 00758 00759 _filter_cb2._collide[group1].set_bit_to(group2, enable); 00760 _filter_cb2._collide[group2].set_bit_to(group1, enable); 00761 } 00762 00763 //////////////////////////////////////////////////////////////////// 00764 // Function: BulletWorld::get_collision_object 00765 // Access: Public 00766 // Description: 00767 //////////////////////////////////////////////////////////////////// 00768 bool BulletWorld:: 00769 get_group_collision_flag(unsigned int group1, unsigned int group2) const { 00770 00771 return _filter_cb2._collide[group1].get_bit(group2); 00772 } 00773 00774 //////////////////////////////////////////////////////////////////// 00775 // Function: BulletWorld::FilterCallback1::needBroadphaseCollision 00776 // Access: Published 00777 // Description: 00778 //////////////////////////////////////////////////////////////////// 00779 bool BulletWorld::btFilterCallback1:: 00780 needBroadphaseCollision(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1) const { 00781 00782 btCollisionObject *obj0 = (btCollisionObject *) proxy0->m_clientObject; 00783 btCollisionObject *obj1 = (btCollisionObject *) proxy1->m_clientObject; 00784 00785 nassertr(obj0, false); 00786 nassertr(obj1, false); 00787 00788 PandaNode *node0 = (PandaNode *) obj0->getUserPointer(); 00789 PandaNode *node1 = (PandaNode *) obj1->getUserPointer(); 00790 00791 nassertr(node0, false); 00792 nassertr(node1, false); 00793 00794 CollideMask mask0 = node0->get_into_collide_mask(); 00795 CollideMask mask1 = node1->get_into_collide_mask(); 00796 00797 return (mask0 & mask1) != 0; 00798 } 00799 00800 //////////////////////////////////////////////////////////////////// 00801 // Function: BulletWorld::FilterCallback2::needBroadphaseCollision 00802 // Access: Published 00803 // Description: 00804 //////////////////////////////////////////////////////////////////// 00805 bool BulletWorld::btFilterCallback2:: 00806 needBroadphaseCollision(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1) const { 00807 00808 btCollisionObject *obj0 = (btCollisionObject *) proxy0->m_clientObject; 00809 btCollisionObject *obj1 = (btCollisionObject *) proxy1->m_clientObject; 00810 00811 nassertr(obj0, false); 00812 nassertr(obj1, false); 00813 00814 PandaNode *node0 = (PandaNode *) obj0->getUserPointer(); 00815 PandaNode *node1 = (PandaNode *) obj1->getUserPointer(); 00816 00817 nassertr(node0, false); 00818 nassertr(node1, false); 00819 00820 CollideMask mask0 = node0->get_into_collide_mask(); 00821 CollideMask mask1 = node1->get_into_collide_mask(); 00822 00823 for (int i=0; i<32; i++) { 00824 if (mask0.get_bit(i)) { 00825 if ((_collide[i] & mask1) != 0) 00826 return true; 00827 } 00828 } 00829 00830 return false; 00831 } 00832 00833 //////////////////////////////////////////////////////////////////// 00834 // Function: BulletWorld::BroadphaseAlgorithm ostream operator 00835 // Description: 00836 //////////////////////////////////////////////////////////////////// 00837 ostream & 00838 operator << (ostream &out, BulletWorld::BroadphaseAlgorithm algorithm) { 00839 00840 switch (algorithm) { 00841 case BulletWorld::BA_sweep_and_prune: 00842 return out << "sap"; 00843 00844 case BulletWorld::BA_dynamic_aabb_tree: 00845 return out << "aabb"; 00846 }; 00847 00848 return out << "**invalid BulletWorld::BroadphaseAlgorithm(" << (int)algorithm << ")**"; 00849 } 00850 00851 //////////////////////////////////////////////////////////////////// 00852 // Function: BulletWorld::BroadphaseAlgorithm istream operator 00853 // Description: 00854 //////////////////////////////////////////////////////////////////// 00855 istream & 00856 operator >> (istream &in, BulletWorld::BroadphaseAlgorithm &algorithm) { 00857 string word; 00858 in >> word; 00859 00860 if (word == "sap") { 00861 algorithm = BulletWorld::BA_sweep_and_prune; 00862 } 00863 else if (word == "aabb") { 00864 algorithm = BulletWorld::BA_dynamic_aabb_tree; 00865 } 00866 else { 00867 bullet_cat.error() 00868 << "Invalid BulletWorld::BroadphaseAlgorithm: " << word << "\n"; 00869 algorithm = BulletWorld::BA_dynamic_aabb_tree; 00870 } 00871 00872 return in; 00873 } 00874 00875 //////////////////////////////////////////////////////////////////// 00876 // Function: BulletWorld::FilterAlgorithm ostream operator 00877 // Description: 00878 //////////////////////////////////////////////////////////////////// 00879 ostream & 00880 operator << (ostream &out, BulletWorld::FilterAlgorithm algorithm) { 00881 00882 switch (algorithm) { 00883 case BulletWorld::FA_mask: 00884 return out << "mask"; 00885 00886 case BulletWorld::FA_groups_mask: 00887 return out << "groups-mask"; 00888 }; 00889 00890 return out << "**invalid BulletWorld::FilterAlgorithm(" << (int)algorithm << ")**"; 00891 } 00892 00893 //////////////////////////////////////////////////////////////////// 00894 // Function: BulletWorld::FilterAlgorithm istream operator 00895 // Description: 00896 //////////////////////////////////////////////////////////////////// 00897 istream & 00898 operator >> (istream &in, BulletWorld::FilterAlgorithm &algorithm) { 00899 string word; 00900 in >> word; 00901 00902 if (word == "mask") { 00903 algorithm = BulletWorld::FA_mask; 00904 } 00905 else if (word == "groups-mask") { 00906 algorithm = BulletWorld::FA_groups_mask; 00907 } 00908 else { 00909 bullet_cat.error() 00910 << "Invalid BulletWorld::FilterAlgorithm: " << word << "\n"; 00911 algorithm = BulletWorld::FA_mask; 00912 } 00913 00914 return in; 00915 } 00916