Panda3D
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.
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  }
124  mark_internal_bounds_stale();
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);
157  mark_internal_bounds_stale();
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 ////////////////////////////////////////////////////////////////////
382 CPT(RenderState) CollisionNode::
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 }
virtual bool preserve_name() const
Returns true if the node&#39;s name has extrinsic meaning and must be preserved across a flatten operatio...
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
virtual PandaNode * make_copy() const
Returns a newly-allocated Node that is a shallow copy of this one.
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
Definition: boundingBox.h:31
CollideMask get_into_collide_mask() const
Returns the current "into" CollideMask.
Definition: collisionNode.I:67
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
Definition: typedObject.I:74
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
virtual CollideMask get_legal_collide_mask() const
Returns the subset of CollideMask bits that may be set for this particular type of PandaNode...
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:122
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
static BitMask< PN_uint32, 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.
virtual bool is_renderable() const
Returns true if there is some value to visiting this particular node during the cull traversal for an...
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:37
virtual void output(ostream &out) const
Writes a brief description of the node to the indicated output stream.
This collects together the pieces of data that are accumulated for each node while walking the scene ...
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.
bool is_nan() const
Returns true if any component of the matrix is not-a-number, false otherwise.
Definition: lmatrix.h:1417
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...
CollideMask get_from_collide_mask() const
Returns the current "from" CollideMask.
Definition: collisionNode.I:53
WordType get_word() const
Returns the entire BitMask as a single word.
Definition: bitMask.I:383
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 int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin()...
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
NodePath get_node_path() const
Constructs and returns an actual NodePath that represents the same path we have just traversed...
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin()...
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
void set_overall_hidden(bool overall_hidden)
Sets or clears the hidden flag.
Definition: pandaNode.I:544
void set_into_collide_mask(CollideMask mask)
Sets the "into" CollideMask.
Definition: collisionNode.I:38
BoundingVolume::BoundsType get_bounds_type() const
Returns the bounding volume type set with set_bounds_type().
Definition: pandaNode.cxx:2284
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 CollideMask get_default_collide_mask()
Returns the default into_collide_mask assigned to new CollisionNodes.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:213
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_collision_node() const
A simple downcast check.
A class to retrieve the individual data elements previously stored in a Datagram. ...
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
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.
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 "from" CollideMask.
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling...
Definition: cullTraverser.h:48
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:658