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                                              DCAST(OccluderEffect, node_effects->get_effect(OccluderEffect::get_class_type())));
00122   }
00123 }
00124 
00125 ////////////////////////////////////////////////////////////////////
00126 //     Function: CullTraverserData::is_in_view_impl
00127 //       Access: Private
00128 //  Description: The private implementation of is_in_view().
00129 ////////////////////////////////////////////////////////////////////
00130 bool CullTraverserData::
00131 is_in_view_impl() {
00132   CPT(BoundingVolume) node_volume = _node_reader.get_bounds();
00133   nassertr(node_volume->is_of_type(GeometricBoundingVolume::get_class_type()), false);
00134   const GeometricBoundingVolume *node_gbv =
00135     DCAST(GeometricBoundingVolume, node_volume);
00136 
00137   if (_view_frustum != (GeometricBoundingVolume *)NULL) {
00138     int result = _view_frustum->contains(node_gbv);
00139     
00140     if (pgraph_cat.is_spam()) {
00141       pgraph_cat.spam()
00142         << _node_path << " cull result = " << hex << result << dec << "\n";
00143     }
00144     
00145     if (result == BoundingVolume::IF_no_intersection) {
00146       // No intersection at all.  Cull.
00147       if (!fake_view_frustum_cull) {
00148         return false;
00149       }
00150       
00151       // If we have fake view-frustum culling enabled, instead of
00152       // actually culling an object we simply force it to be drawn in
00153       // red wireframe.
00154       _view_frustum = (GeometricBoundingVolume *)NULL;
00155       CPT(RenderState) fake_state = get_fake_view_frustum_cull_state();
00156       _state = _state->compose(fake_state);
00157       
00158     } else if ((result & BoundingVolume::IF_all) != 0) {
00159       // The node and its descendents are completely enclosed within
00160       // the frustum.  No need to cull further.
00161       _view_frustum = (GeometricBoundingVolume *)NULL;
00162       
00163     } else {
00164       // The node is partially, but not completely, within the viewing
00165       // frustum.
00166       if (_node_reader.is_final()) {
00167         // Normally we'd keep testing child bounding volumes as we
00168         // continue down.  But this node has the "final" flag, so the
00169         // user is claiming that there is some important reason we
00170         // should consider everything visible at this point.  So be it.
00171         _view_frustum = (GeometricBoundingVolume *)NULL;
00172       }
00173     }
00174   }
00175 
00176   if (!_cull_planes->is_empty()) {
00177     // Also cull against the current clip planes.
00178     int result;
00179     _cull_planes = _cull_planes->do_cull(result, _state, node_gbv);
00180     
00181     if (pgraph_cat.is_spam()) {
00182       pgraph_cat.spam()
00183         << _node_path << " cull planes cull result = " << hex
00184         << result << dec << "\n";
00185       _cull_planes->write(pgraph_cat.spam(false));
00186     }
00187 
00188     if (_node_reader.is_final()) {
00189       // Even though the node may be partially within the clip planes,
00190       // do no more culling against them below this node.
00191       _cull_planes = CullPlanes::make_empty();
00192       
00193       if (pgraph_cat.is_spam()) {
00194         pgraph_cat.spam()
00195           << _node_path << " is_final, cull planes disabled, state:\n";
00196         _state->write(pgraph_cat.spam(false), 2);
00197       }
00198     }
00199     
00200     if (result == BoundingVolume::IF_no_intersection) {
00201       // No intersection at all.  Cull.
00202       if (!fake_view_frustum_cull) {
00203         return false;
00204       }
00205       _cull_planes = CullPlanes::make_empty();
00206       CPT(RenderState) fake_state = get_fake_view_frustum_cull_state();
00207       _state = _state->compose(fake_state);
00208       
00209     } else if ((result & BoundingVolume::IF_all) != 0) {
00210       // The node and its descendents are completely in front of all
00211       // of the clip planes and occluders.  The do_cull() call should
00212       // therefore have removed all of the clip planes and occluders.
00213       nassertr(_cull_planes->is_empty(), true);
00214     }
00215   }
00216 
00217   return true;
00218 }
00219 
00220 ////////////////////////////////////////////////////////////////////
00221 //     Function: CullTraverserData::get_fake_view_frustum_cull_state
00222 //       Access: Private, Static
00223 //  Description: Returns a RenderState for rendering stuff in red
00224 //               wireframe, strictly for the fake_view_frustum_cull
00225 //               effect.
00226 ////////////////////////////////////////////////////////////////////
00227 CPT(RenderState) CullTraverserData::
00228 get_fake_view_frustum_cull_state() {
00229   // Once someone asks for this pointer, we hold its reference count
00230   // and never free it.
00231   static CPT(RenderState) state = (const RenderState *)NULL;
00232   if (state == (const RenderState *)NULL) {
00233     state = RenderState::make
00234       (ColorAttrib::make_flat(LColor(1.0f, 0.0f, 0.0f, 1.0f)),
00235        TextureAttrib::make_all_off(),
00236        RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
00237        RenderState::get_max_priority());
00238   }
00239   return state;
00240 }
00241 
 All Classes Functions Variables Enumerations