Panda3D
 All Classes Functions Variables Enumerations
collisionNode.cxx
1 // Filename: collisionNode.cxx
2 // Created by: drose (16Mar02)
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 #include "collisionNode.h"
16 #include "config_collide.h"
17 
18 #include "geomNode.h"
19 #include "cullTraverserData.h"
20 #include "cullTraverser.h"
21 #include "renderState.h"
22 #include "transformState.h"
23 #include "colorScaleAttrib.h"
24 #include "transparencyAttrib.h"
25 #include "datagram.h"
26 #include "datagramIterator.h"
27 #include "bamReader.h"
28 #include "bamWriter.h"
29 #include "clockObject.h"
30 #include "boundingSphere.h"
31 #include "boundingBox.h"
32 #include "config_mathutil.h"
33 
34 TypeHandle CollisionNode::_type_handle;
35 
36 
37 ////////////////////////////////////////////////////////////////////
38 // Function: CollisionNode::Constructor
39 // Access: Public
40 // Description:
41 ////////////////////////////////////////////////////////////////////
42 CollisionNode::
43 CollisionNode(const string &name) :
44  PandaNode(name),
45  _from_collide_mask(get_default_collide_mask()),
46  _collider_sort(0)
47 {
48  set_cull_callback();
49 
50  // CollisionNodes are hidden by default.
51  set_overall_hidden(true);
52 
53  // CollisionNodes have a certain set of bits on by default.
54  set_into_collide_mask(get_default_collide_mask());
55 }
56 
57 ////////////////////////////////////////////////////////////////////
58 // Function: CollisionNode::Copy Constructor
59 // Access: Protected
60 // Description:
61 ////////////////////////////////////////////////////////////////////
62 CollisionNode::
63 CollisionNode(const CollisionNode &copy) :
64  PandaNode(copy),
65  _from_collide_mask(copy._from_collide_mask),
66  _solids(copy._solids)
67 {
68 }
69 
70 ////////////////////////////////////////////////////////////////////
71 // Function: CollisionNode::Destructor
72 // Access: Public, Virtual
73 // Description:
74 ////////////////////////////////////////////////////////////////////
75 CollisionNode::
76 ~CollisionNode() {
77 }
78 
79 ////////////////////////////////////////////////////////////////////
80 // Function: CollisionNode::make_copy
81 // Access: Public, Virtual
82 // Description: Returns a newly-allocated Node that is a shallow copy
83 // of this one. It will be a different Node pointer,
84 // but its internal data may or may not be shared with
85 // that of the original Node.
86 ////////////////////////////////////////////////////////////////////
88 make_copy() const {
89  return new CollisionNode(*this);
90 }
91 
92 ////////////////////////////////////////////////////////////////////
93 // Function: CollisionNode::preserve_name
94 // Access: Public, Virtual
95 // Description: Returns true if the node's name has extrinsic meaning
96 // and must be preserved across a flatten operation,
97 // false otherwise.
98 ////////////////////////////////////////////////////////////////////
99 bool CollisionNode::
100 preserve_name() const {
101  return true;
102 }
103 
104 ////////////////////////////////////////////////////////////////////
105 // Function: CollisionNode::xform
106 // Access: Public, Virtual
107 // Description: Transforms the contents of this node by the indicated
108 // matrix, if it means anything to do so. For most
109 // kinds of nodes, this does nothing.
110 ////////////////////////////////////////////////////////////////////
111 void CollisionNode::
112 xform(const LMatrix4 &mat) {
113  nassertv(!mat.is_nan());
114 
115  if (mat.almost_equal(LMatrix4::ident_mat())) {
116  return;
117  }
118 
119  Solids::iterator si;
120  for (si = _solids.begin(); si != _solids.end(); ++si) {
121  PT(CollisionSolid) solid = (*si).get_write_pointer();
122  solid->xform(mat);
123  }
125 }
126 
127 ////////////////////////////////////////////////////////////////////
128 // Function: CollisionNode::combine_with
129 // Access: Public, Virtual
130 // Description: Collapses this node with the other node, if possible,
131 // and returns a pointer to the combined node, or NULL
132 // if the two nodes cannot safely be combined.
133 //
134 // The return value may be this, other, or a new node
135 // altogether.
136 //
137 // This function is called from GraphReducer::flatten(),
138 // and need not deal with children; its job is just to
139 // decide whether to collapse the two nodes and what the
140 // collapsed node should look like.
141 ////////////////////////////////////////////////////////////////////
144  if (flatten_collision_nodes) {
145  if (is_exact_type(get_class_type()) &&
146  other->is_exact_type(get_class_type())) {
147  // Two CollisionNodes can combine, but only if they have the same
148  // name, because the name is often meaningful, and only if they
149  // have the same collide masks.
150  CollisionNode *cother = DCAST(CollisionNode, other);
151  if (get_name() == cother->get_name() &&
154  const COWPT(CollisionSolid) *solids_begin = &cother->_solids[0];
155  const COWPT(CollisionSolid) *solids_end = solids_begin + cother->_solids.size();
156  _solids.insert(_solids.end(), solids_begin, solids_end);
158  return this;
159  }
160 
161  // Two CollisionNodes with different names or different collide
162  // masks can't combine.
163  }
164  }
165 
166  return NULL;
167 }
168 
169 ////////////////////////////////////////////////////////////////////
170 // Function: CollisionNode::get_legal_collide_mask
171 // Access: Published, Virtual
172 // Description: Returns the subset of CollideMask bits that may be
173 // set for this particular type of PandaNode. For most
174 // nodes, this is 0; it doesn't make sense to set a
175 // CollideMask for most kinds of nodes.
176 //
177 // For nodes that can be collided with, such as GeomNode
178 // and CollisionNode, this returns all bits on.
179 ////////////////////////////////////////////////////////////////////
182  return CollideMask::all_on();
183 }
184 
185 ////////////////////////////////////////////////////////////////////
186 // Function: CollisionNode::cull_callback
187 // Access: Public, Virtual
188 // Description: This function will be called during the cull
189 // traversal to perform any additional operations that
190 // should be performed at cull time. This may include
191 // additional manipulation of render state or additional
192 // visible/invisible decisions, or any other arbitrary
193 // operation.
194 //
195 // Note that this function will *not* be called unless
196 // set_cull_callback() is called in the constructor of
197 // the derived class. It is necessary to call
198 // set_cull_callback() to indicated that we require
199 // cull_callback() to be called.
200 //
201 // By the time this function is called, the node has
202 // already passed the bounding-volume test for the
203 // viewing frustum, and the node's transform and state
204 // have already been applied to the indicated
205 // CullTraverserData object.
206 //
207 // The return value is true if this node should be
208 // visible, or false if it should be culled.
209 ////////////////////////////////////////////////////////////////////
210 bool CollisionNode::
212  // Append our collision vizzes to the drawing, even though they're
213  // not actually part of the scene graph.
214  Solids::const_iterator si;
215  for (si = _solids.begin(); si != _solids.end(); ++si) {
216  CPT(CollisionSolid) solid = (*si).get_read_pointer();
217  PT(PandaNode) node = solid->get_viz(trav, data, false);
218  if (node != (PandaNode *)NULL) {
219  CullTraverserData next_data(data, node);
220 
221  // We don't want to inherit the render state from above for these
222  // guys.
223  next_data._state = RenderState::make_empty();
224  trav->traverse(next_data);
225  }
226  }
227 
228  if (respect_prev_transform) {
229  // Determine the previous frame's position, relative to the
230  // current position.
231  NodePath node_path = data._node_path.get_node_path();
232  CPT(TransformState) transform = node_path.get_net_transform()->invert_compose(node_path.get_net_prev_transform());
233 
234  if (!transform->is_identity()) {
235  // If we have a velocity, also draw the previous frame's position,
236  // ghosted.
237 
238  for (si = _solids.begin(); si != _solids.end(); ++si) {
239  CPT(CollisionSolid) solid = (*si).get_read_pointer();
240  PT(PandaNode) node = solid->get_viz(trav, data, false);
241  if (node != (PandaNode *)NULL) {
242  CullTraverserData next_data(data, node);
243 
244  next_data._net_transform =
245  next_data._net_transform->compose(transform);
246  next_data._state = get_last_pos_state();
247  trav->traverse(next_data);
248  }
249  }
250  }
251  }
252 
253  // Now carry on to render our child nodes.
254  return true;
255 }
256 
257 ////////////////////////////////////////////////////////////////////
258 // Function: CollisionNode::is_renderable
259 // Access: Public, Virtual
260 // Description: Returns true if there is some value to visiting this
261 // particular node during the cull traversal for any
262 // camera, false otherwise. This will be used to
263 // optimize the result of get_net_draw_show_mask(), so
264 // that any subtrees that contain only nodes for which
265 // is_renderable() is false need not be visited.
266 ////////////////////////////////////////////////////////////////////
267 bool CollisionNode::
268 is_renderable() const {
269  return true;
270 }
271 
272 ////////////////////////////////////////////////////////////////////
273 // Function: CollisionNode::is_collision_node
274 // Access: Published, Virtual
275 // Description: A simple downcast check. Returns true if this kind
276 // of node happens to inherit from CollisionNode, false
277 // otherwise.
278 //
279 // This is provided as a a faster alternative to calling
280 // is_of_type(CollisionNode::get_class_type()).
281 ////////////////////////////////////////////////////////////////////
282 bool CollisionNode::
284  return true;
285 }
286 
287 
288 ////////////////////////////////////////////////////////////////////
289 // Function: CollisionNode::output
290 // Access: Public, Virtual
291 // Description: Writes a brief description of the node to the
292 // indicated output stream. This is invoked by the <<
293 // operator. It may be overridden in derived classes to
294 // include some information relevant to the class.
295 ////////////////////////////////////////////////////////////////////
296 void CollisionNode::
297 output(ostream &out) const {
298  PandaNode::output(out);
299  out << " (" << _solids.size() << " solids)";
300 }
301 
302 ////////////////////////////////////////////////////////////////////
303 // Function: CollisionNode::set_from_collide_mask
304 // Access: Published
305 // Description: Sets the "from" CollideMask. In order for a
306 // collision to be detected from this object into
307 // another object, the intersection of this object's
308 // "from" mask and the other object's "into" mask must
309 // be nonzero.
310 ////////////////////////////////////////////////////////////////////
311 void CollisionNode::
313  _from_collide_mask = mask;
314 }
315 
316 ////////////////////////////////////////////////////////////////////
317 // Function: CollisionNode::compute_internal_bounds
318 // Access: Protected, Virtual
319 // Description: Called when needed to recompute the node's
320 // _internal_bound object. Nodes that contain anything
321 // of substance should redefine this to do the right
322 // thing.
323 ////////////////////////////////////////////////////////////////////
324 void CollisionNode::
325 compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
326  int &internal_vertices,
327  int pipeline_stage,
328  Thread *current_thread) const {
329  pvector<CPT(BoundingVolume) > child_volumes_ref;
330  pvector<const BoundingVolume *> child_volumes;
331  bool all_box = true;
332 
333  Solids::const_iterator gi;
334  for (gi = _solids.begin(); gi != _solids.end(); ++gi) {
335  CPT(CollisionSolid) solid = (*gi).get_read_pointer();
336  CPT(BoundingVolume) volume = solid->get_bounds();
337 
338  if (!volume->is_empty()) {
339  child_volumes_ref.push_back(volume);
340  child_volumes.push_back(volume);
341  if (!volume->is_exact_type(BoundingBox::get_class_type())) {
342  all_box = false;
343  }
344  }
345  }
346 
347  PT(GeometricBoundingVolume) gbv = new BoundingBox;
348 
349  BoundingVolume::BoundsType btype = get_bounds_type();
350  if (btype == BoundingVolume::BT_default) {
351  btype = bounds_type;
352  }
353 
354  if (btype == BoundingVolume::BT_box ||
355  (btype != BoundingVolume::BT_sphere && all_box)) {
356  // If all of the child volumes are a BoundingBox, then our volume
357  // is also a BoundingBox.
358  gbv = new BoundingBox;
359  } else {
360  // Otherwise, it's a sphere.
361  gbv = new BoundingSphere;
362  }
363 
364  if (child_volumes.size() > 0) {
365  const BoundingVolume **child_begin = &child_volumes[0];
366  const BoundingVolume **child_end = child_begin + child_volumes.size();
367  ((BoundingVolume *)gbv)->around(child_begin, child_end);
368  }
369 
370  internal_bounds = gbv;
371  internal_vertices = 0;
372 }
373 
374 ////////////////////////////////////////////////////////////////////
375 // Function: CollisionNode::get_last_pos_state
376 // Access: Protected
377 // Description: Returns a RenderState for rendering the ghosted
378 // collision solid that represents the previous frame's
379 // position, for those collision nodes that indicate a
380 // velocity.
381 ////////////////////////////////////////////////////////////////////
383 get_last_pos_state() {
384  // Once someone asks for this pointer, we hold its reference count
385  // and never free it.
386  static CPT(RenderState) state = (const RenderState *)NULL;
387  if (state == (const RenderState *)NULL) {
388  state = RenderState::make
389  (ColorScaleAttrib::make(LVecBase4(1.0f, 1.0f, 1.0f, 0.5f)),
390  TransparencyAttrib::make(TransparencyAttrib::M_alpha));
391  }
392 
393  return state;
394 }
395 
396 
397 ////////////////////////////////////////////////////////////////////
398 // Function: CollisionNode::register_with_read_factory
399 // Access: Public, Static
400 // Description: Tells the BamReader how to create objects of type
401 // CollisionNode.
402 ////////////////////////////////////////////////////////////////////
403 void CollisionNode::
405  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
406 }
407 
408 ////////////////////////////////////////////////////////////////////
409 // Function: CollisionNode::write_datagram
410 // Access: Public, Virtual
411 // Description: Writes the contents of this object to the datagram
412 // for shipping out to a Bam file.
413 ////////////////////////////////////////////////////////////////////
414 void CollisionNode::
416  PandaNode::write_datagram(manager, dg);
417 
418  int num_solids = _solids.size();
419  if (num_solids >= 0xffff) {
420  dg.add_uint16(0xffff);
421  dg.add_uint32(num_solids);
422  } else {
423  dg.add_uint16(num_solids);
424  }
425  for(int i = 0; i < num_solids; i++) {
426  manager->write_pointer(dg, _solids[i].get_read_pointer());
427  }
428 
429  dg.add_uint32(_from_collide_mask.get_word());
430 }
431 
432 ////////////////////////////////////////////////////////////////////
433 // Function: CollisionNode::complete_pointers
434 // Access: Public, Virtual
435 // Description: Receives an array of pointers, one for each time
436 // manager->read_pointer() was called in fillin().
437 // Returns the number of pointers processed.
438 ////////////////////////////////////////////////////////////////////
439 int CollisionNode::
441  int pi = PandaNode::complete_pointers(p_list, manager);
442 
443  int num_solids = _solids.size();
444  for (int i = 0; i < num_solids; i++) {
445  _solids[i] = DCAST(CollisionSolid, p_list[pi++]);
446  }
447 
448  return pi;
449 }
450 
451 ////////////////////////////////////////////////////////////////////
452 // Function: CollisionNode::make_from_bam
453 // Access: Protected, Static
454 // Description: This function is called by the BamReader's factory
455 // when a new object of type CollisionNode is encountered
456 // in the Bam file. It should create the CollisionNode
457 // and extract its information from the file.
458 ////////////////////////////////////////////////////////////////////
459 TypedWritable *CollisionNode::
460 make_from_bam(const FactoryParams &params) {
461  CollisionNode *node = new CollisionNode("");
462  DatagramIterator scan;
463  BamReader *manager;
464 
465  parse_params(params, scan, manager);
466  node->fillin(scan, manager);
467 
468  return node;
469 }
470 
471 ////////////////////////////////////////////////////////////////////
472 // Function: CollisionNode::fillin
473 // Access: Protected
474 // Description: This internal function is called by make_from_bam to
475 // read in all of the relevant data from the BamFile for
476 // the new CollisionNode.
477 ////////////////////////////////////////////////////////////////////
478 void CollisionNode::
479 fillin(DatagramIterator &scan, BamReader *manager) {
480  PandaNode::fillin(scan, manager);
481 
482  int num_solids = scan.get_uint16();
483  if (num_solids == 0xffff) {
484  num_solids = scan.get_uint32();
485  }
486  _solids.clear();
487  _solids.reserve(num_solids);
488  for(int i = 0; i < num_solids; i++) {
489  manager->read_pointer(scan);
490  // Push back a NULL for each solid, for now. We'll fill them in
491  // later.
492  _solids.push_back((CollisionSolid *)NULL);
493  }
494 
495  _from_collide_mask.set_word(scan.get_uint32());
496 }
static const LMatrix4f & ident_mat()
Returns an identity matrix.
Definition: lmatrix.h:903
A basic node of the scene graph or data graph.
Definition: pandaNode.h:72
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
Definition: boundingBox.h:31
virtual PandaNode * make_copy() const
Returns a newly-allocated Node that is a shallow copy of this one.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: pandaNode.cxx:4164
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:122
static BitMask< WType, nbits > all_on()
Returns a BitMask whose bits are all on.
Definition: bitMask.I:73
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.
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:37
This collects together the pieces of data that are accumulated for each node while walking the scene ...
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
Definition: typedObject.I:74
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:73
PN_uint32 get_uint32()
Extracts an unsigned 32-bit integer.
void set_word(WordType value)
Sets the entire BitMask to the value indicated by the given word.
Definition: bitMask.I:395
PN_uint16 get_uint16()
Extracts an unsigned 16-bit integer.
void traverse(const NodePath &root)
Begins the traversal from the indicated node.
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:39
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
BoundingVolume::BoundsType get_bounds_type() const
Returns the bounding volume type set with set_bounds_type().
Definition: pandaNode.cxx:2284
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data)
This function will be called during the cull traversal to perform any additional operations that shou...
virtual bool is_collision_node() const
A simple downcast check.
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager-&gt;read_pointer() was called in fillin()...
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
void mark_internal_bounds_stale(Thread *current_thread=Thread::get_current_thread())
Should be called by a derived class to mark the internal bounding volume stale, so that compute_inter...
Definition: pandaNode.cxx:2467
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Receives an array of pointers, one for each time manager-&gt;read_pointer() was called in fillin()...
NodePath get_node_path() const
Constructs and returns an actual NodePath that represents the same path we have just traversed...
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:451
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:40
virtual bool preserve_name() const
Returns true if the node&#39;s name has extrinsic meaning and must be preserved across a flatten operatio...
virtual CollideMask get_legal_collide_mask() const
Returns the subset of CollideMask bits that may be set for this particular type of PandaNode...
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:53
void register_factory(TypeHandle handle, CreateFunc *func)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:90
void add_uint16(PN_uint16 value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:181
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:213
virtual void output(ostream &out) const
Writes a brief description of the node to the indicated output stream.
A thread; that is, a lightweight process.
Definition: thread.h:51
void add_uint32(PN_uint32 value)
Adds an unsigned 32-bit integer to the datagram.
Definition: datagram.I:192
A node in the scene graph that can hold any number of CollisionSolids.
Definition: collisionNode.h:33
static void register_with_read_factory()
Tells the BamReader how to create objects of type CollisionNode.
virtual bool is_renderable() const
Returns true if there is some value to visiting this particular node during the cull traversal for an...
bool almost_equal(const LMatrix4f &other, float threshold) const
Returns true if two matrices are memberwise equal within a specified tolerance.
Definition: lmatrix.cxx:879
A class to retrieve the individual data elements previously stored in a Datagram. ...
WordType get_word() const
Returns the entire BitMask as a single word.
Definition: bitMask.I:383
CollideMask get_into_collide_mask() const
Returns the current &quot;into&quot; CollideMask.
Definition: collisionNode.I:67
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
CollideMask get_from_collide_mask() const
Returns the current &quot;from&quot; CollideMask.
Definition: collisionNode.I:53
virtual PandaNode * combine_with(PandaNode *other)
Collapses this node with the other node, if possible, and returns a pointer to the combined node...
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:43
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
A general bitmask class.
Definition: bitMask.h:35
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:165
void set_from_collide_mask(CollideMask mask)
Sets the &quot;from&quot; CollideMask.
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling...
Definition: cullTraverser.h:48
bool is_nan() const
Returns true if any component of the matrix is not-a-number, false otherwise.
Definition: lmatrix.h:1417
virtual void xform(const LMatrix4 &mat)
Transforms the contents of this node by the indicated matrix, if it means anything to do so...
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
Definition: bamWriter.cxx:279
void read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:652