Panda3D
|
00001 // Filename: lodNode.cxx 00002 // Created by: drose (06Mar02) 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 "lodNode.h" 00016 #include "fadeLodNode.h" 00017 #include "cullTraverserData.h" 00018 #include "cullTraverser.h" 00019 #include "config_pgraphnodes.h" 00020 #include "geomVertexData.h" 00021 #include "geomVertexWriter.h" 00022 #include "geomVertexFormat.h" 00023 #include "geomTristrips.h" 00024 #include "mathNumbers.h" 00025 #include "geom.h" 00026 #include "geomNode.h" 00027 #include "transformState.h" 00028 #include "material.h" 00029 #include "materialAttrib.h" 00030 #include "materialPool.h" 00031 #include "renderState.h" 00032 #include "cullFaceAttrib.h" 00033 #include "textureAttrib.h" 00034 #include "boundingSphere.h" 00035 #include "geometricBoundingVolume.h" 00036 #include "look_at.h" 00037 #include "nodePath.h" 00038 #include "shaderAttrib.h" 00039 #include "colorAttrib.h" 00040 #include "clipPlaneAttrib.h" 00041 00042 TypeHandle LODNode::_type_handle; 00043 00044 //////////////////////////////////////////////////////////////////// 00045 // Function: LODNode::make_default_lod 00046 // Access: Published, Static 00047 // Description: Creates a new LODNode of the type specified by the 00048 // default-lod-type config variable. 00049 //////////////////////////////////////////////////////////////////// 00050 PT(LODNode) LODNode:: 00051 make_default_lod(const string &name) { 00052 switch (default_lod_type.get_value()) { 00053 case LNT_pop: 00054 return new LODNode(name); 00055 00056 case LNT_fade: 00057 return new FadeLODNode(name); 00058 00059 default: 00060 pgraph_cat.error() 00061 << "Invalid LODNodeType value: " << (int)default_lod_type << "\n"; 00062 return new LODNode(name); 00063 } 00064 } 00065 00066 //////////////////////////////////////////////////////////////////// 00067 // Function: LODNode::make_copy 00068 // Access: Public, Virtual 00069 // Description: Returns a newly-allocated Node that is a shallow copy 00070 // of this one. It will be a different Node pointer, 00071 // but its internal data may or may not be shared with 00072 // that of the original Node. 00073 //////////////////////////////////////////////////////////////////// 00074 PandaNode *LODNode:: 00075 make_copy() const { 00076 return new LODNode(*this); 00077 } 00078 00079 //////////////////////////////////////////////////////////////////// 00080 // Function: LODNode::safe_to_combine 00081 // Access: Public, Virtual 00082 // Description: Returns true if it is generally safe to combine this 00083 // particular kind of PandaNode with other kinds of 00084 // PandaNodes of compatible type, adding children or 00085 // whatever. For instance, an LODNode should not be 00086 // combined with any other PandaNode, because its set of 00087 // children is meaningful. 00088 //////////////////////////////////////////////////////////////////// 00089 bool LODNode:: 00090 safe_to_combine() const { 00091 return false; 00092 } 00093 00094 //////////////////////////////////////////////////////////////////// 00095 // Function: LODNode::safe_to_combine_children 00096 // Access: Public, Virtual 00097 // Description: Returns true if it is generally safe to combine the 00098 // children of this PandaNode with each other. For 00099 // instance, an LODNode's children should not be 00100 // combined with each other, because the set of children 00101 // is meaningful. 00102 //////////////////////////////////////////////////////////////////// 00103 bool LODNode:: 00104 safe_to_combine_children() const { 00105 return false; 00106 } 00107 00108 //////////////////////////////////////////////////////////////////// 00109 // Function: LODNode::xform 00110 // Access: Public, Virtual 00111 // Description: Transforms the contents of this PandaNode by the 00112 // indicated matrix, if it means anything to do so. For 00113 // most kinds of PandaNodes, this does nothing. 00114 //////////////////////////////////////////////////////////////////// 00115 void LODNode:: 00116 xform(const LMatrix4 &mat) { 00117 CDWriter cdata(_cycler); 00118 00119 cdata->_center = cdata->_center * mat; 00120 00121 // We'll take just the length of the y axis as the matrix's scale. 00122 LVector3 y; 00123 mat.get_row3(y, 1); 00124 PN_stdfloat factor = y.length(); 00125 00126 SwitchVector::iterator si; 00127 for (si = cdata->_switch_vector.begin(); 00128 si != cdata->_switch_vector.end(); 00129 ++si) { 00130 (*si).rescale(factor); 00131 } 00132 } 00133 00134 //////////////////////////////////////////////////////////////////// 00135 // Function: LODNode::cull_callback 00136 // Access: Public, Virtual 00137 // Description: This function will be called during the cull 00138 // traversal to perform any additional operations that 00139 // should be performed at cull time. This may include 00140 // additional manipulation of render state or additional 00141 // visible/invisible decisions, or any other arbitrary 00142 // operation. 00143 // 00144 // Note that this function will *not* be called unless 00145 // set_cull_callback() is called in the constructor of 00146 // the derived class. It is necessary to call 00147 // set_cull_callback() to indicated that we require 00148 // cull_callback() to be called. 00149 // 00150 // By the time this function is called, the node has 00151 // already passed the bounding-volume test for the 00152 // viewing frustum, and the node's transform and state 00153 // have already been applied to the indicated 00154 // CullTraverserData object. 00155 // 00156 // The return value is true if this node should be 00157 // visible, or false if it should be culled. 00158 //////////////////////////////////////////////////////////////////// 00159 bool LODNode:: 00160 cull_callback(CullTraverser *trav, CullTraverserData &data) { 00161 if (is_any_shown()) { 00162 return show_switches_cull_callback(trav, data); 00163 } 00164 00165 consider_verify_lods(trav, data); 00166 00167 CDReader cdata(_cycler); 00168 00169 CPT(TransformState) rel_transform = get_rel_transform(trav, data); 00170 LPoint3 center = cdata->_center * rel_transform->get_mat(); 00171 PN_stdfloat dist2 = center.dot(center); 00172 00173 int num_children = min(get_num_children(), (int)cdata->_switch_vector.size()); 00174 for (int index = 0; index < num_children; ++index) { 00175 const Switch &sw = cdata->_switch_vector[index]; 00176 bool in_range; 00177 if (cdata->_got_force_switch) { 00178 in_range = (cdata->_force_switch == index); 00179 } else { 00180 in_range = sw.in_range_2(dist2*cdata->_lod_scale); 00181 } 00182 00183 if (in_range) { 00184 // This switch level is in range. Draw its children. 00185 PandaNode *child = get_child(index); 00186 if (child != (PandaNode *)NULL) { 00187 CullTraverserData next_data(data, child); 00188 trav->traverse(next_data); 00189 } 00190 } 00191 } 00192 00193 // Now return false indicating that we have already taken care of 00194 // the traversal from here. 00195 return false; 00196 } 00197 00198 //////////////////////////////////////////////////////////////////// 00199 // Function: LODNode::output 00200 // Access: Public, Virtual 00201 // Description: 00202 //////////////////////////////////////////////////////////////////// 00203 void LODNode:: 00204 output(ostream &out) const { 00205 PandaNode::output(out); 00206 CDReader cdata(_cycler); 00207 out << " center(" << cdata->_center << ") "; 00208 if (cdata->_switch_vector.empty()) { 00209 out << "no switches."; 00210 } else { 00211 SwitchVector::const_iterator si; 00212 si = cdata->_switch_vector.begin(); 00213 out << "(" << (*si).get_in() << "/" << (*si).get_out() << ")"; 00214 ++si; 00215 while (si != cdata->_switch_vector.end()) { 00216 out << " (" << (*si).get_in() << "/" << (*si).get_out() << ")"; 00217 ++si; 00218 } 00219 } 00220 } 00221 00222 //////////////////////////////////////////////////////////////////// 00223 // Function: LODNode::is_lod_node 00224 // Access: Published, Virtual 00225 // Description: A simple downcast check. Returns true if this kind 00226 // of node happens to inherit from LODNode, false 00227 // otherwise. 00228 // 00229 // This is provided as a a faster alternative to calling 00230 // is_of_type(LODNode::get_class_type()). 00231 //////////////////////////////////////////////////////////////////// 00232 bool LODNode:: 00233 is_lod_node() const { 00234 return true; 00235 } 00236 00237 //////////////////////////////////////////////////////////////////// 00238 // Function: LODNode::show_switch 00239 // Access: Published 00240 // Description: This is provided as a debugging aid. show_switch() 00241 // will put the LODNode into a special mode where rather 00242 // than computing and drawing the appropriate level of 00243 // the LOD, a ring is drawn around the LODNode center 00244 // indicating the switch distances from the camera for 00245 // the indicated level, and the geometry of the 00246 // indicated level is drawn in wireframe. 00247 // 00248 // Multiple different levels can be visualized this way 00249 // at once. Call hide_switch() or hide_all_switches() to 00250 // undo this mode and restore the LODNode to its normal 00251 // behavior. 00252 //////////////////////////////////////////////////////////////////// 00253 void LODNode:: 00254 show_switch(int index) { 00255 CDWriter cdata(_cycler); 00256 do_show_switch(cdata, index, get_default_show_color(index)); 00257 mark_internal_bounds_stale(); 00258 } 00259 00260 //////////////////////////////////////////////////////////////////// 00261 // Function: LODNode::show_switch 00262 // Access: Published 00263 // Description: This is provided as a debugging aid. show_switch() 00264 // will put the LODNode into a special mode where rather 00265 // than computing and drawing the appropriate level of 00266 // the LOD, a ring is drawn around the LODNode center 00267 // indicating the switch distances from the camera for 00268 // the indicated level, and the geometry of the 00269 // indicated level is drawn in wireframe. 00270 // 00271 // Multiple different levels can be visualized this way 00272 // at once. Call hide_switch() or hide_all_switches() to 00273 // undo this mode and restore the LODNode to its normal 00274 // behavior. 00275 //////////////////////////////////////////////////////////////////// 00276 void LODNode:: 00277 show_switch(int index, const LColor &color) { 00278 CDWriter cdata(_cycler); 00279 do_show_switch(cdata, index, color); 00280 mark_internal_bounds_stale(); 00281 } 00282 00283 //////////////////////////////////////////////////////////////////// 00284 // Function: LODNode::hide_switch 00285 // Access: Published 00286 // Description: Disables a previous call to show_switch(). 00287 //////////////////////////////////////////////////////////////////// 00288 void LODNode:: 00289 hide_switch(int index) { 00290 CDWriter cdata(_cycler); 00291 do_hide_switch(cdata, index); 00292 mark_internal_bounds_stale(); 00293 } 00294 00295 //////////////////////////////////////////////////////////////////// 00296 // Function: LODNode::show_all_switches 00297 // Access: Published 00298 // Description: Shows all levels in their default colors. 00299 //////////////////////////////////////////////////////////////////// 00300 void LODNode:: 00301 show_all_switches() { 00302 CDWriter cdata(_cycler); 00303 for (int i = 0; i < (int)cdata->_switch_vector.size(); ++i) { 00304 do_show_switch(cdata, i, get_default_show_color(i)); 00305 } 00306 mark_internal_bounds_stale(); 00307 } 00308 00309 //////////////////////////////////////////////////////////////////// 00310 // Function: LODNode::hide_all_switches 00311 // Access: Published 00312 // Description: Hides all levels, restoring the LODNode to normal 00313 // operation. 00314 //////////////////////////////////////////////////////////////////// 00315 void LODNode:: 00316 hide_all_switches() { 00317 CDWriter cdata(_cycler); 00318 for (int i = 0; i < (int)cdata->_switch_vector.size(); ++i) { 00319 do_hide_switch(cdata, i); 00320 } 00321 mark_internal_bounds_stale(); 00322 } 00323 00324 //////////////////////////////////////////////////////////////////// 00325 // Function: LODNode::verify_child_bounds 00326 // Access: Published 00327 // Description: Returns true if the bounding volumes for the geometry 00328 // of each fhild node entirely fits within the 00329 // switch_in radius for that child, or false otherwise. 00330 // It is almost always a mistake for the geometry of an 00331 // LOD level to be larger than its switch_in radius. 00332 //////////////////////////////////////////////////////////////////// 00333 bool LODNode:: 00334 verify_child_bounds() const { 00335 bool okflag = true; 00336 CDReader cdata(_cycler); 00337 00338 for (int index = 0; index < (int)cdata->_switch_vector.size(); ++index) { 00339 PN_stdfloat suggested_radius; 00340 if (!do_verify_child_bounds(cdata, index, suggested_radius)) { 00341 const Switch &sw = cdata->_switch_vector[index]; 00342 pgraph_cat.warning() 00343 << "Level " << index << " geometry of " << *this 00344 << " is larger than its switch radius; suggest radius of " 00345 << suggested_radius << " instead of " << sw.get_in() << "\n"; 00346 okflag = false; 00347 } 00348 } 00349 00350 return okflag; 00351 } 00352 00353 //////////////////////////////////////////////////////////////////// 00354 // Function: LODNode::compute_child 00355 // Access: Protected 00356 // Description: Determines which child should be visible according to 00357 // the current camera position. If a child is visible, 00358 // returns its index number; otherwise, returns -1. 00359 //////////////////////////////////////////////////////////////////// 00360 int LODNode:: 00361 compute_child(CullTraverser *trav, CullTraverserData &data) { 00362 if (data.get_net_transform(trav)->is_singular()) { 00363 // If we're under a singular transform, we can't compute the LOD; 00364 // select none of them instead. 00365 return -1; 00366 } 00367 00368 CDReader cdata(_cycler); 00369 00370 if (cdata->_got_force_switch) { 00371 return cdata->_force_switch; 00372 } 00373 00374 CPT(TransformState) rel_transform = get_rel_transform(trav, data); 00375 LPoint3 center = cdata->_center * rel_transform->get_mat(); 00376 PN_stdfloat dist2 = center.dot(center); 00377 00378 for (int index = 0; index < (int)cdata->_switch_vector.size(); ++index) { 00379 if (cdata->_switch_vector[index].in_range_2(dist2*cdata->_lod_scale)) { 00380 if (pgraph_cat.is_debug()) { 00381 pgraph_cat.debug() 00382 << data._node_path << " at distance " << sqrt(dist2) 00383 << ", selected child " << index << "\n"; 00384 } 00385 00386 return index; 00387 } 00388 } 00389 00390 if (pgraph_cat.is_debug()) { 00391 pgraph_cat.debug() 00392 << data._node_path << " at distance " << sqrt(dist2) 00393 << ", no children in range.\n"; 00394 } 00395 00396 return -1; 00397 } 00398 00399 00400 //////////////////////////////////////////////////////////////////// 00401 // Function: LODNode::show_switches_cull_callback 00402 // Access: Protected 00403 // Description: A special version of cull_callback() that is to be 00404 // invoked when the LODNode is in show_switch() mode. 00405 // This just draws the rings and the wireframe geometry 00406 // for the selected switches. 00407 //////////////////////////////////////////////////////////////////// 00408 bool LODNode:: 00409 show_switches_cull_callback(CullTraverser *trav, CullTraverserData &data) { 00410 CDReader cdata(_cycler); 00411 00412 CPT(TransformState) rel_transform = get_rel_transform(trav, data); 00413 LPoint3 center = cdata->_center * rel_transform->get_mat(); 00414 PN_stdfloat dist2 = center.dot(center); 00415 00416 // Now orient the disk(s) in camera space such that their origin is 00417 // at center, and the (0, 0, 0) point in camera space is on the disk. 00418 LMatrix4 mat; 00419 look_at(mat, -center, LVector3(0.0f, 0.0f, 1.0f)); 00420 mat.set_row(3, center); 00421 CPT(TransformState) viz_transform = 00422 rel_transform->invert_compose(TransformState::make_mat(mat)); 00423 00424 for (int index = 0; index < (int)cdata->_switch_vector.size(); ++index) { 00425 const Switch &sw = cdata->_switch_vector[index]; 00426 if (sw.is_shown()) { 00427 bool in_range; 00428 if (cdata->_got_force_switch) { 00429 in_range = (cdata->_force_switch == index); 00430 } else { 00431 in_range = sw.in_range_2(dist2); 00432 } 00433 00434 if (in_range) { 00435 // This switch level is in range. Draw its children in the 00436 // funny wireframe mode. 00437 if (index < get_num_children()) { 00438 PandaNode *child = get_child(index); 00439 if (child != (PandaNode *)NULL) { 00440 CullTraverserData next_data3(data, child); 00441 next_data3._state = next_data3._state->compose(sw.get_viz_model_state()); 00442 trav->traverse(next_data3); 00443 } 00444 } 00445 00446 // And draw the spindle in this color. 00447 CullTraverserData next_data2(data, sw.get_spindle_viz()); 00448 next_data2.apply_transform_and_state(trav, viz_transform, 00449 RenderState::make_empty(), 00450 RenderEffects::make_empty(), 00451 ClipPlaneAttrib::make()); 00452 trav->traverse(next_data2); 00453 } 00454 00455 // Draw the rings for this switch level. We do this after we 00456 // have drawn the geometry and the spindle. 00457 CullTraverserData next_data(data, sw.get_ring_viz()); 00458 next_data.apply_transform_and_state(trav, viz_transform, 00459 RenderState::make_empty(), 00460 RenderEffects::make_empty(), 00461 ClipPlaneAttrib::make()); 00462 trav->traverse(next_data); 00463 } 00464 } 00465 00466 // Now return false indicating that we have already taken care of 00467 // the traversal from here. 00468 return false; 00469 } 00470 00471 //////////////////////////////////////////////////////////////////// 00472 // Function: LODNode::compute_internal_bounds 00473 // Access: Protected, Virtual 00474 // Description: Returns a newly-allocated BoundingVolume that 00475 // represents the internal contents of the node. Should 00476 // be overridden by PandaNode classes that contain 00477 // something internally. 00478 //////////////////////////////////////////////////////////////////// 00479 void LODNode:: 00480 compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, 00481 int &internal_vertices, 00482 int pipeline_stage, 00483 Thread *current_thread) const { 00484 // First, get ourselves a fresh, empty bounding volume. 00485 PT(BoundingVolume) bound = new BoundingSphere; 00486 00487 // If we have any visible rings, those count in the bounding volume. 00488 if (is_any_shown()) { 00489 // Now actually compute the bounding volume by putting it around all 00490 // of our geoms' bounding volumes. 00491 pvector<const BoundingVolume *> child_volumes; 00492 pvector<PT(BoundingVolume) > pt_volumes; 00493 00494 CDStageReader cdata(_cycler, pipeline_stage, current_thread); 00495 00496 SwitchVector::const_iterator si; 00497 for (si = cdata->_switch_vector.begin(); 00498 si != cdata->_switch_vector.end(); 00499 ++si) { 00500 const Switch &sw = (*si); 00501 if (sw.is_shown()) { 00502 PT(BoundingVolume) sphere = new BoundingSphere(cdata->_center, sw.get_in()); 00503 child_volumes.push_back(sphere); 00504 pt_volumes.push_back(sphere); 00505 } 00506 } 00507 00508 const BoundingVolume **child_begin = &child_volumes[0]; 00509 const BoundingVolume **child_end = child_begin + child_volumes.size(); 00510 00511 bound->around(child_begin, child_end); 00512 } 00513 00514 internal_bounds = bound; 00515 internal_vertices = 0; 00516 } 00517 00518 //////////////////////////////////////////////////////////////////// 00519 // Function: LODNode::get_rel_transform 00520 // Access: Protected 00521 // Description: Returns the relative transform to convert from the 00522 // LODNode space to the camera space. 00523 //////////////////////////////////////////////////////////////////// 00524 CPT(TransformState) LODNode:: 00525 get_rel_transform(CullTraverser *trav, CullTraverserData &data) { 00526 // Get a pointer to the camera node. 00527 Camera *camera = trav->get_scene()->get_camera_node(); 00528 00529 // Get the camera space transform. 00530 CPT(TransformState) rel_transform; 00531 00532 NodePath lod_center = camera->get_lod_center(); 00533 if (!lod_center.is_empty()) { 00534 rel_transform = 00535 lod_center.get_net_transform()->invert_compose(data.get_net_transform(trav)); 00536 } else { 00537 NodePath cull_center = camera->get_cull_center(); 00538 if (!cull_center.is_empty()) { 00539 rel_transform = 00540 cull_center.get_net_transform()->invert_compose(data.get_net_transform(trav)); 00541 } else { 00542 rel_transform = data.get_modelview_transform(trav); 00543 } 00544 } 00545 00546 return rel_transform; 00547 } 00548 00549 //////////////////////////////////////////////////////////////////// 00550 // Function: LODNode::do_show_switch 00551 // Access: Private 00552 // Description: The private implementation of show_switch(). 00553 //////////////////////////////////////////////////////////////////// 00554 void LODNode:: 00555 do_show_switch(LODNode::CData *cdata, int index, const LColor &color) { 00556 nassertv(index >= 0 && index < (int)cdata->_switch_vector.size()); 00557 00558 if (!cdata->_switch_vector[index].is_shown()) { 00559 ++cdata->_num_shown; 00560 } 00561 cdata->_switch_vector[index].show(color); 00562 } 00563 00564 //////////////////////////////////////////////////////////////////// 00565 // Function: LODNode::do_hide_switch 00566 // Access: Private 00567 // Description: The private implementation of hide_switch(). 00568 //////////////////////////////////////////////////////////////////// 00569 void LODNode:: 00570 do_hide_switch(LODNode::CData *cdata, int index) { 00571 nassertv(index >= 0 && index < (int)cdata->_switch_vector.size()); 00572 00573 if (cdata->_switch_vector[index].is_shown()) { 00574 --cdata->_num_shown; 00575 } 00576 cdata->_switch_vector[index].hide(); 00577 } 00578 00579 //////////////////////////////////////////////////////////////////// 00580 // Function: LODNode::do_verify_child_bounds 00581 // Access: Private 00582 // Description: The private implementation of verify_child_bounds(), 00583 // this checks the bounding volume of just one child. 00584 // 00585 // If the return value is false, suggested_radius is 00586 // filled with a radius that ought to be large enough to 00587 // include the child. 00588 //////////////////////////////////////////////////////////////////// 00589 bool LODNode:: 00590 do_verify_child_bounds(const LODNode::CData *cdata, int index, 00591 PN_stdfloat &suggested_radius) const { 00592 suggested_radius = 0.0f; 00593 00594 if (index < get_num_children()) { 00595 const Switch &sw = cdata->_switch_vector[index]; 00596 PandaNode *child = get_child(index); 00597 if (child != (PandaNode *)NULL) { 00598 UpdateSeq seq; 00599 CPT(BoundingVolume) bv = child->get_bounds(seq); 00600 00601 if (seq == sw._bounds_seq) { 00602 // We previously verified this child, and it hasn't changed 00603 // since then. 00604 return sw._verify_ok; 00605 } 00606 00607 ((Switch &)sw)._bounds_seq = seq; 00608 ((Switch &)sw)._verify_ok = true; 00609 00610 if (bv->is_empty()) { 00611 // This child has no geometry, so no one cares anyway. 00612 return true; 00613 } 00614 if (bv->is_infinite()) { 00615 // To be strict, we ought to look closer if the child has an 00616 // infinite bounding volume, but in practice this is probably 00617 // just a special case (e.g. the child contains the camera) 00618 // that we don't really want to check. 00619 return true; 00620 } 00621 00622 const Switch &sw = cdata->_switch_vector[index]; 00623 00624 const GeometricBoundingVolume *gbv; 00625 DCAST_INTO_R(gbv, bv, false); 00626 BoundingSphere sphere(cdata->_center, sw.get_in()); 00627 sphere.local_object(); 00628 00629 int flags = sphere.contains(gbv); 00630 if ((flags & BoundingVolume::IF_all) != 0) { 00631 // This child's radius completely encloses its bounding volume. 00632 // Perfect. (And this is the most common case.) 00633 return true; 00634 } 00635 00636 if (flags == 0) { 00637 // This child's radius doesn't even come close to containing 00638 // its volume. 00639 nassertr(!gbv->is_infinite(), false); 00640 sphere.extend_by(gbv); 00641 suggested_radius = sphere.get_radius(); 00642 ((Switch &)sw)._verify_ok = false; 00643 return false; 00644 } 00645 00646 // This child's radius partially encloses its (loose) bounding 00647 // volume. We have to look closer to determine whether it, in 00648 // fact, fully encloses its geometry. 00649 LPoint3 min_point(0.0f, 0.0f, 0.0f); 00650 LPoint3 max_point(0.0f, 0.0f, 0.0f); 00651 00652 bool found_any = false; 00653 child->calc_tight_bounds(min_point, max_point, found_any, 00654 TransformState::make_identity(), 00655 Thread::get_current_thread()); 00656 if (!found_any) { 00657 // Hmm, the child has no geometry after all. 00658 return true; 00659 } 00660 00661 // Now we have a bounding box. Define the largest sphere we can 00662 // that fits within this box. All we can say about this sphere 00663 // is that it should definitely fit entirely within a bounding 00664 // sphere that contains all the points of the child. 00665 LPoint3 box_center = (min_point + max_point) / 2.0f; 00666 PN_stdfloat box_radius = min(min(max_point[0] - box_center[0], 00667 max_point[1] - box_center[1]), 00668 max_point[2] - box_center[2]); 00669 00670 BoundingSphere box_sphere(box_center, box_radius); 00671 box_sphere.local_object(); 00672 00673 // So if any part of this inscribed sphere is outside of the 00674 // radius, then the radius is bad. 00675 flags = sphere.contains(&box_sphere); 00676 if ((flags & BoundingVolume::IF_all) == 0) { 00677 // No good. 00678 if (gbv->is_infinite()) { 00679 sphere.extend_by(&box_sphere); 00680 } else { 00681 sphere.extend_by(gbv); 00682 } 00683 suggested_radius = sphere.get_radius(); 00684 ((Switch &)sw)._verify_ok = false; 00685 return false; 00686 } 00687 } 00688 } 00689 00690 return true; 00691 } 00692 00693 //////////////////////////////////////////////////////////////////// 00694 // Function: LODNode::do_auto_verify_lods 00695 // Access: Private 00696 // Description: Called internally by consider_verify_lods(). 00697 //////////////////////////////////////////////////////////////////// 00698 void LODNode:: 00699 do_auto_verify_lods(CullTraverser *trav, CullTraverserData &data) { 00700 UpdateSeq seq; 00701 get_bounds(seq); 00702 CDLockedReader cdata(_cycler); 00703 00704 if (cdata->_got_force_switch) { 00705 // If we're forcing a particular switch, don't verify the LOD 00706 // sizes, since they don't really apply anymore anyway. Assume 00707 // the user knows what he's doing. 00708 return; 00709 } 00710 00711 if (seq != cdata->_bounds_seq) { 00712 // Time to validate the children again. 00713 for (int index = 0; index < (int)cdata->_switch_vector.size(); ++index) { 00714 PN_stdfloat suggested_radius; 00715 if (!do_verify_child_bounds(cdata, index, suggested_radius)) { 00716 const Switch &sw = cdata->_switch_vector[index]; 00717 ostringstream strm; 00718 strm 00719 << "Level " << index << " geometry of " << data._node_path 00720 << " is larger than its switch radius; suggest radius of " 00721 << suggested_radius << " instead of " << sw.get_in() 00722 << " (configure verify-lods 0 to ignore this error)"; 00723 nassert_raise(strm.str()); 00724 } 00725 } 00726 CDWriter cdataw(_cycler, cdata); 00727 cdataw->_bounds_seq = seq; 00728 } 00729 } 00730 00731 //////////////////////////////////////////////////////////////////// 00732 // Function: LODNode::get_default_show_color 00733 // Access: Private, Static 00734 // Description: Returns a default color appropriate for showing the 00735 // indicated level. 00736 //////////////////////////////////////////////////////////////////// 00737 const LColor &LODNode:: 00738 get_default_show_color(int index) { 00739 static LColor default_colors[] = { 00740 LColor(1.0f, 0.0f, 0.0f, 0.7f), 00741 LColor(0.0f, 1.0f, 0.0f, 0.7f), 00742 LColor(0.0f, 0.0f, 1.0f, 0.7f), 00743 LColor(0.0f, 1.0f, 1.0f, 0.7f), 00744 LColor(1.0f, 0.0f, 1.0f, 0.7f), 00745 LColor(1.0f, 1.0f, 0.0f, 0.7f), 00746 }; 00747 static const int num_default_colors = sizeof(default_colors) / sizeof(LColor); 00748 00749 return default_colors[index % num_default_colors]; 00750 } 00751 00752 00753 //////////////////////////////////////////////////////////////////// 00754 // Function: LODNode::register_with_read_factory 00755 // Access: Public, Static 00756 // Description: Tells the BamReader how to create objects of type 00757 // LODNode. 00758 //////////////////////////////////////////////////////////////////// 00759 void LODNode:: 00760 register_with_read_factory() { 00761 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); 00762 } 00763 00764 //////////////////////////////////////////////////////////////////// 00765 // Function: LODNode::write_datagram 00766 // Access: Public, Virtual 00767 // Description: Writes the contents of this object to the datagram 00768 // for shipping out to a Bam file. 00769 //////////////////////////////////////////////////////////////////// 00770 void LODNode:: 00771 write_datagram(BamWriter *manager, Datagram &dg) { 00772 PandaNode::write_datagram(manager, dg); 00773 manager->write_cdata(dg, _cycler); 00774 } 00775 00776 //////////////////////////////////////////////////////////////////// 00777 // Function: LODNode::make_from_bam 00778 // Access: Protected, Static 00779 // Description: This function is called by the BamReader's factory 00780 // when a new object of type LODNode is encountered 00781 // in the Bam file. It should create the LODNode 00782 // and extract its information from the file. 00783 //////////////////////////////////////////////////////////////////// 00784 TypedWritable *LODNode:: 00785 make_from_bam(const FactoryParams ¶ms) { 00786 LODNode *node = new LODNode(""); 00787 00788 DatagramIterator scan; 00789 BamReader *manager; 00790 00791 parse_params(params, scan, manager); 00792 node->fillin(scan, manager); 00793 00794 return node; 00795 } 00796 00797 //////////////////////////////////////////////////////////////////// 00798 // Function: LODNode::fillin 00799 // Access: Protected 00800 // Description: This internal function is called by make_from_bam to 00801 // read in all of the relevant data from the BamFile for 00802 // the new LODNode. 00803 //////////////////////////////////////////////////////////////////// 00804 void LODNode:: 00805 fillin(DatagramIterator &scan, BamReader *manager) { 00806 PandaNode::fillin(scan, manager); 00807 manager->read_cdata(scan, _cycler); 00808 } 00809 00810 //////////////////////////////////////////////////////////////////// 00811 // Function: LODNode::CData::make_copy 00812 // Access: Public, Virtual 00813 // Description: 00814 //////////////////////////////////////////////////////////////////// 00815 CycleData *LODNode::CData:: 00816 make_copy() const { 00817 return new CData(*this); 00818 } 00819 00820 //////////////////////////////////////////////////////////////////// 00821 // Function: LODNode::CData::check_limits 00822 // Access: Public 00823 // Description: Ensures that the _lowest and _highest members are set 00824 // appropriately after a change to the set of switches. 00825 //////////////////////////////////////////////////////////////////// 00826 void LODNode::CData:: 00827 check_limits() { 00828 _lowest = 0; 00829 _highest = 0; 00830 for (size_t i = 1; i < _switch_vector.size(); ++i) { 00831 if (_switch_vector[i].get_out() > _switch_vector[_lowest].get_out()) { 00832 _lowest = i; 00833 } 00834 if (_switch_vector[i].get_in() < _switch_vector[_highest].get_in()) { 00835 _highest = i; 00836 } 00837 } 00838 } 00839 00840 //////////////////////////////////////////////////////////////////// 00841 // Function: LODNode::CData::write_datagram 00842 // Access: Public, Virtual 00843 // Description: Writes the contents of this object to the datagram 00844 // for shipping out to a Bam file. 00845 //////////////////////////////////////////////////////////////////// 00846 void LODNode::CData:: 00847 write_datagram(BamWriter *manager, Datagram &dg) const { 00848 _center.write_datagram(dg); 00849 00850 dg.add_uint16(_switch_vector.size()); 00851 00852 SwitchVector::const_iterator si; 00853 for (si = _switch_vector.begin(); 00854 si != _switch_vector.end(); 00855 ++si) { 00856 (*si).write_datagram(dg); 00857 } 00858 } 00859 00860 //////////////////////////////////////////////////////////////////// 00861 // Function: LODNode::CData::fillin 00862 // Access: Public, Virtual 00863 // Description: This internal function is called by make_from_bam to 00864 // read in all of the relevant data from the BamFile for 00865 // the new LODNode. 00866 //////////////////////////////////////////////////////////////////// 00867 void LODNode::CData:: 00868 fillin(DatagramIterator &scan, BamReader *manager) { 00869 _center.read_datagram(scan); 00870 00871 _switch_vector.clear(); 00872 00873 int num_switches = scan.get_uint16(); 00874 _switch_vector.reserve(num_switches); 00875 for (int i = 0; i < num_switches; i++) { 00876 Switch sw(0, 0); 00877 sw.read_datagram(scan); 00878 00879 _switch_vector.push_back(sw); 00880 } 00881 _lod_scale = 1; 00882 } 00883 00884 //////////////////////////////////////////////////////////////////// 00885 // Function: LODNode::Switch::compute_ring_viz 00886 // Access: Private 00887 // Description: Computes a Geom suitable for rendering the ring 00888 // associated with this switch. 00889 //////////////////////////////////////////////////////////////////// 00890 void LODNode::Switch:: 00891 compute_ring_viz() { 00892 // We render the ring as a series of concentric ring-shaped triangle 00893 // strips, each of which has num_slices quads. 00894 static const int num_slices = 50; 00895 static const int num_rings = 1; 00896 00897 // There are also two more triangle strips, one for the outer edge, 00898 // and one for the inner edge. 00899 static const PN_stdfloat edge_ratio = 0.1; // ratio of edge height to diameter. 00900 00901 const GeomVertexFormat *format = GeomVertexFormat::get_v3n3cp(); 00902 PT(GeomVertexData) vdata = new GeomVertexData("LOD_ring", format, Geom::UH_static); 00903 00904 // Fill up the vertex table with all of the vertices. 00905 GeomVertexWriter vertex(vdata, InternalName::get_vertex()); 00906 GeomVertexWriter normal(vdata, InternalName::get_normal()); 00907 GeomVertexWriter color(vdata, InternalName::get_color()); 00908 00909 // First, the vertices for the flat ring. 00910 int ri, si; 00911 for (ri = 0; ri <= num_rings; ++ri) { 00912 // r is in the range [0.0, 1.0]. 00913 PN_stdfloat r = (PN_stdfloat)ri / (PN_stdfloat)num_rings; 00914 00915 // d is in the range [_out, _in]. 00916 PN_stdfloat d = r * (_in - _out) + _out; 00917 00918 for (si = 0; si < num_slices; ++si) { 00919 // s is in the range [0.0, 1.0). 00920 PN_stdfloat s = (PN_stdfloat)si / (PN_stdfloat)num_slices; 00921 00922 // t is in the range [0.0, 2pi). 00923 PN_stdfloat t = MathNumbers::pi * 2.0f * s; 00924 00925 PN_stdfloat x = ccos(t); 00926 PN_stdfloat y = csin(t); 00927 vertex.add_data3(x * d, y * d, 0.0f); 00928 normal.add_data3(0.0f, 0.0f, 1.0f); 00929 color.add_data4(_show_color); 00930 } 00931 } 00932 00933 // Next, the vertices for the inner and outer edges. 00934 for (ri = 0; ri <= 1; ++ri) { 00935 PN_stdfloat r = (PN_stdfloat)ri; 00936 PN_stdfloat d = r * (_in - _out) + _out; 00937 00938 for (si = 0; si < num_slices; ++si) { 00939 PN_stdfloat s = (PN_stdfloat)si / (PN_stdfloat)num_slices; 00940 PN_stdfloat t = MathNumbers::pi * 2.0f * s; 00941 00942 PN_stdfloat x = ccos(t); 00943 PN_stdfloat y = csin(t); 00944 00945 vertex.add_data3(x * d, y * d, 0.5f * edge_ratio * d); 00946 normal.add_data3(x, y, 0.0f); 00947 color.add_data4(_show_color); 00948 } 00949 00950 for (si = 0; si < num_slices; ++si) { 00951 PN_stdfloat s = (PN_stdfloat)si / (PN_stdfloat)num_slices; 00952 PN_stdfloat t = MathNumbers::pi * 2.0f * s; 00953 00954 PN_stdfloat x = ccos(t); 00955 PN_stdfloat y = csin(t); 00956 00957 vertex.add_data3(x * d, y * d, -0.5f * edge_ratio * d); 00958 normal.add_data3(x, y, 0.0f); 00959 color.add_data4(_show_color); 00960 } 00961 } 00962 00963 // Now create the triangle strips. One tristrip for each ring. 00964 PT(GeomTristrips) strips = new GeomTristrips(Geom::UH_static); 00965 for (ri = 0; ri < num_rings; ++ri) { 00966 for (si = 0; si < num_slices; ++si) { 00967 strips->add_vertex(ri * num_slices + si); 00968 strips->add_vertex((ri + 1) * num_slices + si); 00969 } 00970 strips->add_vertex(ri * num_slices); 00971 strips->add_vertex((ri + 1) * num_slices); 00972 strips->close_primitive(); 00973 } 00974 00975 // And then one triangle strip for each of the inner and outer 00976 // edges. 00977 for (ri = 0; ri <= 1; ++ri) { 00978 for (si = 0; si < num_slices; ++si) { 00979 strips->add_vertex((num_rings + 1 + ri * 2) * num_slices + si); 00980 strips->add_vertex((num_rings + 1 + ri * 2 + 1) * num_slices + si); 00981 } 00982 strips->add_vertex((num_rings + 1 + ri * 2) * num_slices); 00983 strips->add_vertex((num_rings + 1 + ri * 2 + 1) * num_slices); 00984 strips->close_primitive(); 00985 } 00986 00987 PT(Geom) ring_geom = new Geom(vdata); 00988 ring_geom->add_primitive(strips); 00989 00990 PT(GeomNode) geom_node = new GeomNode("ring"); 00991 geom_node->add_geom(ring_geom); 00992 00993 // Get a material for two-sided lighting. 00994 PT(Material) material = new Material(); 00995 material->set_twoside(true); 00996 material = MaterialPool::get_material(material); 00997 00998 CPT(RenderState) viz_state = 00999 RenderState::make(CullFaceAttrib::make(CullFaceAttrib::M_cull_none), 01000 TextureAttrib::make_off(), 01001 ShaderAttrib::make_off(), 01002 MaterialAttrib::make(material), 01003 RenderState::get_max_priority()); 01004 if (_show_color[3] != 1.0f) { 01005 viz_state = viz_state->add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha), 01006 RenderState::get_max_priority()); 01007 } 01008 01009 geom_node->set_state(viz_state); 01010 01011 _ring_viz = geom_node.p(); 01012 } 01013 01014 //////////////////////////////////////////////////////////////////// 01015 // Function: LODNode::Switch::compute_spindle_viz 01016 // Access: Private 01017 // Description: Computes a Geom suitable for rendering the LODNode 01018 // spindle in the color of this switch. 01019 //////////////////////////////////////////////////////////////////// 01020 void LODNode::Switch:: 01021 compute_spindle_viz() { 01022 // We render the spindle as a cylinder, which consists of num_rings 01023 // rings stacked vertically, each of which is a triangle strip of 01024 // num_slices quads. The scale is -10 .. 10 vertically, with a radius 01025 // of 1.0. 01026 static const int num_slices = 10; 01027 static const int num_rings = 10; 01028 01029 const GeomVertexFormat *format = GeomVertexFormat::get_v3n3cp(); 01030 PT(GeomVertexData) vdata = new GeomVertexData("LOD_spindle", format, Geom::UH_static); 01031 01032 // Fill up the vertex table with all of the vertices. 01033 GeomVertexWriter vertex(vdata, InternalName::get_vertex()); 01034 GeomVertexWriter normal(vdata, InternalName::get_normal()); 01035 GeomVertexWriter color(vdata, InternalName::get_color()); 01036 01037 int ri, si; 01038 for (ri = 0; ri <= num_rings; ++ri) { 01039 // r is in the range [0.0, 1.0]. 01040 PN_stdfloat r = (PN_stdfloat)ri / (PN_stdfloat)num_rings; 01041 01042 // z is in the range [100.0, -100.0] 01043 PN_stdfloat z = 100.0f - r * 200.0f; 01044 01045 for (si = 0; si < num_slices; ++si) { 01046 // s is in the range [0.0, 1.0). 01047 PN_stdfloat s = (PN_stdfloat)si / (PN_stdfloat)num_slices; 01048 01049 // t is in the range [0.0, 2pi). 01050 PN_stdfloat t = MathNumbers::pi * 2.0f * s; 01051 01052 PN_stdfloat x = ccos(t); 01053 PN_stdfloat y = csin(t); 01054 vertex.add_data3(x, y, z); 01055 normal.add_data3(x, y, 0.0f); 01056 color.add_data4(_show_color); 01057 } 01058 } 01059 01060 // Now create the triangle strips. One tristrip for each ring. 01061 PT(GeomTristrips) strips = new GeomTristrips(Geom::UH_static); 01062 for (ri = 0; ri < num_rings; ++ri) { 01063 for (si = 0; si < num_slices; ++si) { 01064 strips->add_vertex(ri * num_slices + si); 01065 strips->add_vertex((ri + 1) * num_slices + si); 01066 } 01067 strips->add_vertex(ri * num_slices); 01068 strips->add_vertex((ri + 1) * num_slices); 01069 strips->close_primitive(); 01070 } 01071 01072 PT(Geom) spindle_geom = new Geom(vdata); 01073 spindle_geom->add_primitive(strips); 01074 01075 PT(GeomNode) geom_node = new GeomNode("spindle"); 01076 geom_node->add_geom(spindle_geom); 01077 01078 CPT(RenderState) viz_state = 01079 RenderState::make(CullFaceAttrib::make(CullFaceAttrib::M_cull_clockwise), 01080 TextureAttrib::make_off(), 01081 ShaderAttrib::make_off(), 01082 RenderState::get_max_priority()); 01083 if (_show_color[3] != 1.0f) { 01084 viz_state = viz_state->add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha), 01085 RenderState::get_max_priority()); 01086 } 01087 01088 geom_node->set_state(viz_state); 01089 01090 _spindle_viz = geom_node.p(); 01091 } 01092 01093 //////////////////////////////////////////////////////////////////// 01094 // Function: LODNode::Switch::compute_viz_model_state 01095 // Access: Private 01096 // Description: Computes a RenderState for rendering the children of 01097 // this switch in colored wireframe mode. 01098 //////////////////////////////////////////////////////////////////// 01099 void LODNode::Switch:: 01100 compute_viz_model_state() { 01101 // The RenderState::make() function only takes up to four attribs at 01102 // once. Since we need more attribs than that, we have to make up 01103 // our state in two steps. 01104 _viz_model_state = RenderState::make(RenderModeAttrib::make(RenderModeAttrib::M_wireframe), 01105 TextureAttrib::make_off(), 01106 ShaderAttrib::make_off(), 01107 ColorAttrib::make_flat(_show_color), 01108 RenderState::get_max_priority()); 01109 CPT(RenderState) st2 = RenderState::make(TransparencyAttrib::make(TransparencyAttrib::M_none), 01110 RenderState::get_max_priority()); 01111 _viz_model_state = _viz_model_state->compose(st2); 01112 }