Panda3D

cullPlanes.cxx

00001 // Filename: cullPlanes.cxx
00002 // Created by:  drose (23Aug05)
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 "cullPlanes.h"
00016 #include "cullTraverserData.h"
00017 
00018 
00019 ////////////////////////////////////////////////////////////////////
00020 //     Function: CullPlanes::make_empty
00021 //       Access: Public, Static
00022 //  Description: Returns a pointer to an empty CullPlanes object.
00023 ////////////////////////////////////////////////////////////////////
00024 CPT(CullPlanes) CullPlanes::
00025 make_empty() {
00026   static CPT(CullPlanes) empty;
00027   if (empty == NULL) {
00028     empty = new CullPlanes;
00029     // Artificially tick the reference count, just to ensure we won't
00030     // accidentally modify this object in any of the copy-on-write
00031     // operations below.
00032     empty->ref();
00033   }
00034   return empty;
00035 }
00036 
00037 ////////////////////////////////////////////////////////////////////
00038 //     Function: CullPlanes::xform
00039 //       Access: Public
00040 //  Description: Returns a pointer to a new CullPlanes object that is
00041 //               the same as this one, but with the clip planes
00042 //               modified by the indicated transform.
00043 ////////////////////////////////////////////////////////////////////
00044 CPT(CullPlanes) CullPlanes::
00045 xform(const LMatrix4f &mat) const {
00046   PT(CullPlanes) new_planes;
00047   if (get_ref_count() == 1) {
00048     new_planes = (CullPlanes *)this;
00049   } else {
00050     new_planes = new CullPlanes(*this);
00051   }
00052 
00053   for (Planes::iterator pi = new_planes->_planes.begin();
00054        pi != new_planes->_planes.end();
00055        ++pi) {
00056     if ((*pi).second->get_ref_count() != 1) {
00057       (*pi).second = DCAST(BoundingPlane, (*pi).second->make_copy());
00058     }
00059     (*pi).second->xform(mat);
00060   }
00061 
00062   return new_planes;
00063 }
00064 
00065 ////////////////////////////////////////////////////////////////////
00066 //     Function: CullPlanes::apply_state
00067 //       Access: Public
00068 //  Description: Returns a pointer to a new CullPlanes object that is
00069 //               the same as this one, but with the indicated
00070 //               attributes applied to the state.
00071 //
00072 //               In particular, any new ClipPlanes given in
00073 //               net_attrib, if it is not NULL, will be added to the
00074 //               state, unless those ClipPlanes are also listed in
00075 //               off_attrib.
00076 ////////////////////////////////////////////////////////////////////
00077 CPT(CullPlanes) CullPlanes::
00078 apply_state(const CullTraverser *trav, const CullTraverserData *data,
00079             const ClipPlaneAttrib *net_attrib,
00080             const ClipPlaneAttrib *off_attrib) const {
00081   if (net_attrib == (ClipPlaneAttrib *)NULL) {
00082     return this;
00083   }
00084 
00085   PT(CullPlanes) new_planes;
00086   if (get_ref_count() == 1) {
00087     new_planes = (CullPlanes *)this;
00088   } else {
00089     new_planes = new CullPlanes(*this);
00090   }
00091 
00092   CPT(TransformState) net_transform = NULL;
00093 
00094   int num_on_planes = net_attrib->get_num_on_planes();
00095   for (int i = 0; i < num_on_planes; ++i) {
00096     NodePath clip_plane = net_attrib->get_on_plane(i);
00097     Planes::const_iterator pi = new_planes->_planes.find(clip_plane);
00098     if (pi == new_planes->_planes.end()) {
00099       if (!off_attrib->has_off_plane(clip_plane)) {
00100         // Here's a new clip plane; add it to the list.  For this we
00101         // need the net transform to this node.
00102         if (net_transform == (TransformState *)NULL) {
00103           net_transform = data->get_net_transform(trav);
00104         }
00105 
00106         PlaneNode *plane_node = DCAST(PlaneNode, clip_plane.node());
00107         CPT(TransformState) new_transform = 
00108           net_transform->invert_compose(clip_plane.get_net_transform());
00109         
00110         Planef plane = plane_node->get_plane() * new_transform->get_mat();
00111         new_planes->_planes[clip_plane] = new BoundingPlane(-plane);
00112       }
00113     }
00114   }
00115 
00116   return new_planes;
00117 }
00118 
00119 ////////////////////////////////////////////////////////////////////
00120 //     Function: CullPlanes::do_cull
00121 //       Access: Public
00122 //  Description: Tests the indicated bounding volume against all of
00123 //               the clip planes in this object.  Sets result to an
00124 //               appropriate union of
00125 //               BoundingVolume::IntersectionFlags, similar to the
00126 //               result of BoundingVolume::contains().
00127 //
00128 //               Also, if the bounding volume is completely in front
00129 //               of any of the clip planes, removes those planes both
00130 //               from this object and from the indicated state,
00131 //               returning a new CullPlanes object in that case.
00132 ////////////////////////////////////////////////////////////////////
00133 CPT(CullPlanes) CullPlanes::
00134 do_cull(int &result, CPT(RenderState) &state,
00135         const GeometricBoundingVolume *node_gbv) const {
00136   result = 
00137     BoundingVolume::IF_all | BoundingVolume::IF_possible | BoundingVolume::IF_some;
00138 
00139   CPT(ClipPlaneAttrib) orig_cpa = DCAST(ClipPlaneAttrib, state->get_attrib(ClipPlaneAttrib::get_class_slot()));
00140   
00141   // If there are no clip planes in the state, the node is completely
00142   // in front of all zero of the clip planes.  (This can happen if
00143   // someone directly changes the state during the traversal.)
00144   if (orig_cpa == (ClipPlaneAttrib *)NULL) {
00145     return new CullPlanes;
00146   }
00147 
00148   CPT(CullPlanes) new_planes = this;
00149   CPT(ClipPlaneAttrib) new_cpa = orig_cpa;
00150 
00151   Planes::const_iterator pi;
00152   for (pi = _planes.begin(); pi != _planes.end(); ++pi) {
00153     int plane_result = (*pi).second->contains(node_gbv);
00154     if (plane_result == BoundingVolume::IF_no_intersection) {
00155       // The node is completely behind this clip plane.  Short-circuit
00156       // the rest of the logic; none of the other planes matter.
00157       result = plane_result;
00158       return new_planes;
00159     }
00160 
00161     if ((plane_result & BoundingVolume::IF_all) != 0) {
00162       // The node is completely in front of this clip plane.  We don't
00163       // need to consider this plane ever again for any descendents of
00164       // this node.
00165       new_planes = new_planes->remove_plane((*pi).first);
00166       nassertr(new_planes != this, new_planes);
00167       new_cpa = DCAST(ClipPlaneAttrib, new_cpa->remove_on_plane((*pi).first));
00168     }
00169 
00170     result &= plane_result;
00171   }
00172 
00173   if (new_cpa != orig_cpa) {
00174     if (new_cpa->is_identity()) {
00175       state = state->remove_attrib(ClipPlaneAttrib::get_class_slot());
00176     } else {
00177       state = state->add_attrib(new_cpa);
00178     }
00179   }
00180     
00181   return new_planes;
00182 }
00183 
00184 ////////////////////////////////////////////////////////////////////
00185 //     Function: CullPlanes::remove_plane
00186 //       Access: Public
00187 //  Description: Returns a pointer to a new CullPlanes object that is
00188 //               the same as this one, but with the indicated
00189 //               clip plane removed.
00190 ////////////////////////////////////////////////////////////////////
00191 CPT(CullPlanes) CullPlanes::
00192 remove_plane(const NodePath &clip_plane) const {
00193   PT(CullPlanes) new_planes;
00194   if (get_ref_count() == 1) {
00195     new_planes = (CullPlanes *)this;
00196   } else {
00197     new_planes = new CullPlanes(*this);
00198   }
00199 
00200   Planes::iterator pi = new_planes->_planes.find(clip_plane);
00201   nassertr(pi != new_planes->_planes.end(), new_planes);
00202   new_planes->_planes.erase(pi);
00203 
00204   return new_planes;
00205 }
00206 
00207 ////////////////////////////////////////////////////////////////////
00208 //     Function: CullPlanes::write
00209 //       Access: Public
00210 //  Description: 
00211 ////////////////////////////////////////////////////////////////////
00212 void CullPlanes::
00213 write(ostream &out) const {
00214   out << "CullPlanes (" << _planes.size() << " planes):\n";
00215   Planes::const_iterator pi;
00216   for (pi = _planes.begin(); pi != _planes.end(); ++pi) {
00217     out << "  " << (*pi).first << " : " << *(*pi).second << "\n";
00218   }
00219 }
 All Classes Functions Variables Enumerations