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 LMatrix4f &mat) {
00113   nassertv(!mat.is_nan());
00114 
00115   if (mat.almost_equal(LMatrix4f::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 ////////////////////////////////////////////////////////////////////
00274 //     Function: CollisionNode::output
00275 //       Access: Public, Virtual
00276 //  Description: Writes a brief description of the node to the
00277 //               indicated output stream.  This is invoked by the <<
00278 //               operator.  It may be overridden in derived classes to
00279 //               include some information relevant to the class.
00280 ////////////////////////////////////////////////////////////////////
00281 void CollisionNode::
00282 output(ostream &out) const {
00283   PandaNode::output(out);
00284   out << " (" << _solids.size() << " solids)";
00285 }
00286 
00287 ////////////////////////////////////////////////////////////////////
00288 //     Function: CollisionNode::set_from_collide_mask
00289 //       Access: Published
00290 //  Description: Sets the "from" CollideMask.  In order for a
00291 //               collision to be detected from this object into
00292 //               another object, the intersection of this object's
00293 //               "from" mask and the other object's "into" mask must
00294 //               be nonzero.
00295 ////////////////////////////////////////////////////////////////////
00296 void CollisionNode::
00297 set_from_collide_mask(CollideMask mask) {
00298   _from_collide_mask = mask;
00299 }
00300 
00301 ////////////////////////////////////////////////////////////////////
00302 //     Function: CollisionNode::compute_internal_bounds
00303 //       Access: Protected, Virtual
00304 //  Description: Called when needed to recompute the node's
00305 //               _internal_bound object.  Nodes that contain anything
00306 //               of substance should redefine this to do the right
00307 //               thing.
00308 ////////////////////////////////////////////////////////////////////
00309 void CollisionNode::
00310 compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
00311                         int &internal_vertices,
00312                         int pipeline_stage,
00313                         Thread *current_thread) const {
00314   pvector<CPT(BoundingVolume) > child_volumes_ref;
00315   pvector<const BoundingVolume *> child_volumes;
00316   bool all_box = true;
00317 
00318   Solids::const_iterator gi;
00319   for (gi = _solids.begin(); gi != _solids.end(); ++gi) {
00320     CPT(CollisionSolid) solid = (*gi).get_read_pointer();
00321     CPT(BoundingVolume) volume = solid->get_bounds();
00322 
00323     if (!volume->is_empty()) {
00324       child_volumes_ref.push_back(volume);
00325       child_volumes.push_back(volume);
00326       if (!volume->is_exact_type(BoundingBox::get_class_type())) {
00327         all_box = false;
00328       }
00329     }
00330   }
00331 
00332   PT(GeometricBoundingVolume) gbv = new BoundingBox;
00333 
00334   BoundingVolume::BoundsType btype = get_bounds_type();
00335   if (btype == BoundingVolume::BT_default) {
00336     btype = bounds_type;
00337   }
00338 
00339   if (btype == BoundingVolume::BT_box ||
00340       (btype != BoundingVolume::BT_sphere && all_box)) {
00341     // If all of the child volumes are a BoundingBox, then our volume
00342     // is also a BoundingBox.
00343     gbv = new BoundingBox;
00344   } else {
00345     // Otherwise, it's a sphere.
00346     gbv = new BoundingSphere;
00347   }
00348 
00349   if (child_volumes.size() > 0) {
00350     const BoundingVolume **child_begin = &child_volumes[0];
00351     const BoundingVolume **child_end = child_begin + child_volumes.size();
00352     ((BoundingVolume *)gbv)->around(child_begin, child_end);
00353   }
00354   
00355   internal_bounds = gbv;
00356   internal_vertices = 0;
00357 }
00358 
00359 ////////////////////////////////////////////////////////////////////
00360 //     Function: CollisionNode::get_last_pos_state
00361 //       Access: Protected
00362 //  Description: Returns a RenderState for rendering the ghosted
00363 //               collision solid that represents the previous frame's
00364 //               position, for those collision nodes that indicate a
00365 //               velocity.
00366 ////////////////////////////////////////////////////////////////////
00367 CPT(RenderState) CollisionNode::
00368 get_last_pos_state() {
00369   // Once someone asks for this pointer, we hold its reference count
00370   // and never free it.
00371   static CPT(RenderState) state = (const RenderState *)NULL;
00372   if (state == (const RenderState *)NULL) {
00373     state = RenderState::make
00374       (ColorScaleAttrib::make(LVecBase4f(1.0f, 1.0f, 1.0f, 0.5f)),
00375        TransparencyAttrib::make(TransparencyAttrib::M_alpha));
00376   }
00377 
00378   return state;
00379 }
00380 
00381 
00382 ////////////////////////////////////////////////////////////////////
00383 //     Function: CollisionNode::register_with_read_factory
00384 //       Access: Public, Static
00385 //  Description: Tells the BamReader how to create objects of type
00386 //               CollisionNode.
00387 ////////////////////////////////////////////////////////////////////
00388 void CollisionNode::
00389 register_with_read_factory() {
00390   BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
00391 }
00392 
00393 ////////////////////////////////////////////////////////////////////
00394 //     Function: CollisionNode::write_datagram
00395 //       Access: Public, Virtual
00396 //  Description: Writes the contents of this object to the datagram
00397 //               for shipping out to a Bam file.
00398 ////////////////////////////////////////////////////////////////////
00399 void CollisionNode::
00400 write_datagram(BamWriter *manager, Datagram &dg) {
00401   PandaNode::write_datagram(manager, dg);
00402 
00403   int num_solids = _solids.size();
00404   if (num_solids >= 0xffff) {
00405     dg.add_uint16(0xffff);
00406     dg.add_uint32(num_solids);
00407   } else {
00408     dg.add_uint16(num_solids);
00409   }
00410   for(int i = 0; i < num_solids; i++) {
00411     manager->write_pointer(dg, _solids[i].get_read_pointer());
00412   }
00413 
00414   dg.add_uint32(_from_collide_mask.get_word());
00415 }
00416 
00417 ////////////////////////////////////////////////////////////////////
00418 //     Function: CollisionNode::complete_pointers
00419 //       Access: Public, Virtual
00420 //  Description: Receives an array of pointers, one for each time
00421 //               manager->read_pointer() was called in fillin().
00422 //               Returns the number of pointers processed.
00423 ////////////////////////////////////////////////////////////////////
00424 int CollisionNode::
00425 complete_pointers(TypedWritable **p_list, BamReader *manager) {
00426   int pi = PandaNode::complete_pointers(p_list, manager);
00427 
00428   int num_solids = _solids.size();
00429   for (int i = 0; i < num_solids; i++) {
00430     _solids[i] = DCAST(CollisionSolid, p_list[pi++]);
00431   }
00432 
00433   return pi;
00434 }
00435 
00436 ////////////////////////////////////////////////////////////////////
00437 //     Function: CollisionNode::make_from_bam
00438 //       Access: Protected, Static
00439 //  Description: This function is called by the BamReader's factory
00440 //               when a new object of type CollisionNode is encountered
00441 //               in the Bam file.  It should create the CollisionNode
00442 //               and extract its information from the file.
00443 ////////////////////////////////////////////////////////////////////
00444 TypedWritable *CollisionNode::
00445 make_from_bam(const FactoryParams &params) {
00446   CollisionNode *node = new CollisionNode("");
00447   DatagramIterator scan;
00448   BamReader *manager;
00449 
00450   parse_params(params, scan, manager);
00451   node->fillin(scan, manager);
00452 
00453   return node;
00454 }
00455 
00456 ////////////////////////////////////////////////////////////////////
00457 //     Function: CollisionNode::fillin
00458 //       Access: Protected
00459 //  Description: This internal function is called by make_from_bam to
00460 //               read in all of the relevant data from the BamFile for
00461 //               the new CollisionNode.
00462 ////////////////////////////////////////////////////////////////////
00463 void CollisionNode::
00464 fillin(DatagramIterator &scan, BamReader *manager) {
00465   PandaNode::fillin(scan, manager);
00466 
00467   int num_solids = scan.get_uint16();
00468   if (num_solids == 0xffff) {
00469     num_solids = scan.get_uint32();
00470   }
00471   _solids.clear();
00472   _solids.reserve(num_solids);
00473   for(int i = 0; i < num_solids; i++) {
00474     manager->read_pointer(scan);
00475     // Push back a NULL for each solid, for now.  We'll fill them in
00476     // later.
00477     _solids.push_back((CollisionSolid *)NULL);
00478   }
00479 
00480   _from_collide_mask.set_word(scan.get_uint32());
00481 }
 All Classes Functions Variables Enumerations