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