Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/pgraph/cullTraverser.cxx

Go to the documentation of this file.
00001 // Filename: cullTraverser.cxx
00002 // Created by:  drose (23Feb02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "cullTraverser.h"
00020 #include "cullTraverserData.h"
00021 #include "transformState.h"
00022 #include "renderState.h"
00023 #include "fogAttrib.h"
00024 #include "cullHandler.h"
00025 #include "dcast.h"
00026 #include "geomNode.h"
00027 #include "config_pgraph.h"
00028 #include "boundingSphere.h"
00029 #include "geomSphere.h"
00030 #include "colorAttrib.h"
00031 #include "renderModeAttrib.h"
00032 #include "cullFaceAttrib.h"
00033 #include "depthOffsetAttrib.h"
00034 
00035 
00036 TypeHandle CullTraverser::_type_handle;
00037 
00038 ////////////////////////////////////////////////////////////////////
00039 //     Function: CullTraverser::Constructor
00040 //       Access: Public
00041 //  Description: 
00042 ////////////////////////////////////////////////////////////////////
00043 CullTraverser::
00044 CullTraverser() {
00045   _camera_mask = DrawMask::all_on();
00046   _initial_state = RenderState::make_empty();
00047   _depth_offset_decals = false;
00048   _cull_handler = (CullHandler *)NULL;
00049 }
00050 
00051 ////////////////////////////////////////////////////////////////////
00052 //     Function: CullTraverser::Copy Constructor
00053 //       Access: Public
00054 //  Description: 
00055 ////////////////////////////////////////////////////////////////////
00056 CullTraverser::
00057 CullTraverser(const CullTraverser &copy) :
00058   _scene_setup(copy._scene_setup),
00059   _camera_mask(copy._camera_mask),
00060   _initial_state(copy._initial_state),
00061   _depth_offset_decals(copy._depth_offset_decals),
00062   _view_frustum(copy._view_frustum),
00063   _guard_band(copy._guard_band),
00064   _cull_handler(copy._cull_handler)
00065 {
00066 }
00067 
00068 ////////////////////////////////////////////////////////////////////
00069 //     Function: CullTraverser::traverse
00070 //       Access: Public
00071 //  Description: Begins the traversal from the indicated node.
00072 ////////////////////////////////////////////////////////////////////
00073 void CullTraverser::
00074 traverse(const NodePath &root) {
00075   nassertv(_cull_handler != (CullHandler *)NULL);
00076   nassertv(_scene_setup != (SceneSetup *)NULL);
00077 
00078   CullTraverserData data(root, get_render_transform(),
00079                          TransformState::make_identity(),
00080                          _initial_state, _view_frustum, _guard_band);
00081   traverse(data);
00082 }
00083 
00084 ////////////////////////////////////////////////////////////////////
00085 //     Function: CullTraverser::traverse
00086 //       Access: Public
00087 //  Description: Traverses from the next node with the given
00088 //               data, which has been constructed with the node but
00089 //               has not yet been converted into the node's space.
00090 ////////////////////////////////////////////////////////////////////
00091 void CullTraverser::
00092 traverse(CullTraverserData &data) {
00093   // Most nodes will have no transform or state, and will not
00094   // contain decals or require a special cull callback.  As an
00095   // optimization, we should tag nodes with these properties as
00096   // being "fancy", and skip this processing for non-fancy nodes.
00097   if (data.is_in_view(_camera_mask)) {
00098     PandaNode *node = data.node();
00099 
00100     const RenderEffects *node_effects = node->get_effects();
00101     if (node_effects->has_show_bounds()) {
00102       // If we should show the bounding volume for this node, make it
00103       // up now.
00104       show_bounds(data);
00105     }
00106 
00107     data.apply_transform_and_state(this);
00108 
00109     const RenderState *node_state = node->get_state();
00110     const FogAttrib *fog = node_state->get_fog();
00111     if (fog != (const FogAttrib *)NULL && fog->get_fog() != (Fog *)NULL) {
00112       // If we just introduced a FogAttrib here, call adjust_to_camera()
00113       // now.  This maybe isn't the perfect time to call it, but it's
00114       // good enough; and at this time we have all the information we
00115       // need for it.
00116       fog->get_fog()->adjust_to_camera(get_camera_transform());
00117     }
00118 
00119     if (node->has_cull_callback()) {
00120       if (!node->cull_callback(this, data)) {
00121         return;
00122       }
00123     }
00124 
00125     traverse_below(data);
00126   }
00127 }
00128 
00129 ////////////////////////////////////////////////////////////////////
00130 //     Function: CullTraverser::traverse_below
00131 //       Access: Public
00132 //  Description: Traverses all the children of the indicated node,
00133 //               with the given data, which been converted into the
00134 //               node's space.
00135 ////////////////////////////////////////////////////////////////////
00136 void CullTraverser::
00137 traverse_below(CullTraverserData &data) {
00138   PandaNode *node = data.node();
00139   const RenderEffects *node_effects = node->get_effects();
00140   bool has_decal = node_effects->has_decal();
00141   if (has_decal && !_depth_offset_decals) {
00142     // Start the three-pass decal rendering if we're not using
00143     // DepthOffsetAttribs to implement decals.
00144     start_decal(data);
00145     
00146   } else {
00147     if (node->is_geom_node()) {
00148       GeomNode *geom_node = DCAST(GeomNode, node);
00149       
00150       // Get all the Geoms, with no decalling.
00151       int num_geoms = geom_node->get_num_geoms();
00152       for (int i = 0; i < num_geoms; i++) {
00153         CullableObject *object = new CullableObject(data, geom_node, i);
00154         _cull_handler->record_object(object);
00155       }
00156     }
00157 
00158     if (has_decal) {
00159       // If we *are* implementing decals with DepthOffsetAttribs,
00160       // apply it now, so that each child of this node gets offset by
00161       // a tiny amount.
00162       data._state = data._state->compose(get_depth_offset_state());
00163 #ifndef NDEBUG
00164       // This is just a sanity check message.
00165       if (!node->is_geom_node()) {
00166         pgraph_cat.error()
00167           << "DecalEffect applied to " << *node << ", not a GeomNode.\n";
00168       }
00169 #endif
00170     }
00171 
00172     // Now visit all the node's children.  We cannot use the
00173     // node->get_children() interface, because that will keep a read
00174     // pointer open, and we might end up changing this node during the
00175     // traversal.
00176     int num_children = node->get_num_children();
00177     if (node->has_selective_visibility()) {
00178       int i = node->get_first_visible_child();
00179       while (i < num_children) {
00180         CullTraverserData next_data(data, node->get_child(i));
00181         traverse(next_data);
00182         i = node->get_next_visible_child(i);
00183       }
00184       
00185     } else {
00186       for (int i = 0; i < num_children; i++) {
00187         CullTraverserData next_data(data, node->get_child(i));
00188         traverse(next_data);
00189       }
00190     }
00191   }
00192 }
00193 
00194 ////////////////////////////////////////////////////////////////////
00195 //     Function: CullTraverser::show_bounds
00196 //       Access: Private
00197 //  Description: Draws an appropriate visualization of the node's
00198 //               external bounding volume.
00199 ////////////////////////////////////////////////////////////////////
00200 void CullTraverser::
00201 show_bounds(CullTraverserData &data) {
00202   PandaNode *node = data.node();
00203 
00204   PT(Geom) bounds_viz = make_bounds_viz(node->get_bound());
00205   if (bounds_viz != (Geom *)NULL) {
00206     CullableObject *outer_viz = 
00207       new CullableObject(bounds_viz, get_bounds_outer_viz_state(), 
00208                          data._render_transform);
00209     _cull_handler->record_object(outer_viz);
00210 
00211     CullableObject *inner_viz = 
00212       new CullableObject(bounds_viz, get_bounds_inner_viz_state(), 
00213                          data._render_transform);
00214     _cull_handler->record_object(inner_viz);
00215   }
00216 }
00217 
00218 ////////////////////////////////////////////////////////////////////
00219 //     Function: CullTraverser::make_bounds_viz
00220 //       Access: Private
00221 //  Description: Returns an appropriate visualization of the indicated
00222 //               bounding volume.
00223 ////////////////////////////////////////////////////////////////////
00224 PT(Geom) CullTraverser::
00225 make_bounds_viz(const BoundingVolume &vol) {
00226   PT(Geom) geom;
00227   if (vol.is_infinite()) {
00228     // No way to draw an infinite bounding volume.
00229 
00230   } else if (vol.is_of_type(BoundingSphere::get_class_type())) {
00231     const BoundingSphere *sphere = DCAST(BoundingSphere, &vol);
00232     
00233     geom = new GeomSphere;
00234     PTA_Vertexf verts;
00235     LPoint3f center = sphere->get_center();
00236     verts.push_back(center);
00237     center[0] += sphere->get_radius();
00238     verts.push_back(center);
00239     geom->set_coords(verts);
00240     geom->set_num_prims(1);
00241     
00242   } else {
00243     pgraph_cat.warning()
00244       << "Don't know how to draw a representation of "
00245       << vol.get_class_type() << "\n";
00246   }
00247 
00248   return geom;
00249 }
00250 
00251 ////////////////////////////////////////////////////////////////////
00252 //     Function: CullTraverser::get_bounds_outer_viz_state
00253 //       Access: Private, Static
00254 //  Description: Returns a RenderState for rendering the outside
00255 //               surfaces of the bounding volume visualizations.
00256 ////////////////////////////////////////////////////////////////////
00257 CPT(RenderState) CullTraverser::
00258 get_bounds_outer_viz_state() {
00259   // Once someone asks for this pointer, we hold its reference count
00260   // and never free it.
00261   static CPT(RenderState) state = (const RenderState *)NULL;
00262   if (state == (const RenderState *)NULL) {
00263     state = RenderState::make
00264       (ColorAttrib::make_flat(Colorf(0.3f, 1.0f, 0.5f, 1.0f)),
00265        RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
00266        CullFaceAttrib::make(CullFaceAttrib::M_cull_clockwise));
00267   }
00268   return state;
00269 }
00270 
00271 ////////////////////////////////////////////////////////////////////
00272 //     Function: CullTraverser::get_bounds_inner_viz_state
00273 //       Access: Private, Static
00274 //  Description: Returns a RenderState for rendering the inside
00275 //               surfaces of the bounding volume visualizations.
00276 ////////////////////////////////////////////////////////////////////
00277 CPT(RenderState) CullTraverser::
00278 get_bounds_inner_viz_state() {
00279   // Once someone asks for this pointer, we hold its reference count
00280   // and never free it.
00281   static CPT(RenderState) state = (const RenderState *)NULL;
00282   if (state == (const RenderState *)NULL) {
00283     state = RenderState::make
00284       (ColorAttrib::make_flat(Colorf(0.15f, 0.5f, 0.25f, 1.0f)),
00285        RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
00286        CullFaceAttrib::make(CullFaceAttrib::M_cull_counter_clockwise));
00287   }
00288   return state;
00289 }
00290 
00291 ////////////////////////////////////////////////////////////////////
00292 //     Function: CullTraverser::get_depth_offset_state
00293 //       Access: Private, Static
00294 //  Description: Returns a RenderState for increasing the DepthOffset
00295 //               by one.
00296 ////////////////////////////////////////////////////////////////////
00297 CPT(RenderState) CullTraverser::
00298 get_depth_offset_state() {
00299   // Once someone asks for this pointer, we hold its reference count
00300   // and never free it.
00301   static CPT(RenderState) state = (const RenderState *)NULL;
00302   if (state == (const RenderState *)NULL) {
00303     state = RenderState::make
00304       (DepthOffsetAttrib::make(1));
00305   }
00306   return state;
00307 }
00308 
00309 
00310 ////////////////////////////////////////////////////////////////////
00311 //     Function: CullTraverser::start_decal
00312 //       Access: Private
00313 //  Description: Collects a base node and all of the decals applied to
00314 //               it.  This involves recursing below the base GeomNode
00315 //               to find all the decal geoms.
00316 ////////////////////////////////////////////////////////////////////
00317 void CullTraverser::
00318 start_decal(const CullTraverserData &data) {
00319   PandaNode *node = data.node();
00320   if (!node->is_geom_node()) {
00321     pgraph_cat.error()
00322       << "DecalEffect applied to " << *node << ", not a GeomNode.\n";
00323     return;
00324   }
00325 
00326   // Build a chain of CullableObjects.  The head of the chain will be
00327   // all of the base Geoms in order, followed by an empty
00328   // CullableObject node, followed by all of the decal Geoms, in
00329   // order.
00330 
00331   // Since the CullableObject is a linked list which gets built in
00332   // LIFO order, we start with the decals.
00333   CullableObject *decals = (CullableObject *)NULL;
00334   PandaNode::Children cr = node->get_children();
00335   int num_children = cr.get_num_children();
00336   if (node->has_selective_visibility()) {
00337     int i = node->get_first_visible_child();
00338     while (i < num_children) {
00339       CullTraverserData next_data(data, cr.get_child(i));
00340       decals = r_get_decals(next_data, decals);
00341       i = node->get_next_visible_child(i);
00342     }
00343     
00344   } else {
00345     for (int i = num_children - 1; i >= 0; i--) {
00346       CullTraverserData next_data(data, cr.get_child(i));
00347       decals = r_get_decals(next_data, decals);
00348     }
00349   }
00350 
00351   // Now create a new, empty CullableObject to separate the decals
00352   // from the non-decals.
00353   CullableObject *separator = new CullableObject(decals);
00354 
00355   // And now get the base Geoms, again in reverse order.
00356   CullableObject *object = separator;
00357   GeomNode *geom_node = DCAST(GeomNode, node);
00358   int num_geoms = geom_node->get_num_geoms();
00359   for (int i = num_geoms - 1; i >= 0; i--) {
00360     object = new CullableObject(data, geom_node, i, object);
00361   }
00362 
00363   if (object != separator) {
00364     // Finally, send the whole list down to the CullHandler for
00365     // processing.  The first Geom in the node now represents the
00366     // overall state.
00367     _cull_handler->record_object(object);
00368   }
00369 }
00370 
00371 ////////////////////////////////////////////////////////////////////
00372 //     Function: CullTraverser::r_get_decals
00373 //       Access: Private
00374 //  Description: Recursively gets all the decals applied to a
00375 //               particular GeomNode.  These are built into a
00376 //               CullableObject list in LIFO order (so that the
00377 //               traversing the list will extract them in the order
00378 //               they were encountered in the scene graph).
00379 ////////////////////////////////////////////////////////////////////
00380 CullableObject *CullTraverser::
00381 r_get_decals(CullTraverserData &data, CullableObject *decals) {
00382   if (data.is_in_view(_camera_mask)) {
00383     PandaNode *node = data.node();
00384 
00385     const RenderEffects *node_effects = node->get_effects();
00386     if (node_effects->has_show_bounds()) {
00387       // If we should show the bounding volume for this node, make it
00388       // up now.
00389       show_bounds(data);
00390     }
00391 
00392     data.apply_transform_and_state(this);
00393 
00394     // First, visit all of the node's children.
00395     int num_children = node->get_num_children();
00396     if (node->has_selective_visibility()) {
00397       int i = node->get_first_visible_child();
00398       while (i < num_children) {
00399         CullTraverserData next_data(data, node->get_child(i));
00400         decals = r_get_decals(next_data, decals);
00401         i = node->get_next_visible_child(i);
00402       }
00403       
00404     } else {
00405       for (int i = num_children - 1; i >= 0; i--) {
00406         CullTraverserData next_data(data, node->get_child(i));
00407         decals = r_get_decals(next_data, decals);
00408       }
00409     }
00410 
00411     // Now, tack on any geoms within the node.
00412     if (node->is_geom_node()) {
00413       GeomNode *geom_node = DCAST(GeomNode, node);
00414       
00415       int num_geoms = geom_node->get_num_geoms();
00416       for (int i = num_geoms - 1; i >= 0; i--) {
00417         decals = new CullableObject(data, geom_node, i, decals);
00418       }
00419     }
00420   }
00421 
00422   return decals;
00423 }

Generated on Fri May 2 00:41:29 2003 for Panda by doxygen1.3