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