00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
00034
00035
00036
00037 BulletWorld::
00038 BulletWorld() {
00039
00040
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
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
00062 _configuration = new btSoftBodyRigidBodyCollisionConfiguration();
00063
00064
00065 _dispatcher = new btCollisionDispatcher(_configuration);
00066
00067
00068 _solver = new btSequentialImpulseConstraintSolver;
00069
00070
00071 _world = new btSoftRigidDynamicsWorld(_dispatcher, _broadphase, _solver, _configuration);
00072 _world->setGravity(btVector3(0.0f, 0.0f, 0.0f));
00073
00074
00075 _world->getPairCache()->setInternalGhostPairCallback(&_ghost_cb);
00076
00077
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
00090 _info.m_dispatcher = _dispatcher;
00091 _info.m_broadphase = _broadphase;
00092 _info.m_gravity = _world->getGravity();
00093 _info.m_sparsesdf.Initialize();
00094
00095
00096 btGImpactCollisionAlgorithm::registerAlgorithm(_dispatcher);
00097
00098
00099 _world->getDispatchInfo().m_enableSPU = true;
00100 _world->getDispatchInfo().m_useContinuous = true;
00101 _world->getSolverInfo().m_splitImpulse = false;
00102 _world->getSolverInfo().m_numIterations = bullet_solver_iterations;
00103 }
00104
00105
00106
00107
00108
00109
00110 BulletSoftBodyWorldInfo BulletWorld::
00111 get_world_info() {
00112
00113 return BulletSoftBodyWorldInfo(_info);
00114 }
00115
00116
00117
00118
00119
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
00130
00131
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
00142
00143
00144
00145 const LVector3 BulletWorld::
00146 get_gravity() const {
00147
00148 return btVector3_to_LVector3(_world->getGravity());
00149 }
00150
00151
00152
00153
00154
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
00164 _pstat_p2b.start();
00165 sync_p2b(dt, num_substeps);
00166 _pstat_p2b.stop();
00167
00168
00169 _pstat_simulation.start();
00170 int n = _world->stepSimulation((btScalar)dt, max_substeps, (btScalar)stepsize);
00171 _pstat_simulation.stop();
00172
00173
00174 _pstat_b2p.start();
00175 sync_b2p();
00176 _info.m_sparsesdf.GarbageCollect(bullet_gc_lifetime);
00177 _pstat_b2p.stop();
00178
00179
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
00193
00194
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
00218
00219
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
00247
00248
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
00261
00262
00263
00264 void BulletWorld::
00265 clear_debug_node() {
00266
00267 _debug = NULL;
00268 _world->setDebugDrawer(NULL);
00269 }
00270
00271
00272
00273
00274
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
00298
00299
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
00323
00324
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
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
00352
00353
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
00377
00378
00379
00380 void BulletWorld::
00381 attach_ghost(BulletGhostNode *node) {
00382
00383 nassertv(node);
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
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
00420
00421
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
00445
00446
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
00473
00474
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
00497
00498
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
00520
00521
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
00545
00546
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
00568
00569
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
00591
00592
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
00610
00611
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
00629
00630
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
00653
00654
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
00672
00673
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
00692
00693
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
00706
00707
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
00749
00750
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
00765
00766
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
00776
00777
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
00802
00803
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
00835
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
00853
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
00877
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
00895
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