Panda3D
|
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 }