Panda3D

collisionNode.cxx

00001 // Filename: collisionNode.cxx
00002 // Created by:  drose (16Mar02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "collisionNode.h"
00016 #include "config_collide.h"
00017 
00018 #include "geomNode.h"
00019 #include "cullTraverserData.h"
00020 #include "cullTraverser.h"
00021 #include "renderState.h"
00022 #include "transformState.h"
00023 #include "colorScaleAttrib.h"
00024 #include "transparencyAttrib.h"
00025 #include "datagram.h"
00026 #include "datagramIterator.h"
00027 #include "bamReader.h"
00028 #include "bamWriter.h"
00029 #include "clockObject.h"
00030 #include "boundingSphere.h"
00031 #include "boundingBox.h"
00032 #include "config_mathutil.h"
00033 
00034 TypeHandle CollisionNode::_type_handle;
00035 
00036 
00037 ////////////////////////////////////////////////////////////////////
00038 //     Function: CollisionNode::Constructor
00039 //       Access: Public
00040 //  Description:
00041 ////////////////////////////////////////////////////////////////////
00042 CollisionNode::
00043 CollisionNode(const string &name) :
00044   PandaNode(name),
00045   _from_collide_mask(get_default_collide_mask()),
00046   _collider_sort(0)
00047 {
00048   set_cull_callback();
00049 
00050   // CollisionNodes are hidden by default.
00051   set_overall_hidden(true);
00052 
00053   // CollisionNodes have a certain set of bits on by default.
00054   set_into_collide_mask(get_default_collide_mask());
00055 }
00056 
00057 ////////////////////////////////////////////////////////////////////
00058 //     Function: CollisionNode::Copy Constructor
00059 //       Access: Protected
00060 //  Description:
00061 ////////////////////////////////////////////////////////////////////
00062 CollisionNode::
00063 CollisionNode(const CollisionNode &copy) :
00064   PandaNode(copy),
00065   _from_collide_mask(copy._from_collide_mask),
00066   _solids(copy._solids)
00067 {
00068 }
00069 
00070 ////////////////////////////////////////////////////////////////////
00071 //     Function: CollisionNode::Destructor
00072 //       Access: Public, Virtual
00073 //  Description:
00074 ////////////////////////////////////////////////////////////////////
00075 CollisionNode::
00076 ~CollisionNode() {
00077 }
00078 
00079 ////////////////////////////////////////////////////////////////////
00080 //     Function: CollisionNode::make_copy
00081 //       Access: Public, Virtual
00082 //  Description: Returns a newly-allocated Node that is a shallow copy
00083 //               of this one.  It will be a different Node pointer,
00084 //               but its internal data may or may not be shared with
00085 //               that of the original Node.
00086 ////////////////////////////////////////////////////////////////////
00087 PandaNode *CollisionNode::
00088 make_copy() const {
00089   return new CollisionNode(*this);
00090 }
00091 
00092 ////////////////////////////////////////////////////////////////////
00093 //     Function: CollisionNode::preserve_name
00094 //       Access: Public, Virtual
00095 //  Description: Returns true if the node's name has extrinsic meaning
00096 //               and must be preserved across a flatten operation,
00097 //               false otherwise.
00098 ////////////////////////////////////////////////////////////////////
00099 bool CollisionNode::
00100 preserve_name() const {
00101   return true;
00102 }
00103 
00104 ////////////////////////////////////////////////////////////////////
00105 //     Function: CollisionNode::xform
00106 //       Access: Public, Virtual
00107 //  Description: Transforms the contents of this node by the indicated
00108 //               matrix, if it means anything to do so.  For most
00109 //               kinds of nodes, this does nothing.
00110 ////////////////////////////////////////////////////////////////////
00111 void CollisionNode::
00112 xform(const LMatrix4 &mat) {
00113   nassertv(!mat.is_nan());
00114 
00115   if (mat.almost_equal(LMatrix4::ident_mat())) {
00116     return;
00117   }
00118 
00119   Solids::iterator si;
00120   for (si = _solids.begin(); si != _solids.end(); ++si) {
00121     PT(CollisionSolid) solid = (*si).get_write_pointer();
00122     solid->xform(mat);
00123   }
00124   mark_internal_bounds_stale();
00125 }
00126 
00127 ////////////////////////////////////////////////////////////////////
00128 //     Function: CollisionNode::combine_with
00129 //       Access: Public, Virtual
00130 //  Description: Collapses this node with the other node, if possible,
00131 //               and returns a pointer to the combined node, or NULL
00132 //               if the two nodes cannot safely be combined.
00133 //
00134 //               The return value may be this, other, or a new node
00135 //               altogether.
00136 //
00137 //               This function is called from GraphReducer::flatten(),
00138 //               and need not deal with children; its job is just to
00139 //               decide whether to collapse the two nodes and what the
00140 //               collapsed node should look like.
00141 ////////////////////////////////////////////////////////////////////
00142 PandaNode *CollisionNode::
00143 combine_with(PandaNode *other) {
00144   if (flatten_collision_nodes) {
00145     if (is_exact_type(get_class_type()) &&
00146         other->is_exact_type(get_class_type())) {
00147       // Two CollisionNodes can combine, but only if they have the same
00148       // name, because the name is often meaningful, and only if they
00149       // have the same collide masks.
00150       CollisionNode *cother = DCAST(CollisionNode, other);
00151       if (get_name() == cother->get_name() &&
00152           get_from_collide_mask() == cother->get_from_collide_mask() &&
00153           get_into_collide_mask() == cother->get_into_collide_mask()) {
00154         const COWPT(CollisionSolid) *solids_begin = &cother->_solids[0];
00155         const COWPT(CollisionSolid) *solids_end = solids_begin + cother->_solids.size();
00156         _solids.insert(_solids.end(), solids_begin, solids_end);
00157         mark_internal_bounds_stale();
00158         return this;
00159       }
00160       
00161       // Two CollisionNodes with different names or different collide
00162       // masks can't combine.
00163     }
00164   }
00165 
00166   return NULL;
00167 }
00168 
00169 ////////////////////////////////////////////////////////////////////
00170 //     Function: CollisionNode::get_legal_collide_mask
00171 //       Access: Published, Virtual
00172 //  Description: Returns the subset of CollideMask bits that may be
00173 //               set for this particular type of PandaNode.  For most
00174 //               nodes, this is 0; it doesn't make sense to set a
00175 //               CollideMask for most kinds of nodes.
00176 //
00177 //               For nodes that can be collided with, such as GeomNode
00178 //               and CollisionNode, this returns all bits on.
00179 ////////////////////////////////////////////////////////////////////
00180 CollideMask CollisionNode::
00181 get_legal_collide_mask() const {
00182   return CollideMask::all_on();
00183 }
00184 
00185 ////////////////////////////////////////////////////////////////////
00186 //     Function: CollisionNode::cull_callback
00187 //       Access: Public, Virtual
00188 //  Description: This function will be called during the cull
00189 //               traversal to perform any additional operations that
00190 //               should be performed at cull time.  This may include
00191 //               additional manipulation of render state or additional
00192 //               visible/invisible decisions, or any other arbitrary
00193 //               operation.
00194 //
00195 //               Note that this function will *not* be called unless
00196 //               set_cull_callback() is called in the constructor of
00197 //               the derived class.  It is necessary to call
00198 //               set_cull_callback() to indicated that we require
00199 //               cull_callback() to be called.
00200 //
00201 //               By the time this function is called, the node has
00202 //               already passed the bounding-volume test for the
00203 //               viewing frustum, and the node's transform and state
00204 //               have already been applied to the indicated
00205 //               CullTraverserData object.
00206 //
00207 //               The return value is true if this node should be
00208 //               visible, or false if it should be culled.
00209 ////////////////////////////////////////////////////////////////////
00210 bool CollisionNode::
00211 cull_callback(CullTraverser *trav, CullTraverserData &data) {
00212   // Append our collision vizzes to the drawing, even though they're
00213   // not actually part of the scene graph.
00214   Solids::const_iterator si;
00215   for (si = _solids.begin(); si != _solids.end(); ++si) {
00216     CPT(CollisionSolid) solid = (*si).get_read_pointer();
00217     PT(PandaNode) node = solid->get_viz(trav, data, false);
00218     if (node != (PandaNode *)NULL) {
00219       CullTraverserData next_data(data, node);
00220 
00221       // We don't want to inherit the render state from above for these
00222       // guys.
00223       next_data._state = RenderState::make_empty();
00224       trav->traverse(next_data);
00225     }
00226   }
00227 
00228   if (respect_prev_transform) {
00229     // Determine the previous frame's position, relative to the
00230     // current position.
00231     NodePath node_path = data._node_path.get_node_path();
00232     CPT(TransformState) transform = node_path.get_net_transform()->invert_compose(node_path.get_net_prev_transform());
00233     
00234     if (!transform->is_identity()) {
00235       // If we have a velocity, also draw the previous frame's position,
00236       // ghosted.
00237       
00238       for (si = _solids.begin(); si != _solids.end(); ++si) {
00239         CPT(CollisionSolid) solid = (*si).get_read_pointer();
00240         PT(PandaNode) node = solid->get_viz(trav, data, false);
00241         if (node != (PandaNode *)NULL) {
00242           CullTraverserData next_data(data, node);
00243           
00244           next_data._net_transform = 
00245             next_data._net_transform->compose(transform);
00246           next_data._state = get_last_pos_state();
00247           trav->traverse(next_data);
00248         }
00249       }
00250     }
00251   }
00252 
00253   // Now carry on to render our child nodes.
00254   return true;
00255 }
00256 
00257 ////////////////////////////////////////////////////////////////////
00258 //     Function: CollisionNode::is_renderable
00259 //       Access: Public, Virtual
00260 //  Description: Returns true if there is some value to visiting this
00261 //               particular node during the cull traversal for any
00262 //               camera, false otherwise.  This will be used to
00263 //               optimize the result of get_net_draw_show_mask(), so
00264 //               that any subtrees that contain only nodes for which
00265 //               is_renderable() is false need not be visited.
00266 ////////////////////////////////////////////////////////////////////
00267 bool CollisionNode::
00268 is_renderable() const {
00269   return true;
00270 }
00271 
00272 ////////////////////////////////////////////////////////////////////
00273 //     Function: CollisionNode::is_collision_node
00274 //       Access: Published, Virtual
00275 //  Description: A simple downcast check.  Returns true if this kind
00276 //               of node happens to inherit from CollisionNode, false
00277 //               otherwise.
00278 //
00279 //               This is provided as a a faster alternative to calling
00280 //               is_of_type(CollisionNode::get_class_type()).
00281 ////////////////////////////////////////////////////////////////////
00282 bool CollisionNode::
00283 is_collision_node() const {
00284   return true;
00285 }
00286 
00287 
00288 ////////////////////////////////////////////////////////////////////
00289 //     Function: CollisionNode::output
00290 //       Access: Public, Virtual
00291 //  Description: Writes a brief description of the node to the
00292 //               indicated output stream.  This is invoked by the <<
00293 //               operator.  It may be overridden in derived classes to
00294 //               include some information relevant to the class.
00295 ////////////////////////////////////////////////////////////////////
00296 void CollisionNode::
00297 output(ostream &out) const {
00298   PandaNode::output(out);
00299   out << " (" << _solids.size() << " solids)";
00300 }
00301 
00302 ////////////////////////////////////////////////////////////////////
00303 //     Function: CollisionNode::set_from_collide_mask
00304 //       Access: Published
00305 //  Description: Sets the "from" CollideMask.  In order for a
00306 //               collision to be detected from this object into
00307 //               another object, the intersection of this object's
00308 //               "from" mask and the other object's "into" mask must
00309 //               be nonzero.
00310 ////////////////////////////////////////////////////////////////////
00311 void CollisionNode::
00312 set_from_collide_mask(CollideMask mask) {
00313   _from_collide_mask = mask;
00314 }
00315 
00316 ////////////////////////////////////////////////////////////////////
00317 //     Function: CollisionNode::compute_internal_bounds
00318 //       Access: Protected, Virtual
00319 //  Description: Called when needed to recompute the node's
00320 //               _internal_bound object.  Nodes that contain anything
00321 //               of substance should redefine this to do the right
00322 //               thing.
00323 ////////////////////////////////////////////////////////////////////
00324 void CollisionNode::
00325 compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
00326                         int &internal_vertices,
00327                         int pipeline_stage,
00328                         Thread *current_thread) const {
00329   pvector<CPT(BoundingVolume) > child_volumes_ref;
00330   pvector<const BoundingVolume *> child_volumes;
00331   bool all_box = true;
00332 
00333   Solids::const_iterator gi;
00334   for (gi = _solids.begin(); gi != _solids.end(); ++gi) {
00335     CPT(CollisionSolid) solid = (*gi).get_read_pointer();
00336     CPT(BoundingVolume) volume = solid->get_bounds();
00337 
00338     if (!volume->is_empty()) {
00339       child_volumes_ref.push_back(volume);
00340       child_volumes.push_back(volume);
00341       if (!volume->is_exact_type(BoundingBox::get_class_type())) {
00342         all_box = false;
00343       }
00344     }
00345   }
00346 
00347   PT(GeometricBoundingVolume) gbv = new BoundingBox;
00348 
00349   BoundingVolume::BoundsType btype = get_bounds_type();
00350   if (btype == BoundingVolume::BT_default) {
00351     btype = bounds_type;
00352   }
00353 
00354   if (btype == BoundingVolume::BT_box ||
00355       (btype != BoundingVolume::BT_sphere && all_box)) {
00356     // If all of the child volumes are a BoundingBox, then our volume
00357     // is also a BoundingBox.
00358     gbv = new BoundingBox;
00359   } else {
00360     // Otherwise, it's a sphere.
00361     gbv = new BoundingSphere;
00362   }
00363 
00364   if (child_volumes.size() > 0) {
00365     const BoundingVolume **child_begin = &child_volumes[0];
00366     const BoundingVolume **child_end = child_begin + child_volumes.size();
00367     ((BoundingVolume *)gbv)->around(child_begin, child_end);
00368   }
00369   
00370   internal_bounds = gbv;
00371   internal_vertices = 0;
00372 }
00373 
00374 ////////////////////////////////////////////////////////////////////
00375 //     Function: CollisionNode::get_last_pos_state
00376 //       Access: Protected
00377 //  Description: Returns a RenderState for rendering the ghosted
00378 //               collision solid that represents the previous frame's
00379 //               position, for those collision nodes that indicate a
00380 //               velocity.
00381 ////////////////////////////////////////////////////////////////////
00382 CPT(RenderState) CollisionNode::
00383 get_last_pos_state() {
00384   // Once someone asks for this pointer, we hold its reference count
00385   // and never free it.
00386   static CPT(RenderState) state = (const RenderState *)NULL;
00387   if (state == (const RenderState *)NULL) {
00388     state = RenderState::make
00389       (ColorScaleAttrib::make(LVecBase4(1.0f, 1.0f, 1.0f, 0.5f)),
00390        TransparencyAttrib::make(TransparencyAttrib::M_alpha));
00391   }
00392 
00393   return state;
00394 }
00395 
00396 
00397 ////////////////////////////////////////////////////////////////////
00398 //     Function: CollisionNode::register_with_read_factory
00399 //       Access: Public, Static
00400 //  Description: Tells the BamReader how to create objects of type
00401 //               CollisionNode.
00402 ////////////////////////////////////////////////////////////////////
00403 void CollisionNode::
00404 register_with_read_factory() {
00405   BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
00406 }
00407 
00408 ////////////////////////////////////////////////////////////////////
00409 //     Function: CollisionNode::write_datagram
00410 //       Access: Public, Virtual
00411 //  Description: Writes the contents of this object to the datagram
00412 //               for shipping out to a Bam file.
00413 ////////////////////////////////////////////////////////////////////
00414 void CollisionNode::
00415 write_datagram(BamWriter *manager, Datagram &dg) {
00416   PandaNode::write_datagram(manager, dg);
00417 
00418   int num_solids = _solids.size();
00419   if (num_solids >= 0xffff) {
00420     dg.add_uint16(0xffff);
00421     dg.add_uint32(num_solids);
00422   } else {
00423     dg.add_uint16(num_solids);
00424   }
00425   for(int i = 0; i < num_solids; i++) {
00426     manager->write_pointer(dg, _solids[i].get_read_pointer());
00427   }
00428 
00429   dg.add_uint32(_from_collide_mask.get_word());
00430 }
00431 
00432 ////////////////////////////////////////////////////////////////////
00433 //     Function: CollisionNode::complete_pointers
00434 //       Access: Public, Virtual
00435 //  Description: Receives an array of pointers, one for each time
00436 //               manager->read_pointer() was called in fillin().
00437 //               Returns the number of pointers processed.
00438 ////////////////////////////////////////////////////////////////////
00439 int CollisionNode::
00440 complete_pointers(TypedWritable **p_list, BamReader *manager) {
00441   int pi = PandaNode::complete_pointers(p_list, manager);
00442 
00443   int num_solids = _solids.size();
00444   for (int i = 0; i < num_solids; i++) {
00445     _solids[i] = DCAST(CollisionSolid, p_list[pi++]);
00446   }
00447 
00448   return pi;
00449 }
00450 
00451 ////////////////////////////////////////////////////////////////////
00452 //     Function: CollisionNode::make_from_bam
00453 //       Access: Protected, Static
00454 //  Description: This function is called by the BamReader's factory
00455 //               when a new object of type CollisionNode is encountered
00456 //               in the Bam file.  It should create the CollisionNode
00457 //               and extract its information from the file.
00458 ////////////////////////////////////////////////////////////////////
00459 TypedWritable *CollisionNode::
00460 make_from_bam(const FactoryParams &params) {
00461   CollisionNode *node = new CollisionNode("");
00462   DatagramIterator scan;
00463   BamReader *manager;
00464 
00465   parse_params(params, scan, manager);
00466   node->fillin(scan, manager);
00467 
00468   return node;
00469 }
00470 
00471 ////////////////////////////////////////////////////////////////////
00472 //     Function: CollisionNode::fillin
00473 //       Access: Protected
00474 //  Description: This internal function is called by make_from_bam to
00475 //               read in all of the relevant data from the BamFile for
00476 //               the new CollisionNode.
00477 ////////////////////////////////////////////////////////////////////
00478 void CollisionNode::
00479 fillin(DatagramIterator &scan, BamReader *manager) {
00480   PandaNode::fillin(scan, manager);
00481 
00482   int num_solids = scan.get_uint16();
00483   if (num_solids == 0xffff) {
00484     num_solids = scan.get_uint32();
00485   }
00486   _solids.clear();
00487   _solids.reserve(num_solids);
00488   for(int i = 0; i < num_solids; i++) {
00489     manager->read_pointer(scan);
00490     // Push back a NULL for each solid, for now.  We'll fill them in
00491     // later.
00492     _solids.push_back((CollisionSolid *)NULL);
00493   }
00494 
00495   _from_collide_mask.set_word(scan.get_uint32());
00496 }
 All Classes Functions Variables Enumerations