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