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
45  set_into_collide_mask(CollideMask::all_on());
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  */
83 get_legal_collide_mask() const {
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  */
106 safe_to_transform() const {
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  */
120 safe_to_modify_transform() const {
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  */
132 safe_to_combine() const {
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  */
143 safe_to_combine_children() const {
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  */
153 safe_to_flatten_below() const {
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  CPT(TransformState) prev_transform = get_transform();
357  bool scale_changed = false;
358  if (!prev_transform->is_identity() && prev_transform->get_scale() != LVecBase3(1.0, 1.0, 1.0)) {
359  // As a hack, temporarily release the lock, since transform_changed will
360  // otherwise deadlock trying to grab it again. See GitHub issue #689.
361  LightMutex &lock = BulletWorld::get_global_lock();
362  lock.release();
363  set_transform(prev_transform->set_scale(LVecBase3(1.0, 1.0, 1.0)));
364  lock.acquire();
365  scale_changed = true;
366  }
367 
368  // Root shape
369  btCollisionShape *previous = get_object()->getCollisionShape();
370  btCollisionShape *next;
371 
372  if (_shapes.size() == 0) {
373  nassertv(previous->getShapeType() == EMPTY_SHAPE_PROXYTYPE);
374 
375  if (ts->is_identity()) {
376  // After adding the shape we will have one shape, but with transform.
377  // We need to wrap the shape within a compound shape, in oder to be able
378  // to set the local transform.
379  next = shape;
380  }
381  else {
382  // After adding the shape we will have a total of one shape, without
383  // local transform. We can set the shape directly.
384  next = new btCompoundShape();
385  ((btCompoundShape *)next)->addChildShape(trans, shape);
386  }
387 
388  get_object()->setCollisionShape(next);
389  _shape = next;
390 
391  delete previous;
392  }
393  else if (_shapes.size() == 1) {
394  if (previous->getShapeType() == COMPOUND_SHAPE_PROXYTYPE) {
395  // We have one shape, and add another shape. The previous shape is
396  // already a compound shape. So we just need to add the second shape to
397  // the compound shape.
398  next = previous;
399 
400  ((btCompoundShape *)next)->addChildShape(trans, shape);
401  }
402  else {
403  // We have one shape which is NOT a compound shape, and want to add a
404  // second shape. We need to wrap both shapes within a compound shape.
405  next = new btCompoundShape();
406 
407  btTransform previous_trans = btTransform::getIdentity();
408  ((btCompoundShape *)next)->addChildShape(previous_trans, previous);
409  ((btCompoundShape *)next)->addChildShape(trans, shape);
410 
411  get_object()->setCollisionShape(next);
412  _shape = next;
413  }
414  }
415  else {
416  // We already have two or more shapes, and want to add another. So we
417  // already have a compound shape as wrapper, and just need to add the new
418  // shape to the compound.
419  nassertv(previous->getShapeType() == COMPOUND_SHAPE_PROXYTYPE);
420 
421  next = previous;
422  ((btCompoundShape *)next)->addChildShape(trans, shape);
423  }
424 
425  _shapes.push_back(bullet_shape);
426 
427  // Restore the local scaling again
428  if (scale_changed) {
429  CPT(TransformState) transform = get_transform()->set_scale(prev_transform->get_scale());
430  LightMutex &lock = BulletWorld::get_global_lock();
431  lock.release();
432  set_transform(std::move(transform));
433  lock.acquire();
434  }
435 
436  do_shape_changed();
437 }
438 
439 /**
440  *
441  */
442 void BulletBodyNode::
443 remove_shape(BulletShape *shape) {
444  LightMutexHolder holder(BulletWorld::get_global_lock());
445 
446  nassertv(get_object());
447 
448  BulletShapes::iterator found;
449  PT(BulletShape) ptshape = shape;
450  found = find(_shapes.begin(), _shapes.end(), ptshape);
451 
452  if (found == _shapes.end()) {
453  bullet_cat.warning() << "shape not attached" << std::endl;
454  }
455  else {
456  _shapes.erase(found);
457 
458  // Determine the new root shape
459  btCollisionShape *previous = get_object()->getCollisionShape();
460  btCollisionShape *next;
461 
462  if (_shapes.size() == 0) {
463  // No more shapes remaining
464  next = new btEmptyShape();
465 
466  get_object()->setCollisionShape(next);
467  _shape = next;
468 
469  // The previous shape might be a compound. Then delete it.
470  if (previous->getShapeType() == COMPOUND_SHAPE_PROXYTYPE) {
471  delete previous;
472  }
473  }
474  else if (_shapes.size() == 1) {
475  // Only one shape remaining
476  nassertv(previous->getShapeType() == COMPOUND_SHAPE_PROXYTYPE)
477 
478  btCompoundShape *compound = (btCompoundShape *)previous;
479  compound->removeChildShape(shape->ptr());
480 
481  nassertv(compound->getNumChildShapes() == 1);
482 
483  // The compound is no longer required if the remaining shape has no
484  // transform
485  btTransform trans = compound->getChildTransform(0);
486  if (is_identity(trans)) {
487  next = compound->getChildShape(0);
488 
489  get_object()->setCollisionShape(next);
490  _shape = next;
491 
492  delete compound;
493  }
494  }
495  else {
496  // More than one shape are remaining
497  nassertv(previous->getShapeType() == COMPOUND_SHAPE_PROXYTYPE)
498 
499  btCompoundShape *compound = (btCompoundShape *)previous;
500  compound->removeChildShape(shape->ptr());
501  }
502 
503  do_shape_changed();
504  }
505 }
506 
507 /**
508  * Returns TRUE if the transform is an identity transform, otherwise FALSE.
509  */
510 bool BulletBodyNode::
511 is_identity(btTransform &trans) {
512 
513  btVector3 null(0, 0, 0);
514 
515  return (trans.getOrigin() == null
516  && trans.getRotation().getAxis() == null);
517 }
518 
519 /**
520  *
521  */
522 LPoint3 BulletBodyNode::
523 get_shape_pos(int idx) const {
524  LightMutexHolder holder(BulletWorld::get_global_lock());
525 
526  nassertr(idx >= 0 && idx < (int)_shapes.size(), LPoint3::zero());
527 
528  btCollisionShape *root = get_object()->getCollisionShape();
529  if (root->getShapeType() == COMPOUND_SHAPE_PROXYTYPE) {
530  btCompoundShape *compound = (btCompoundShape *)root;
531 
532  btTransform trans = compound->getChildTransform(idx);
533  return btVector3_to_LVector3(trans.getOrigin());
534  }
535 
536  return LPoint3::zero();
537 }
538 
539 /**
540  *
541  */
542 LMatrix4 BulletBodyNode::
543 get_shape_mat(int idx) const {
544  LightMutexHolder holder(BulletWorld::get_global_lock());
545 
546  return do_get_shape_transform(idx)->get_mat();
547 }
548 
549 /**
550  *
551  */
552 CPT(TransformState) BulletBodyNode::
553 do_get_shape_transform(int idx) const {
554 
555  nassertr(idx >= 0 && idx < (int)_shapes.size(), TransformState::make_identity());
556 
557  btCollisionShape *root = get_object()->getCollisionShape();
558  if (root->getShapeType() == COMPOUND_SHAPE_PROXYTYPE) {
559  btCompoundShape *compound = (btCompoundShape *)root;
560 
561  btTransform trans = compound->getChildTransform(idx);
562  return btTrans_to_TransformState(trans);
563 
564  // The above code assumes that shape's index in _shapes member is the same
565  // as the shapes index within the compound. If it turns out that this is
566  // not always true we could use the following code:
567  /*
568  btCollisionShape *shape = get_shape(idx)->ptr();
569  for (int i=0; i<compound->getNumChildShapes(); i++) {
570  if (compound->getChildShape(i) == shape) {
571  btTransform trans = compound->getChildTransform(idx);
572  return btTrans_to_LMatrix4(trans);
573  }
574  }
575  */
576  }
577 
578  return TransformState::make_identity();
579 }
580 
581 /**
582  *
583  */
584 CPT(TransformState) BulletBodyNode::
585 get_shape_transform(int idx) const {
586  LightMutexHolder holder(BulletWorld::get_global_lock());
587 
588  return do_get_shape_transform(idx);
589 }
590 
591 
592 /**
593  * Hook which will be called whenever the total shape of a body changed. Used
594  * for example to update the mass properties (inertia) of a rigid body. The
595  * default implementation does nothing.
596  * Assumes the lock(bullet global lock) is held
597  */
598 void BulletBodyNode::
599 do_shape_changed() {
600 
601 }
602 
603 /**
604  *
605  */
606 void BulletBodyNode::
607 set_deactivation_time(PN_stdfloat dt) {
608  LightMutexHolder holder(BulletWorld::get_global_lock());
609 
610  get_object()->setDeactivationTime(dt);
611 }
612 
613 /**
614  *
615  */
616 PN_stdfloat BulletBodyNode::
617 get_deactivation_time() const {
618  LightMutexHolder holder(BulletWorld::get_global_lock());
619 
620  return get_object()->getDeactivationTime();
621 }
622 
623 /**
624  *
625  */
626 bool BulletBodyNode::
627 is_active() const {
628  LightMutexHolder holder(BulletWorld::get_global_lock());
629 
630  return get_object()->isActive();
631 }
632 
633 /**
634  *
635  */
636 void BulletBodyNode::
637 set_active(bool active, bool force) {
638  LightMutexHolder holder(BulletWorld::get_global_lock());
639 
640  if (active) {
641  get_object()->activate(force);
642  }
643  else {
644  if (force) {
645  get_object()->forceActivationState(ISLAND_SLEEPING);
646  }
647  else {
648  get_object()->setActivationState(ISLAND_SLEEPING);
649  }
650  }
651 }
652 
653 /**
654  *
655  */
656 void BulletBodyNode::
657 force_active(bool active) {
658 
659  set_active(active, true);
660 }
661 
662 /**
663  * If true, this object will be deactivated after a certain amount of time has
664  * passed without movement. If false, the object will always remain active.
665  */
666 void BulletBodyNode::
667 set_deactivation_enabled(bool enabled) {
668  LightMutexHolder holder(BulletWorld::get_global_lock());
669 
670  // Don't change the state if it's currently active and we enable
671  // deactivation.
672  bool is_enabled = get_object()->getActivationState() != DISABLE_DEACTIVATION;
673  if (enabled != is_enabled) {
674 
675  // It's OK to set to ACTIVE_TAG even if we don't mean to activate it; it
676  // will be disabled right away if the deactivation timer has run out.
677  int state = (enabled) ? ACTIVE_TAG : DISABLE_DEACTIVATION;
678  get_object()->forceActivationState(state);
679  }
680 }
681 
682 /**
683  *
684  */
685 bool BulletBodyNode::
686 is_deactivation_enabled() const {
687  LightMutexHolder holder(BulletWorld::get_global_lock());
688 
689  return (get_object()->getActivationState() != DISABLE_DEACTIVATION);
690 }
691 
692 /**
693  *
694  */
695 bool BulletBodyNode::
696 check_collision_with(PandaNode *node) {
697  LightMutexHolder holder(BulletWorld::get_global_lock());
698 
699  btCollisionObject *obj = BulletWorld::get_collision_object(node);
700 
701  if (obj) {
702  return get_object()->checkCollideWith(obj);
703  }
704  else {
705  return false;
706  }
707 }
708 
709 /**
710  *
711  */
712 LVecBase3 BulletBodyNode::
713 get_anisotropic_friction() const {
714  LightMutexHolder holder(BulletWorld::get_global_lock());
715 
716  return btVector3_to_LVecBase3(get_object()->getAnisotropicFriction());
717 }
718 
719 /**
720  *
721  */
722 void BulletBodyNode::
723 set_anisotropic_friction(const LVecBase3 &friction) {
724  LightMutexHolder holder(BulletWorld::get_global_lock());
725 
726  nassertv(!friction.is_nan());
727  get_object()->setAnisotropicFriction(LVecBase3_to_btVector3(friction));
728 }
729 
730 /**
731  *
732  */
733 bool BulletBodyNode::
734 has_contact_response() const {
735  LightMutexHolder holder(BulletWorld::get_global_lock());
736 
737  return get_object()->hasContactResponse();
738 }
739 
740 /**
741  *
742  */
743 PN_stdfloat BulletBodyNode::
744 get_contact_processing_threshold() const {
745  LightMutexHolder holder(BulletWorld::get_global_lock());
746 
747  return get_object()->getContactProcessingThreshold();
748 }
749 
750 /**
751  * The constraint solver can discard solving contacts, if the distance is
752  * above this threshold.
753  */
754 void BulletBodyNode::
755 set_contact_processing_threshold(PN_stdfloat threshold) {
756  LightMutexHolder holder(BulletWorld::get_global_lock());
757 
758  get_object()->setContactProcessingThreshold(threshold);
759 }
760 
761 /**
762  *
763  */
764 PN_stdfloat BulletBodyNode::
765 get_ccd_swept_sphere_radius() const {
766  LightMutexHolder holder(BulletWorld::get_global_lock());
767 
768  return get_object()->getCcdSweptSphereRadius();
769 }
770 
771 /**
772  *
773  */
774 void BulletBodyNode::
775 set_ccd_swept_sphere_radius(PN_stdfloat radius) {
776  LightMutexHolder holder(BulletWorld::get_global_lock());
777 
778  return get_object()->setCcdSweptSphereRadius(radius);
779 }
780 
781 /**
782  *
783  */
784 PN_stdfloat BulletBodyNode::
785 get_ccd_motion_threshold() const {
786  LightMutexHolder holder(BulletWorld::get_global_lock());
787 
788  return get_object()->getCcdMotionThreshold();
789 }
790 
791 /**
792  *
793  */
794 void BulletBodyNode::
795 set_ccd_motion_threshold(PN_stdfloat threshold) {
796  LightMutexHolder holder(BulletWorld::get_global_lock());
797 
798  return get_object()->setCcdMotionThreshold(threshold);
799 }
800 
801 /**
802  *
803  */
804 void BulletBodyNode::
805 add_shapes_from_collision_solids(CollisionNode *cnode) {
806  LightMutexHolder holder(BulletWorld::get_global_lock());
807 
808  PT(BulletTriangleMesh) mesh = nullptr;
809 
810  for (size_t j = 0; j < cnode->get_num_solids(); ++j) {
811  CPT(CollisionSolid) solid = cnode->get_solid(j);
812  TypeHandle type = solid->get_type();
813 
814  // CollisionSphere
815  if (CollisionSphere::get_class_type() == type) {
816  CPT(CollisionSphere) sphere = DCAST(CollisionSphere, solid);
817  CPT(TransformState) ts = TransformState::make_pos(sphere->get_center());
818 
819  do_add_shape(BulletSphereShape::make_from_solid(sphere), ts);
820  }
821 
822  // CollisionBox
823  else if (CollisionBox::get_class_type() == type) {
824  CPT(CollisionBox) box = DCAST(CollisionBox, solid);
825  CPT(TransformState) ts = TransformState::make_pos(box->get_center());
826 
827  do_add_shape(BulletBoxShape::make_from_solid(box), ts);
828  }
829 
830  // CollisionCapsule
831  else if (CollisionCapsule::get_class_type() == type) {
832  CPT(CollisionCapsule) capsule = DCAST(CollisionCapsule, solid);
833  CPT(TransformState) ts = TransformState::make_pos((capsule->get_point_b() + capsule->get_point_a()) / 2.0);
834 
835  do_add_shape(BulletCapsuleShape::make_from_solid(capsule), ts);
836  }
837 
838  // CollisionPlane
839  else if (CollisionPlane::get_class_type() == type) {
840  CPT(CollisionPlane) plane = DCAST(CollisionPlane, solid);
841 
842  do_add_shape(BulletPlaneShape::make_from_solid(plane));
843  }
844 
845  // CollisionGeom
846  else if (CollisionPolygon::get_class_type() == type) {
847  CPT(CollisionPolygon) polygon = DCAST(CollisionPolygon, solid);
848 
849  if (!mesh) {
850  mesh = new BulletTriangleMesh();
851  }
852 
853  for (size_t i = 2; i < polygon->get_num_points(); ++i) {
854  LPoint3 p1 = polygon->get_point(0);
855  LPoint3 p2 = polygon->get_point(i - 1);
856  LPoint3 p3 = polygon->get_point(i);
857 
858  mesh->do_add_triangle(p1, p2, p3, true);
859  }
860  }
861  }
862 
863  if (mesh && mesh->do_get_num_triangles() > 0) {
864  do_add_shape(new BulletTriangleMeshShape(mesh, true));
865  }
866 }
867 
868 /**
869  * This method enforces an update of the Bullet transform, that is copies the
870  * scene graph transform to the Bullet transform. This is achieved by alling
871  * the protected PandaNode hook 'transform_changed'.
872  */
875 
876  transform_changed();
877 }
878 
879 /**
880  * Returns the current bounds of all collision shapes owned by this body.
881  */
883 get_shape_bounds() const {
884  LightMutexHolder holder(BulletWorld::get_global_lock());
885 
886 /*
887  btTransform tr;
888  tr.setIdentity();
889  btVector3 aabbMin,aabbMax;
890  ptr()->getAabb(tr,aabbMin,aabbMax);
891  btVector3 o = tr.getOrigin();
892 cout << "aabbMin " << aabbMin.x() << " " << aabbMin.y() << " " << aabbMin.z() << endl;
893 cout << "aabbMax " << aabbMax.x() << " " << aabbMax.y() << " " << aabbMax.z() << endl;
894 cout << "origin " << aabbMin.x() << " " << aabbMin.y() << " " << aabbMin.z() << endl;
895 */
896 
897  btVector3 center;
898  btScalar radius = 0;
899 
900  if (_shape) {
901  _shape->getBoundingSphere(center, radius);
902  }
903 
904  BoundingSphere bounds(btVector3_to_LPoint3(center), (PN_stdfloat)radius);
905 
906  return bounds;
907 }
908 
909 /**
910  * Writes the contents of this object to the datagram for shipping out to a
911  * Bam file.
912  */
914 write_datagram(BamWriter *manager, Datagram &dg) {
915  PandaNode::write_datagram(manager, dg);
916 
917  dg.add_bool(is_static());
918  dg.add_bool(is_kinematic());
919  dg.add_bool(notifies_collisions());
920  dg.add_bool(get_collision_response());
921  dg.add_stdfloat(get_contact_processing_threshold());
922  // dg.add_bool(is_active());
923  dg.add_stdfloat(get_deactivation_time());
924  dg.add_bool(is_deactivation_enabled());
925  // dg.add_bool(is_debug_enabled());
926  dg.add_stdfloat(get_restitution());
927  dg.add_stdfloat(get_friction());
928 #if BT_BULLET_VERSION >= 281
929  dg.add_stdfloat(get_rolling_friction());
930 #else
931  dg.add_stdfloat(0);
932 #endif
933  if (has_anisotropic_friction()) {
934  dg.add_bool(true);
935  get_anisotropic_friction().write_datagram(dg);
936  } else {
937  dg.add_bool(false);
938  }
939  dg.add_stdfloat(get_ccd_swept_sphere_radius());
940  dg.add_stdfloat(get_ccd_motion_threshold());
941 
942  for (unsigned int i = 0; i < _shapes.size(); ++i) {
943  manager->write_pointer(dg, get_shape(i));
944  manager->write_pointer(dg, get_shape_transform(i));
945  }
946 
947  // Write NULL pointer to indicate the end of the list.
948  manager->write_pointer(dg, nullptr);
949 }
950 
951 /**
952  * Receives an array of pointers, one for each time manager->read_pointer()
953  * was called in fillin(). Returns the number of pointers processed.
954  */
956 complete_pointers(TypedWritable **p_list, BamReader *manager) {
957  int pi = PandaNode::complete_pointers(p_list, manager);
958 
959  PT(BulletShape) shape = DCAST(BulletShape, p_list[pi++]);
960 
961  while (shape != nullptr) {
962  const TransformState *trans = DCAST(TransformState, p_list[pi++]);
963  add_shape(shape, trans);
964 
965  shape = DCAST(BulletShape, p_list[pi++]);
966  }
967 
968  return pi;
969 }
970 
971 /**
972  * Some objects require all of their nested pointers to have been completed
973  * before the objects themselves can be completed. If this is the case,
974  * override this method to return true, and be careful with circular
975  * references (which would make the object unreadable from a bam file).
976  */
978 require_fully_complete() const {
979  // We require the shape pointers to be complete before we add them.
980  return true;
981 }
982 
983 /**
984  * This internal function is called by make_from_bam to read in all of the
985  * relevant data from the BamFile for the new BulletBodyNode.
986  */
987 void BulletBodyNode::
988 fillin(DatagramIterator &scan, BamReader *manager) {
989  PandaNode::fillin(scan, manager);
990 
991  set_static(scan.get_bool());
992  set_kinematic(scan.get_bool());
993  notify_collisions(scan.get_bool());
994  set_collision_response(scan.get_bool());
996  // set_active(scan.get_bool(), true);
997  set_deactivation_time(scan.get_stdfloat());
999  set_restitution(scan.get_stdfloat());
1000  set_friction(scan.get_stdfloat());
1001 #if BT_BULLET_VERSION >= 281
1002  set_rolling_friction(scan.get_stdfloat());
1003 #else
1004  scan.get_stdfloat();
1005 #endif
1006  if (scan.get_bool()) {
1007  LVector3 friction;
1008  friction.read_datagram(scan);
1009  set_anisotropic_friction(friction);
1010  }
1011  set_ccd_swept_sphere_radius(scan.get_stdfloat());
1012  set_ccd_motion_threshold(scan.get_stdfloat());
1013 
1014  // Read shapes. The list is bounded by a NULL pointer.
1015  while (manager->read_pointer(scan)) {
1016  // Each shape comes with a TransformState.
1017  manager->read_pointer(scan);
1018  }
1019 }
CPT(TransformState) BulletBodyNode
Hook which will be called whenever the total shape of a body changed.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:610
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
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
static BitMask< uint32_t, nbits > all_on()
Returns a BitMask whose bits are all on.
Definition: bitMask.I:32
This defines a bounding sphere, consisting of a center and a radius.
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 bool require_fully_complete() const
Some objects require all of their nested pointers to have been completed before the objects themselve...
virtual bool safe_to_flatten() const
Returns true if it is generally safe to flatten out this particular kind of Node by duplicating insta...
void set_transform_dirty()
This method enforces an update of the Bullet transform, that is copies the scene graph transform to t...
virtual bool safe_to_transform() const
Returns true if it is generally safe to transform this particular kind of Node by calling the xform()...
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 ...
get_shape_bounds
Returns the current bounds of all collision shapes owned by this body.
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 void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
virtual bool safe_to_modify_transform() const
Returns true if it is safe to automatically adjust the transform on this kind of node.
set_contact_processing_threshold
The constraint solver can discard solving contacts, if the distance is above this threshold.
virtual CollideMask get_legal_collide_mask() const
Returns the subset of CollideMask bits that may be set for this particular type of PandaNode.
virtual bool safe_to_combine_children() const
Returns true if it is generally safe to combine the children of this PandaNode with each other.
static BulletCapsuleShape * make_from_solid(const CollisionCapsule *solid)
Constructs a new BulletCapsuleShape using the information from a CollisionCapsule from the builtin co...
A cuboid collision volume or object.
Definition: collisionBox.h:27
This implements a solid consisting of a cylinder with hemispherical endcaps, also known as a capsule ...
A node in the scene graph that can hold any number of CollisionSolids.
Definition: collisionNode.h:30
The abstract base class for all things that can collide with other things in the world,...
A spherical collision volume or object.
A class to retrieve the individual data elements previously stored in a Datagram.
PN_stdfloat get_stdfloat()
Extracts either a 32-bit or a 64-bit floating-point number, according to Datagram::set_stdfloat_doubl...
bool get_bool()
Extracts a boolean value.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
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
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:34
void release() const
Releases the lightMutex.
void acquire() const
Grabs the lightMutex if it is available.
Similar to MutexHolder, but for a light mutex.
This is a standard, non-reentrant mutex, similar to the Mutex class.
Definition: lightMutex.h:41
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
set_transform
Sets the transform that will be applied to this node and below.
Definition: pandaNode.h:183
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:3583
Indicates a coordinate-system transform on vertices.
bool is_identity() const
Returns true if the transform represents the identity matrix, false otherwise.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
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().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.