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"
23 #include "bulletTriangleMeshShape.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 */
82 CollideMask BulletBodyNode::
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 */
94 bool BulletBodyNode::
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::
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 */
119 bool BulletBodyNode::
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 */
131 bool BulletBodyNode::
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 */
142 bool BulletBodyNode::
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 */
152 bool BulletBodyNode::
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 */
873 void BulletBodyNode::
874 set_transform_dirty() {
875
876 transform_changed();
877 }
878
879 /**
880 * Returns the current bounds of all collision shapes owned by this body.
881 */
882 BoundingSphere BulletBodyNode::
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 */
913 void BulletBodyNode::
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 */
955 int BulletBodyNode::
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 */
977 bool BulletBodyNode::
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());
995 set_contact_processing_threshold(scan.get_stdfloat());
996 // set_active(scan.get_bool(), true);
997 set_deactivation_time(scan.get_stdfloat());
998 set_deactivation_enabled(scan.get_bool());
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
CPT(TransformState) BulletBodyNode
Hook which will be called whenever the total shape of a body changed.
Definition: bulletBodyNode.cxx:552
bulletBodyNode.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bulletBoxShape.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bulletCapsuleShape.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bulletPlaneShape.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bulletShape.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bulletSphereShape.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bulletTriangleMeshShape.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bulletTriangleMesh.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bulletWorld.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BamReader
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
BamReader::read_pointer
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:610
BamWriter
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
BamWriter::write_pointer
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
BitMask< uint32_t, 32 >
BitMask< uint32_t, 32 >::all_on
static BitMask< uint32_t, nbits > all_on()
Returns a BitMask whose bits are all on.
Definition: bitMask.I:32
BoundingSphere
This defines a bounding sphere, consisting of a center and a radius.
Definition: boundingSphere.h:25
BulletBodyNode
Definition: bulletBodyNode.h:33
BulletBodyNode::complete_pointers
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
Definition: bulletBodyNode.cxx:956
BulletBodyNode::require_fully_complete
virtual bool require_fully_complete() const
Some objects require all of their nested pointers to have been completed before the objects themselve...
Definition: bulletBodyNode.cxx:978
BulletBodyNode::safe_to_flatten
virtual bool safe_to_flatten() const
Returns true if it is generally safe to flatten out this particular kind of Node by duplicating insta...
Definition: bulletBodyNode.cxx:95
BulletBodyNode::set_transform_dirty
void set_transform_dirty()
This method enforces an update of the Bullet transform, that is copies the scene graph transform to t...
Definition: bulletBodyNode.cxx:874
BulletBodyNode::safe_to_transform
virtual bool safe_to_transform() const
Returns true if it is generally safe to transform this particular kind of Node by calling the xform()...
Definition: bulletBodyNode.cxx:106
BulletBodyNode::safe_to_flatten_below
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 ...
Definition: bulletBodyNode.cxx:153
BulletBodyNode::get_shape_bounds
get_shape_bounds
Returns the current bounds of all collision shapes owned by this body.
Definition: bulletBodyNode.h:124
BulletBodyNode::set_deactivation_enabled
set_deactivation_enabled
If true, this object will be deactivated after a certain amount of time has passed without movement.
Definition: bulletBodyNode.h:133
BulletBodyNode::safe_to_combine
virtual bool safe_to_combine() const
Returns true if it is generally safe to combine this particular kind of PandaNode with other kinds of...
Definition: bulletBodyNode.cxx:132
BulletBodyNode::write_datagram
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: bulletBodyNode.cxx:914
BulletBodyNode::safe_to_modify_transform
virtual bool safe_to_modify_transform() const
Returns true if it is safe to automatically adjust the transform on this kind of node.
Definition: bulletBodyNode.cxx:120
BulletBodyNode::set_contact_processing_threshold
set_contact_processing_threshold
The constraint solver can discard solving contacts, if the distance is above this threshold.
Definition: bulletBodyNode.h:130
BulletBodyNode::get_legal_collide_mask
virtual CollideMask get_legal_collide_mask() const
Returns the subset of CollideMask bits that may be set for this particular type of PandaNode.
Definition: bulletBodyNode.cxx:83
BulletBodyNode::safe_to_combine_children
virtual bool safe_to_combine_children() const
Returns true if it is generally safe to combine the children of this PandaNode with each other.
Definition: bulletBodyNode.cxx:143
BulletCapsuleShape::make_from_solid
static BulletCapsuleShape * make_from_solid(const CollisionCapsule *solid)
Constructs a new BulletCapsuleShape using the information from a CollisionCapsule from the builtin co...
Definition: bulletCapsuleShape.cxx:93
BulletShape
Definition: bulletShape.h:27
BulletTriangleMeshShape
Definition: bulletTriangleMeshShape.h:30
BulletTriangleMesh
Definition: bulletTriangleMesh.h:32
CollisionBox
A cuboid collision volume or object.
Definition: collisionBox.h:27
CollisionCapsule
This implements a solid consisting of a cylinder with hemispherical endcaps, also known as a capsule ...
Definition: collisionCapsule.h:27
CollisionNode
A node in the scene graph that can hold any number of CollisionSolids.
Definition: collisionNode.h:30
CollisionPlane
Definition: collisionPlane.h:27
CollisionPolygon
Definition: collisionPolygon.h:29
CollisionSolid
The abstract base class for all things that can collide with other things in the world,...
Definition: collisionSolid.h:45
CollisionSphere
A spherical collision volume or object.
Definition: collisionSphere.h:25
DatagramIterator
A class to retrieve the individual data elements previously stored in a Datagram.
Definition: datagramIterator.h:27
DatagramIterator::get_stdfloat
PN_stdfloat get_stdfloat()
Extracts either a 32-bit or a 64-bit floating-point number, according to Datagram::set_stdfloat_doubl...
Definition: datagramIterator.I:242
DatagramIterator::get_bool
bool get_bool()
Extracts a boolean value.
Definition: datagramIterator.I:48
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
Datagram::add_stdfloat
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
Datagram::add_bool
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:34
LightMutexDirect::release
void release() const
Releases the lightMutex.
Definition: lightMutexDirect.I:69
LightMutexDirect::acquire
void acquire() const
Grabs the lightMutex if it is available.
Definition: lightMutexDirect.I:56
LightMutexHolder
Similar to MutexHolder, but for a light mutex.
Definition: lightMutexHolder.h:25
LightMutex
This is a standard, non-reentrant mutex, similar to the Mutex class.
Definition: lightMutex.h:41
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
PandaNode::set_transform
set_transform
Sets the transform that will be applied to this node and below.
Definition: pandaNode.h:183
PandaNode::write_datagram
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
TransformState
Indicates a coordinate-system transform on vertices.
Definition: transformState.h:54
TransformState::is_identity
bool is_identity() const
Returns true if the transform represents the identity matrix, false otherwise.
Definition: transformState.I:197
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
TypedWritable
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
TypedWritable::complete_pointers
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().
Definition: typedWritable.cxx:81
collisionBox.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
collisionCapsule.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
collisionPlane.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
collisionPolygon.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
collisionSphere.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
config_bullet.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.