Panda3D

lodNode.cxx

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 &params) {
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 }
 All Classes Functions Variables Enumerations