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
A basic node of the scene graph or data graph.
Definition: pandaNode.h:64
Indicates a coordinate-system transform on vertices.
int contains(const GeometricBoundingVolume *vol) const
Returns the appropriate set of IntersectionFlags to indicate the amount of intersection with the indi...
This is the state information the CollisionTraverser retains for each level during traversal.
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 ...
get_from_collide_mask
Returns the current "from" CollideMask.
Definition: collisionNode.h:59
bool any_in_bounds()
Checks the bounding volume of the current node against each of our colliders.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
void prepare_collider(const ColliderDef &def, const NodePath &root)
Adds the indicated Collider to the set of Colliders in the current level state.
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:1721
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 ...
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:30
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:161
bool is_identity() const
Returns true if the transform represents the identity matrix, false otherwise.
static int get_max_colliders()
Returns the maximum number of colliders that may be added to the CollisionLevelStateBase at any one t...