15 #include "collisionTraverser.h"
16 #include "collisionNode.h"
17 #include "collisionEntry.h"
18 #include "collisionPolygon.h"
19 #include "collisionGeom.h"
20 #include "collisionRecorder.h"
21 #include "collisionVisualizer.h"
22 #include "collisionSphere.h"
23 #include "collisionBox.h"
24 #include "collisionTube.h"
25 #include "collisionPolygon.h"
26 #include "collisionPlane.h"
27 #include "config_collide.h"
28 #include "boundingSphere.h"
29 #include "transformState.h"
33 #include "geomTriangles.h"
34 #include "geomVertexReader.h"
37 #include "pStatTimer.h"
42 PStatCollector CollisionTraverser::_collisions_pcollector(
"App:Collisions");
44 PStatCollector CollisionTraverser::_cnode_volume_pcollector(
"Collision Volumes:CollisionNode");
45 PStatCollector CollisionTraverser::_gnode_volume_pcollector(
"Collision Volumes:GeomNode");
46 PStatCollector CollisionTraverser::_geom_volume_pcollector(
"Collision Volumes:Geom");
58 inline bool operator () (
int a,
int b)
const {
59 const CollisionTraverser::OrderedColliderDef &ocd_a = _trav._ordered_colliders[a];
60 const CollisionTraverser::OrderedColliderDef &ocd_b = _trav._ordered_colliders[b];
61 return DCAST(
CollisionNode, ocd_a._node_path.node())->get_collider_sort() < DCAST(
CollisionNode, ocd_b._node_path.node())->get_collider_sort();
73 CollisionTraverser(
const string &name) :
75 _this_pcollector(_collisions_pcollector, name)
77 _respect_prev_transform = respect_prev_transform;
78 #ifdef DO_COLLISION_RECORDING
79 _recorder = (CollisionRecorder *)NULL;
89 ~CollisionTraverser() {
90 #ifdef DO_COLLISION_RECORDING
111 nassertv(_ordered_colliders.size() == _colliders.size());
115 Colliders::iterator ci = _colliders.find(collider);
116 if (ci != _colliders.end()) {
118 if ((*ci).second != handler) {
121 (*ci).second = handler;
124 Handlers::iterator hi = _handlers.find(old_handler);
125 nassertv(hi != _handlers.end());
127 nassertv((*hi).second >= 0);
128 if ((*hi).second == 0) {
132 hi = _handlers.find(handler);
133 if (hi == _handlers.end()) {
134 _handlers.insert(Handlers::value_type(handler, 1));
142 _colliders.insert(Colliders::value_type(collider, handler));
143 OrderedColliderDef ocdef;
144 ocdef._node_path = collider;
145 ocdef._in_graph =
true;
146 _ordered_colliders.push_back(ocdef);
148 Handlers::iterator hi = _handlers.find(handler);
149 if (hi == _handlers.end()) {
150 _handlers.insert(Handlers::value_type(handler, 1));
156 nassertv(_ordered_colliders.size() == _colliders.size());
170 nassertr(_ordered_colliders.size() == _colliders.size(),
false);
172 Colliders::iterator ci = _colliders.find(collider);
173 if (ci == _colliders.end()) {
181 Handlers::iterator hi = _handlers.find(handler);
182 nassertr(hi != _handlers.end(),
false);
184 nassertr((*hi).second >= 0,
false);
185 if ((*hi).second == 0) {
189 _colliders.erase(ci);
191 OrderedColliders::iterator oci;
192 oci = _ordered_colliders.begin();
193 while (oci != _ordered_colliders.end() &&
194 (*oci)._node_path != collider) {
198 nassertr(oci != _ordered_colliders.end(),
false);
199 _ordered_colliders.erase(oci);
201 nassertr(_ordered_colliders.size() == _colliders.size(),
false);
214 Colliders::const_iterator ci = _colliders.find(collider);
215 return (ci != _colliders.end());
226 nassertr(_ordered_colliders.size() == _colliders.size(), 0);
227 return _ordered_colliders.size();
238 nassertr(_ordered_colliders.size() == _colliders.size(),
NodePath());
239 nassertr(n >= 0 && n < (
int)_ordered_colliders.size(),
NodePath());
240 return _ordered_colliders[n]._node_path;
252 Colliders::const_iterator ci = _colliders.find(collider);
253 if (ci != _colliders.end()) {
268 _ordered_colliders.clear();
277 void CollisionTraverser::
281 #ifdef DO_COLLISION_RECORDING
282 if (has_recorder()) {
283 get_recorder()->begin_traversal();
285 #endif // DO_COLLISION_RECORDING
287 Handlers::iterator hi;
288 for (hi = _handlers.begin(); hi != _handlers.end(); ++hi) {
289 if ((*hi).first->wants_all_potential_collidees()) {
290 (*hi).first->set_root(root);
292 (*hi).first->begin_group();
295 bool traversal_done =
false;
297 !allow_collider_multiple) {
300 LevelStatesSingle level_states;
301 prepare_colliders_single(level_states, root);
303 if (level_states.size() == 1 || !allow_collider_multiple) {
304 traversal_done =
true;
308 for (
size_t pass = 0; pass < level_states.size(); ++pass) {
310 PStatTimer pass_timer(get_pass_collector(pass));
312 r_traverse_single(level_states[pass], pass);
317 if (!traversal_done &&
320 LevelStatesDouble level_states;
321 prepare_colliders_double(level_states, root);
323 if (level_states.size() == 1) {
324 traversal_done =
true;
326 for (
size_t pass = 0; pass < level_states.size(); ++pass) {
328 PStatTimer pass_timer(get_pass_collector(pass));
330 r_traverse_double(level_states[pass], pass);
335 if (!traversal_done) {
337 LevelStatesQuad level_states;
338 prepare_colliders_quad(level_states, root);
340 traversal_done =
true;
342 for (
size_t pass = 0; pass < level_states.size(); ++pass) {
344 PStatTimer pass_timer(get_pass_collector(pass));
346 r_traverse_quad(level_states[pass], pass);
350 hi = _handlers.begin();
351 while (hi != _handlers.end()) {
352 if (!(*hi).first->end_group()) {
354 hi = remove_handler(hi);
360 #ifdef DO_COLLISION_RECORDING
361 if (has_recorder()) {
362 get_recorder()->end_traversal();
364 #endif // DO_COLLISION_RECORDING
366 CollisionLevelStateBase::_node_volume_pcollector.flush_level();
367 _cnode_volume_pcollector.flush_level();
368 _gnode_volume_pcollector.flush_level();
369 _geom_volume_pcollector.flush_level();
378 #ifdef DO_COLLISION_RECORDING
401 void CollisionTraverser::
402 set_recorder(CollisionRecorder *recorder) {
403 if (recorder != _recorder) {
405 if (_recorder != (CollisionRecorder *)NULL) {
406 nassertv(_recorder->_trav ==
this);
410 _recorder = recorder;
413 if (_recorder != (CollisionRecorder *)NULL) {
414 nassertv(_recorder->_trav !=
this);
416 _recorder->_trav->clear_recorder();
419 _recorder->_trav =
this;
434 CollisionVisualizer *CollisionTraverser::
435 show_collisions(
const NodePath &root) {
437 CollisionVisualizer *viz =
new CollisionVisualizer(
"show_collisions");
449 void CollisionTraverser::
451 if (!_collision_visualizer_np.is_empty()) {
452 _collision_visualizer_np.remove_node();
457 #endif // DO_COLLISION_RECORDING
464 void CollisionTraverser::
465 output(ostream &out)
const {
466 out <<
"CollisionTraverser, " << _colliders.size()
467 <<
" colliders and " << _handlers.size() <<
" handlers.\n";
475 void CollisionTraverser::
476 write(ostream &out,
int indent_level)
const {
477 indent(out, indent_level)
478 <<
"CollisionTraverser, " << _colliders.size()
479 <<
" colliders and " << _handlers.size() <<
" handlers:\n";
481 OrderedColliders::const_iterator oci;
482 for (oci = _ordered_colliders.begin();
483 oci != _ordered_colliders.end();
485 NodePath cnode_path = (*oci)._node_path;
486 bool in_graph = (*oci)._in_graph;
488 Colliders::const_iterator ci;
489 ci = _colliders.find(cnode_path);
490 nassertv(ci != _colliders.end());
495 indent(out, indent_level + 2)
498 out <<
" handled by " << handler->get_type() <<
"\n";
506 int num_solids = cnode->get_num_solids();
507 for (
int i = 0; i < num_solids; ++i) {
508 cnode->get_solid(i)->write(out, indent_level + 4);
524 void CollisionTraverser::
527 int num_colliders = _colliders.size();
536 level_state.reserve(min(num_colliders, max_colliders));
540 int *indirect = (
int *)alloca(
sizeof(
int) * num_colliders);
542 for (i = 0; i < num_colliders; ++i) {
547 int num_remaining_colliders = num_colliders;
548 for (i = 0; i < num_colliders; ++i) {
549 OrderedColliderDef &ocd = _ordered_colliders[indirect[i]];
550 NodePath cnode_path = ocd._node_path;
556 <<
"Collider " << cnode_path
557 <<
" is not in scene graph. Ignoring.\n";
558 ocd._in_graph =
false;
562 ocd._in_graph =
true;
567 def._node_path = cnode_path;
569 int num_solids = cnode->get_num_solids();
570 for (
int s = 0; s < num_solids; ++s) {
572 def._collider = collider;
573 level_state.prepare_collider(def, root);
578 level_states.push_back(level_state);
580 level_state.reserve(min(num_remaining_colliders, max_colliders));
585 --num_remaining_colliders;
586 nassertv(num_remaining_colliders >= 0);
589 if (level_state.get_num_colliders() != 0) {
590 level_states.push_back(level_state);
592 nassertv(num_remaining_colliders == 0);
600 void CollisionTraverser::
612 DCAST_INTO_V(cnode, node);
616 DCAST_INTO_V(node_gbv, node_bv);
620 entry._into_node = cnode;
622 if (_respect_prev_transform) {
623 entry._flags |= CollisionEntry::F_respect_prev_transform;
626 int num_colliders = level_state.get_num_colliders();
627 for (
int c = 0; c < num_colliders; ++c) {
629 entry._from_node = level_state.get_collider_node(c);
631 if ((entry._from_node->get_from_collide_mask() &
636 entry._from_node_path = level_state.get_collider_node_path(c);
637 entry._from = level_state.get_collider(c);
639 compare_collider_to_node(
650 if (collide_cat.is_spam()) {
652 <<
"Reached " << *node <<
"\n";
657 DCAST_INTO_V(gnode, node);
661 DCAST_INTO_V(node_gbv, node_bv);
665 entry._into_node = gnode;
667 if (_respect_prev_transform) {
668 entry._flags |= CollisionEntry::F_respect_prev_transform;
671 int num_colliders = level_state.get_num_colliders();
672 for (
int c = 0; c < num_colliders; ++c) {
674 entry._from_node = level_state.get_collider_node(c);
676 if ((entry._from_node->get_from_collide_mask() &
681 entry._from_node_path = level_state.get_collider_node_path(c);
682 entry._from = level_state.get_collider(c);
684 compare_collider_to_geom_node(
698 if (index >= 0 && index < node->get_num_children()) {
700 r_traverse_single(next_state, pass);
710 int index = DCAST(
LODNode, node)->get_lowest_switch();
713 for (
int i = 0; i < num_children; ++i) {
717 ~
GeomNode::get_default_collide_mask());
719 r_traverse_single(next_state, pass);
726 for (
int i = 0; i < num_children; ++i) {
728 r_traverse_single(next_state, pass);
743 void CollisionTraverser::
746 int num_colliders = _colliders.size();
755 level_state.
reserve(min(num_colliders, max_colliders));
759 int *indirect = (
int *)alloca(
sizeof(
int) * num_colliders);
761 for (i = 0; i < num_colliders; ++i) {
766 int num_remaining_colliders = num_colliders;
767 for (i = 0; i < num_colliders; ++i) {
768 OrderedColliderDef &ocd = _ordered_colliders[indirect[i]];
769 NodePath cnode_path = ocd._node_path;
775 <<
"Collider " << cnode_path
776 <<
" is not in scene graph. Ignoring.\n";
777 ocd._in_graph =
false;
781 ocd._in_graph =
true;
786 def._node_path = cnode_path;
788 int num_solids = cnode->get_num_solids();
789 for (
int s = 0; s < num_solids; ++s) {
791 def._collider = collider;
792 level_state.prepare_collider(def, root);
797 level_states.push_back(level_state);
799 level_state.
reserve(min(num_remaining_colliders, max_colliders));
804 --num_remaining_colliders;
805 nassertv(num_remaining_colliders >= 0);
808 if (level_state.get_num_colliders() != 0) {
809 level_states.push_back(level_state);
811 nassertv(num_remaining_colliders == 0);
819 void CollisionTraverser::
831 DCAST_INTO_V(cnode, node);
835 DCAST_INTO_V(node_gbv, node_bv);
839 entry._into_node = cnode;
841 if (_respect_prev_transform) {
842 entry._flags |= CollisionEntry::F_respect_prev_transform;
845 int num_colliders = level_state.get_num_colliders();
846 for (
int c = 0; c < num_colliders; ++c) {
848 entry._from_node = level_state.get_collider_node(c);
850 if ((entry._from_node->get_from_collide_mask() &
855 entry._from_node_path = level_state.get_collider_node_path(c);
856 entry._from = level_state.get_collider(c);
858 compare_collider_to_node(
869 if (collide_cat.is_spam()) {
871 <<
"Reached " << *node <<
"\n";
876 DCAST_INTO_V(gnode, node);
880 DCAST_INTO_V(node_gbv, node_bv);
884 entry._into_node = gnode;
886 if (_respect_prev_transform) {
887 entry._flags |= CollisionEntry::F_respect_prev_transform;
890 int num_colliders = level_state.get_num_colliders();
891 for (
int c = 0; c < num_colliders; ++c) {
893 entry._from_node = level_state.get_collider_node(c);
895 if ((entry._from_node->get_from_collide_mask() &
900 entry._from_node_path = level_state.get_collider_node_path(c);
901 entry._from = level_state.get_collider(c);
903 compare_collider_to_geom_node(
917 if (index >= 0 && index < node->get_num_children()) {
919 r_traverse_double(next_state, pass);
929 int index = DCAST(
LODNode, node)->get_lowest_switch();
932 for (
int i = 0; i < num_children; ++i) {
936 ~
GeomNode::get_default_collide_mask());
938 r_traverse_double(next_state, pass);
945 for (
int i = 0; i < num_children; ++i) {
947 r_traverse_double(next_state, pass);
962 void CollisionTraverser::
965 int num_colliders = _colliders.size();
974 level_state.
reserve(min(num_colliders, max_colliders));
978 int *indirect = (
int *)alloca(
sizeof(
int) * num_colliders);
980 for (i = 0; i < num_colliders; ++i) {
985 int num_remaining_colliders = num_colliders;
986 for (i = 0; i < num_colliders; ++i) {
987 OrderedColliderDef &ocd = _ordered_colliders[indirect[i]];
988 NodePath cnode_path = ocd._node_path;
994 <<
"Collider " << cnode_path
995 <<
" is not in scene graph. Ignoring.\n";
996 ocd._in_graph =
false;
1000 ocd._in_graph =
true;
1005 def._node_path = cnode_path;
1007 int num_solids = cnode->get_num_solids();
1008 for (
int s = 0; s < num_solids; ++s) {
1010 def._collider = collider;
1011 level_state.prepare_collider(def, root);
1016 level_states.push_back(level_state);
1017 level_state.clear();
1018 level_state.
reserve(min(num_remaining_colliders, max_colliders));
1023 --num_remaining_colliders;
1024 nassertv(num_remaining_colliders >= 0);
1027 if (level_state.get_num_colliders() != 0) {
1028 level_states.push_back(level_state);
1030 nassertv(num_remaining_colliders == 0);
1038 void CollisionTraverser::
1050 DCAST_INTO_V(cnode, node);
1054 DCAST_INTO_V(node_gbv, node_bv);
1058 entry._into_node = cnode;
1060 if (_respect_prev_transform) {
1061 entry._flags |= CollisionEntry::F_respect_prev_transform;
1064 int num_colliders = level_state.get_num_colliders();
1065 for (
int c = 0; c < num_colliders; ++c) {
1067 entry._from_node = level_state.get_collider_node(c);
1069 if ((entry._from_node->get_from_collide_mask() &
1074 entry._from_node_path = level_state.get_collider_node_path(c);
1075 entry._from = level_state.get_collider(c);
1077 compare_collider_to_node(
1088 if (collide_cat.is_spam()) {
1090 <<
"Reached " << *node <<
"\n";
1095 DCAST_INTO_V(gnode, node);
1099 DCAST_INTO_V(node_gbv, node_bv);
1103 entry._into_node = gnode;
1105 if (_respect_prev_transform) {
1106 entry._flags |= CollisionEntry::F_respect_prev_transform;
1109 int num_colliders = level_state.get_num_colliders();
1110 for (
int c = 0; c < num_colliders; ++c) {
1112 entry._from_node = level_state.get_collider_node(c);
1114 if ((entry._from_node->get_from_collide_mask() &
1119 entry._from_node_path = level_state.get_collider_node_path(c);
1120 entry._from = level_state.get_collider(c);
1122 compare_collider_to_geom_node(
1136 if (index >= 0 && index < node->get_num_children()) {
1138 r_traverse_quad(next_state, pass);
1148 int index = DCAST(
LODNode, node)->get_lowest_switch();
1151 for (
int i = 0; i < num_children; ++i) {
1155 ~
GeomNode::get_default_collide_mask());
1157 r_traverse_quad(next_state, pass);
1164 for (
int i = 0; i < num_children; ++i) {
1166 r_traverse_quad(next_state, pass);
1176 void CollisionTraverser::
1181 bool within_node_bounds =
true;
1184 within_node_bounds = (into_node_gbv->
contains(from_parent_gbv) != 0);
1185 _cnode_volume_pcollector.add_level(1);
1188 if (within_node_bounds) {
1190 DCAST_INTO_V(cnode, entry._into_node);
1191 int num_solids = cnode->get_num_solids();
1193 <<
"Colliding against CollisionNode " << entry._into_node
1194 <<
" which has " << num_solids <<
" collision solids.\n";
1195 for (
int s = 0; s < num_solids; ++s) {
1196 entry._into = cnode->get_solid(s);
1204 if (num_solids > 1 &&
1211 DCAST_INTO_V(solid_gbv, solid_bv);
1214 compare_collider_to_solid(entry, from_node_gbv, solid_gbv);
1224 void CollisionTraverser::
1229 bool within_node_bounds =
true;
1232 within_node_bounds = (into_node_gbv->
contains(from_parent_gbv) != 0);
1233 _gnode_volume_pcollector.add_level(1);
1236 if (within_node_bounds) {
1238 DCAST_INTO_V(gnode, entry._into_node);
1240 for (
int s = 0; s < num_geoms; ++s) {
1242 const Geom *geom = DCAST(
Geom, gnode->get_geom(s));
1243 if (geom != (
Geom *)NULL) {
1246 if (num_geoms > 1 &&
1253 DCAST_INTO_V(geom_gbv, geom_bv);
1256 compare_collider_to_geom(entry, geom, from_node_gbv, geom_gbv);
1267 void CollisionTraverser::
1271 bool within_solid_bounds =
true;
1274 within_solid_bounds = (solid_gbv->
contains(from_node_gbv) != 0);
1279 if (collide_cat.is_spam()) {
1280 collide_cat.spam(
false)
1281 <<
"Comparing to solid: " << *from_node_gbv
1282 <<
" to " << *solid_gbv <<
", within_solid_bounds = "
1283 << within_solid_bounds <<
"\n";
1287 if (within_solid_bounds) {
1288 Colliders::const_iterator ci;
1290 nassertv(ci != _colliders.end());
1291 entry.test_intersection((*ci).second,
this);
1300 void CollisionTraverser::
1304 bool within_geom_bounds =
true;
1307 within_geom_bounds = (geom_gbv->
contains(from_node_gbv) != 0);
1308 _geom_volume_pcollector.add_level(1);
1310 if (within_geom_bounds) {
1311 Colliders::const_iterator ci;
1313 nassertv(ci != _colliders.end());
1317 CPT(
GeomVertexData) data = geom->get_vertex_data()->animate_vertices(true, current_thread);
1320 int num_primitives = geom->get_num_primitives();
1321 for (
int i = 0; i < num_primitives; ++i) {
1324 nassertv(tris->is_of_type(
GeomTriangles::get_class_type()));
1326 if (tris->is_indexed()) {
1329 while (!index.is_at_end()) {
1332 vertex.set_row_unsafe(index.get_data1i());
1333 v[0] = vertex.get_data3();
1334 vertex.set_row_unsafe(index.get_data1i());
1335 v[1] = vertex.get_data3();
1336 vertex.set_row_unsafe(index.get_data1i());
1337 v[2] = vertex.get_data3();
1342 bool within_solid_bounds =
true;
1345 sphere->around(v, v + 3);
1346 within_solid_bounds = (sphere->contains(from_node_gbv) != 0);
1348 CollisionGeom::_volume_pcollector.add_level(1);
1351 if (within_solid_bounds) {
1353 entry._into = cgeom;
1354 entry.test_intersection((*ci).second, this);
1362 for (
int i = 0; i < num_vertices; i += 3) {
1365 v[0] = vertex.get_data3();
1366 v[1] = vertex.get_data3();
1367 v[2] = vertex.get_data3();
1372 bool within_solid_bounds =
true;
1374 PT(BoundingSphere) sphere = new BoundingSphere;
1375 sphere->around(v, v + 3);
1376 within_solid_bounds = (sphere->contains(from_node_gbv) != 0);
1378 CollisionGeom::_volume_pcollector.add_level(1);
1381 if (within_solid_bounds) {
1383 entry._into = cgeom;
1384 entry.test_intersection((*ci).second, this);
1408 nassertr(hi != _handlers.end(), hi);
1411 Handlers::iterator hnext = hi;
1413 _handlers.erase(hi);
1417 Colliders::iterator ci;
1418 ci = _colliders.begin();
1419 while (ci != _colliders.end()) {
1420 if ((*ci).second == handler) {
1424 Colliders::iterator cnext = ci;
1426 _colliders.erase(ci);
1430 OrderedColliders::iterator oci;
1431 oci = _ordered_colliders.begin();
1432 while (oci != _ordered_colliders.end() &&
1433 (*oci)._node_path != node_path) {
1436 nassertr(oci != _ordered_colliders.end(), hi);
1437 _ordered_colliders.erase(oci);
1439 nassertr(_ordered_colliders.size() == _colliders.size(), hi);
1457 get_pass_collector(
int pass) {
1458 nassertr(pass >= 0, _this_pcollector);
1459 while ((
int)_pass_collectors.size() <= pass) {
1461 name <<
"pass" << (_pass_collectors.size() + 1);
1463 _pass_collectors.push_back(col);
1465 _solid_collide_collectors.push_back(sc_col);
1468 return _pass_collectors[pass];
A basic node of the scene graph or data graph.
virtual int get_visible_child() const
Returns the index number of the currently visible child of this node.
The abstract interface to a number of classes that decide what to do when a collision is detected...
This is the base class for all three-component vectors and points.
virtual bool has_single_child_visibility() const
Should be overridden by derived classes to return true if this kind of node has the special property ...
virtual bool is_collision_node() const
A simple downcast check.
PandaNode * get_child(int n) const
Returns the nth child of the node.
This is the state information the CollisionTraverser retains for each level during traversal...
The abstract base class for all things that can collide with other things in the world, and all the things they can collide with (except geometry).
This defines a bounding sphere, consisting of a center and a radius.
bool has_collider(const NodePath &collider) const
Returns true if the indicated node is current in the set of nodes that will be tested each frame for ...
void set_include_mask(CollideMask include_mask)
Specifies the mask that is applied to the into CollideMask of nodes in the scene graph before testing...
CollideMask get_into_collide_mask() const
Returns the "into" collide mask for this node.
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
PandaNode * node() const
Returns the referenced node of the path.
PrimitiveType get_primitive_type() const
Returns the fundamental primitive type that is common to all GeomPrimitives added within the Geom...
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
static void flush_level()
Flushes the PStatCollectors used during traversal.
void add_collider(const NodePath &collider, CollisionHandler *handler)
Adds a new CollisionNode, representing an object that will be tested for collisions into other object...
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
int contains(const GeometricBoundingVolume *vol) const
Returns the appropriate set of IntersectionFlags to indicate the amount of intersection with the indi...
virtual bool is_lod_node() const
A simple downcast check.
bool has_collider(int n) const
Returns true if the nth collider in the LevelState is still part of the level.
static Thread * get_current_thread()
Returns a pointer to the currently-executing Thread object.
void clear_colliders()
Completely empties the set of collision nodes and their associated handlers.
This is our own Panda specialization on the default STL vector.
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
A lightweight class that represents a single element that may be timed and/or counted via stats...
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
A base class for all things which can have a name.
int get_first_vertex() const
Returns the first vertex number referenced by the primitive.
static bool verify_points(const LPoint3 &a, const LPoint3 &b, const LPoint3 &c)
Verifies that the indicated set of points will define a valid CollisionPolygon: that is...
NodePath get_collider(int n) const
Returns the nth CollisionNode that has been added to the traverser via add_collider().
bool any_in_bounds()
Checks the bounding volume of the current node against each of our colliders.
int get_num_children() const
Returns the number of children of the node.
Defines a single collision event.
const CollisionSolid * get_into() const
Returns the CollisionSolid pointer for the particular solid was collided into.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
A container for geometry primitives.
const GeometricBoundingVolume * get_parent_bound(int n) const
Returns the bounding volume of the indicated collider, transformed into the previous node's transform...
Children get_children(Thread *current_thread=Thread::get_current_thread()) const
Returns an object that can be used to walk through the list of children of the node.
A special CollisionPolygon created just for the purpose of detecting collision against geometry...
PandaNode * node() const
Returns the PandaNode pointer of the node we have traversed to.
const GeometricBoundingVolume * get_local_bound(int n) const
Returns the bounding volume of the indicated collider, transformed into the current node's transform ...
void reserve(int num_colliders)
Indicates an intention to add the indicated number of colliders to the level state.
static void flush_level()
Flushes the PStatCollectors used during traversal.
PandaNode * get_child(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the nth child node of this node.
int get_num_vertices() const
Returns the number of indices used by all the primitives in this object.
NodePath get_node_path() const
Returns the NodePath representing the node instance we have traversed to.
A thread; that is, a lightweight process.
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
static void flush_level()
Flushes the PStatCollectors used during traversal.
A node in the scene graph that can hold any number of CollisionSolids.
bool is_empty() const
Returns true if the NodePath contains no nodes.
Defines a series of disconnected triangles.
bool remove_collider(const NodePath &collider)
Removes the collider (and its associated handler) from the set of CollisionNodes that will be tested ...
NodePath get_from_node_path() const
Returns the NodePath that represents the CollisionNode that contains the CollisionSolid that triggere...
This class manages the traversal through the scene graph to detect collisions.
CollideMask get_into_collide_mask() const
Returns the current "into" CollideMask.
virtual bool is_geom_node() const
A simple downcast check.
TypeHandle is the identifier used to differentiate C++ class types.
static void flush_level()
Flushes the PStatCollectors used during traversal.
bool apply_transform()
Applies the inverse transform from the current node, if any, onto all the colliders in the level stat...
CollisionHandler * get_handler(const NodePath &collider) const
Returns the handler that is currently assigned to serve the indicated collision node, or NULL if the node is not on the traverser's set of active nodes.
bool is_same_graph(const NodePath &other, Thread *current_thread=Thread::get_current_thread()) const
Returns true if the node represented by this NodePath is parented within the same graph as that of th...
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
A node that holds Geom objects, renderable pieces of geometry.
NodePath attach_new_node(PandaNode *node, int sort=0, Thread *current_thread=Thread::get_current_thread()) const
Attaches a new node, with or without existing parents, to the scene graph below the referenced node o...
int get_num_geoms() const
Returns the number of geoms in the node.
int get_num_colliders() const
Returns the number of CollisionNodes that have been added to the traverser via add_collider().
static void flush_level()
Flushes the PStatCollectors used during traversal.
static int get_max_colliders()
Returns the maximum number of colliders that may be added to the CollisionLevelStateBase at any one t...