Panda3D

bulletWorld.cxx

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 
 All Classes Functions Variables Enumerations