Panda3D
|
00001 // Filename: sheetNode.cxx 00002 // Created by: drose (11Oct03) 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 "sheetNode.h" 00016 #include "cullTraverser.h" 00017 #include "cullTraverserData.h" 00018 #include "cullableObject.h" 00019 #include "cullHandler.h" 00020 #include "bamWriter.h" 00021 #include "bamReader.h" 00022 #include "datagram.h" 00023 #include "datagramIterator.h" 00024 #include "pStatTimer.h" 00025 #include "geom.h" 00026 #include "geomTristrips.h" 00027 #include "geomVertexWriter.h" 00028 #include "boundingSphere.h" 00029 #include "colorAttrib.h" 00030 #include "renderState.h" 00031 00032 TypeHandle SheetNode::_type_handle; 00033 00034 PStatCollector SheetNode::_sheet_node_pcollector("*:SheetNode"); 00035 00036 //////////////////////////////////////////////////////////////////// 00037 // Function: SheetNode::CData::make_copy 00038 // Access: Public, Virtual 00039 // Description: 00040 //////////////////////////////////////////////////////////////////// 00041 CycleData *SheetNode::CData:: 00042 make_copy() const { 00043 return new CData(*this); 00044 } 00045 00046 //////////////////////////////////////////////////////////////////// 00047 // Function: SheetNode::CData::write_datagram 00048 // Access: Public, Virtual 00049 // Description: Writes the contents of this object to the datagram 00050 // for shipping out to a Bam file. 00051 //////////////////////////////////////////////////////////////////// 00052 void SheetNode::CData:: 00053 write_datagram(BamWriter *writer, Datagram &dg) const { 00054 // For now, we write a NULL pointer. Eventually we will write out 00055 // the NurbsSurfaceEvaluator pointer. 00056 writer->write_pointer(dg, (TypedWritable *)NULL); 00057 } 00058 00059 //////////////////////////////////////////////////////////////////// 00060 // Function: SheetNode::CData::fillin 00061 // Access: Public, Virtual 00062 // Description: This internal function is called by make_from_bam to 00063 // read in all of the relevant data from the BamFile for 00064 // the new SheetNode. 00065 //////////////////////////////////////////////////////////////////// 00066 void SheetNode::CData:: 00067 fillin(DatagramIterator &scan, BamReader *reader) { 00068 // For now, we skip over the NULL pointer that we wrote out. 00069 reader->skip_pointer(scan); 00070 _surface.clear(); 00071 } 00072 00073 //////////////////////////////////////////////////////////////////// 00074 // Function: SheetNode::Constructor 00075 // Access: Public 00076 // Description: 00077 //////////////////////////////////////////////////////////////////// 00078 SheetNode:: 00079 SheetNode(const string &name) : 00080 PandaNode(name) 00081 { 00082 set_cull_callback(); 00083 } 00084 00085 //////////////////////////////////////////////////////////////////// 00086 // Function: SheetNode::Copy Constructor 00087 // Access: Protected 00088 // Description: 00089 //////////////////////////////////////////////////////////////////// 00090 SheetNode:: 00091 SheetNode(const SheetNode ©) : 00092 PandaNode(copy), 00093 _cycler(copy._cycler) 00094 { 00095 } 00096 00097 //////////////////////////////////////////////////////////////////// 00098 // Function: SheetNode::make_copy 00099 // Access: Public, Virtual 00100 // Description: Returns a newly-allocated Node that is a shallow copy 00101 // of this one. It will be a different Node pointer, 00102 // but its internal data may or may not be shared with 00103 // that of the original Node. 00104 //////////////////////////////////////////////////////////////////// 00105 PandaNode *SheetNode:: 00106 make_copy() const { 00107 return new SheetNode(*this); 00108 } 00109 00110 //////////////////////////////////////////////////////////////////// 00111 // Function: SheetNode::safe_to_transform 00112 // Access: Public, Virtual 00113 // Description: Returns true if it is generally safe to transform 00114 // this particular kind of Node by calling the xform() 00115 // method, false otherwise. For instance, it's usually 00116 // a bad idea to attempt to xform a SheetNode. 00117 //////////////////////////////////////////////////////////////////// 00118 bool SheetNode:: 00119 safe_to_transform() const { 00120 return false; 00121 } 00122 00123 //////////////////////////////////////////////////////////////////// 00124 // Function: SheetNode::cull_callback 00125 // Access: Public, Virtual 00126 // Description: This function will be called during the cull 00127 // traversal to perform any additional operations that 00128 // should be performed at cull time. This may include 00129 // additional manipulation of render state or additional 00130 // visible/invisible decisions, or any other arbitrary 00131 // operation. 00132 // 00133 // Note that this function will *not* be called unless 00134 // set_cull_callback() is called in the constructor of 00135 // the derived class. It is necessary to call 00136 // set_cull_callback() to indicated that we require 00137 // cull_callback() to be called. 00138 // 00139 // By the time this function is called, the node has 00140 // already passed the bounding-volume test for the 00141 // viewing frustum, and the node's transform and state 00142 // have already been applied to the indicated 00143 // CullTraverserData object. 00144 // 00145 // The return value is true if this node should be 00146 // visible, or false if it should be culled. 00147 //////////////////////////////////////////////////////////////////// 00148 bool SheetNode:: 00149 cull_callback(CullTraverser *trav, CullTraverserData &data) { 00150 // Statistics 00151 PStatTimer timer(_sheet_node_pcollector); 00152 00153 // Create some geometry on-the-fly to render the sheet. 00154 if (get_num_u_subdiv() > 0 && get_num_v_subdiv() > 0) { 00155 NurbsSurfaceEvaluator *surface = get_surface(); 00156 if (surface != (NurbsSurfaceEvaluator *)NULL) { 00157 PT(NurbsSurfaceResult) result = surface->evaluate(data._node_path.get_node_path()); 00158 00159 if (result->get_num_u_segments() > 0 && result->get_num_v_segments() > 0) { 00160 render_sheet(trav, data, result); 00161 } 00162 } 00163 } 00164 00165 return true; 00166 } 00167 00168 //////////////////////////////////////////////////////////////////// 00169 // Function: SheetNode::is_renderable 00170 // Access: Public, Virtual 00171 // Description: Returns true if there is some value to visiting this 00172 // particular node during the cull traversal for any 00173 // camera, false otherwise. This will be used to 00174 // optimize the result of get_net_draw_show_mask(), so 00175 // that any subtrees that contain only nodes for which 00176 // is_renderable() is false need not be visited. 00177 //////////////////////////////////////////////////////////////////// 00178 bool SheetNode:: 00179 is_renderable() const { 00180 return true; 00181 } 00182 00183 //////////////////////////////////////////////////////////////////// 00184 // Function: SheetNode::output 00185 // Access: Public, Virtual 00186 // Description: 00187 //////////////////////////////////////////////////////////////////// 00188 void SheetNode:: 00189 output(ostream &out) const { 00190 PandaNode::output(out); 00191 NurbsSurfaceEvaluator *surface = get_surface(); 00192 if (surface != (NurbsSurfaceEvaluator *)NULL) { 00193 out << " " << *surface; 00194 } else { 00195 out << " (no surface)"; 00196 } 00197 } 00198 00199 //////////////////////////////////////////////////////////////////// 00200 // Function: SheetNode::write 00201 // Access: Public, Virtual 00202 // Description: 00203 //////////////////////////////////////////////////////////////////// 00204 void SheetNode:: 00205 write(ostream &out, int indent_level) const { 00206 PandaNode::write(out, indent_level); 00207 NurbsSurfaceEvaluator *surface = get_surface(); 00208 if (surface != (NurbsSurfaceEvaluator *)NULL) { 00209 indent(out, indent_level + 2) << *surface << "\n"; 00210 } else { 00211 indent(out, indent_level + 2) << "(no surface)\n"; 00212 } 00213 } 00214 00215 //////////////////////////////////////////////////////////////////// 00216 // Function: SheetNode::reset_bound 00217 // Access: Published 00218 // Description: Recomputes the bounding volume. This is normally 00219 // called automatically, but it must occasionally be 00220 // called explicitly when the surface has changed 00221 // properties outside of this node's knowledge. 00222 //////////////////////////////////////////////////////////////////// 00223 void SheetNode:: 00224 reset_bound(const NodePath &rel_to) { 00225 Thread *current_thread = Thread::get_current_thread(); 00226 int pipeline_stage = current_thread->get_pipeline_stage(); 00227 do_recompute_bounds(rel_to, pipeline_stage, current_thread); 00228 mark_internal_bounds_stale(current_thread); 00229 } 00230 00231 //////////////////////////////////////////////////////////////////// 00232 // Function: SheetNode::compute_internal_bounds 00233 // Access: Protected, Virtual 00234 // Description: Called when needed to recompute the node's 00235 // _internal_bound object. Nodes that contain anything 00236 // of substance should redefine this to do the right 00237 // thing. 00238 //////////////////////////////////////////////////////////////////// 00239 void SheetNode:: 00240 compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, 00241 int &internal_vertices, 00242 int pipeline_stage, 00243 Thread *current_thread) const { 00244 PT(BoundingVolume) bounds = 00245 do_recompute_bounds(NodePath((PandaNode *)this), pipeline_stage, 00246 current_thread); 00247 00248 internal_bounds = bounds; 00249 internal_vertices = 0; // TODO--estimate this better. 00250 } 00251 00252 //////////////////////////////////////////////////////////////////// 00253 // Function: SheetNode::do_recompute_bounds 00254 // Access: Private 00255 // Description: Does the actual internal recompute. 00256 //////////////////////////////////////////////////////////////////// 00257 PT(BoundingVolume) SheetNode:: 00258 do_recompute_bounds(const NodePath &rel_to, int pipeline_stage, 00259 Thread *current_thread) const { 00260 // TODO: fix the bounds so that it properly reflects the indicated 00261 // pipeline stage. At the moment, we cheat and get some of the 00262 // properties from the current pipeline stage, the lazy way. 00263 00264 // First, get ourselves a fresh, empty bounding volume. 00265 PT(BoundingVolume) bound = new BoundingSphere; 00266 00267 NurbsSurfaceEvaluator *surface = get_surface(); 00268 if (surface != (NurbsSurfaceEvaluator *)NULL) { 00269 NurbsSurfaceEvaluator::Vert3Array verts; 00270 get_surface()->get_vertices(verts, rel_to); 00271 00272 GeometricBoundingVolume *gbv; 00273 DCAST_INTO_R(gbv, bound, bound); 00274 gbv->around(&verts[0], &verts[0] + verts.size()); 00275 } 00276 return bound; 00277 } 00278 00279 //////////////////////////////////////////////////////////////////// 00280 // Function: SheetNode::render_sheet 00281 // Access: Private 00282 // Description: Draws the sheet as a series of tristrips along its 00283 // length. 00284 //////////////////////////////////////////////////////////////////// 00285 void SheetNode:: 00286 render_sheet(CullTraverser *trav, CullTraverserData &data, 00287 NurbsSurfaceResult *result) { 00288 bool use_vertex_color = get_use_vertex_color(); 00289 00290 int num_u_segments = result->get_num_u_segments(); 00291 int num_v_segments = result->get_num_v_segments(); 00292 int num_u_verts = get_num_u_subdiv() + 1; 00293 int num_v_verts = get_num_v_subdiv() + 1; 00294 00295 CPT(GeomVertexFormat) format; 00296 if (use_vertex_color) { 00297 format = GeomVertexFormat::get_v3n3cpt2(); 00298 } else { 00299 format = GeomVertexFormat::get_v3n3t2(); 00300 } 00301 PT(GeomVertexData) vdata = new GeomVertexData 00302 ("sheet", format, Geom::UH_stream); 00303 int expected_num_vertices = num_u_segments * (num_u_verts + 1) * num_v_segments * num_v_verts; 00304 vdata->reserve_num_rows(expected_num_vertices); 00305 00306 GeomVertexWriter vertex(vdata, InternalName::get_vertex()); 00307 GeomVertexWriter normal(vdata, InternalName::get_normal()); 00308 GeomVertexWriter color(vdata, InternalName::get_color()); 00309 GeomVertexWriter texcoord(vdata, InternalName::get_texcoord()); 00310 00311 for (int ui = 0; ui < num_u_segments; ui++) { 00312 for (int uni = 0; uni <= num_u_verts; uni++) { 00313 PN_stdfloat u0 = (PN_stdfloat)uni / (PN_stdfloat)num_u_verts; 00314 PN_stdfloat u0_tc = result->get_segment_u(ui, u0); 00315 00316 for (int vi = 0; vi < num_v_segments; vi++) { 00317 for (int vni = 0; vni < num_v_verts; vni++) { 00318 PN_stdfloat v = (PN_stdfloat)vni / (PN_stdfloat)(num_v_verts - 1); 00319 PN_stdfloat v_tc = result->get_segment_v(vi, v); 00320 00321 LPoint3 point; 00322 LVector3 norm; 00323 result->eval_segment_point(ui, vi, u0, v, point); 00324 result->eval_segment_normal(ui, vi, u0, v, norm); 00325 vertex.add_data3(point); 00326 normal.add_data3(norm); 00327 texcoord.add_data2(u0_tc, v_tc); 00328 00329 if (use_vertex_color) { 00330 LColor c0; 00331 result->eval_segment_extended_points(ui, vi, u0, v, 0, &c0[0], 4); 00332 color.add_data4(c0); 00333 } 00334 } 00335 } 00336 } 00337 } 00338 nassertv(vdata->get_num_rows() == expected_num_vertices); 00339 00340 PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_stream); 00341 00342 int expected_num_tristrips = num_u_segments * num_u_verts * num_v_segments; 00343 int expected_verts_per_tristrip = num_v_verts * 2; 00344 00345 int expected_prim_vertices = (expected_num_tristrips - 1) * (expected_verts_per_tristrip + strip->get_num_unused_vertices_per_primitive()) + expected_verts_per_tristrip; 00346 00347 strip->reserve_num_vertices(expected_prim_vertices); 00348 00349 int verts_per_row = num_v_segments * num_v_verts; 00350 00351 for (int ui = 0; ui < num_u_segments; ui++) { 00352 for (int uni = 0; uni < num_u_verts; uni++) { 00353 int row_start_index = ((ui * (num_u_verts + 1)) + uni) * verts_per_row; 00354 00355 for (int vi = 0; vi < num_v_segments; vi++) { 00356 for (int vni = 0; vni < num_v_verts; vni++) { 00357 int vert_index_0 = row_start_index + (vi * num_v_verts) + vni; 00358 int vert_index_1 = vert_index_0 + verts_per_row; 00359 strip->add_vertex(vert_index_0); 00360 strip->add_vertex(vert_index_1); 00361 } 00362 strip->close_primitive(); 00363 } 00364 } 00365 } 00366 nassertv(strip->get_num_vertices() == expected_prim_vertices); 00367 00368 PT(Geom) geom = new Geom(vdata); 00369 geom->add_primitive(strip); 00370 00371 CPT(RenderState) state = data._state; 00372 if (use_vertex_color) { 00373 state = state->add_attrib(ColorAttrib::make_vertex()); 00374 } 00375 00376 CullableObject *object = 00377 new CullableObject(geom, state, 00378 data.get_net_transform(trav), 00379 data.get_modelview_transform(trav), 00380 trav->get_gsg()); 00381 trav->get_cull_handler()->record_object(object, trav); 00382 } 00383 00384 //////////////////////////////////////////////////////////////////// 00385 // Function: SheetNode::register_with_read_factory 00386 // Access: Public, Static 00387 // Description: Tells the BamReader how to create objects of type 00388 // SheetNode. 00389 //////////////////////////////////////////////////////////////////// 00390 void SheetNode:: 00391 register_with_read_factory() { 00392 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); 00393 } 00394 00395 //////////////////////////////////////////////////////////////////// 00396 // Function: SheetNode::write_datagram 00397 // Access: Public, Virtual 00398 // Description: Writes the contents of this object to the datagram 00399 // for shipping out to a Bam file. 00400 //////////////////////////////////////////////////////////////////// 00401 void SheetNode:: 00402 write_datagram(BamWriter *manager, Datagram &dg) { 00403 PandaNode::write_datagram(manager, dg); 00404 manager->write_cdata(dg, _cycler); 00405 } 00406 00407 //////////////////////////////////////////////////////////////////// 00408 // Function: SheetNode::make_from_bam 00409 // Access: Protected, Static 00410 // Description: This function is called by the BamReader's factory 00411 // when a new object of type SheetNode is encountered 00412 // in the Bam file. It should create the SheetNode 00413 // and extract its information from the file. 00414 //////////////////////////////////////////////////////////////////// 00415 TypedWritable *SheetNode:: 00416 make_from_bam(const FactoryParams ¶ms) { 00417 SheetNode *node = new SheetNode(""); 00418 DatagramIterator scan; 00419 BamReader *manager; 00420 00421 parse_params(params, scan, manager); 00422 node->fillin(scan, manager); 00423 00424 return node; 00425 } 00426 00427 //////////////////////////////////////////////////////////////////// 00428 // Function: SheetNode::fillin 00429 // Access: Protected 00430 // Description: This internal function is called by make_from_bam to 00431 // read in all of the relevant data from the BamFile for 00432 // the new SheetNode. 00433 //////////////////////////////////////////////////////////////////// 00434 void SheetNode:: 00435 fillin(DatagramIterator &scan, BamReader *manager) { 00436 PandaNode::fillin(scan, manager); 00437 manager->read_cdata(scan, _cycler); 00438 }