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 ©) : 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 ¶ms) { 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 }