Panda3D
bulletWorld.cxx
1 // Filename: bulletWorld.cxx
2 // Created by: enn0x (23Jan10)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "bulletWorld.h"
16 #include "bulletPersistentManifold.h"
17 #include "bulletShape.h"
18 #include "bulletSoftBodyWorldInfo.h"
19 
20 #include "collideMask.h"
21 
22 #define clamp(x, x_min, x_max) max(min(x, x_max), x_min)
23 
24 TypeHandle BulletWorld::_type_handle;
25 
26 PStatCollector BulletWorld::_pstat_physics("App:Bullet:DoPhysics");
27 PStatCollector BulletWorld::_pstat_simulation("App:Bullet:DoPhysics:Simulation");
28 PStatCollector BulletWorld::_pstat_debug("App:Bullet:DoPhysics:Debug");
29 PStatCollector BulletWorld::_pstat_p2b("App:Bullet:DoPhysics:SyncP2B");
30 PStatCollector BulletWorld::_pstat_b2p("App:Bullet:DoPhysics:SyncB2P");
31 
32 PT(CallbackObject) bullet_contact_added_callback;
33 
34 ////////////////////////////////////////////////////////////////////
35 // Function: BulletWorld::Constructor
36 // Access: Published
37 // Description:
38 ////////////////////////////////////////////////////////////////////
39 BulletWorld::
40 BulletWorld() {
41 
42  // Init groups filter matrix
43  for (int i=0; i<32; i++) {
44  _filter_cb2._collide[i].clear();
45  _filter_cb2._collide[i].set_bit(i);
46  }
47 
48  // Broadphase
49  btScalar dx(bullet_sap_extents);
50  btVector3 extents(dx, dx, dx);
51 
52  switch (bullet_broadphase_algorithm) {
53  case BA_sweep_and_prune:
54  _broadphase = new btAxisSweep3(extents, extents, 1024);
55  break;
56  case BA_dynamic_aabb_tree:
57  _broadphase = new btDbvtBroadphase();
58  break;
59  default:
60  bullet_cat.error() << "no proper broadphase algorithm!" << endl;
61  }
62  nassertv(_broadphase);
63 
64  // Configuration
65  _configuration = new btSoftBodyRigidBodyCollisionConfiguration();
66  nassertv(_configuration);
67 
68  // Dispatcher
69  _dispatcher = new btCollisionDispatcher(_configuration);
70  nassertv(_dispatcher);
71 
72  // Solver
73  _solver = new btSequentialImpulseConstraintSolver;
74  nassertv(_solver);
75 
76  // World
77  _world = new btSoftRigidDynamicsWorld(_dispatcher, _broadphase, _solver, _configuration);
78  nassertv(_world);
79  nassertv(_world->getPairCache());
80 
81  _world->setWorldUserInfo(this);
82  _world->setGravity(btVector3(0.0f, 0.0f, 0.0f));
83 
84  // Ghost-pair callback
85  _world->getPairCache()->setInternalGhostPairCallback(&_ghost_cb);
86 
87  // Filter callback
88  switch (bullet_filter_algorithm) {
89  case FA_mask:
90  _filter_cb = &_filter_cb1;
91  break;
92  case FA_groups_mask:
93  _filter_cb = &_filter_cb2;
94  break;
95  case FA_callback:
96  _filter_cb = &_filter_cb3;
97  break;
98  default:
99  bullet_cat.error() << "no proper filter algorithm!" << endl;
100  _filter_cb = NULL;
101  }
102 
103  _world->getPairCache()->setOverlapFilterCallback(_filter_cb);
104 
105  // Tick callback
106  _tick_callback_obj = NULL;
107 
108  // SoftBodyWorldInfo
109  _info.m_dispatcher = _dispatcher;
110  _info.m_broadphase = _broadphase;
111  _info.m_gravity.setValue(0.0f, 0.0f, 0.0f);
112  _info.m_sparsesdf.Initialize();
113 
114  // Register GIMPACT algorithm
115  btGImpactCollisionAlgorithm::registerAlgorithm(_dispatcher);
116 
117  // Some prefered settings
118  _world->getDispatchInfo().m_enableSPU = true; // default: true
119  _world->getDispatchInfo().m_useContinuous = true; // default: true
120  _world->getSolverInfo().m_splitImpulse = false; // default: false
121  _world->getSolverInfo().m_numIterations = bullet_solver_iterations;
122 }
123 
124 ////////////////////////////////////////////////////////////////////
125 // Function: BulletWorld::get_world_info
126 // Access: Published
127 // Description:
128 ////////////////////////////////////////////////////////////////////
129 BulletSoftBodyWorldInfo BulletWorld::
130 get_world_info() {
131 
132  return BulletSoftBodyWorldInfo(_info);
133 }
134 
135 ////////////////////////////////////////////////////////////////////
136 // Function: BulletWorld::set_gravity
137 // Access: Published
138 // Description:
139 ////////////////////////////////////////////////////////////////////
140 void BulletWorld::
141 set_gravity(const LVector3 &gravity) {
142 
143  _world->setGravity(LVecBase3_to_btVector3(gravity));
144  _info.m_gravity.setValue(gravity.get_x(), gravity.get_y(), gravity.get_z());
145 }
146 
147 ////////////////////////////////////////////////////////////////////
148 // Function: BulletWorld::set_gravity
149 // Access: Published
150 // Description:
151 ////////////////////////////////////////////////////////////////////
152 void BulletWorld::
153 set_gravity(PN_stdfloat gx, PN_stdfloat gy, PN_stdfloat gz) {
154 
155  _world->setGravity(btVector3((btScalar)gx, (btScalar)gy, (btScalar)gz));
156  _info.m_gravity.setValue((btScalar)gx, (btScalar)gy, (btScalar)gz);
157 }
158 
159 ////////////////////////////////////////////////////////////////////
160 // Function: BulletWorld::get_gravity
161 // Access: Published
162 // Description:
163 ////////////////////////////////////////////////////////////////////
164 const LVector3 BulletWorld::
165 get_gravity() const {
166 
167  return btVector3_to_LVector3(_world->getGravity());
168 }
169 
170 ////////////////////////////////////////////////////////////////////
171 // Function: BulletWorld::do_physics
172 // Access: Published
173 // Description:
174 ////////////////////////////////////////////////////////////////////
175 int BulletWorld::
176 do_physics(PN_stdfloat dt, int max_substeps, PN_stdfloat stepsize) {
177 
178  _pstat_physics.start();
179 
180  int num_substeps = clamp(int(dt / stepsize), 1, max_substeps);
181 
182  // Synchronize Panda to Bullet
183  _pstat_p2b.start();
184  sync_p2b(dt, num_substeps);
185  _pstat_p2b.stop();
186 
187  // Simulation
188  _pstat_simulation.start();
189  int n = _world->stepSimulation((btScalar)dt, max_substeps, (btScalar)stepsize);
190  _pstat_simulation.stop();
191 
192  // Synchronize Bullet to Panda
193  _pstat_b2p.start();
194  sync_b2p();
195  _info.m_sparsesdf.GarbageCollect(bullet_gc_lifetime);
196  _pstat_b2p.stop();
197 
198  // Render debug
199  if (_debug) {
200  _pstat_debug.start();
201  _debug->sync_b2p(_world);
202  _pstat_debug.stop();
203  }
204 
205  _pstat_physics.stop();
206 
207  return n;
208 }
209 
210 ////////////////////////////////////////////////////////////////////
211 // Function: BulletWorld::sync_p2b
212 // Access: Private
213 // Description:
214 ////////////////////////////////////////////////////////////////////
215 void BulletWorld::
216 sync_p2b(PN_stdfloat dt, int num_substeps) {
217 
218  for (int i=0; i < get_num_rigid_bodies(); i++) {
219  get_rigid_body(i)->sync_p2b();
220  }
221 
222  for (int i=0; i < get_num_soft_bodies(); i++) {
223  get_soft_body(i)->sync_p2b();
224  }
225 
226  for (int i=0; i < get_num_ghosts(); i++) {
227  get_ghost(i)->sync_p2b();
228  }
229 
230  for (int i=0; i < get_num_characters(); i++) {
231  get_character(i)->sync_p2b(dt, num_substeps);
232  }
233 }
234 
235 ////////////////////////////////////////////////////////////////////
236 // Function: BulletWorld::sync_b2p
237 // Access: Private
238 // Description:
239 ////////////////////////////////////////////////////////////////////
240 void BulletWorld::
241 sync_b2p() {
242 
243  for (int i=0; i < get_num_vehicles(); i++) {
244  get_vehicle(i)->sync_b2p();
245  }
246 
247  for (int i=0; i < get_num_rigid_bodies(); i++) {
248  get_rigid_body(i)->sync_b2p();
249  }
250 
251  for (int i=0; i < get_num_soft_bodies(); i++) {
252  get_soft_body(i)->sync_b2p();
253  }
254 
255  for (int i=0; i < get_num_ghosts(); i++) {
256  get_ghost(i)->sync_b2p();
257  }
258 
259  for (int i=0; i < get_num_characters(); i++) {
260  get_character(i)->sync_b2p();
261  }
262 }
263 
264 ////////////////////////////////////////////////////////////////////
265 // Function: BulletWorld::attach
266 // Access: Published
267 // Description:
268 ////////////////////////////////////////////////////////////////////
269 void BulletWorld::
270 attach(TypedObject *object) {
271 
272  if (object->is_of_type(BulletGhostNode::get_class_type())) {
273  attach_ghost(DCAST(BulletGhostNode, object));
274  }
275  else if (object->is_of_type(BulletRigidBodyNode::get_class_type())) {
276  attach_rigid_body(DCAST(BulletRigidBodyNode, object));
277  }
278  else if (object->is_of_type(BulletSoftBodyNode::get_class_type())) {
279  attach_soft_body(DCAST(BulletSoftBodyNode, object));
280  }
281  else if (object->is_of_type(BulletBaseCharacterControllerNode::get_class_type())) {
283  }
284  else if (object->is_of_type(BulletVehicle::get_class_type())) {
285  attach_vehicle(DCAST(BulletVehicle, object));
286  }
287  else if (object->is_of_type(BulletConstraint::get_class_type())) {
288  attach_constraint(DCAST(BulletConstraint, object));
289  }
290  else {
291  bullet_cat->error() << "not a bullet world object!" << endl;
292  }
293 }
294 
295 ////////////////////////////////////////////////////////////////////
296 // Function: BulletWorld::remove
297 // Access: Published
298 // Description:
299 ////////////////////////////////////////////////////////////////////
300 void BulletWorld::
301 remove(TypedObject *object) {
302 
303  if (object->is_of_type(BulletGhostNode::get_class_type())) {
304  remove_ghost(DCAST(BulletGhostNode, object));
305  }
306  else if (object->is_of_type(BulletRigidBodyNode::get_class_type())) {
307  remove_rigid_body(DCAST(BulletRigidBodyNode, object));
308  }
309  else if (object->is_of_type(BulletSoftBodyNode::get_class_type())) {
310  remove_soft_body(DCAST(BulletSoftBodyNode, object));
311  }
312  else if (object->is_of_type(BulletBaseCharacterControllerNode::get_class_type())) {
314  }
315  else if (object->is_of_type(BulletVehicle::get_class_type())) {
316  remove_vehicle(DCAST(BulletVehicle, object));
317  }
318  else if (object->is_of_type(BulletConstraint::get_class_type())) {
319  remove_constraint(DCAST(BulletConstraint, object));
320  }
321  else {
322  bullet_cat->error() << "not a bullet world object!" << endl;
323  }
324 }
325 
326 ////////////////////////////////////////////////////////////////////
327 // Function: BulletWorld::attach_rigid_body
328 // Access: Published
329 // Description: Deprecated!
330 // Please use BulletWorld::attach
331 ////////////////////////////////////////////////////////////////////
332 void BulletWorld::
334 
335  nassertv(node);
336 
337  btRigidBody *ptr = btRigidBody::upcast(node->get_object());
338 
339  BulletRigidBodies::iterator found;
340  PT(BulletRigidBodyNode) ptnode = node;
341  found = find(_bodies.begin(), _bodies.end(), ptnode);
342 
343  if (found == _bodies.end()) {
344  _bodies.push_back(node);
345  _world->addRigidBody(ptr);
346  }
347  else {
348  bullet_cat.warning() << "rigid body already attached" << endl;
349  }
350 }
351 
352 ////////////////////////////////////////////////////////////////////
353 // Function: BulletWorld::remove_rigid_body
354 // Access: Published
355 // Description: Deprecated.!
356 // Please use BulletWorld::remove
357 ////////////////////////////////////////////////////////////////////
358 void BulletWorld::
360 
361  nassertv(node);
362 
363  btRigidBody *ptr = btRigidBody::upcast(node->get_object());
364 
365  BulletRigidBodies::iterator found;
366  PT(BulletRigidBodyNode) ptnode = node;
367  found = find(_bodies.begin(), _bodies.end(), ptnode);
368 
369  if (found == _bodies.end()) {
370  bullet_cat.warning() << "rigid body not attached" << endl;
371  }
372  else {
373  _bodies.erase(found);
374  _world->removeRigidBody(ptr);
375  }
376 }
377 
378 ////////////////////////////////////////////////////////////////////
379 // Function: BulletWorld::attach_soft_body
380 // Access: Published
381 // Description: Deprecated!
382 // Please use BulletWorld::attach
383 ////////////////////////////////////////////////////////////////////
384 void BulletWorld::
386 
387  nassertv(node);
388 
389  btSoftBody *ptr = btSoftBody::upcast(node->get_object());
390 
391  // TODO: group/filter settings (see ghost objects too)
392  short group = btBroadphaseProxy::DefaultFilter;
393  short mask = btBroadphaseProxy::AllFilter;
394 
395  BulletSoftBodies::iterator found;
396  PT(BulletSoftBodyNode) ptnode = node;
397  found = find(_softbodies.begin(), _softbodies.end(), ptnode);
398 
399  if (found == _softbodies.end()) {
400  _softbodies.push_back(node);
401  _world->addSoftBody(ptr, group, mask);
402  }
403  else {
404  bullet_cat.warning() << "soft body already attached" << endl;
405  }
406 }
407 
408 ////////////////////////////////////////////////////////////////////
409 // Function: BulletWorld::remove_soft_body
410 // Access: Published
411 // Description: Deprecated.!
412 // Please use BulletWorld::remove
413 ////////////////////////////////////////////////////////////////////
414 void BulletWorld::
416 
417  nassertv(node);
418 
419  btSoftBody *ptr = btSoftBody::upcast(node->get_object());
420 
421  BulletSoftBodies::iterator found;
422  PT(BulletSoftBodyNode) ptnode = node;
423  found = find(_softbodies.begin(), _softbodies.end(), ptnode);
424 
425  if (found == _softbodies.end()) {
426  bullet_cat.warning() << "soft body not attached" << endl;
427  }
428  else {
429  _softbodies.erase(found);
430  _world->removeSoftBody(ptr);
431  }
432 }
433 
434 ////////////////////////////////////////////////////////////////////
435 // Function: BulletWorld::attach_ghost
436 // Access: Published
437 // Description: Deprecated!
438 // Please use BulletWorld::attach
439 ////////////////////////////////////////////////////////////////////
440 void BulletWorld::
442 
443  nassertv(node);
444 
445  // TODO group/filter settings...
446 /*
447 enum CollisionFilterGroups {
448  DefaultFilter = 1,
449  StaticFilter = 2,
450  KinematicFilter = 4,
451  DebrisFilter = 8,
452  SensorTrigger = 16,
453  CharacterFilter = 32,
454  AllFilter = -1
455 }
456 */
457 
458  short group = btBroadphaseProxy::SensorTrigger;
459  short mask = btBroadphaseProxy::AllFilter
460  & ~btBroadphaseProxy::StaticFilter
461  & ~btBroadphaseProxy::SensorTrigger;
462 
463  btGhostObject *ptr = btGhostObject::upcast(node->get_object());
464 
465  BulletGhosts::iterator found;
466  PT(BulletGhostNode) ptnode = node;
467  found = find(_ghosts.begin(), _ghosts.end(), ptnode);
468 
469  if (found == _ghosts.end()) {
470  _ghosts.push_back(node);
471  _world->addCollisionObject(ptr, group, mask);
472  }
473  else {
474  bullet_cat.warning() << "ghost already attached" << endl;
475  }
476 }
477 
478 ////////////////////////////////////////////////////////////////////
479 // Function: BulletWorld::remove_ghost
480 // Access: Published
481 // Description: Deprecated.!
482 // Please use BulletWorld::remove
483 ////////////////////////////////////////////////////////////////////
484 void BulletWorld::
486 
487  nassertv(node);
488 
489  btGhostObject *ptr = btGhostObject::upcast(node->get_object());
490 
491  BulletGhosts::iterator found;
492  PT(BulletGhostNode) ptnode = node;
493  found = find(_ghosts.begin(), _ghosts.end(), ptnode);
494 
495  if (found == _ghosts.end()) {
496  bullet_cat.warning() << "ghost not attached" << endl;
497  }
498  else {
499  _ghosts.erase(found);
500  _world->removeCollisionObject(ptr);
501  }
502 }
503 
504 ////////////////////////////////////////////////////////////////////
505 // Function: BulletWorld::attach_character
506 // Access: Published
507 // Description: Deprecated!
508 // Please use BulletWorld::attach
509 ////////////////////////////////////////////////////////////////////
510 void BulletWorld::
512 
513  nassertv(node);
514 
515  BulletCharacterControllers::iterator found;
516  PT(BulletBaseCharacterControllerNode) ptnode = node;
517  found = find(_characters.begin(), _characters.end(), ptnode);
518 
519  if (found == _characters.end()) {
520  _characters.push_back(node);
521 
522  _world->addCollisionObject(node->get_ghost(),
523  btBroadphaseProxy::CharacterFilter,
524  btBroadphaseProxy::StaticFilter|btBroadphaseProxy::DefaultFilter);
525 
526  _world->addCharacter(node->get_character());
527  }
528  else {
529  bullet_cat.warning() << "character already attached" << endl;
530  }
531 }
532 
533 ////////////////////////////////////////////////////////////////////
534 // Function: BulletWorld::remove_character
535 // Access: Published
536 // Description: Deprecated.!
537 // Please use BulletWorld::remove
538 ////////////////////////////////////////////////////////////////////
539 void BulletWorld::
541 
542  nassertv(node);
543 
544  BulletCharacterControllers::iterator found;
545  PT(BulletBaseCharacterControllerNode) ptnode = node;
546  found = find(_characters.begin(), _characters.end(), ptnode);
547 
548  if (found == _characters.end()) {
549  bullet_cat.warning() << "character not attached" << endl;
550  }
551  else {
552  _characters.erase(found);
553  _world->removeCollisionObject(node->get_ghost());
554  _world->removeCharacter(node->get_character());
555  }
556 }
557 
558 ////////////////////////////////////////////////////////////////////
559 // Function: BulletWorld::attach_vehicle
560 // Access: Published
561 // Description: Deprecated!
562 // Please use BulletWorld::attach
563 ////////////////////////////////////////////////////////////////////
564 void BulletWorld::
566 
567  nassertv(vehicle);
568 
569  BulletVehicles::iterator found;
570  PT(BulletVehicle) ptvehicle = vehicle;
571  found = find(_vehicles.begin(), _vehicles.end(), ptvehicle);
572 
573  if (found == _vehicles.end()) {
574  _vehicles.push_back(vehicle);
575  _world->addVehicle(vehicle->get_vehicle());
576  }
577  else {
578  bullet_cat.warning() << "vehicle already attached" << endl;
579  }
580 }
581 
582 ////////////////////////////////////////////////////////////////////
583 // Function: BulletWorld::remove_vehicle
584 // Access: Published
585 // Description: Deprecated.!
586 // Please use BulletWorld::remove
587 ////////////////////////////////////////////////////////////////////
588 void BulletWorld::
590 
591  nassertv(vehicle);
592 
593  remove_rigid_body(vehicle->get_chassis());
594 
595  BulletVehicles::iterator found;
596  PT(BulletVehicle) ptvehicle = vehicle;
597  found = find(_vehicles.begin(), _vehicles.end(), ptvehicle);
598 
599  if (found == _vehicles.end()) {
600  bullet_cat.warning() << "vehicle not attached" << endl;
601  }
602  else {
603  _vehicles.erase(found);
604  _world->removeVehicle(vehicle->get_vehicle());
605  }
606 }
607 
608 ////////////////////////////////////////////////////////////////////
609 // Function: BulletWorld::attach_constraint
610 // Access: Published
611 // Description: Attaches a single constraint to a world. Collision
612 // checks between the linked objects will be disabled
613 // if the second parameter is set to TRUE.
614 ////////////////////////////////////////////////////////////////////
615 void BulletWorld::
616 attach_constraint(BulletConstraint *constraint, bool linked_collision) {
617 
618  nassertv(constraint);
619 
620  BulletConstraints::iterator found;
621  PT(BulletConstraint) ptconstraint = constraint;
622  found = find(_constraints.begin(), _constraints.end(), ptconstraint);
623 
624  if (found == _constraints.end()) {
625  _constraints.push_back(constraint);
626  _world->addConstraint(constraint->ptr(), linked_collision);
627  }
628  else {
629  bullet_cat.warning() << "constraint already attached" << endl;
630  }
631 }
632 
633 ////////////////////////////////////////////////////////////////////
634 // Function: BulletWorld::remove_constraint
635 // Access: Published
636 // Description: Deprecated.!
637 // Please use BulletWorld::remove
638 ////////////////////////////////////////////////////////////////////
639 void BulletWorld::
641 
642  nassertv(constraint);
643 
644  BulletConstraints::iterator found;
645  PT(BulletConstraint) ptconstraint = constraint;
646  found = find(_constraints.begin(), _constraints.end(), ptconstraint);
647 
648  if (found == _constraints.end()) {
649  bullet_cat.warning() << "constraint not attached" << endl;
650  }
651  else {
652  _constraints.erase(found);
653  _world->removeConstraint(constraint->ptr());
654  }
655 }
656 
657 ////////////////////////////////////////////////////////////////////
658 // Function: BulletWorld::ray_test_closest
659 // Access: Published
660 // Description:
661 ////////////////////////////////////////////////////////////////////
662 BulletClosestHitRayResult BulletWorld::
663 ray_test_closest(const LPoint3 &from_pos, const LPoint3 &to_pos, const CollideMask &mask) const {
664 
665  nassertr(!from_pos.is_nan(), BulletClosestHitRayResult::empty());
666  nassertr(!to_pos.is_nan(), BulletClosestHitRayResult::empty());
667 
668  const btVector3 from = LVecBase3_to_btVector3(from_pos);
669  const btVector3 to = LVecBase3_to_btVector3(to_pos);
670 
671  BulletClosestHitRayResult cb(from, to, mask);
672  _world->rayTest(from, to, cb);
673  return cb;
674 }
675 
676 ////////////////////////////////////////////////////////////////////
677 // Function: BulletWorld::ray_test_all
678 // Access: Published
679 // Description:
680 ////////////////////////////////////////////////////////////////////
681 BulletAllHitsRayResult BulletWorld::
682 ray_test_all(const LPoint3 &from_pos, const LPoint3 &to_pos, const CollideMask &mask) const {
683 
684  nassertr(!from_pos.is_nan(), BulletAllHitsRayResult::empty());
685  nassertr(!to_pos.is_nan(), BulletAllHitsRayResult::empty());
686 
687  const btVector3 from = LVecBase3_to_btVector3(from_pos);
688  const btVector3 to = LVecBase3_to_btVector3(to_pos);
689 
690  BulletAllHitsRayResult cb(from, to, mask);
691  _world->rayTest(from, to, cb);
692  return cb;
693 }
694 
695 ////////////////////////////////////////////////////////////////////
696 // Function: BulletWorld::sweep_test_closest
697 // Access: Published
698 // Description:
699 ////////////////////////////////////////////////////////////////////
700 BulletClosestHitSweepResult BulletWorld::
701 sweep_test_closest(BulletShape *shape, const TransformState &from_ts, const TransformState &to_ts, const CollideMask &mask, PN_stdfloat penetration) const {
702 
703  nassertr(shape, BulletClosestHitSweepResult::empty());
704  nassertr(shape->is_convex(), BulletClosestHitSweepResult::empty());
705  nassertr(!from_ts.is_invalid(), BulletClosestHitSweepResult::empty());
706  nassertr(!to_ts.is_invalid(), BulletClosestHitSweepResult::empty());
707 
708  const btConvexShape *convex = (const btConvexShape *) shape->ptr();
709  const btVector3 from_pos = LVecBase3_to_btVector3(from_ts.get_pos());
710  const btVector3 to_pos = LVecBase3_to_btVector3(to_ts.get_pos());
711  const btTransform from_trans = LMatrix4_to_btTrans(from_ts.get_mat());
712  const btTransform to_trans = LMatrix4_to_btTrans(to_ts.get_mat());
713 
714  BulletClosestHitSweepResult cb(from_pos, to_pos, mask);
715  _world->convexSweepTest(convex, from_trans, to_trans, cb, penetration);
716  return cb;
717 }
718 
719 ////////////////////////////////////////////////////////////////////
720 // Function: BulletWorld::filter_test
721 // Access: Published
722 // Description: Performs a test if two bodies should collide or
723 // not, based on the collision filter setting.
724 ////////////////////////////////////////////////////////////////////
725 bool BulletWorld::
726 filter_test(PandaNode *node0, PandaNode *node1) const {
727 
728  nassertr(node0, false);
729  nassertr(node1, false);
730  nassertr(_filter_cb, false);
731 
732  btCollisionObject *obj0 = get_collision_object(node0);
733  btCollisionObject *obj1 = get_collision_object(node1);
734 
735  nassertr(obj0, false);
736  nassertr(obj1, false);
737 
738  btBroadphaseProxy *proxy0 = obj0->getBroadphaseHandle();
739  btBroadphaseProxy *proxy1 = obj1->getBroadphaseHandle();
740 
741  nassertr(proxy0, false);
742  nassertr(proxy1, false);
743 
744  return _filter_cb->needBroadphaseCollision(proxy0, proxy1);
745 }
746 
747 ////////////////////////////////////////////////////////////////////
748 // Function: BulletWorld::contact_test
749 // Access: Published
750 // Description: Performas a test for all bodies which are
751 // currently in contact with the given body.
752 // The test returns a BulletContactResult object
753 // which may contain zero, one or more contacts.
754 //
755 // If the optional parameter use_filter is set to
756 // TRUE this test will consider filter settings.
757 // Otherwise all objects in contact are reported,
758 // no matter if they would collide or not.
759 ////////////////////////////////////////////////////////////////////
761 contact_test(PandaNode *node, bool use_filter) const {
762 
763  btCollisionObject *obj = get_collision_object(node);
764 
766 
767  if (obj) {
768 #if BT_BULLET_VERSION >= 281
769  if (use_filter) {
770  cb.use_filter(_filter_cb, obj->getBroadphaseHandle());
771  }
772 #endif
773 
774  _world->contactTest(obj, cb);
775  }
776 
777  return cb;
778 }
779 
780 ////////////////////////////////////////////////////////////////////
781 // Function: BulletWorld::contact_pair_test
782 // Access: Published
783 // Description: Performas a test if the two bodies given as
784 // parameters are in contact or not.
785 // The test returns a BulletContactResult object
786 // which may contain zero or one contacts.
787 ////////////////////////////////////////////////////////////////////
789 contact_test_pair(PandaNode *node0, PandaNode *node1) const {
790 
791  btCollisionObject *obj0 = get_collision_object(node0);
792  btCollisionObject *obj1 = get_collision_object(node1);
793 
795 
796  if (obj0 && obj1) {
797 
798  _world->contactPairTest(obj0, obj1, cb);
799  }
800 
801  return cb;
802 }
803 
804 ////////////////////////////////////////////////////////////////////
805 // Function: BulletWorld::get_manifold
806 // Access: Published
807 // Description:
808 ////////////////////////////////////////////////////////////////////
809 BulletPersistentManifold *BulletWorld::
810 get_manifold(int idx) const {
811 
812  nassertr(idx < get_num_manifolds(), NULL);
813 
814  btPersistentManifold *ptr = _dispatcher->getManifoldByIndexInternal(idx);
815  return (ptr) ? new BulletPersistentManifold(ptr) : NULL;
816 }
817 
818 ////////////////////////////////////////////////////////////////////
819 // Function: BulletWorld::get_collision_object
820 // Access: Public
821 // Description:
822 ////////////////////////////////////////////////////////////////////
823 btCollisionObject *BulletWorld::
824 get_collision_object(PandaNode *node) {
825 
826  if (node->is_of_type(BulletRigidBodyNode::get_class_type())) {
827  return ((BulletRigidBodyNode *)node)->get_object();
828  }
829  else if (node->is_of_type(BulletGhostNode::get_class_type())) {
830  return ((BulletGhostNode *)node)->get_object();
831  }
832  else if (node->is_of_type(BulletBaseCharacterControllerNode::get_class_type())) {
833  return ((BulletBaseCharacterControllerNode *)node)->get_ghost();
834  }
835  else if (node->is_of_type(BulletSoftBodyNode::get_class_type())) {
836  return ((BulletSoftBodyNode *)node)->get_object();
837  }
838 
839  return NULL;
840 }
841 
842 ////////////////////////////////////////////////////////////////////
843 // Function: BulletWorld::set_group_collision_flag
844 // Access: Public
845 // Description:
846 ////////////////////////////////////////////////////////////////////
847 void BulletWorld::
848 set_group_collision_flag(unsigned int group1, unsigned int group2, bool enable) {
849 
850  if (bullet_filter_algorithm != FA_groups_mask) {
851  bullet_cat.warning() << "filter algorithm is not 'groups-mask'" << endl;
852  }
853 
854  _filter_cb2._collide[group1].set_bit_to(group2, enable);
855  _filter_cb2._collide[group2].set_bit_to(group1, enable);
856 }
857 
858 ////////////////////////////////////////////////////////////////////
859 // Function: BulletWorld::get_group_collision_flag
860 // Access: Public
861 // Description:
862 ////////////////////////////////////////////////////////////////////
863 bool BulletWorld::
864 get_group_collision_flag(unsigned int group1, unsigned int group2) const {
865 
866  return _filter_cb2._collide[group1].get_bit(group2);
867 }
868 
869 ////////////////////////////////////////////////////////////////////
870 // Function: BulletWorld::set_contact_added_callback
871 // Access: Published
872 // Description:
873 ////////////////////////////////////////////////////////////////////
874 void BulletWorld::
875 set_contact_added_callback(CallbackObject *obj) {
876 
877  _world->getSolverInfo().m_solverMode |= SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION;
878  _world->getSolverInfo().m_solverMode |= SOLVER_USE_2_FRICTION_DIRECTIONS;
879  _world->getSolverInfo().m_solverMode |= SOLVER_ENABLE_FRICTION_DIRECTION_CACHING;
880 
881  bullet_contact_added_callback = obj;
882 }
883 
884 ////////////////////////////////////////////////////////////////////
885 // Function: BulletWorld::clear_contact_added_callback
886 // Access: Published
887 // Description:
888 ////////////////////////////////////////////////////////////////////
889 void BulletWorld::
890 clear_contact_added_callback() {
891 
892  _world->getSolverInfo().m_solverMode &= ~SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION;
893  _world->getSolverInfo().m_solverMode &= ~SOLVER_USE_2_FRICTION_DIRECTIONS;
894  _world->getSolverInfo().m_solverMode &= ~SOLVER_ENABLE_FRICTION_DIRECTION_CACHING;
895 
896  bullet_contact_added_callback = NULL;
897 }
898 
899 ////////////////////////////////////////////////////////////////////
900 // Function: BulletWorld::set_tick_callback
901 // Access: Published
902 // Description:
903 ////////////////////////////////////////////////////////////////////
904 void BulletWorld::
905 set_tick_callback(CallbackObject *obj, bool is_pretick) {
906 
907  nassertv(obj != NULL);
908  _tick_callback_obj = obj;
909  _world->setInternalTickCallback(&BulletWorld::tick_callback, this, is_pretick);
910 }
911 
912 ////////////////////////////////////////////////////////////////////
913 // Function: BulletWorld::clear_tick_callback
914 // Access: Published
915 // Description:
916 ////////////////////////////////////////////////////////////////////
917 void BulletWorld::
918 clear_tick_callback() {
919 
920  _tick_callback_obj = NULL;
921  _world->setInternalTickCallback(NULL);
922 }
923 
924 ///////////////////////////////////////////////////////////////////
925 // Function: BulletWorld::tick_callback
926 // Access: Private
927 // Description:
928 ////////////////////////////////////////////////////////////////////
929 void BulletWorld::
930 tick_callback(btDynamicsWorld *world, btScalar timestep) {
931 
932  nassertv(world->getWorldUserInfo());
933 
934  BulletWorld *w = static_cast<BulletWorld *>(world->getWorldUserInfo());
935  CallbackObject *obj = w->_tick_callback_obj;
936  if (obj) {
937  BulletTickCallbackData cbdata(timestep);
938  obj->do_callback(&cbdata);
939  }
940 }
941 
942 ////////////////////////////////////////////////////////////////////
943 // Function: BulletWorld::set_filter_callback
944 // Access: Published
945 // Description:
946 ////////////////////////////////////////////////////////////////////
947 void BulletWorld::
948 set_filter_callback(CallbackObject *obj) {
949 
950  nassertv(obj != NULL);
951 
952  if (bullet_filter_algorithm != FA_callback) {
953  bullet_cat.warning() << "filter algorithm is not 'callback'" << endl;
954  }
955 
956  _filter_cb3._filter_callback_obj = obj;
957 }
958 
959 ////////////////////////////////////////////////////////////////////
960 // Function: BulletWorld::clear_filter_callback
961 // Access: Published
962 // Description:
963 ////////////////////////////////////////////////////////////////////
964 void BulletWorld::
965 clear_filter_callback() {
966 
967  _filter_cb3._filter_callback_obj = NULL;
968 }
969 
970 ////////////////////////////////////////////////////////////////////
971 // Function: BulletWorld::FilterCallback1::needBroadphaseCollision
972 // Access: Published
973 // Description:
974 ////////////////////////////////////////////////////////////////////
975 bool BulletWorld::btFilterCallback1::
976 needBroadphaseCollision(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1) const {
977 
978  btCollisionObject *obj0 = (btCollisionObject *) proxy0->m_clientObject;
979  btCollisionObject *obj1 = (btCollisionObject *) proxy1->m_clientObject;
980 
981  nassertr(obj0, false);
982  nassertr(obj1, false);
983 
984  PandaNode *node0 = (PandaNode *) obj0->getUserPointer();
985  PandaNode *node1 = (PandaNode *) obj1->getUserPointer();
986 
987  nassertr(node0, false);
988  nassertr(node1, false);
989 
990  CollideMask mask0 = node0->get_into_collide_mask();
991  CollideMask mask1 = node1->get_into_collide_mask();
992 
993  return (mask0 & mask1) != 0;
994 }
995 
996 ////////////////////////////////////////////////////////////////////
997 // Function: BulletWorld::FilterCallback2::needBroadphaseCollision
998 // Access: Published
999 // Description:
1000 ////////////////////////////////////////////////////////////////////
1001 bool BulletWorld::btFilterCallback2::
1002 needBroadphaseCollision(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1) const {
1003 
1004  btCollisionObject *obj0 = (btCollisionObject *) proxy0->m_clientObject;
1005  btCollisionObject *obj1 = (btCollisionObject *) proxy1->m_clientObject;
1006 
1007  nassertr(obj0, false);
1008  nassertr(obj1, false);
1009 
1010  PandaNode *node0 = (PandaNode *) obj0->getUserPointer();
1011  PandaNode *node1 = (PandaNode *) obj1->getUserPointer();
1012 
1013  nassertr(node0, false);
1014  nassertr(node1, false);
1015 
1016  CollideMask mask0 = node0->get_into_collide_mask();
1017  CollideMask mask1 = node1->get_into_collide_mask();
1018 
1019 //cout << mask0 << " " << mask1 << endl;
1020 
1021  for (int i=0; i<32; i++) {
1022  if (mask0.get_bit(i)) {
1023  if ((_collide[i] & mask1) != 0)
1024 //cout << "collide: i=" << i << " _collide[i]" << _collide[i] << endl;
1025  return true;
1026  }
1027  }
1028 
1029  return false;
1030 }
1031 
1032 ////////////////////////////////////////////////////////////////////
1033 // Function: BulletWorld::FilterCallback3::needBroadphaseCollision
1034 // Access: Published
1035 // Description:
1036 ////////////////////////////////////////////////////////////////////
1037 bool BulletWorld::btFilterCallback3::
1038 needBroadphaseCollision(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1) const {
1039 
1040  nassertr(_filter_callback_obj, false);
1041 
1042  btCollisionObject *obj0 = (btCollisionObject *) proxy0->m_clientObject;
1043  btCollisionObject *obj1 = (btCollisionObject *) proxy1->m_clientObject;
1044 
1045  nassertr(obj0, false);
1046  nassertr(obj1, false);
1047 
1048  PandaNode *node0 = (PandaNode *) obj0->getUserPointer();
1049  PandaNode *node1 = (PandaNode *) obj1->getUserPointer();
1050 
1051  nassertr(node0, false);
1052  nassertr(node1, false);
1053 
1054  BulletFilterCallbackData cbdata(node0, node1);
1055  _filter_callback_obj->do_callback(&cbdata);
1056  return cbdata.get_collide();
1057 }
1058 
1059 ////////////////////////////////////////////////////////////////////
1060 // Function: BulletWorld::BroadphaseAlgorithm ostream operator
1061 // Description:
1062 ////////////////////////////////////////////////////////////////////
1063 ostream &
1064 operator << (ostream &out, BulletWorld::BroadphaseAlgorithm algorithm) {
1065 
1066  switch (algorithm) {
1067  case BulletWorld::BA_sweep_and_prune:
1068  return out << "sap";
1069 
1070  case BulletWorld::BA_dynamic_aabb_tree:
1071  return out << "aabb";
1072  };
1073 
1074  return out << "**invalid BulletWorld::BroadphaseAlgorithm(" << (int)algorithm << ")**";
1075 }
1076 
1077 ////////////////////////////////////////////////////////////////////
1078 // Function: BulletWorld::BroadphaseAlgorithm istream operator
1079 // Description:
1080 ////////////////////////////////////////////////////////////////////
1081 istream &
1082 operator >> (istream &in, BulletWorld::BroadphaseAlgorithm &algorithm) {
1083  string word;
1084  in >> word;
1085 
1086  if (word == "sap") {
1087  algorithm = BulletWorld::BA_sweep_and_prune;
1088  }
1089  else if (word == "aabb") {
1090  algorithm = BulletWorld::BA_dynamic_aabb_tree;
1091  }
1092  else {
1093  bullet_cat.error()
1094  << "Invalid BulletWorld::BroadphaseAlgorithm: " << word << "\n";
1095  algorithm = BulletWorld::BA_dynamic_aabb_tree;
1096  }
1097 
1098  return in;
1099 }
1100 
1101 ////////////////////////////////////////////////////////////////////
1102 // Function: BulletWorld::FilterAlgorithm ostream operator
1103 // Description:
1104 ////////////////////////////////////////////////////////////////////
1105 ostream &
1106 operator << (ostream &out, BulletWorld::FilterAlgorithm algorithm) {
1107 
1108  switch (algorithm) {
1109  case BulletWorld::FA_mask:
1110  return out << "mask";
1111  case BulletWorld::FA_groups_mask:
1112  return out << "groups-mask";
1113  case BulletWorld::FA_callback:
1114  return out << "callback";
1115  };
1116  return out << "**invalid BulletWorld::FilterAlgorithm(" << (int)algorithm << ")**";
1117 }
1118 
1119 ////////////////////////////////////////////////////////////////////
1120 // Function: BulletWorld::FilterAlgorithm istream operator
1121 // Description:
1122 ////////////////////////////////////////////////////////////////////
1123 istream &
1124 operator >> (istream &in, BulletWorld::FilterAlgorithm &algorithm) {
1125  string word;
1126  in >> word;
1127 
1128  if (word == "mask") {
1129  algorithm = BulletWorld::FA_mask;
1130  }
1131  else if (word == "groups-mask") {
1132  algorithm = BulletWorld::FA_groups_mask;
1133  }
1134  else if (word == "callback") {
1135  algorithm = BulletWorld::FA_callback;
1136  }
1137  else {
1138  bullet_cat.error()
1139  << "Invalid BulletWorld::FilterAlgorithm: " << word << "\n";
1140  algorithm = BulletWorld::FA_mask;
1141  }
1142  return in;
1143 }
1144 
CollideMask get_into_collide_mask() const
Returns the "into" collide mask for this node.
Definition: pandaNode.I:582
A basic node of the scene graph or data graph.
Definition: pandaNode.h:72
void remove_soft_body(BulletSoftBodyNode *node)
Deprecated.
void attach_rigid_body(BulletRigidBodyNode *node)
Deprecated! Please use BulletWorld::attach.
void attach_vehicle(BulletVehicle *vehicle)
Deprecated! Please use BulletWorld::attach.
BulletContactResult contact_test_pair(PandaNode *node0, PandaNode *node1) const
Performas a test if the two bodies given as parameters are in contact or not.
BulletContactResult contact_test(PandaNode *node, bool use_filter=false) const
Performas a test for all bodies which are currently in contact with the given body.
static BulletAllHitsRayResult empty()
Named constructor intended to be used for asserts with have to return a concrete value.
void remove_vehicle(BulletVehicle *vehicle)
Deprecated.
This is an abstract class that all classes which use TypeHandle, and also provide virtual functions t...
Definition: typedObject.h:98
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
Definition: lvector3.h:100
void remove_ghost(BulletGhostNode *node)
Deprecated.
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
Definition: lpoint3.h:99
void attach_soft_body(BulletSoftBodyNode *node)
Deprecated! Please use BulletWorld::attach.
bool is_nan() const
Returns true if any component of the vector is not-a-number, false otherwise.
Definition: lvecBase3.h:464
void remove_rigid_body(BulletRigidBodyNode *node)
Deprecated.
Simulates a raycast vehicle which casts a ray per wheel at the ground as a cheap replacement for comp...
Definition: bulletVehicle.h:65
static BulletClosestHitRayResult empty()
Named constructor intended to be used for asserts with have to return a concrete value.
bool get_bit(int index) const
Returns true if the nth bit is set, false if it is cleared.
Definition: bitMask.I:212
A lightweight class that represents a single element that may be timed and/or counted via stats...
virtual void do_callback(CallbackData *cbdata)
This method called when the callback is triggered; it replaces* the original function.
void attach_ghost(BulletGhostNode *node)
Deprecated! Please use BulletWorld::attach.
static BulletClosestHitSweepResult empty()
Named constructor intended to be used for asserts with have to return a concrete value.
This is a generic object that can be assigned to a callback at various points in the rendering proces...
bool filter_test(PandaNode *node0, PandaNode *node1) const
Performs a test if two bodies should collide or not, based on the collision filter setting...
void remove_character(BulletBaseCharacterControllerNode *node)
Deprecated.
void attach_constraint(BulletConstraint *constraint, bool linked_collision=false)
Attaches a single constraint to a world.
BulletRigidBodyNode * get_chassis()
Returns the chassis of this vehicle.
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:63
void attach_character(BulletBaseCharacterControllerNode *node)
Deprecated! Please use BulletWorld::attach.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
void remove_constraint(BulletConstraint *constraint)
Deprecated.