Panda3D
Loading...
Searching...
No Matches
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
33TypeHandle BulletBodyNode::_type_handle;
34
35/**
36 *
37 */
38BulletBodyNode::
39BulletBodyNode(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 */
51BulletBodyNode::
52BulletBodyNode(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 */
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 */
95safe_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 */
106safe_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 */
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 */
132safe_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 */
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 */
153safe_to_flatten_below() const {
154
155 return false;
156}
157
158/**
159 *
160 */
161void BulletBodyNode::
162do_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 */
177void BulletBodyNode::
178output(std::ostream &out) const {
179 LightMutexHolder holder(BulletWorld::get_global_lock());
180
181 do_output(out);
182}
183
184/**
185 *
186 */
187void BulletBodyNode::
188set_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 */
206bool BulletBodyNode::
207get_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 */
216bool BulletBodyNode::
217is_static() const {
218 LightMutexHolder holder(BulletWorld::get_global_lock());
219
220 return get_object()->isStaticObject();
221}
222
223/**
224 *
225 */
226bool BulletBodyNode::
227is_kinematic() const {
228 LightMutexHolder holder(BulletWorld::get_global_lock());
229
230 return get_object()->isKinematicObject();
231}
232
233/**
234 *
235 */
236PN_stdfloat BulletBodyNode::
237get_restitution() const {
238 LightMutexHolder holder(BulletWorld::get_global_lock());
239
240 return get_object()->getRestitution();
241}
242
243/**
244 *
245 */
246void BulletBodyNode::
247set_restitution(PN_stdfloat restitution) {
248 LightMutexHolder holder(BulletWorld::get_global_lock());
249
250 return get_object()->setRestitution(restitution);
251}
252
253/**
254 *
255 */
256PN_stdfloat BulletBodyNode::
257get_friction() const {
258 LightMutexHolder holder(BulletWorld::get_global_lock());
259
260 return get_object()->getFriction();
261}
262
263/**
264 *
265 */
266void BulletBodyNode::
267set_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 */
277PN_stdfloat BulletBodyNode::
278get_rolling_friction() const {
279 LightMutexHolder holder(BulletWorld::get_global_lock());
280
281 return get_object()->getRollingFriction();
282}
283
284/**
285 *
286 */
287void BulletBodyNode::
288set_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 */
298bool BulletBodyNode::
299has_anisotropic_friction() const {
300 LightMutexHolder holder(BulletWorld::get_global_lock());
301
302 return get_object()->hasAnisotropicFriction();
303}
304
305/**
306 *
307 */
308int BulletBodyNode::
309get_num_shapes() const {
310 LightMutexHolder holder(BulletWorld::get_global_lock());
311
312 return _shapes.size();
313}
314
315/**
316 *
317 */
318BulletShape *BulletBodyNode::
319get_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 */
329void BulletBodyNode::
330add_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 */
339void BulletBodyNode::
340do_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 */
442void BulletBodyNode::
443remove_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 */
510bool BulletBodyNode::
511is_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 */
522LPoint3 BulletBodyNode::
523get_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 */
542LMatrix4 BulletBodyNode::
543get_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 */
552CPT(TransformState) BulletBodyNode::
553do_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 */
584CPT(TransformState) BulletBodyNode::
585get_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 */
598void BulletBodyNode::
599do_shape_changed() {
600
601}
602
603/**
604 *
605 */
606void BulletBodyNode::
607set_deactivation_time(PN_stdfloat dt) {
608 LightMutexHolder holder(BulletWorld::get_global_lock());
609
610 get_object()->setDeactivationTime(dt);
611}
612
613/**
614 *
615 */
616PN_stdfloat BulletBodyNode::
617get_deactivation_time() const {
618 LightMutexHolder holder(BulletWorld::get_global_lock());
619
620 return get_object()->getDeactivationTime();
621}
622
623/**
624 *
625 */
626bool BulletBodyNode::
627is_active() const {
628 LightMutexHolder holder(BulletWorld::get_global_lock());
629
630 return get_object()->isActive();
631}
632
633/**
634 *
635 */
636void BulletBodyNode::
637set_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 */
656void BulletBodyNode::
657force_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 */
667set_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 */
685bool BulletBodyNode::
686is_deactivation_enabled() const {
687 LightMutexHolder holder(BulletWorld::get_global_lock());
688
689 return (get_object()->getActivationState() != DISABLE_DEACTIVATION);
690}
691
692/**
693 *
694 */
695bool BulletBodyNode::
696check_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 */
712LVecBase3 BulletBodyNode::
713get_anisotropic_friction() const {
714 LightMutexHolder holder(BulletWorld::get_global_lock());
715
716 return btVector3_to_LVecBase3(get_object()->getAnisotropicFriction());
717}
718
719/**
720 *
721 */
722void BulletBodyNode::
723set_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 */
733bool BulletBodyNode::
734has_contact_response() const {
735 LightMutexHolder holder(BulletWorld::get_global_lock());
736
737 return get_object()->hasContactResponse();
738}
739
740/**
741 *
742 */
743PN_stdfloat BulletBodyNode::
744get_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 */
755set_contact_processing_threshold(PN_stdfloat threshold) {
756 LightMutexHolder holder(BulletWorld::get_global_lock());
757
758 get_object()->setContactProcessingThreshold(threshold);
759}
760
761/**
762 *
763 */
764PN_stdfloat BulletBodyNode::
765get_ccd_swept_sphere_radius() const {
766 LightMutexHolder holder(BulletWorld::get_global_lock());
767
768 return get_object()->getCcdSweptSphereRadius();
769}
770
771/**
772 *
773 */
774void BulletBodyNode::
775set_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 */
784PN_stdfloat BulletBodyNode::
785get_ccd_motion_threshold() const {
786 LightMutexHolder holder(BulletWorld::get_global_lock());
787
788 return get_object()->getCcdMotionThreshold();
789}
790
791/**
792 *
793 */
794void BulletBodyNode::
795set_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 */
804void BulletBodyNode::
805add_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 */
883get_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();
892cout << "aabbMin " << aabbMin.x() << " " << aabbMin.y() << " " << aabbMin.z() << endl;
893cout << "aabbMax " << aabbMax.x() << " " << aabbMax.y() << " " << aabbMax.z() << endl;
894cout << "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 */
914write_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 */
956complete_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 */
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 */
987void BulletBodyNode::
988fillin(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}
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.
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.
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.
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.
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.
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.
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.