Panda3D
|
00001 // Filename: occluderNode.cxx 00002 // Created by: jenes (11Mar11) 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 "occluderNode.h" 00016 00017 #include "geomNode.h" 00018 #include "cullTraverserData.h" 00019 #include "cullTraverser.h" 00020 #include "renderState.h" 00021 #include "plane.h" 00022 #include "pnmImage.h" 00023 #include "textureAttrib.h" 00024 #include "colorAttrib.h" 00025 #include "depthOffsetAttrib.h" 00026 #include "cullFaceAttrib.h" 00027 #include "transparencyAttrib.h" 00028 #include "transformState.h" 00029 #include "cullableObject.h" 00030 #include "cullHandler.h" 00031 #include "boundingSphere.h" 00032 #include "geomVertexData.h" 00033 #include "geomTriangles.h" 00034 #include "geomLinestrips.h" 00035 #include "geomVertexWriter.h" 00036 #include "geom.h" 00037 #include "datagram.h" 00038 #include "datagramIterator.h" 00039 #include "bamReader.h" 00040 #include "bamWriter.h" 00041 00042 #include "plane.h" 00043 00044 TypeHandle OccluderNode::_type_handle; 00045 PT(Texture) OccluderNode::_viz_tex; 00046 00047 00048 //////////////////////////////////////////////////////////////////// 00049 // Function: OccluderNode::Constructor 00050 // Access: Public 00051 // Description: The default constructor creates a default occlusion 00052 // polygon in the XZ plane (or XY plane in a y-up 00053 // coordinate system). Use the normal Panda set_pos(), 00054 // set_hpr(), set_scale() to position it appropriately, 00055 // or replace the vertices with set_vertices(). 00056 //////////////////////////////////////////////////////////////////// 00057 OccluderNode:: 00058 OccluderNode(const string &name) : 00059 PandaNode(name) 00060 { 00061 set_cull_callback(); 00062 // OccluderNodes are hidden by default. 00063 set_overall_hidden(true); 00064 set_double_sided(false); 00065 set_min_coverage(0.0); 00066 set_vertices(LPoint3::rfu(-1.0, 0.0, -1.0), 00067 LPoint3::rfu(1.0, 0.0, -1.0), 00068 LPoint3::rfu(1.0, 0.0, 1.0), 00069 LPoint3::rfu(-1.0, 0.0, 1.0)); 00070 } 00071 00072 //////////////////////////////////////////////////////////////////// 00073 // Function: OccluderNode::Copy Constructor 00074 // Access: Protected 00075 // Description: 00076 //////////////////////////////////////////////////////////////////// 00077 OccluderNode:: 00078 OccluderNode(const OccluderNode ©) : 00079 PandaNode(copy), 00080 _double_sided(copy._double_sided), 00081 _min_coverage(copy._min_coverage), 00082 _vertices(copy._vertices) 00083 { 00084 } 00085 00086 //////////////////////////////////////////////////////////////////// 00087 // Function: OccluderNode::Destructor 00088 // Access: Public, Virtual 00089 // Description: 00090 //////////////////////////////////////////////////////////////////// 00091 OccluderNode:: 00092 ~OccluderNode() { 00093 } 00094 00095 //////////////////////////////////////////////////////////////////// 00096 // Function: OccluderNode::make_copy 00097 // Access: Public, Virtual 00098 // Description: Returns a newly-allocated Node that is a shallow copy 00099 // of this one. It will be a different Node pointer, 00100 // but its internal data may or may not be shared with 00101 // that of the original Node. 00102 //////////////////////////////////////////////////////////////////// 00103 PandaNode *OccluderNode:: 00104 make_copy() const { 00105 return new OccluderNode(*this); 00106 } 00107 00108 //////////////////////////////////////////////////////////////////// 00109 // Function: OccluderNode::preserve_name 00110 // Access: Public, Virtual 00111 // Description: Returns true if the node's name has extrinsic meaning 00112 // and must be preserved across a flatten operation, 00113 // false otherwise. 00114 //////////////////////////////////////////////////////////////////// 00115 bool OccluderNode:: 00116 preserve_name() const { 00117 return true; 00118 } 00119 00120 //////////////////////////////////////////////////////////////////// 00121 // Function: OccluderNode::xform 00122 // Access: Public, Virtual 00123 // Description: Transforms the contents of this node by the indicated 00124 // matrix, if it means anything to do so. For most 00125 // kinds of nodes, this does nothing. 00126 //////////////////////////////////////////////////////////////////// 00127 void OccluderNode:: 00128 xform(const LMatrix4 &mat) { 00129 nassertv(!mat.is_nan()); 00130 00131 for (Vertices::iterator vi = _vertices.begin(); 00132 vi != _vertices.end(); 00133 ++vi) { 00134 (*vi) = (*vi) * mat; 00135 } 00136 } 00137 00138 //////////////////////////////////////////////////////////////////// 00139 // Function: OccluderNode::cull_callback 00140 // Access: Public, Virtual 00141 // Description: This function will be called during the cull 00142 // traversal to perform any additional operations that 00143 // should be performed at cull time. This may include 00144 // additional manipulation of render state or additional 00145 // visible/invisible decisions, or any other arbitrary 00146 // operation. 00147 // 00148 // Note that this function will *not* be called unless 00149 // set_cull_callback() is called in the constructor of 00150 // the derived class. It is necessary to call 00151 // set_cull_callback() to indicated that we require 00152 // cull_callback() to be called. 00153 // 00154 // By the time this function is called, the node has 00155 // already passed the bounding-volume test for the 00156 // viewing frustum, and the node's transform and state 00157 // have already been applied to the indicated 00158 // CullTraverserData object. 00159 // 00160 // The return value is true if this node should be 00161 // visible, or false if it should be culled. 00162 //////////////////////////////////////////////////////////////////// 00163 bool OccluderNode:: 00164 cull_callback(CullTraverser *trav, CullTraverserData &data) { 00165 // Normally, an OccluderNode is invisible. But if someone shows it, 00166 // we will draw a visualization, a checkerboard-textured polygon. 00167 CullableObject *occluder_viz = 00168 new CullableObject(get_occluder_viz(trav, data), get_occluder_viz_state(trav, data), 00169 data.get_net_transform(trav), 00170 data.get_modelview_transform(trav), 00171 trav->get_gsg()); 00172 trav->get_cull_handler()->record_object(occluder_viz, trav); 00173 00174 // Also get the frame. 00175 nassertr(_frame_viz != (Geom *)NULL, false); 00176 CullableObject *frame_viz = 00177 new CullableObject(_frame_viz, get_frame_viz_state(trav, data), 00178 data.get_net_transform(trav), 00179 data.get_modelview_transform(trav), 00180 trav->get_gsg()); 00181 trav->get_cull_handler()->record_object(frame_viz, trav); 00182 00183 // Now carry on to render our child nodes. 00184 return true; 00185 } 00186 00187 //////////////////////////////////////////////////////////////////// 00188 // Function: OccluderNode::is_renderable 00189 // Access: Public, Virtual 00190 // Description: Returns true if there is some value to visiting this 00191 // particular node during the cull traversal for any 00192 // camera, false otherwise. This will be used to 00193 // optimize the result of get_net_draw_show_mask(), so 00194 // that any subtrees that contain only nodes for which 00195 // is_renderable() is false need not be visited. 00196 //////////////////////////////////////////////////////////////////// 00197 bool OccluderNode:: 00198 is_renderable() const { 00199 return true; 00200 } 00201 00202 00203 //////////////////////////////////////////////////////////////////// 00204 // Function: OccluderNode::output 00205 // Access: Public, Virtual 00206 // Description: Writes a brief description of the node to the 00207 // indicated output stream. This is invoked by the << 00208 // operator. It may be overridden in derived classes to 00209 // include some information relevant to the class. 00210 //////////////////////////////////////////////////////////////////// 00211 void OccluderNode:: 00212 output(ostream &out) const { 00213 PandaNode::output(out); 00214 } 00215 00216 //////////////////////////////////////////////////////////////////// 00217 // Function: OccluderNode::compute_internal_bounds 00218 // Access: Protected, Virtual 00219 // Description: Called when needed to recompute the node's 00220 // _internal_bound object. Nodes that contain anything 00221 // of substance should redefine this to do the right 00222 // thing. 00223 //////////////////////////////////////////////////////////////////// 00224 void OccluderNode:: 00225 compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, 00226 int &internal_vertices, 00227 int pipeline_stage, 00228 Thread *current_thread) const { 00229 // First, get ourselves a fresh, empty bounding volume. 00230 PT(BoundingVolume) bound = new BoundingSphere; 00231 GeometricBoundingVolume *gbv = DCAST(GeometricBoundingVolume, bound); 00232 00233 // Now actually compute the bounding volume by putting it around all 00234 // of our vertices. 00235 if (!_vertices.empty()) { 00236 const LPoint3 *vertices_begin = &_vertices[0]; 00237 const LPoint3 *vertices_end = vertices_begin + _vertices.size(); 00238 gbv->around(vertices_begin, vertices_end); 00239 } 00240 00241 internal_bounds = bound; 00242 internal_vertices = 0; 00243 } 00244 00245 //////////////////////////////////////////////////////////////////// 00246 // Function: OccluderNode::get_occluder_viz 00247 // Access: Protected 00248 // Description: Returns a Geom that represents the visualization of 00249 // the OccluderNode, as seen from the front. 00250 //////////////////////////////////////////////////////////////////// 00251 PT(Geom) OccluderNode:: 00252 get_occluder_viz(CullTraverser *trav, CullTraverserData &data) { 00253 if (_occluder_viz == (Geom *)NULL) { 00254 nassertr(_vertices.size() == 4, NULL); 00255 00256 if (pgraph_cat.is_debug()) { 00257 pgraph_cat.debug() 00258 << "Recomputing viz for " << *this << "\n"; 00259 } 00260 00261 PT(GeomVertexData) vdata = new GeomVertexData 00262 (get_name(), GeomVertexFormat::get_v3n3t2(), Geom::UH_static); 00263 00264 // Compute the polygon normal from the first three vertices. 00265 LPlane plane(_vertices[0], _vertices[1], _vertices[2]); 00266 LVector3 poly_normal = plane.get_normal(); 00267 00268 GeomVertexWriter vertex(vdata, InternalName::get_vertex()); 00269 GeomVertexWriter normal(vdata, InternalName::get_normal()); 00270 GeomVertexWriter texcoord(vdata, InternalName::get_texcoord()); 00271 vertex.add_data3(_vertices[0]); 00272 normal.add_data3(poly_normal); 00273 texcoord.add_data2(0.0, 0.0); 00274 00275 vertex.add_data3(_vertices[1]); 00276 normal.add_data3(poly_normal); 00277 texcoord.add_data2(8.0, 0.0); 00278 00279 vertex.add_data3(_vertices[2]); 00280 normal.add_data3(poly_normal); 00281 texcoord.add_data2(8.0, 8.0); 00282 00283 vertex.add_data3(_vertices[3]); 00284 normal.add_data3(poly_normal); 00285 texcoord.add_data2(0.0, 8.0); 00286 00287 PT(GeomTriangles) triangles = new GeomTriangles(Geom::UH_static); 00288 triangles->add_vertices(0, 1, 2); 00289 triangles->close_primitive(); 00290 triangles->add_vertices(0, 2, 3); 00291 triangles->close_primitive(); 00292 00293 _occluder_viz = new Geom(vdata); 00294 _occluder_viz->add_primitive(triangles); 00295 00296 PT(GeomLinestrips) lines = new GeomLinestrips(Geom::UH_static); 00297 lines->add_vertices(0, 1, 2, 3); 00298 lines->add_vertex(0); 00299 lines->close_primitive(); 00300 00301 _frame_viz = new Geom(vdata); 00302 _frame_viz->add_primitive(lines); 00303 } 00304 00305 return _occluder_viz; 00306 } 00307 00308 //////////////////////////////////////////////////////////////////// 00309 // Function: OccluderNode::get_occluder_viz_state 00310 // Access: Protected 00311 // Description: Returns the RenderState to apply to the visualization. 00312 //////////////////////////////////////////////////////////////////// 00313 CPT(RenderState) OccluderNode:: 00314 get_occluder_viz_state(CullTraverser *trav, CullTraverserData &data) { 00315 if (_viz_tex == NULL) { 00316 // Create a default texture. We set it up as a 2x2 graytone 00317 // checkerboard, since that's real easy, and it doesn't look like 00318 // a CollisionPolygon. 00319 _viz_tex = new Texture("occluder_viz"); 00320 _viz_tex->setup_2d_texture(2, 2, Texture::T_unsigned_byte, Texture::F_luminance); 00321 PTA_uchar image; 00322 image.set_data("\x20\x80\x80\x20"); 00323 _viz_tex->set_ram_image(image); 00324 _viz_tex->set_minfilter(Texture::FT_nearest); 00325 _viz_tex->set_magfilter(Texture::FT_nearest); 00326 } 00327 00328 static CPT(RenderState) viz_state; 00329 if (viz_state == NULL) { 00330 viz_state = RenderState::make 00331 (ColorAttrib::make_flat(LVecBase4(1.0f, 1.0f, 1.0f, 0.5f)), 00332 TransparencyAttrib::make(TransparencyAttrib::M_alpha), 00333 DepthOffsetAttrib::make(), 00334 TextureAttrib::make(_viz_tex)); 00335 viz_state = viz_state->adjust_all_priorities(1); 00336 } 00337 00338 CPT(RenderState) state = viz_state; 00339 if (is_double_sided()) { 00340 state = viz_state->set_attrib(CullFaceAttrib::make(CullFaceAttrib::M_cull_none), 1); 00341 } else { 00342 state = viz_state->set_attrib(CullFaceAttrib::make(CullFaceAttrib::M_cull_clockwise), 1); 00343 } 00344 00345 return state->compose(viz_state); 00346 } 00347 00348 //////////////////////////////////////////////////////////////////// 00349 // Function: OccluderNode::get_frame_viz_state 00350 // Access: Protected 00351 // Description: Returns the RenderState to apply to the frame. 00352 //////////////////////////////////////////////////////////////////// 00353 CPT(RenderState) OccluderNode:: 00354 get_frame_viz_state(CullTraverser *trav, CullTraverserData &data) { 00355 static CPT(RenderState) viz_state; 00356 if (viz_state == NULL) { 00357 viz_state = RenderState::make 00358 (ColorAttrib::make_flat(LVecBase4(0.0f, 0.0f, 0.0f, 1.0f)), 00359 TextureAttrib::make_off()); 00360 viz_state = viz_state->adjust_all_priorities(1); 00361 } 00362 00363 return data._state->compose(viz_state); 00364 } 00365 00366 //////////////////////////////////////////////////////////////////// 00367 // Function: OccluderNode::register_with_read_factory 00368 // Access: Public, Static 00369 // Description: Tells the BamReader how to create objects of type 00370 // OccluderNode. 00371 //////////////////////////////////////////////////////////////////// 00372 void OccluderNode:: 00373 register_with_read_factory() { 00374 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); 00375 } 00376 00377 //////////////////////////////////////////////////////////////////// 00378 // Function: OccluderNode::write_datagram 00379 // Access: Public, Virtual 00380 // Description: Writes the contents of this object to the datagram 00381 // for shipping out to a Bam file. 00382 //////////////////////////////////////////////////////////////////// 00383 void OccluderNode:: 00384 write_datagram(BamWriter *manager, Datagram &dg) { 00385 PandaNode::write_datagram(manager, dg); 00386 00387 dg.add_uint16(_vertices.size()); 00388 for (Vertices::const_iterator vi = _vertices.begin(); 00389 vi != _vertices.end(); 00390 ++vi) { 00391 (*vi).write_datagram(dg); 00392 } 00393 } 00394 00395 //////////////////////////////////////////////////////////////////// 00396 // Function: OccluderNode::complete_pointers 00397 // Access: Public, Virtual 00398 // Description: Receives an array of pointers, one for each time 00399 // manager->read_pointer() was called in fillin(). 00400 // Returns the number of pointers processed. 00401 //////////////////////////////////////////////////////////////////// 00402 int OccluderNode:: 00403 complete_pointers(TypedWritable **p_list, BamReader *manager) { 00404 int pi = PandaNode::complete_pointers(p_list, manager); 00405 00406 return pi; 00407 } 00408 00409 //////////////////////////////////////////////////////////////////// 00410 // Function: OccluderNode::make_from_bam 00411 // Access: Protected, Static 00412 // Description: This function is called by the BamReader's factory 00413 // when a new object of type OccluderNode is encountered 00414 // in the Bam file. It should create the OccluderNode 00415 // and extract its information from the file. 00416 //////////////////////////////////////////////////////////////////// 00417 TypedWritable *OccluderNode:: 00418 make_from_bam(const FactoryParams ¶ms) { 00419 OccluderNode *node = new OccluderNode(""); 00420 DatagramIterator scan; 00421 BamReader *manager; 00422 00423 parse_params(params, scan, manager); 00424 node->fillin(scan, manager); 00425 00426 return node; 00427 } 00428 00429 //////////////////////////////////////////////////////////////////// 00430 // Function: OccluderNode::fillin 00431 // Access: Protected 00432 // Description: This internal function is called by make_from_bam to 00433 // read in all of the relevant data from the BamFile for 00434 // the new OccluderNode. 00435 //////////////////////////////////////////////////////////////////// 00436 void OccluderNode:: 00437 fillin(DatagramIterator &scan, BamReader *manager) { 00438 PandaNode::fillin(scan, manager); 00439 00440 int num_vertices = scan.get_uint16(); 00441 _vertices.clear(); 00442 _vertices.reserve(num_vertices); 00443 for (int i = 0; i < num_vertices; i++) { 00444 LPoint3 vertex; 00445 vertex.read_datagram(scan); 00446 _vertices.push_back(vertex); 00447 } 00448 }