Panda3D
bulletBodyNode.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file bulletBodyNode.cxx
10  * @author enn0x
11  * @date 2010-11-19
12  */
13 
14 #include "bulletBodyNode.h"
15 
16 #include "config_bullet.h"
17 
18 #include "bulletShape.h"
19 #include "bulletBoxShape.h"
20 #include "bulletCapsuleShape.h"
21 #include "bulletPlaneShape.h"
22 #include "bulletSphereShape.h"
24 #include "bulletTriangleMesh.h"
25 #include "bulletWorld.h"
26 
27 #include "collisionBox.h"
28 #include "collisionPlane.h"
29 #include "collisionSphere.h"
30 #include "collisionPolygon.h"
31 #include "collisionCapsule.h"
32 
33 TypeHandle BulletBodyNode::_type_handle;
34 
35 /**
36  *
37  */
38 BulletBodyNode::
39 BulletBodyNode(const char *name) : PandaNode(name) {
40 
41  // Shape
42  _shape = new btEmptyShape();
43 
44  // Default collide mask
46 }
47 
48 /**
49  *
50  */
51 BulletBodyNode::
52 BulletBodyNode(const BulletBodyNode &copy) :
53  PandaNode(copy)
54 {
55  LightMutexHolder holder(BulletWorld::get_global_lock());
56 
57  _shapes = copy._shapes;
58  if (copy._shape && copy._shape->getShapeType() == COMPOUND_SHAPE_PROXYTYPE) {
59  // btCompoundShape does not define a copy constructor. Manually copy.
60  btCompoundShape *shape = new btCompoundShape;
61  _shape = shape;
62 
63  btCompoundShape *copy_shape = (btCompoundShape *)copy._shape;
64  int num_children = copy_shape->getNumChildShapes();
65  for (int i = 0; i < num_children; ++i) {
66  shape->addChildShape(copy_shape->getChildTransform(i),
67  copy_shape->getChildShape(i));
68  }
69  }
70  else if (copy._shape && copy._shape->getShapeType() == EMPTY_SHAPE_PROXYTYPE) {
71  _shape = new btEmptyShape();
72  }
73  else {
74  _shape = copy._shape;
75  }
76 }
77 
78 /**
79  * Returns the subset of CollideMask bits that may be set for this particular
80  * type of PandaNode. For BodyNodes this returns all bits on.
81  */
84 
85  return CollideMask::all_on();
86 }
87 
88 /**
89  * Returns true if it is generally safe to flatten out this particular kind of
90  * Node by duplicating instances, false otherwise (for instance, a Camera
91  * cannot be safely flattened, because the Camera pointer itself is
92  * meaningful).
93  */
95 safe_to_flatten() const {
96 
97  return false;
98 }
99 
100 /**
101  * Returns true if it is generally safe to transform this particular kind of
102  * Node by calling the xform() method, false otherwise. For instance, it's
103  * usually a bad idea to attempt to xform a Character.
104  */
105 bool BulletBodyNode::
107 
108  return false;
109 }
110 
111 /**
112  * Returns true if it is safe to automatically adjust the transform on this
113  * kind of node. Usually, this is only a bad idea if the user expects to find
114  * a particular transform on the node.
115  *
116  * ModelNodes with the preserve_transform flag set are presently the only
117  * kinds of nodes that should not have their transform even adjusted.
118  */
119 bool BulletBodyNode::
121 
122  return false;
123 }
124 
125 /**
126  * Returns true if it is generally safe to combine this particular kind of
127  * PandaNode with other kinds of PandaNodes of compatible type, adding
128  * children or whatever. For instance, an LODNode should not be combined with
129  * any other PandaNode, because its set of children is meaningful.
130  */
131 bool BulletBodyNode::
133 
134  return false;
135 }
136 
137 /**
138  * Returns true if it is generally safe to combine the children of this
139  * PandaNode with each other. For instance, an LODNode's children should not
140  * be combined with each other, because the set of children is meaningful.
141  */
142 bool BulletBodyNode::
144 
145  return false;
146 }
147 
148 /**
149  * Returns true if a flatten operation may safely continue past this node, or
150  * false if nodes below this node may not be molested.
151  */
152 bool BulletBodyNode::
154 
155  return false;
156 }
157 
158 /**
159  *
160  */
161 void BulletBodyNode::
162 do_output(std::ostream &out) const {
163 
164  PandaNode::output(out);
165 
166  out << " (" << _shapes.size() << " shapes)";
167 
168  out << (get_object()->isActive() ? " active" : " inactive");
169 
170  if (get_object()->isStaticObject()) out << " static";
171  if (get_object()->isKinematicObject()) out << " kinematic";
172 }
173 
174 /**
175  *
176  */
177 void BulletBodyNode::
178 output(std::ostream &out) const {
179  LightMutexHolder holder(BulletWorld::get_global_lock());
180 
181  do_output(out);
182 }
183 
184 /**
185  *
186  */
187 void BulletBodyNode::
188 set_collision_flag(int flag, bool value) {
189  LightMutexHolder holder(BulletWorld::get_global_lock());
190 
191  int flags = get_object()->getCollisionFlags();
192 
193  if (value == true) {
194  flags |= flag;
195  }
196  else {
197  flags &= ~(flag);
198  }
199 
200  get_object()->setCollisionFlags(flags);
201 }
202 
203 /**
204  *
205  */
206 bool BulletBodyNode::
207 get_collision_flag(int flag) const {
208  LightMutexHolder holder(BulletWorld::get_global_lock());
209 
210  return (get_object()->getCollisionFlags() & flag) ? true : false;
211 }
212 
213 /**
214  *
215  */
216 bool BulletBodyNode::
217 is_static() const {
218  LightMutexHolder holder(BulletWorld::get_global_lock());
219 
220  return get_object()->isStaticObject();
221 }
222 
223 /**
224  *
225  */
226 bool BulletBodyNode::
227 is_kinematic() const {
228  LightMutexHolder holder(BulletWorld::get_global_lock());
229 
230  return get_object()->isKinematicObject();
231 }
232 
233 /**
234  *
235  */
236 PN_stdfloat BulletBodyNode::
237 get_restitution() const {
238  LightMutexHolder holder(BulletWorld::get_global_lock());
239 
240  return get_object()->getRestitution();
241 }
242 
243 /**
244  *
245  */
246 void BulletBodyNode::
247 set_restitution(PN_stdfloat restitution) {
248  LightMutexHolder holder(BulletWorld::get_global_lock());
249 
250  return get_object()->setRestitution(restitution);
251 }
252 
253 /**
254  *
255  */
256 PN_stdfloat BulletBodyNode::
257 get_friction() const {
258  LightMutexHolder holder(BulletWorld::get_global_lock());
259 
260  return get_object()->getFriction();
261 }
262 
263 /**
264  *
265  */
266 void BulletBodyNode::
267 set_friction(PN_stdfloat friction) {
268  LightMutexHolder holder(BulletWorld::get_global_lock());
269 
270  return get_object()->setFriction(friction);
271 }
272 
273 #if BT_BULLET_VERSION >= 281
274 /**
275  *
276  */
277 PN_stdfloat BulletBodyNode::
278 get_rolling_friction() const {
279  LightMutexHolder holder(BulletWorld::get_global_lock());
280 
281  return get_object()->getRollingFriction();
282 }
283 
284 /**
285  *
286  */
287 void BulletBodyNode::
288 set_rolling_friction(PN_stdfloat friction) {
289  LightMutexHolder holder(BulletWorld::get_global_lock());
290 
291  return get_object()->setRollingFriction(friction);
292 }
293 #endif
294 
295 /**
296  *
297  */
298 bool BulletBodyNode::
299 has_anisotropic_friction() const {
300  LightMutexHolder holder(BulletWorld::get_global_lock());
301 
302  return get_object()->hasAnisotropicFriction();
303 }
304 
305 /**
306  *
307  */
308 int BulletBodyNode::
309 get_num_shapes() const {
310  LightMutexHolder holder(BulletWorld::get_global_lock());
311 
312  return _shapes.size();
313 }
314 
315 /**
316  *
317  */
318 BulletShape *BulletBodyNode::
319 get_shape(int idx) const {
320  LightMutexHolder holder(BulletWorld::get_global_lock());
321 
322  nassertr(idx >= 0 && idx < (int)_shapes.size(), nullptr);
323  return _shapes[idx];
324 }
325 
326 /**
327  *
328  */
329 void BulletBodyNode::
330 add_shape(BulletShape *bullet_shape, const TransformState *ts) {
331  LightMutexHolder holder(BulletWorld::get_global_lock());
332 
333  do_add_shape(bullet_shape, ts);
334 }
335 
336 /**
337  * Assumes the lock(bullet global lock) is held by the caller
338  */
339 void BulletBodyNode::
340 do_add_shape(BulletShape *bullet_shape, const TransformState *ts) {
341 
342  nassertv(get_object());
343  nassertv(ts);
344 
345  btCollisionShape *shape = bullet_shape->ptr();
346  nassertv(shape != nullptr);
347 
348  nassertv(!(shape->getShapeType() == CONVEX_HULL_SHAPE_PROXYTYPE &&
349  ((btConvexHullShape *)shape)->getNumVertices() == 0));
350 
351  // Transform
352  btTransform trans = TransformState_to_btTrans(ts);
353 
354  // Reset the shape scaling before we add a shape, and remember the current
355  // Scale so we can restore it later...
356  NodePath np = NodePath::any_path((PandaNode *)this);
357  LVector3 scale = np.get_scale();
358  np.set_scale(1.0);
359 
360  // Root shape
361  btCollisionShape *previous = get_object()->getCollisionShape();
362  btCollisionShape *next;
363 
364  if (_shapes.size() == 0) {
365  nassertv(previous->getShapeType() == EMPTY_SHAPE_PROXYTYPE);
366 
367  if (ts->is_identity()) {
368  // After adding the shape we will have one shape, but with transform.
369  // We need to wrap the shape within a compound shape, in oder to be able
370  // to set the local transform.
371  next = shape;
372  }
373  else {
374  // After adding the shape we will have a total of one shape, without
375  // local transform. We can set the shape directly.
376  next = new btCompoundShape();
377  ((btCompoundShape *)next)->addChildShape(trans, shape);
378  }
379 
380  get_object()->setCollisionShape(next);
381  _shape = next;
382 
383  delete previous;
384  }
385  else if (_shapes.size() == 1) {
386  if (previous->getShapeType() == COMPOUND_SHAPE_PROXYTYPE) {
387  // We have one shape, and add another shape. The previous shape is
388  // already a compound shape. So we just need to add the second shape to
389  // the compound shape.
390  next = previous;
391 
392  ((btCompoundShape *)next)->addChildShape(trans, shape);
393  }
394  else {
395  // We have one shape which is NOT a compound shape, and want to add a
396  // second shape. We need to wrap both shapes within a compound shape.
397  next = new btCompoundShape();
398 
399  btTransform previous_trans = btTransform::getIdentity();
400  ((btCompoundShape *)next)->addChildShape(previous_trans, previous);
401  ((btCompoundShape *)next)->addChildShape(trans, shape);
402 
403  get_object()->setCollisionShape(next);
404  _shape = next;
405  }
406  }
407  else {
408  // We already have two or more shapes, and want to add another. So we
409  // already have a compound shape as wrapper, and just need to add the new
410  // shape to the compound.
411  nassertv(previous->getShapeType() == COMPOUND_SHAPE_PROXYTYPE);
412 
413  next = previous;
414  ((btCompoundShape *)next)->addChildShape(trans, shape);
415  }
416 
417  _shapes.push_back(bullet_shape);
418 
419  // Restore the local scaling again
420  np.set_scale(scale);
421 
422  do_shape_changed();
423 }
424 
425 /**
426  *
427  */
428 void BulletBodyNode::
429 remove_shape(BulletShape *shape) {
430  LightMutexHolder holder(BulletWorld::get_global_lock());
431 
432  nassertv(get_object());
433 
434  BulletShapes::iterator found;
435  PT(BulletShape) ptshape = shape;
436  found = find(_shapes.begin(), _shapes.end(), ptshape);
437 
438  if (found == _shapes.end()) {
439  bullet_cat.warning() << "shape not attached" << std::endl;
440  }
441  else {
442  _shapes.erase(found);
443 
444  // Determine the new root shape
445  btCollisionShape *previous = get_object()->getCollisionShape();
446  btCollisionShape *next;
447 
448  if (_shapes.size() == 0) {
449  // No more shapes remaining
450  next = new btEmptyShape();
451 
452  get_object()->setCollisionShape(next);
453  _shape = next;
454 
455  // The previous shape might be a compound. Then delete it.
456  if (previous->getShapeType() == COMPOUND_SHAPE_PROXYTYPE) {
457  delete previous;
458  }
459  }
460  else if (_shapes.size() == 1) {
461  // Only one shape remaining
462  nassertv(previous->getShapeType() == COMPOUND_SHAPE_PROXYTYPE)
463 
464  btCompoundShape *compound = (btCompoundShape *)previous;
465  compound->removeChildShape(shape->ptr());
466 
467  nassertv(compound->getNumChildShapes() == 1);
468 
469  // The compound is no longer required if the remaining shape has no
470  // transform
471  btTransform trans = compound->getChildTransform(0);
472  if (is_identity(trans)) {
473  next = compound->getChildShape(0);
474 
475  get_object()->setCollisionShape(next);
476  _shape = next;
477 
478  delete compound;
479  }
480  }
481  else {
482  // More than one shape are remaining
483  nassertv(previous->getShapeType() == COMPOUND_SHAPE_PROXYTYPE)
484 
485  btCompoundShape *compound = (btCompoundShape *)previous;
486  compound->removeChildShape(shape->ptr());
487  }
488 
489  do_shape_changed();
490  }
491 }
492 
493 /**
494  * Returns TRUE if the transform is an identity transform, otherwise FALSE.
495  */
496 bool BulletBodyNode::
497 is_identity(btTransform &trans) {
498 
499  btVector3 null(0, 0, 0);
500 
501  return (trans.getOrigin() == null
502  && trans.getRotation().getAxis() == null);
503 }
504 
505 /**
506  *
507  */
508 LPoint3 BulletBodyNode::
509 get_shape_pos(int idx) const {
510  LightMutexHolder holder(BulletWorld::get_global_lock());
511 
512  nassertr(idx >= 0 && idx < (int)_shapes.size(), LPoint3::zero());
513 
514  btCollisionShape *root = get_object()->getCollisionShape();
515  if (root->getShapeType() == COMPOUND_SHAPE_PROXYTYPE) {
516  btCompoundShape *compound = (btCompoundShape *)root;
517 
518  btTransform trans = compound->getChildTransform(idx);
519  return btVector3_to_LVector3(trans.getOrigin());
520  }
521 
522  return LPoint3::zero();
523 }
524 
525 /**
526  *
527  */
528 LMatrix4 BulletBodyNode::
529 get_shape_mat(int idx) const {
530  LightMutexHolder holder(BulletWorld::get_global_lock());
531 
532  return do_get_shape_transform(idx)->get_mat();
533 }
534 
535 /**
536  *
537  */
538 CPT(TransformState) BulletBodyNode::
539 do_get_shape_transform(int idx) const {
540 
541  nassertr(idx >= 0 && idx < (int)_shapes.size(), TransformState::make_identity());
542 
543  btCollisionShape *root = get_object()->getCollisionShape();
544  if (root->getShapeType() == COMPOUND_SHAPE_PROXYTYPE) {
545  btCompoundShape *compound = (btCompoundShape *)root;
546 
547  btTransform trans = compound->getChildTransform(idx);
548  return btTrans_to_TransformState(trans);
549 
550  // The above code assumes that shape's index in _shapes member is the same
551  // as the shapes index within the compound. If it turns out that this is
552  // not always true we could use the following code:
553  /*
554  btCollisionShape *shape = get_shape(idx)->ptr();
555  for (int i=0; i<compound->getNumChildShapes(); i++) {
556  if (compound->getChildShape(i) == shape) {
557  btTransform trans = compound->getChildTransform(idx);
558  return btTrans_to_LMatrix4(trans);
559  }
560  }
561  */
562  }
563 
564  return TransformState::make_identity();
565 }
566 
567 /**
568  *
569  */
570 CPT(TransformState) BulletBodyNode::
571 get_shape_transform(int idx) const {
572  LightMutexHolder holder(BulletWorld::get_global_lock());
573 
574  return do_get_shape_transform(idx);
575 }
576 
577 
578 /**
579  * Hook which will be called whenever the total shape of a body changed. Used
580  * for example to update the mass properties (inertia) of a rigid body. The
581  * default implementation does nothing.
582  * Assumes the lock(bullet global lock) is held
583  */
584 void BulletBodyNode::
585 do_shape_changed() {
586 
587 }
588 
589 /**
590  *
591  */
592 void BulletBodyNode::
593 set_deactivation_time(PN_stdfloat dt) {
594  LightMutexHolder holder(BulletWorld::get_global_lock());
595 
596  get_object()->setDeactivationTime(dt);
597 }
598 
599 /**
600  *
601  */
602 PN_stdfloat BulletBodyNode::
603 get_deactivation_time() const {
604  LightMutexHolder holder(BulletWorld::get_global_lock());
605 
606  return get_object()->getDeactivationTime();
607 }
608 
609 /**
610  *
611  */
612 bool BulletBodyNode::
613 is_active() const {
614  LightMutexHolder holder(BulletWorld::get_global_lock());
615 
616  return get_object()->isActive();
617 }
618 
619 /**
620  *
621  */
622 void BulletBodyNode::
623 set_active(bool active, bool force) {
624  LightMutexHolder holder(BulletWorld::get_global_lock());
625 
626  if (active) {
627  get_object()->activate(force);
628  }
629  else {
630  if (force) {
631  get_object()->forceActivationState(ISLAND_SLEEPING);
632  }
633  else {
634  get_object()->setActivationState(ISLAND_SLEEPING);
635  }
636  }
637 }
638 
639 /**
640  *
641  */
642 void BulletBodyNode::
643 force_active(bool active) {
644 
645  set_active(active, true);
646 }
647 
648 /**
649  * If true, this object will be deactivated after a certain amount of time has
650  * passed without movement. If false, the object will always remain active.
651  */
652 void BulletBodyNode::
653 set_deactivation_enabled(bool enabled) {
654  LightMutexHolder holder(BulletWorld::get_global_lock());
655 
656  // Don't change the state if it's currently active and we enable
657  // deactivation.
658  bool is_enabled = get_object()->getActivationState() != DISABLE_DEACTIVATION;
659  if (enabled != is_enabled) {
660 
661  // It's OK to set to ACTIVE_TAG even if we don't mean to activate it; it
662  // will be disabled right away if the deactivation timer has run out.
663  int state = (enabled) ? ACTIVE_TAG : DISABLE_DEACTIVATION;
664  get_object()->forceActivationState(state);
665  }
666 }
667 
668 /**
669  *
670  */
671 bool BulletBodyNode::
672 is_deactivation_enabled() const {
673  LightMutexHolder holder(BulletWorld::get_global_lock());
674 
675  return (get_object()->getActivationState() != DISABLE_DEACTIVATION);
676 }
677 
678 /**
679  *
680  */
681 bool BulletBodyNode::
682 check_collision_with(PandaNode *node) {
683  LightMutexHolder holder(BulletWorld::get_global_lock());
684 
685  btCollisionObject *obj = BulletWorld::get_collision_object(node);
686 
687  if (obj) {
688  return get_object()->checkCollideWith(obj);
689  }
690  else {
691  return false;
692  }
693 }
694 
695 /**
696  *
697  */
698 LVecBase3 BulletBodyNode::
699 get_anisotropic_friction() const {
700  LightMutexHolder holder(BulletWorld::get_global_lock());
701 
702  return btVector3_to_LVecBase3(get_object()->getAnisotropicFriction());
703 }
704 
705 /**
706  *
707  */
708 void BulletBodyNode::
709 set_anisotropic_friction(const LVecBase3 &friction) {
710  LightMutexHolder holder(BulletWorld::get_global_lock());
711 
712  nassertv(!friction.is_nan());
713  get_object()->setAnisotropicFriction(LVecBase3_to_btVector3(friction));
714 }
715 
716 /**
717  *
718  */
719 bool BulletBodyNode::
720 has_contact_response() const {
721  LightMutexHolder holder(BulletWorld::get_global_lock());
722 
723  return get_object()->hasContactResponse();
724 }
725 
726 /**
727  *
728  */
729 PN_stdfloat BulletBodyNode::
730 get_contact_processing_threshold() const {
731  LightMutexHolder holder(BulletWorld::get_global_lock());
732 
733  return get_object()->getContactProcessingThreshold();
734 }
735 
736 /**
737  * The constraint solver can discard solving contacts, if the distance is
738  * above this threshold.
739  */
740 void BulletBodyNode::
741 set_contact_processing_threshold(PN_stdfloat threshold) {
742  LightMutexHolder holder(BulletWorld::get_global_lock());
743 
744  get_object()->setContactProcessingThreshold(threshold);
745 }
746 
747 /**
748  *
749  */
750 PN_stdfloat BulletBodyNode::
751 get_ccd_swept_sphere_radius() const {
752  LightMutexHolder holder(BulletWorld::get_global_lock());
753 
754  return get_object()->getCcdSweptSphereRadius();
755 }
756 
757 /**
758  *
759  */
760 void BulletBodyNode::
761 set_ccd_swept_sphere_radius(PN_stdfloat radius) {
762  LightMutexHolder holder(BulletWorld::get_global_lock());
763 
764  return get_object()->setCcdSweptSphereRadius(radius);
765 }
766 
767 /**
768  *
769  */
770 PN_stdfloat BulletBodyNode::
771 get_ccd_motion_threshold() const {
772  LightMutexHolder holder(BulletWorld::get_global_lock());
773 
774  return get_object()->getCcdMotionThreshold();
775 }
776 
777 /**
778  *
779  */
780 void BulletBodyNode::
781 set_ccd_motion_threshold(PN_stdfloat threshold) {
782  LightMutexHolder holder(BulletWorld::get_global_lock());
783 
784  return get_object()->setCcdMotionThreshold(threshold);
785 }
786 
787 /**
788  *
789  */
790 void BulletBodyNode::
791 add_shapes_from_collision_solids(CollisionNode *cnode) {
792  LightMutexHolder holder(BulletWorld::get_global_lock());
793 
794  PT(BulletTriangleMesh) mesh = nullptr;
795 
796  for (size_t j = 0; j < cnode->get_num_solids(); ++j) {
797  CPT(CollisionSolid) solid = cnode->get_solid(j);
798  TypeHandle type = solid->get_type();
799 
800  // CollisionSphere
801  if (CollisionSphere::get_class_type() == type) {
802  CPT(CollisionSphere) sphere = DCAST(CollisionSphere, solid);
803  CPT(TransformState) ts = TransformState::make_pos(sphere->get_center());
804 
805  do_add_shape(BulletSphereShape::make_from_solid(sphere), ts);
806  }
807 
808  // CollisionBox
809  else if (CollisionBox::get_class_type() == type) {
810  CPT(CollisionBox) box = DCAST(CollisionBox, solid);
811  CPT(TransformState) ts = TransformState::make_pos(box->get_center());
812 
813  do_add_shape(BulletBoxShape::make_from_solid(box), ts);
814  }
815 
816  // CollisionCapsule
817  else if (CollisionCapsule::get_class_type() == type) {
818  CPT(CollisionCapsule) capsule = DCAST(CollisionCapsule, solid);
819  CPT(TransformState) ts = TransformState::make_pos((capsule->get_point_b() + capsule->get_point_a()) / 2.0);
820 
821  do_add_shape(BulletCapsuleShape::make_from_solid(capsule), ts);
822  }
823 
824  // CollisionPlane
825  else if (CollisionPlane::get_class_type() == type) {
826  CPT(CollisionPlane) plane = DCAST(CollisionPlane, solid);
827 
828  do_add_shape(BulletPlaneShape::make_from_solid(plane));
829  }
830 
831  // CollisionGeom
832  else if (CollisionPolygon::get_class_type() == type) {
833  CPT(CollisionPolygon) polygon = DCAST(CollisionPolygon, solid);
834 
835  if (!mesh) {
836  mesh = new BulletTriangleMesh();
837  }
838 
839  for (size_t i = 2; i < polygon->get_num_points(); ++i) {
840  LPoint3 p1 = polygon->get_point(0);
841  LPoint3 p2 = polygon->get_point(i - 1);
842  LPoint3 p3 = polygon->get_point(i);
843 
844  mesh->do_add_triangle(p1, p2, p3, true);
845  }
846  }
847  }
848 
849  if (mesh && mesh->do_get_num_triangles() > 0) {
850  do_add_shape(new BulletTriangleMeshShape(mesh, true));
851  }
852 }
853 
854 /**
855  * This method enforces an update of the Bullet transform, that is copies the
856  * scene graph transform to the Bullet transform. This is achieved by alling
857  * the protected PandaNode hook 'transform_changed'.
858  */
859 void BulletBodyNode::
861 
862  transform_changed();
863 }
864 
865 /**
866  * Returns the current bounds of all collision shapes owned by this body.
867  */
868 BoundingSphere BulletBodyNode::
869 get_shape_bounds() const {
870  LightMutexHolder holder(BulletWorld::get_global_lock());
871 
872 /*
873  btTransform tr;
874  tr.setIdentity();
875  btVector3 aabbMin,aabbMax;
876  ptr()->getAabb(tr,aabbMin,aabbMax);
877  btVector3 o = tr.getOrigin();
878 cout << "aabbMin " << aabbMin.x() << " " << aabbMin.y() << " " << aabbMin.z() << endl;
879 cout << "aabbMax " << aabbMax.x() << " " << aabbMax.y() << " " << aabbMax.z() << endl;
880 cout << "origin " << aabbMin.x() << " " << aabbMin.y() << " " << aabbMin.z() << endl;
881 */
882 
883  btVector3 center;
884  btScalar radius = 0;
885 
886  if (_shape) {
887  _shape->getBoundingSphere(center, radius);
888  }
889 
890  BoundingSphere bounds(btVector3_to_LPoint3(center), (PN_stdfloat)radius);
891 
892  return bounds;
893 }
894 
895 /**
896  * Writes the contents of this object to the datagram for shipping out to a
897  * Bam file.
898  */
899 void BulletBodyNode::
901  PandaNode::write_datagram(manager, dg);
902 
903  dg.add_bool(is_static());
904  dg.add_bool(is_kinematic());
905  dg.add_bool(notifies_collisions());
906  dg.add_bool(get_collision_response());
907  dg.add_stdfloat(get_contact_processing_threshold());
908  // dg.add_bool(is_active());
909  dg.add_stdfloat(get_deactivation_time());
910  dg.add_bool(is_deactivation_enabled());
911  // dg.add_bool(is_debug_enabled());
912  dg.add_stdfloat(get_restitution());
913  dg.add_stdfloat(get_friction());
914 #if BT_BULLET_VERSION >= 281
915  dg.add_stdfloat(get_rolling_friction());
916 #else
917  dg.add_stdfloat(0);
918 #endif
919  if (has_anisotropic_friction()) {
920  dg.add_bool(true);
921  get_anisotropic_friction().write_datagram(dg);
922  } else {
923  dg.add_bool(false);
924  }
925  dg.add_stdfloat(get_ccd_swept_sphere_radius());
926  dg.add_stdfloat(get_ccd_motion_threshold());
927 
928  for (unsigned int i = 0; i < _shapes.size(); ++i) {
929  manager->write_pointer(dg, get_shape(i));
930  manager->write_pointer(dg, get_shape_transform(i));
931  }
932 
933  // Write NULL pointer to indicate the end of the list.
934  manager->write_pointer(dg, nullptr);
935 }
936 
937 /**
938  * Receives an array of pointers, one for each time manager->read_pointer()
939  * was called in fillin(). Returns the number of pointers processed.
940  */
943  int pi = PandaNode::complete_pointers(p_list, manager);
944 
945  PT(BulletShape) shape = DCAST(BulletShape, p_list[pi++]);
946 
947  while (shape != nullptr) {
948  const TransformState *trans = DCAST(TransformState, p_list[pi++]);
949  add_shape(shape, trans);
950 
951  shape = DCAST(BulletShape, p_list[pi++]);
952  }
953 
954  return pi;
955 }
956 
957 /**
958  * Some objects require all of their nested pointers to have been completed
959  * before the objects themselves can be completed. If this is the case,
960  * override this method to return true, and be careful with circular
961  * references (which would make the object unreadable from a bam file).
962  */
963 bool BulletBodyNode::
965  // We require the shape pointers to be complete before we add them.
966  return true;
967 }
968 
969 /**
970  * This internal function is called by make_from_bam to read in all of the
971  * relevant data from the BamFile for the new BulletBodyNode.
972  */
973 void BulletBodyNode::
974 fillin(DatagramIterator &scan, BamReader *manager) {
975  PandaNode::fillin(scan, manager);
976 
977  set_static(scan.get_bool());
978  set_kinematic(scan.get_bool());
979  notify_collisions(scan.get_bool());
980  set_collision_response(scan.get_bool());
982  // set_active(scan.get_bool(), true);
983  set_deactivation_time(scan.get_stdfloat());
985  set_restitution(scan.get_stdfloat());
986  set_friction(scan.get_stdfloat());
987 #if BT_BULLET_VERSION >= 281
988  set_rolling_friction(scan.get_stdfloat());
989 #else
990  scan.get_stdfloat();
991 #endif
992  if (scan.get_bool()) {
993  LVector3 friction;
994  friction.read_datagram(scan);
995  set_anisotropic_friction(friction);
996  }
997  set_ccd_swept_sphere_radius(scan.get_stdfloat());
998  set_ccd_motion_threshold(scan.get_stdfloat());
999 
1000  // Read shapes. The list is bounded by a NULL pointer.
1001  while (manager->read_pointer(scan)) {
1002  // Each shape comes with a TransformState.
1003  manager->read_pointer(scan);
1004  }
1005 }
A basic node of the scene graph or data graph.
Definition: pandaNode.h:64
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void set_transform_dirty()
This method enforces an update of the Bullet transform, that is copies the scene graph transform to t...
Indicates a coordinate-system transform on vertices.
bool get_bool()
Extracts a boolean value.
PN_stdfloat get_stdfloat()
Extracts either a 32-bit or a 64-bit floating-point number, according to Datagram::set_stdfloat_doubl...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: pandaNode.cxx:3589
virtual bool require_fully_complete() const
Some objects require all of their nested pointers to have been completed before the objects themselve...
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
static BitMask< WType, nbits > all_on()
Returns a BitMask whose bits are all on.
Definition: bitMask.I:32
The abstract base class for all things that can collide with other things in the world,...
set_contact_processing_threshold
The constraint solver can discard solving contacts, if the distance is above this threshold.
virtual bool safe_to_flatten_below() const
Returns true if a flatten operation may safely continue past this node, or false if nodes below this ...
This defines a bounding sphere, consisting of a center and a radius.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
A cuboid collision volume or object.
Definition: collisionBox.h:27
void set_scale(PN_stdfloat scale)
Sets the scale component of the transform, leaving translation and rotation untouched.
Definition: nodePath.I:675
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
A spherical collision volume or object.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static NodePath any_path(PandaNode *node, Thread *current_thread=Thread::get_current_thread())
Returns a new NodePath that represents any arbitrary path from the root to the indicated node.
Definition: nodePath.I:62
void add_stdfloat(PN_stdfloat value)
Adds either a 32-bit or a 64-bit floating-point number, according to set_stdfloat_double().
Definition: datagram.I:133
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual bool safe_to_modify_transform() const
Returns true if it is safe to automatically adjust the transform on this kind of node.
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:34
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
Similar to MutexHolder, but for a light mutex.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual bool safe_to_flatten() const
Returns true if it is generally safe to flatten out this particular kind of Node by duplicating insta...
This implements a solid consisting of a cylinder with hemispherical endcaps, also known as a capsule ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
set_into_collide_mask
Sets the "into" CollideMask.
Definition: pandaNode.h:264
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
virtual CollideMask get_legal_collide_mask() const
Returns the subset of CollideMask bits that may be set for this particular type of PandaNode.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:610
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A node in the scene graph that can hold any number of CollisionSolids.
Definition: collisionNode.h:30
LVecBase3 get_scale() const
Retrieves the scale component of the transform.
Definition: nodePath.cxx:1128
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual bool safe_to_transform() const
Returns true if it is generally safe to transform this particular kind of Node by calling the xform()...
static BulletCapsuleShape * make_from_solid(const CollisionCapsule *solid)
Constructs a new BulletCapsuleShape using the information from a CollisionCapsule from the builtin co...
A class to retrieve the individual data elements previously stored in a Datagram.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
CPT(TransformState) BulletBodyNode
Hook which will be called whenever the total shape of a body changed.
A general bitmask class.
Definition: bitMask.h:32
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:161
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
Definition: bamWriter.cxx:317
set_deactivation_enabled
If true, this object will be deactivated after a certain amount of time has passed without movement.
virtual bool safe_to_combine() const
Returns true if it is generally safe to combine this particular kind of PandaNode with other kinds of...
virtual bool safe_to_combine_children() const
Returns true if it is generally safe to combine the children of this PandaNode with each other.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool is_identity() const
Returns true if the transform represents the identity matrix, false otherwise.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.