Panda3D

cullTraverserData.cxx

00001 // Filename: cullTraverserData.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 "cullTraverserData.h"
00016 #include "cullTraverser.h"
00017 #include "config_pgraph.h"
00018 #include "pandaNode.h"
00019 #include "colorAttrib.h"
00020 #include "textureAttrib.h"
00021 #include "renderModeAttrib.h"
00022 #include "clipPlaneAttrib.h"
00023 #include "boundingPlane.h"
00024 #include "billboardEffect.h"
00025 #include "compassEffect.h"
00026 #include "polylightEffect.h"
00027 #include "renderState.h"
00028 
00029 
00030 ////////////////////////////////////////////////////////////////////
00031 //     Function: CullTraverserData::get_modelview_transform
00032 //       Access: Published
00033 //  Description: Returns the modelview transform: the relative
00034 //               transform from the camera to the model.
00035 ////////////////////////////////////////////////////////////////////
00036 CPT(TransformState) CullTraverserData::
00037 get_modelview_transform(const CullTraverser *trav) const {
00038   return trav->get_world_transform()->compose(_net_transform);
00039 }
00040 
00041 ////////////////////////////////////////////////////////////////////
00042 //     Function: CullTraverserData::apply_transform_and_state
00043 //       Access: Published
00044 //  Description: Applies the transform and state from the current
00045 //               node onto the current data.  This also evaluates
00046 //               billboards, etc.
00047 ////////////////////////////////////////////////////////////////////
00048 void CullTraverserData::
00049 apply_transform_and_state(CullTraverser *trav) {
00050   CPT(RenderState) node_state = _node_reader.get_state();
00051 
00052   if (trav->has_tag_state_key() && 
00053       _node_reader.has_tag(trav->get_tag_state_key())) {
00054     // Here's a node that has been tagged with the special key for our
00055     // current camera.  This indicates some special state transition
00056     // for this node, which is unique to this camera.
00057     const Camera *camera = trav->get_scene()->get_camera_node();
00058     string tag_state = _node_reader.get_tag(trav->get_tag_state_key());
00059     node_state = node_state->compose(camera->get_tag_state(tag_state));
00060   }
00061   _node_reader.compose_draw_mask(_draw_mask);
00062 
00063   apply_transform_and_state(trav, _node_reader.get_transform(),
00064                             node_state, _node_reader.get_effects(),
00065                             _node_reader.get_off_clip_planes());
00066 }
00067 
00068 ////////////////////////////////////////////////////////////////////
00069 //     Function: CullTraverserData::apply_transform_and_state
00070 //       Access: Published
00071 //  Description: Applies the indicated transform and state changes
00072 //               (e.g. as extracted from a node) onto the current
00073 //               data.  This also evaluates billboards, etc.
00074 ////////////////////////////////////////////////////////////////////
00075 void CullTraverserData::
00076 apply_transform_and_state(CullTraverser *trav, 
00077                           CPT(TransformState) node_transform, 
00078                           CPT(RenderState) node_state,
00079                           CPT(RenderEffects) node_effects,
00080                           const RenderAttrib *off_clip_planes) {
00081   if (node_effects->has_cull_callback()) {
00082     node_effects->cull_callback(trav, *this, node_transform, node_state);
00083   }
00084 
00085   if (!node_transform->is_identity()) {
00086     _net_transform = _net_transform->compose(node_transform);
00087 
00088     if ((_view_frustum != (GeometricBoundingVolume *)NULL) ||
00089         (!_cull_planes->is_empty())) {
00090       // We need to move the viewing frustums into the node's
00091       // coordinate space by applying the node's inverse transform.
00092       if (node_transform->is_singular()) {
00093         // But we can't invert a singular transform!  Instead of
00094         // trying, we'll just give up on frustum culling from this
00095         // point down.
00096         _view_frustum = (GeometricBoundingVolume *)NULL;
00097         _cull_planes = CullPlanes::make_empty();
00098 
00099       } else {
00100         CPT(TransformState) inv_transform = 
00101           node_transform->invert_compose(TransformState::make_identity());
00102 
00103         // Copy the bounding volumes for the frustums so we can
00104         // transform them.
00105         if (_view_frustum != (GeometricBoundingVolume *)NULL) {
00106           _view_frustum = DCAST(GeometricBoundingVolume, _view_frustum->make_copy());
00107           _view_frustum->xform(inv_transform->get_mat());
00108         }
00109 
00110         _cull_planes = _cull_planes->xform(inv_transform->get_mat());
00111       }
00112     }
00113   }
00114 
00115   _state = _state->compose(node_state);
00116 
00117   if (clip_plane_cull) {
00118     _cull_planes = _cull_planes->apply_state(trav, this, 
00119                                              DCAST(ClipPlaneAttrib, node_state->get_attrib(ClipPlaneAttrib::get_class_slot())),
00120                                              DCAST(ClipPlaneAttrib, off_clip_planes));
00121   }
00122 }
00123 
00124 ////////////////////////////////////////////////////////////////////
00125 //     Function: CullTraverserData::is_in_view_impl
00126 //       Access: Private
00127 //  Description: The private implementation of is_in_view().
00128 ////////////////////////////////////////////////////////////////////
00129 bool CullTraverserData::
00130 is_in_view_impl() {
00131   CPT(BoundingVolume) node_volume = _node_reader.get_bounds();
00132   nassertr(node_volume->is_of_type(GeometricBoundingVolume::get_class_type()), false);
00133   const GeometricBoundingVolume *node_gbv =
00134     DCAST(GeometricBoundingVolume, node_volume);
00135 
00136   if (_view_frustum != (GeometricBoundingVolume *)NULL) {
00137     int result = _view_frustum->contains(node_gbv);
00138     
00139     if (pgraph_cat.is_spam()) {
00140       pgraph_cat.spam()
00141         << _node_path << " cull result = " << hex << result << dec << "\n";
00142     }
00143     
00144     if (result == BoundingVolume::IF_no_intersection) {
00145       // No intersection at all.  Cull.
00146       if (!fake_view_frustum_cull) {
00147         return false;
00148       }
00149       
00150       // If we have fake view-frustum culling enabled, instead of
00151       // actually culling an object we simply force it to be drawn in
00152       // red wireframe.
00153       _view_frustum = (GeometricBoundingVolume *)NULL;
00154       CPT(RenderState) fake_state = get_fake_view_frustum_cull_state();
00155       _state = _state->compose(fake_state);
00156       
00157     } else if ((result & BoundingVolume::IF_all) != 0) {
00158       // The node and its descendents are completely enclosed within
00159       // the frustum.  No need to cull further.
00160       _view_frustum = (GeometricBoundingVolume *)NULL;
00161       
00162     } else {
00163       // The node is partially, but not completely, within the viewing
00164       // frustum.
00165       if (_node_reader.is_final()) {
00166         // Normally we'd keep testing child bounding volumes as we
00167         // continue down.  But this node has the "final" flag, so the
00168         // user is claiming that there is some important reason we
00169         // should consider everything visible at this point.  So be it.
00170         _view_frustum = (GeometricBoundingVolume *)NULL;
00171       }
00172     }
00173   }
00174 
00175   if (!_cull_planes->is_empty()) {
00176     // Also cull against the current clip planes.
00177     int result;
00178     _cull_planes = _cull_planes->do_cull(result, _state, node_gbv);
00179     
00180     if (pgraph_cat.is_spam()) {
00181       pgraph_cat.spam()
00182         << _node_path << " cull planes cull result = " << hex
00183         << result << dec << "\n";
00184       _cull_planes->write(pgraph_cat.spam(false));
00185     }
00186 
00187     if (_node_reader.is_final()) {
00188       // Even though the node may be partially within the clip planes,
00189       // do no more culling against them below this node.
00190       _cull_planes = CullPlanes::make_empty();
00191       
00192       if (pgraph_cat.is_spam()) {
00193         pgraph_cat.spam()
00194           << _node_path << " is_final, cull planes disabled, state:\n";
00195         _state->write(pgraph_cat.spam(false), 2);
00196       }
00197     }
00198     
00199     if (result == BoundingVolume::IF_no_intersection) {
00200       // No intersection at all.  Cull.
00201       return false;
00202       
00203     } else if ((result & BoundingVolume::IF_all) != 0) {
00204       // The node and its descendents are completely in front of all
00205       // of the clip planes.  The do_cull() call should therefore have
00206       // removed all of the clip planes.
00207       nassertr(_cull_planes->is_empty(), true);
00208     }
00209   }
00210 
00211   return true;
00212 }
00213 
00214 ////////////////////////////////////////////////////////////////////
00215 //     Function: CullTraverserData::get_fake_view_frustum_cull_state
00216 //       Access: Private, Static
00217 //  Description: Returns a RenderState for rendering stuff in red
00218 //               wireframe, strictly for the fake_view_frustum_cull
00219 //               effect.
00220 ////////////////////////////////////////////////////////////////////
00221 CPT(RenderState) CullTraverserData::
00222 get_fake_view_frustum_cull_state() {
00223   // Once someone asks for this pointer, we hold its reference count
00224   // and never free it.
00225   static CPT(RenderState) state = (const RenderState *)NULL;
00226   if (state == (const RenderState *)NULL) {
00227     state = RenderState::make
00228       (ColorAttrib::make_flat(Colorf(1.0f, 0.0f, 0.0f, 1.0f)),
00229        TextureAttrib::make_all_off(),
00230        RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
00231        RenderState::get_max_priority());
00232   }
00233   return state;
00234 }
00235 
 All Classes Functions Variables Enumerations