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