Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/collide/collisionNode.cxx

Go to the documentation of this file.
00001 // Filename: collisionNode.cxx
00002 // Created by:  drose (16Mar02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "collisionNode.h"
00020 #include "config_collide.h"
00021 
00022 #include "geomNode.h"
00023 #include "cullTraverserData.h"
00024 #include "cullTraverser.h"
00025 #include "renderState.h"
00026 #include "transformState.h"
00027 #include "colorScaleAttrib.h"
00028 #include "transparencyAttrib.h"
00029 #include "datagram.h"
00030 #include "datagramIterator.h"
00031 #include "bamReader.h"
00032 #include "bamWriter.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(CollideMask::all_on()),
00046   _into_collide_mask(CollideMask::all_on()),
00047   _velocity(0.0f, 0.0f, 0.0f),
00048   _flags(0)
00049 {
00050   // CollisionNodes are hidden by default.
00051   set_draw_mask(DrawMask::all_off());
00052 }
00053 
00054 ////////////////////////////////////////////////////////////////////
00055 //     Function: CollisionNode::Copy Constructor
00056 //       Access: Protected
00057 //  Description:
00058 ////////////////////////////////////////////////////////////////////
00059 CollisionNode::
00060 CollisionNode(const CollisionNode &copy) :
00061   PandaNode(copy),
00062   _from_collide_mask(copy._from_collide_mask),
00063   _into_collide_mask(copy._into_collide_mask),
00064   _velocity(copy._velocity),
00065   _flags(copy._flags),
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     CollisionSolid *solid = (*si);
00122 
00123     // We may have to copy each of our solids as we transform them if
00124     // someone else is sharing their pointers.
00125     if (solid->get_ref_count() > 1) {
00126       solid = solid->make_copy();
00127       (*si) = solid;
00128     }
00129 
00130     solid->xform(mat);
00131   }
00132   mark_bound_stale();
00133 }
00134 
00135 ////////////////////////////////////////////////////////////////////
00136 //     Function: CollisionNode::combine_with
00137 //       Access: Public, Virtual
00138 //  Description: Collapses this node with the other node, if possible,
00139 //               and returns a pointer to the combined node, or NULL
00140 //               if the two nodes cannot safely be combined.
00141 //
00142 //               The return value may be this, other, or a new node
00143 //               altogether.
00144 //
00145 //               This function is called from GraphReducer::flatten(),
00146 //               and need not deal with children; its job is just to
00147 //               decide whether to collapse the two nodes and what the
00148 //               collapsed node should look like.
00149 ////////////////////////////////////////////////////////////////////
00150 PandaNode *CollisionNode::
00151 combine_with(PandaNode *other) {
00152   if (is_exact_type(get_class_type()) &&
00153       other->is_exact_type(get_class_type())) {
00154     // Two CollisionNodes can combine, but only if they have the same
00155     // name, because the name is often meaningful.
00156     CollisionNode *cother = DCAST(CollisionNode, other);
00157     if (get_name() == cother->get_name()) {
00158       const PT(CollisionSolid) *solids_begin = &cother->_solids[0];
00159       const PT(CollisionSolid) *solids_end = solids_begin + cother->_solids.size();
00160       _solids.insert(_solids.end(), solids_begin, solids_end);
00161       mark_bound_stale();
00162       return this;
00163     }
00164 
00165     // Two CollisionNodes with different names can't combine.
00166     return (PandaNode *)NULL;
00167   }
00168 
00169   return PandaNode::combine_with(other);
00170 }
00171 
00172 ////////////////////////////////////////////////////////////////////
00173 //     Function: CollisionNode::has_cull_callback
00174 //       Access: Public, Virtual
00175 //  Description: Should be overridden by derived classes to return
00176 //               true if cull_callback() has been defined.  Otherwise,
00177 //               returns false to indicate cull_callback() does not
00178 //               need to be called for this node during the cull
00179 //               traversal.
00180 ////////////////////////////////////////////////////////////////////
00181 bool CollisionNode::
00182 has_cull_callback() const {
00183   return true;
00184 }
00185 
00186 ////////////////////////////////////////////////////////////////////
00187 //     Function: CollisionNode::cull_callback
00188 //       Access: Public, Virtual
00189 //  Description: If has_cull_callback() returns true, this function
00190 //               will be called during the cull traversal to perform
00191 //               any additional operations that should be performed at
00192 //               cull time.  This may include additional manipulation
00193 //               of render state or additional visible/invisible
00194 //               decisions, or any other arbitrary operation.
00195 //
00196 //               By the time this function is called, the node has
00197 //               already passed the bounding-volume test for the
00198 //               viewing frustum, and the node's transform and state
00199 //               have already been applied to the indicated
00200 //               CullTraverserData object.
00201 //
00202 //               The return value is true if this node should be
00203 //               visible, or false if it should be culled.
00204 ////////////////////////////////////////////////////////////////////
00205 bool CollisionNode::
00206 cull_callback(CullTraverser *trav, CullTraverserData &data) {
00207   // Append our collision vizzes to the drawing, even though they're
00208   // not actually part of the scene graph.
00209   Solids::iterator si;
00210   for (si = _solids.begin(); si != _solids.end(); ++si) {
00211     CollisionSolid *solid = (*si);
00212     PandaNode *node = solid->get_viz();
00213     CullTraverserData next_data(data, node);
00214 
00215     // We don't want to inherit the render state from above for these
00216     // guys.
00217     next_data._state = RenderState::make_empty();
00218     trav->traverse(next_data);
00219   }
00220 
00221   if (has_velocity()) {
00222     // If we have a velocity, also draw the previous frame's position,
00223     // ghosted.
00224     CPT(TransformState) transform = TransformState::make_pos(-get_velocity());
00225     for (si = _solids.begin(); si != _solids.end(); ++si) {
00226       CollisionSolid *solid = (*si);
00227       PandaNode *node = solid->get_viz();
00228       CullTraverserData next_data(data, node);
00229 
00230       next_data._render_transform = 
00231         next_data._render_transform->compose(transform);
00232       next_data._state = get_last_pos_state();
00233       trav->traverse(next_data);
00234     }
00235   }
00236 
00237   // Now carry on to render our child nodes.
00238   return true;
00239 }
00240 
00241 
00242 ////////////////////////////////////////////////////////////////////
00243 //     Function: CollisionNode::output
00244 //       Access: Public, Virtual
00245 //  Description: Writes a brief description of the node to the
00246 //               indicated output stream.  This is invoked by the <<
00247 //               operator.  It may be overridden in derived classes to
00248 //               include some information relevant to the class.
00249 ////////////////////////////////////////////////////////////////////
00250 void CollisionNode::
00251 output(ostream &out) const {
00252   PandaNode::output(out);
00253   out << " (" << _solids.size() << " solids)";
00254 }
00255 
00256 
00257 ////////////////////////////////////////////////////////////////////
00258 //     Function: CollisionNode::set_velocity
00259 //       Access: Published, Virtual
00260 //  Description: Indicates the instantaneous velocity of the node.
00261 //               This is only meaningful for nodes that represent
00262 //               "colliders", that is, nodes added to a
00263 //               CollisionTraverser to be tested for collision into
00264 //               other objects.
00265 //
00266 //               The velocity vector represents the delta from this
00267 //               node's position last frame to its current position.
00268 //               The collision traverser automatically clears it after
00269 //               it has performed the traversal.
00270 //
00271 //               This velocity information is optional and, if
00272 //               available, is used by the collision traverser to help
00273 //               determine which walls the collider is actually
00274 //               intersecting with, and which it is simply passing by.
00275 ////////////////////////////////////////////////////////////////////
00276 void CollisionNode::
00277 set_velocity(const LVector3f &vel) {
00278   _velocity = vel;
00279   _flags |= F_has_velocity;
00280 }
00281 
00282 ////////////////////////////////////////////////////////////////////
00283 //     Function: CollisionNode::recompute_bound
00284 //       Access: Protected, Virtual
00285 //  Description: Recomputes the dynamic bounding volume for this
00286 //               object.  This is the bounding volume for the node and
00287 //               all of its children, and normally does not need to be
00288 //               specialized beyond PandaNode; we specialize this
00289 //               function just so we can piggyback on it the
00290 //               setting the _net_collide_mask bits.
00291 ////////////////////////////////////////////////////////////////////
00292 BoundingVolume *CollisionNode::
00293 recompute_bound() {
00294   BoundingVolume *result = PandaNode::recompute_bound();
00295   add_net_collide_mask(get_into_collide_mask());
00296   return result;
00297 }
00298 
00299 ////////////////////////////////////////////////////////////////////
00300 //     Function: CollisionNode::recompute_internal_bound
00301 //       Access: Protected, Virtual
00302 //  Description: Called when needed to recompute the node's
00303 //               _internal_bound object.  Nodes that contain anything
00304 //               of substance should redefine this to do the right
00305 //               thing.
00306 ////////////////////////////////////////////////////////////////////
00307 BoundingVolume *CollisionNode::
00308 recompute_internal_bound() {
00309   // First, get ourselves a fresh, empty bounding volume.
00310   BoundingVolume *bound = PandaNode::recompute_internal_bound();
00311   nassertr(bound != (BoundingVolume *)NULL, bound);
00312 
00313   // Now actually compute the bounding volume by putting it around all
00314   // of our solids' bounding volumes.
00315   pvector<const BoundingVolume *> child_volumes;
00316 
00317   Solids::const_iterator gi;
00318   for (gi = _solids.begin(); gi != _solids.end(); ++gi) {
00319     child_volumes.push_back(&(*gi)->get_bound());
00320   }
00321 
00322   const BoundingVolume **child_begin = &child_volumes[0];
00323   const BoundingVolume **child_end = child_begin + child_volumes.size();
00324 
00325   bool success =
00326     bound->around(child_begin, child_end);
00327 
00328 #ifdef NOTIFY_DEBUG
00329   if (!success) {
00330     collide_cat.error()
00331       << "Unable to generate bounding volume for " << *this << ":\n"
00332       << "Cannot put " << bound->get_type() << " around:\n";
00333     for (int i = 0; i < (int)child_volumes.size(); i++) {
00334       collide_cat.error(false)
00335         << "  " << *child_volumes[i] << "\n";
00336     }
00337   }
00338 #endif
00339 
00340   return bound;
00341 }
00342 
00343 ////////////////////////////////////////////////////////////////////
00344 //     Function: CollisionNode::get_last_pos_state
00345 //       Access: Protected
00346 //  Description: Returns a RenderState for rendering the ghosted
00347 //               collision solid that represents the previous frame's
00348 //               position, for those collision nodes that indicate a
00349 //               velocity.
00350 ////////////////////////////////////////////////////////////////////
00351 CPT(RenderState) CollisionNode::
00352 get_last_pos_state() {
00353   // Once someone asks for this pointer, we hold its reference count
00354   // and never free it.
00355   static CPT(RenderState) state = (const RenderState *)NULL;
00356   if (state == (const RenderState *)NULL) {
00357     state = RenderState::make
00358       (ColorScaleAttrib::make(LVecBase4f(1.0f, 1.0f, 1.0f, 0.5f)),
00359        TransparencyAttrib::make(TransparencyAttrib::M_alpha));
00360   }
00361 
00362   return state;
00363 }
00364 
00365 
00366 ////////////////////////////////////////////////////////////////////
00367 //     Function: CollisionNode::register_with_read_factory
00368 //       Access: Public, Static
00369 //  Description: Tells the BamReader how to create objects of type
00370 //               CollisionNode.
00371 ////////////////////////////////////////////////////////////////////
00372 void CollisionNode::
00373 register_with_read_factory() {
00374   BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
00375 }
00376 
00377 ////////////////////////////////////////////////////////////////////
00378 //     Function: CollisionNode::write_datagram
00379 //       Access: Public, Virtual
00380 //  Description: Writes the contents of this object to the datagram
00381 //               for shipping out to a Bam file.
00382 ////////////////////////////////////////////////////////////////////
00383 void CollisionNode::
00384 write_datagram(BamWriter *manager, Datagram &dg) {
00385   PandaNode::write_datagram(manager, dg);
00386 
00387   int num_solids = _solids.size();
00388   dg.add_uint16(num_solids);
00389   for(int i = 0; i < num_solids; i++) {
00390     manager->write_pointer(dg, _solids[i]);
00391   }
00392 
00393   dg.add_uint32(_from_collide_mask.get_word());
00394   dg.add_uint32(_into_collide_mask.get_word());
00395   dg.add_uint8(_flags);
00396 }
00397 
00398 ////////////////////////////////////////////////////////////////////
00399 //     Function: CollisionNode::complete_pointers
00400 //       Access: Public, Virtual
00401 //  Description: Receives an array of pointers, one for each time
00402 //               manager->read_pointer() was called in fillin().
00403 //               Returns the number of pointers processed.
00404 ////////////////////////////////////////////////////////////////////
00405 int CollisionNode::
00406 complete_pointers(TypedWritable **p_list, BamReader *manager) {
00407   int pi = PandaNode::complete_pointers(p_list, manager);
00408 
00409   int num_solids = _solids.size();
00410   for (int i = 0; i < num_solids; i++) {
00411     _solids[i] = DCAST(CollisionSolid, p_list[pi++]);
00412   }
00413 
00414   return pi;
00415 }
00416 
00417 ////////////////////////////////////////////////////////////////////
00418 //     Function: CollisionNode::make_from_bam
00419 //       Access: Protected, Static
00420 //  Description: This function is called by the BamReader's factory
00421 //               when a new object of type CollisionNode is encountered
00422 //               in the Bam file.  It should create the CollisionNode
00423 //               and extract its information from the file.
00424 ////////////////////////////////////////////////////////////////////
00425 TypedWritable *CollisionNode::
00426 make_from_bam(const FactoryParams &params) {
00427   CollisionNode *node = new CollisionNode("");
00428   DatagramIterator scan;
00429   BamReader *manager;
00430 
00431   parse_params(params, scan, manager);
00432   node->fillin(scan, manager);
00433 
00434   return node;
00435 }
00436 
00437 ////////////////////////////////////////////////////////////////////
00438 //     Function: CollisionNode::fillin
00439 //       Access: Protected
00440 //  Description: This internal function is called by make_from_bam to
00441 //               read in all of the relevant data from the BamFile for
00442 //               the new CollisionNode.
00443 ////////////////////////////////////////////////////////////////////
00444 void CollisionNode::
00445 fillin(DatagramIterator &scan, BamReader *manager) {
00446   PandaNode::fillin(scan, manager);
00447 
00448   int num_solids = scan.get_uint16();
00449   _solids.clear();
00450   _solids.reserve(num_solids);
00451   for(int i = 0; i < num_solids; i++) {
00452     manager->read_pointer(scan);
00453     // Push back a NULL for each solid, for now.  We'll fill them in
00454     // later.
00455     _solids.push_back((CollisionSolid *)NULL);
00456   }
00457 
00458   _from_collide_mask.set_word(scan.get_uint32());
00459   _into_collide_mask.set_word(scan.get_uint32());
00460   _flags = scan.get_uint8();
00461 }

Generated on Fri May 2 00:35:36 2003 for Panda by doxygen1.3