Panda3D
collisionLevelState.I
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 collisionLevelState.I
10  * @author drose
11  * @date 2007-04-05
12  */
13 
14 #ifndef CPPPARSER
15 /**
16  *
17  */
18 template<class MaskType>
20 CollisionLevelState(const NodePath &node_path) :
21  CollisionLevelStateBase(node_path),
22  _current(CurrentMask::all_off())
23 {
24 }
25 #endif // CPPPARSER
26 
27 #ifndef CPPPARSER
28 /**
29  * This constructor goes to the next child node in the traversal.
30  */
31 template<class MaskType>
34  CollisionLevelStateBase(parent, child),
35  _current(parent._current)
36 {
37 }
38 #endif // CPPPARSER
39 
40 #ifndef CPPPARSER
41 /**
42  *
43  */
44 template<class MaskType>
48  _current(copy._current)
49 {
50 }
51 #endif // CPPPARSER
52 
53 #ifndef CPPPARSER
54 /**
55  *
56  */
57 template<class MaskType>
60  CollisionLevelStateBase::operator = (copy);
61  _current = copy._current;
62 }
63 #endif // CPPPARSER
64 
65 #ifndef CPPPARSER
66 /**
67  *
68  */
69 template<class MaskType>
71 clear() {
72  CollisionLevelStateBase::clear();
73  _current.clear();
74 }
75 #endif // CPPPARSER
76 
77 #ifndef CPPPARSER
78 /**
79  * Adds the indicated Collider to the set of Colliders in the current level
80  * state.
81  */
82 template<class MaskType>
84 prepare_collider(const ColliderDef &def, const NodePath &root) {
85  int index = (int)_colliders.size();
86  nassertv(!CurrentMask::has_max_num_bits() ||
87  index <= CurrentMask::get_max_num_bits());
88 
90  _current.set_bit(index);
91 }
92 #endif // CPPPARSER
93 
94 #ifndef CPPPARSER
95 /**
96  * Checks the bounding volume of the current node against each of our
97  * colliders. Eliminates from the current collider list any that are outside
98  * of the bounding volume. Returns true if any colliders remain, false if all
99  * of them fall outside this node's bounding volume.
100  */
101 template<class MaskType>
104 #ifndef NDEBUG
105  int indent_level = 0;
106  if (collide_cat.is_spam()) {
107  indent_level = _node_path.get_num_nodes() * 2;
108  collide_cat.spam();
109  indent(collide_cat.spam(false), indent_level)
110  << "Considering " << _node_path.get_node_path() << "\n";
111  }
112 #endif // NDEBUG
113 
114  PandaNode *pnode = node();
115 
116  CPT(BoundingVolume) node_bv = pnode->get_bounds();
117  if (node_bv->is_of_type(GeometricBoundingVolume::get_class_type())) {
118  const GeometricBoundingVolume *node_gbv = (const GeometricBoundingVolume *)node_bv.p();
119  CollideMask this_mask = pnode->get_net_collide_mask();
120 
121  int num_colliders = get_num_colliders();
122  for (int c = 0; c < num_colliders; c++) {
123  if (has_collider(c)) {
124  CollisionNode *cnode = get_collider_node(c);
125  bool is_in = false;
126 
127  // Don't even bother testing the bounding volume if there are no
128  // collide bits in common between our collider and this node.
129  CollideMask from_mask = cnode->get_from_collide_mask() & _include_mask;
130  if (!(from_mask & this_mask).is_zero()) {
131  // Also don't test a node with itself, or with any of its
132  // descendants.
133  if (pnode == cnode) {
134 #ifndef NDEBUG
135  if (collide_cat.is_spam()) {
136  indent(collide_cat.spam(false), indent_level)
137  << "Not comparing " << c << " to " << _node_path
138  << " (same node)\n";
139  }
140 #endif // NDEBUG
141 
142  } else {
143  // There are bits in common, and it's not the same instance, so go
144  // ahead and try the bounding volume.
145  const GeometricBoundingVolume *col_gbv =
146  get_local_bound(c);
147 
148  is_in = true; // If there's no bounding volume, we're implicitly in.
149 
150  if (col_gbv != nullptr) {
151  is_in = (node_gbv->contains(col_gbv) != 0);
152  _node_volume_pcollector.add_level(1);
153 
154 #ifndef NDEBUG
155  if (collide_cat.is_spam()) {
156  indent(collide_cat.spam(false), indent_level)
157  << "Comparing " << c << ": " << *col_gbv
158  << " to " << *node_gbv << ", is_in = " << is_in << "\n";
159  }
160 #endif // NDEBUG
161  }
162  }
163  }
164 
165  if (!is_in) {
166  // This collider cannot intersect with any geometry at this node or
167  // below.
168  omit_collider(c);
169  }
170  }
171  }
172  }
173 
174 #ifndef NDEBUG
175  if (collide_cat.is_spam()) {
176  int num_active_colliders = 0;
177  int num_colliders = get_num_colliders();
178  for (int c = 0; c < num_colliders; c++) {
179  if (has_collider(c)) {
180  num_active_colliders++;
181  }
182  }
183 
184  collide_cat.spam();
185  indent(collide_cat.spam(false), indent_level)
186  << _node_path.get_node_path() << " has " << num_active_colliders
187  << " interested colliders";
188  if (num_colliders != 0) {
189  collide_cat.spam(false)
190  << " (";
191  for (int c = 0; c < num_colliders; c++) {
192  if (has_collider(c)) {
193  CollisionNode *cnode = get_collider_node(c);
194  collide_cat.spam(false)
195  << " " << c << ". " << cnode->get_name();
196  }
197  }
198  collide_cat.spam(false)
199  << " )";
200  }
201  collide_cat.spam(false)
202  << "\n";
203  }
204 #endif // NDEBUG
205  return has_any_collider();
206 }
207 #endif // CPPPARSER
208 
209 #ifndef CPPPARSER
210 /**
211  * Applies the inverse transform from the current node, if any, onto all the
212  * colliders in the level state.
213  *
214  * Returns true if the inverse transform is valid, or false if it is not valid
215  * (e.g. the transform has a scale to zero). If the inverse transform is not
216  * valid, the caller should not visit this node.
217  */
218 template<class MaskType>
221  // The "parent" bounds list remembers the bounds list of the previous node.
222  _parent_bounds = _local_bounds;
223 
224  if (node()->is_final()) {
225  // If this node has a "final" bounds, we blank out all of the from
226  // bounding volumes, since we've already tested against this node's into
227  // bounds, and there's no need to test any further bounding volumes at
228  // this node level or below.
229  BoundingVolumes new_bounds;
230 
231  int num_colliders = get_num_colliders();
232  new_bounds.reserve(num_colliders);
233  for (int c = 0; c < num_colliders; c++) {
234  new_bounds.push_back(nullptr);
235  }
236 
237  _local_bounds = new_bounds;
238 
239  } else {
240  // Otherwise, in the usual case, the bounds tests will continue.
241  // Recompute the bounds list of this node (if we have a transform).
242  const TransformState *node_transform = node()->get_transform();
243  if (!node_transform->is_identity()) {
244  CPT(TransformState) inv_transform =
245  node_transform->invert_compose(TransformState::make_identity());
246  if (!inv_transform->has_mat()) {
247  // No inverse.
248  return false;
249  }
250 
251  const LMatrix4 &mat = inv_transform->get_mat();
252 
253  // Now build the new bounding volumes list.
254  BoundingVolumes new_bounds;
255 
256  int num_colliders = get_num_colliders();
257  new_bounds.reserve(num_colliders);
258  for (int c = 0; c < num_colliders; c++) {
259  if (!has_collider(c) ||
260  get_local_bound(c) == nullptr) {
261  new_bounds.push_back(nullptr);
262  } else {
263  const GeometricBoundingVolume *old_bound = get_local_bound(c);
264  GeometricBoundingVolume *new_bound =
265  DCAST(GeometricBoundingVolume, old_bound->make_copy());
266  new_bound->xform(mat);
267  new_bounds.push_back(new_bound);
268  }
269  }
270 
271  _local_bounds = new_bounds;
272  }
273  }
274 
275  return true;
276 }
277 #endif // CPPPARSER
278 
279 #ifndef CPPPARSER
280 /**
281  * Returns true if there is any the maximum number of colliders that may be
282  * added to the CollisionLevelStateBase at any one time.
283  */
284 template<class MaskType>
287  return CurrentMask::has_max_num_bits();
288 }
289 #endif // CPPPARSER
290 
291 #ifndef CPPPARSER
292 /**
293  * Returns the maximum number of colliders that may be added to the
294  * CollisionLevelStateBase at any one time.
295  */
296 template<class MaskType>
299  return CurrentMask::get_max_num_bits();
300 }
301 #endif // CPPPARSER
302 
303 #ifndef CPPPARSER
304 /**
305  * Returns true if the nth collider in the LevelState is still part of the
306  * level.
307  */
308 template<class MaskType>
310 has_collider(int n) const {
311  nassertr(n >= 0 && n < (int)_colliders.size(), false);
312  return (_current.get_bit(n));
313 }
314 #endif // CPPPARSER
315 
316 #ifndef CPPPARSER
317 /**
318  *
319  */
320 template<class MaskType>
322 has_any_collider() const {
323  return !_current.is_zero();
324 }
325 #endif // CPPPARSER
326 
327 #ifndef CPPPARSER
328 /**
329  *
330  */
331 template<class MaskType>
333 omit_collider(int n) {
334  nassertv(n >= 0 && n < (int)_colliders.size());
335  nassertv(has_collider(n));
336 
337  _current.clear_bit(n);
338 }
339 #endif // CPPPARSER
TransformState::is_identity
bool is_identity() const
Returns true if the transform represents the identity matrix, false otherwise.
Definition: transformState.I:197
indent
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
CollisionLevelState::prepare_collider
void prepare_collider(const ColliderDef &def, const NodePath &root)
Adds the indicated Collider to the set of Colliders in the current level state.
Definition: collisionLevelState.I:84
CollisionTraverser::get_num_colliders
get_num_colliders
Returns the number of CollisionNodes that have been added to the traverser via add_collider().
Definition: collisionTraverser.h:62
BitMask< uint32_t, 32 >
CollisionLevelState::has_collider
bool has_collider(int n) const
Returns true if the nth collider in the LevelState is still part of the level.
Definition: collisionLevelState.I:310
GeometricBoundingVolume::contains
int contains(const GeometricBoundingVolume *vol) const
Returns the appropriate set of IntersectionFlags to indicate the amount of intersection with the indi...
Definition: geometricBoundingVolume.I:68
TransformState
Indicates a coordinate-system transform on vertices.
Definition: transformState.h:54
GeometricBoundingVolume
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
Definition: geometricBoundingVolume.h:29
CollisionLevelState::any_in_bounds
bool any_in_bounds()
Checks the bounding volume of the current node against each of our colliders.
Definition: collisionLevelState.I:103
CollisionTraverser::has_collider
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 ...
Definition: collisionTraverser.cxx:199
CollisionLevelState::has_max_colliders
static bool has_max_colliders()
Returns true if there is any the maximum number of colliders that may be added to the CollisionLevelS...
Definition: collisionLevelState.I:286
NodePath
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
CollisionLevelState
This is the state information the CollisionTraverser retains for each level during traversal.
Definition: collisionLevelState.h:33
CollisionLevelState::apply_transform
bool apply_transform()
Applies the inverse transform from the current node, if any, onto all the colliders in the level stat...
Definition: collisionLevelState.I:220
CollisionLevelStateBase::ColliderDef
Definition: collisionLevelStateBase.h:45
CollisionNode::get_from_collide_mask
get_from_collide_mask
Returns the current "from" CollideMask.
Definition: collisionNode.h:59
CollisionLevelState::get_max_colliders
static int get_max_colliders()
Returns the maximum number of colliders that may be added to the CollisionLevelStateBase at any one t...
Definition: collisionLevelState.I:298
CollisionLevelStateBase::prepare_collider
void prepare_collider(const ColliderDef &def, const NodePath &root)
Adds the indicated Collider to the set of Colliders in the current level state.
Definition: collisionLevelStateBase.cxx:49
BoundingVolume
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
Definition: boundingVolume.h:41
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:64
CollisionLevelStateBase
This is the state information the CollisionTraverser retains for each level during traversal.
Definition: collisionLevelStateBase.h:43
PandaNode::get_net_collide_mask
CollideMask get_net_collide_mask(Thread *current_thread=Thread::get_current_thread()) const
Returns the union of all into_collide_mask() values set at CollisionNodes at this level and below.
Definition: pandaNode.cxx:1715
CollisionNode
A node in the scene graph that can hold any number of CollisionSolids.
Definition: collisionNode.h:30