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