Panda3D
sheetNode.cxx
1 // Filename: sheetNode.cxx
2 // Created by: drose (11Oct03)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "sheetNode.h"
16 #include "cullTraverser.h"
17 #include "cullTraverserData.h"
18 #include "cullableObject.h"
19 #include "cullHandler.h"
20 #include "bamWriter.h"
21 #include "bamReader.h"
22 #include "datagram.h"
23 #include "datagramIterator.h"
24 #include "pStatTimer.h"
25 #include "geom.h"
26 #include "geomTristrips.h"
27 #include "geomVertexWriter.h"
28 #include "boundingSphere.h"
29 #include "colorAttrib.h"
30 #include "renderState.h"
31 
32 TypeHandle SheetNode::_type_handle;
33 
34 PStatCollector SheetNode::_sheet_node_pcollector("*:SheetNode");
35 
36 ////////////////////////////////////////////////////////////////////
37 // Function: SheetNode::CData::make_copy
38 // Access: Public, Virtual
39 // Description:
40 ////////////////////////////////////////////////////////////////////
41 CycleData *SheetNode::CData::
42 make_copy() const {
43  return new CData(*this);
44 }
45 
46 ////////////////////////////////////////////////////////////////////
47 // Function: SheetNode::CData::write_datagram
48 // Access: Public, Virtual
49 // Description: Writes the contents of this object to the datagram
50 // for shipping out to a Bam file.
51 ////////////////////////////////////////////////////////////////////
52 void SheetNode::CData::
53 write_datagram(BamWriter *writer, Datagram &dg) const {
54  // For now, we write a NULL pointer. Eventually we will write out
55  // the NurbsSurfaceEvaluator pointer.
56  writer->write_pointer(dg, (TypedWritable *)NULL);
57 }
58 
59 ////////////////////////////////////////////////////////////////////
60 // Function: SheetNode::CData::fillin
61 // Access: Public, Virtual
62 // Description: This internal function is called by make_from_bam to
63 // read in all of the relevant data from the BamFile for
64 // the new SheetNode.
65 ////////////////////////////////////////////////////////////////////
66 void SheetNode::CData::
67 fillin(DatagramIterator &scan, BamReader *reader) {
68  // For now, we skip over the NULL pointer that we wrote out.
69  reader->skip_pointer(scan);
70  _surface.clear();
71 }
72 
73 ////////////////////////////////////////////////////////////////////
74 // Function: SheetNode::Constructor
75 // Access: Public
76 // Description:
77 ////////////////////////////////////////////////////////////////////
78 SheetNode::
79 SheetNode(const string &name) :
80  PandaNode(name)
81 {
82  set_cull_callback();
83 }
84 
85 ////////////////////////////////////////////////////////////////////
86 // Function: SheetNode::Copy Constructor
87 // Access: Protected
88 // Description:
89 ////////////////////////////////////////////////////////////////////
90 SheetNode::
91 SheetNode(const SheetNode &copy) :
92  PandaNode(copy),
93  _cycler(copy._cycler)
94 {
95 }
96 
97 ////////////////////////////////////////////////////////////////////
98 // Function: SheetNode::make_copy
99 // Access: Public, Virtual
100 // Description: Returns a newly-allocated Node that is a shallow copy
101 // of this one. It will be a different Node pointer,
102 // but its internal data may or may not be shared with
103 // that of the original Node.
104 ////////////////////////////////////////////////////////////////////
106 make_copy() const {
107  return new SheetNode(*this);
108 }
109 
110 ////////////////////////////////////////////////////////////////////
111 // Function: SheetNode::safe_to_transform
112 // Access: Public, Virtual
113 // Description: Returns true if it is generally safe to transform
114 // this particular kind of Node by calling the xform()
115 // method, false otherwise. For instance, it's usually
116 // a bad idea to attempt to xform a SheetNode.
117 ////////////////////////////////////////////////////////////////////
118 bool SheetNode::
120  return false;
121 }
122 
123 ////////////////////////////////////////////////////////////////////
124 // Function: SheetNode::cull_callback
125 // Access: Public, Virtual
126 // Description: This function will be called during the cull
127 // traversal to perform any additional operations that
128 // should be performed at cull time. This may include
129 // additional manipulation of render state or additional
130 // visible/invisible decisions, or any other arbitrary
131 // operation.
132 //
133 // Note that this function will *not* be called unless
134 // set_cull_callback() is called in the constructor of
135 // the derived class. It is necessary to call
136 // set_cull_callback() to indicated that we require
137 // cull_callback() to be called.
138 //
139 // By the time this function is called, the node has
140 // already passed the bounding-volume test for the
141 // viewing frustum, and the node's transform and state
142 // have already been applied to the indicated
143 // CullTraverserData object.
144 //
145 // The return value is true if this node should be
146 // visible, or false if it should be culled.
147 ////////////////////////////////////////////////////////////////////
148 bool SheetNode::
150  // Statistics
151  PStatTimer timer(_sheet_node_pcollector);
152 
153  // Create some geometry on-the-fly to render the sheet.
154  if (get_num_u_subdiv() > 0 && get_num_v_subdiv() > 0) {
155  NurbsSurfaceEvaluator *surface = get_surface();
156  if (surface != (NurbsSurfaceEvaluator *)NULL) {
157  PT(NurbsSurfaceResult) result = surface->evaluate(data._node_path.get_node_path());
158 
159  if (result->get_num_u_segments() > 0 && result->get_num_v_segments() > 0) {
160  render_sheet(trav, data, result);
161  }
162  }
163  }
164 
165  return true;
166 }
167 
168 ////////////////////////////////////////////////////////////////////
169 // Function: SheetNode::is_renderable
170 // Access: Public, Virtual
171 // Description: Returns true if there is some value to visiting this
172 // particular node during the cull traversal for any
173 // camera, false otherwise. This will be used to
174 // optimize the result of get_net_draw_show_mask(), so
175 // that any subtrees that contain only nodes for which
176 // is_renderable() is false need not be visited.
177 ////////////////////////////////////////////////////////////////////
178 bool SheetNode::
179 is_renderable() const {
180  return true;
181 }
182 
183 ////////////////////////////////////////////////////////////////////
184 // Function: SheetNode::output
185 // Access: Public, Virtual
186 // Description:
187 ////////////////////////////////////////////////////////////////////
188 void SheetNode::
189 output(ostream &out) const {
190  PandaNode::output(out);
191  NurbsSurfaceEvaluator *surface = get_surface();
192  if (surface != (NurbsSurfaceEvaluator *)NULL) {
193  out << " " << *surface;
194  } else {
195  out << " (no surface)";
196  }
197 }
198 
199 ////////////////////////////////////////////////////////////////////
200 // Function: SheetNode::write
201 // Access: Public, Virtual
202 // Description:
203 ////////////////////////////////////////////////////////////////////
204 void SheetNode::
205 write(ostream &out, int indent_level) const {
206  PandaNode::write(out, indent_level);
207  NurbsSurfaceEvaluator *surface = get_surface();
208  if (surface != (NurbsSurfaceEvaluator *)NULL) {
209  indent(out, indent_level + 2) << *surface << "\n";
210  } else {
211  indent(out, indent_level + 2) << "(no surface)\n";
212  }
213 }
214 
215 ////////////////////////////////////////////////////////////////////
216 // Function: SheetNode::reset_bound
217 // Access: Published
218 // Description: Recomputes the bounding volume. This is normally
219 // called automatically, but it must occasionally be
220 // called explicitly when the surface has changed
221 // properties outside of this node's knowledge.
222 ////////////////////////////////////////////////////////////////////
223 void SheetNode::
224 reset_bound(const NodePath &rel_to) {
225  Thread *current_thread = Thread::get_current_thread();
226  int pipeline_stage = current_thread->get_pipeline_stage();
227  do_recompute_bounds(rel_to, pipeline_stage, current_thread);
228  mark_internal_bounds_stale(current_thread);
229 }
230 
231 ////////////////////////////////////////////////////////////////////
232 // Function: SheetNode::compute_internal_bounds
233 // Access: Protected, Virtual
234 // Description: Called when needed to recompute the node's
235 // _internal_bound object. Nodes that contain anything
236 // of substance should redefine this to do the right
237 // thing.
238 ////////////////////////////////////////////////////////////////////
239 void SheetNode::
240 compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
241  int &internal_vertices,
242  int pipeline_stage,
243  Thread *current_thread) const {
244  PT(BoundingVolume) bounds =
245  do_recompute_bounds(NodePath((PandaNode *)this), pipeline_stage,
246  current_thread);
247 
248  internal_bounds = bounds;
249  internal_vertices = 0; // TODO--estimate this better.
250 }
251 
252 ////////////////////////////////////////////////////////////////////
253 // Function: SheetNode::do_recompute_bounds
254 // Access: Private
255 // Description: Does the actual internal recompute.
256 ////////////////////////////////////////////////////////////////////
257 PT(BoundingVolume) SheetNode::
258 do_recompute_bounds(const NodePath &rel_to, int pipeline_stage,
259  Thread *current_thread) const {
260  // TODO: fix the bounds so that it properly reflects the indicated
261  // pipeline stage. At the moment, we cheat and get some of the
262  // properties from the current pipeline stage, the lazy way.
263 
264  // First, get ourselves a fresh, empty bounding volume.
265  PT(BoundingVolume) bound = new BoundingSphere;
266 
267  NurbsSurfaceEvaluator *surface = get_surface();
268  if (surface != (NurbsSurfaceEvaluator *)NULL) {
270  get_surface()->get_vertices(verts, rel_to);
271 
273  DCAST_INTO_R(gbv, bound, bound);
274  gbv->around(&verts[0], &verts[0] + verts.size());
275  }
276  return bound;
277 }
278 
279 ////////////////////////////////////////////////////////////////////
280 // Function: SheetNode::render_sheet
281 // Access: Private
282 // Description: Draws the sheet as a series of tristrips along its
283 // length.
284 ////////////////////////////////////////////////////////////////////
285 void SheetNode::
286 render_sheet(CullTraverser *trav, CullTraverserData &data,
287  NurbsSurfaceResult *result) {
288  bool use_vertex_color = get_use_vertex_color();
289 
290  int num_u_segments = result->get_num_u_segments();
291  int num_v_segments = result->get_num_v_segments();
292  int num_u_verts = get_num_u_subdiv() + 1;
293  int num_v_verts = get_num_v_subdiv() + 1;
294 
295  CPT(GeomVertexFormat) format;
296  if (use_vertex_color) {
297  format = GeomVertexFormat::get_v3n3cpt2();
298  } else {
299  format = GeomVertexFormat::get_v3n3t2();
300  }
301  PT(GeomVertexData) vdata = new GeomVertexData
302  ("sheet", format, Geom::UH_stream);
303  int expected_num_vertices = num_u_segments * (num_u_verts + 1) * num_v_segments * num_v_verts;
304  vdata->reserve_num_rows(expected_num_vertices);
305 
306  GeomVertexWriter vertex(vdata, InternalName::get_vertex());
307  GeomVertexWriter normal(vdata, InternalName::get_normal());
308  GeomVertexWriter color(vdata, InternalName::get_color());
309  GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
310 
311  for (int ui = 0; ui < num_u_segments; ui++) {
312  for (int uni = 0; uni <= num_u_verts; uni++) {
313  PN_stdfloat u0 = (PN_stdfloat)uni / (PN_stdfloat)num_u_verts;
314  PN_stdfloat u0_tc = result->get_segment_u(ui, u0);
315 
316  for (int vi = 0; vi < num_v_segments; vi++) {
317  for (int vni = 0; vni < num_v_verts; vni++) {
318  PN_stdfloat v = (PN_stdfloat)vni / (PN_stdfloat)(num_v_verts - 1);
319  PN_stdfloat v_tc = result->get_segment_v(vi, v);
320 
321  LPoint3 point;
322  LVector3 norm;
323  result->eval_segment_point(ui, vi, u0, v, point);
324  result->eval_segment_normal(ui, vi, u0, v, norm);
325  vertex.add_data3(point);
326  normal.add_data3(norm);
327  texcoord.add_data2(u0_tc, v_tc);
328 
329  if (use_vertex_color) {
330  LColor c0;
331  result->eval_segment_extended_points(ui, vi, u0, v, 0, &c0[0], 4);
332  color.add_data4(c0);
333  }
334  }
335  }
336  }
337  }
338  nassertv(vdata->get_num_rows() == expected_num_vertices);
339 
340  PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_stream);
341 
342  int expected_num_tristrips = num_u_segments * num_u_verts * num_v_segments;
343  int expected_verts_per_tristrip = num_v_verts * 2;
344 
345  int expected_prim_vertices = (expected_num_tristrips - 1) * (expected_verts_per_tristrip + strip->get_num_unused_vertices_per_primitive()) + expected_verts_per_tristrip;
346 
347  strip->reserve_num_vertices(expected_prim_vertices);
348 
349  int verts_per_row = num_v_segments * num_v_verts;
350 
351  for (int ui = 0; ui < num_u_segments; ui++) {
352  for (int uni = 0; uni < num_u_verts; uni++) {
353  int row_start_index = ((ui * (num_u_verts + 1)) + uni) * verts_per_row;
354 
355  for (int vi = 0; vi < num_v_segments; vi++) {
356  for (int vni = 0; vni < num_v_verts; vni++) {
357  int vert_index_0 = row_start_index + (vi * num_v_verts) + vni;
358  int vert_index_1 = vert_index_0 + verts_per_row;
359  strip->add_vertex(vert_index_0);
360  strip->add_vertex(vert_index_1);
361  }
362  strip->close_primitive();
363  }
364  }
365  }
366  nassertv(strip->get_num_vertices() == expected_prim_vertices);
367 
368  PT(Geom) geom = new Geom(vdata);
369  geom->add_primitive(strip);
370 
371  CPT(RenderState) state = data._state;
372  if (use_vertex_color) {
373  state = state->add_attrib(ColorAttrib::make_vertex());
374  }
375 
376  CullableObject *object =
377  new CullableObject(geom, state,
378  data.get_internal_transform(trav));
379  trav->get_cull_handler()->record_object(object, trav);
380 }
381 
382 ////////////////////////////////////////////////////////////////////
383 // Function: SheetNode::register_with_read_factory
384 // Access: Public, Static
385 // Description: Tells the BamReader how to create objects of type
386 // SheetNode.
387 ////////////////////////////////////////////////////////////////////
388 void SheetNode::
390  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
391 }
392 
393 ////////////////////////////////////////////////////////////////////
394 // Function: SheetNode::write_datagram
395 // Access: Public, Virtual
396 // Description: Writes the contents of this object to the datagram
397 // for shipping out to a Bam file.
398 ////////////////////////////////////////////////////////////////////
399 void SheetNode::
401  PandaNode::write_datagram(manager, dg);
402  manager->write_cdata(dg, _cycler);
403 }
404 
405 ////////////////////////////////////////////////////////////////////
406 // Function: SheetNode::make_from_bam
407 // Access: Protected, Static
408 // Description: This function is called by the BamReader's factory
409 // when a new object of type SheetNode is encountered
410 // in the Bam file. It should create the SheetNode
411 // and extract its information from the file.
412 ////////////////////////////////////////////////////////////////////
413 TypedWritable *SheetNode::
414 make_from_bam(const FactoryParams &params) {
415  SheetNode *node = new SheetNode("");
416  DatagramIterator scan;
417  BamReader *manager;
418 
419  parse_params(params, scan, manager);
420  node->fillin(scan, manager);
421 
422  return node;
423 }
424 
425 ////////////////////////////////////////////////////////////////////
426 // Function: SheetNode::fillin
427 // Access: Protected
428 // Description: This internal function is called by make_from_bam to
429 // read in all of the relevant data from the BamFile for
430 // the new SheetNode.
431 ////////////////////////////////////////////////////////////////////
432 void SheetNode::
433 fillin(DatagramIterator &scan, BamReader *manager) {
434  PandaNode::fillin(scan, manager);
435  manager->read_cdata(scan, _cycler);
436 }
virtual bool safe_to_transform() const
Returns true if it is generally safe to transform this particular kind of Node by calling the xform()...
Definition: sheetNode.cxx:119
A basic node of the scene graph or data graph.
Definition: pandaNode.h:72
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
CullHandler * get_cull_handler() const
Returns the object that will receive the culled Geoms.
PN_stdfloat get_segment_v(int vi, PN_stdfloat v) const
Accepts a v value in the range [0, 1], and assumed to be relative to the indicated segment (as in eva...
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: pandaNode.cxx:4164
virtual PandaNode * make_copy() const
Returns a newly-allocated Node that is a shallow copy of this one.
Definition: sheetNode.cxx:106
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:122
int get_pipeline_stage() const
Returns the Pipeline stage number associated with this thread.
Definition: thread.I:84
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler)
Reads in the indicated CycleData object.
Definition: bamReader.cxx:753
This defines a bounding sphere, consisting of a center and a radius.
A single page of data maintained by a PipelineCycler.
Definition: cycleData.h:50
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:37
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler)
Writes out the indicated CycleData object.
Definition: bamWriter.cxx:398
void add_data2(PN_stdfloat x, PN_stdfloat y)
Sets the write row to a particular 2-component value, and advances the write row. ...
void skip_pointer(DatagramIterator &scan)
Reads and discards a pointer value from the Bam file.
Definition: bamReader.cxx:715
int get_num_u_subdiv() const
Returns the number of subdivisions per cubic segment to draw in the U direction.
Definition: sheetNode.I:116
This collects together the pieces of data that are accumulated for each node while walking the scene ...
NurbsSurfaceEvaluator * get_surface() const
Returns the surface represented by the SheetNode.
Definition: sheetNode.I:61
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
Definition: lvector3.h:100
Defines a series of triangle strips.
Definition: geomTristrips.h:25
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:34
PN_stdfloat get_segment_u(int ui, PN_stdfloat u) const
Accepts a u value in the range [0, 1], and assumed to be relative to the indicated segment (as in eva...
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
Definition: lpoint3.h:99
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:73
int get_num_v_segments() const
Returns the number of piecewise continuous segments within the surface in the V direction.
This class is an abstraction for evaluating NURBS surfaces.
void add_data4(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z, PN_stdfloat w)
Sets the write row to a particular 4-component value, and advances the write row. ...
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data)
This function will be called during the cull traversal to perform any additional operations that shou...
Definition: sheetNode.cxx:149
static Thread * get_current_thread()
Returns a pointer to the currently-executing Thread object.
Definition: thread.I:145
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
A lightweight class that represents a single element that may be timed and/or counted via stats...
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
NodePath get_node_path() const
Constructs and returns an actual NodePath that represents the same path we have just traversed...
This class draws a visible representation of the NURBS surface stored in its NurbsSurfaceEvaluator.
Definition: sheetNode.h:36
The smallest atom of cull.
virtual void record_object(CullableObject *object, const CullTraverser *traverser)
This callback function is intended to be overridden by a derived class.
Definition: cullHandler.cxx:52
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: sheetNode.cxx:400
The result of a NurbsSurfaceEvaluator.
A container for geometry primitives.
Definition: geom.h:58
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:40
void add_data3(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Sets the write row to a particular 3-component value, and advances the write row. ...
void eval_segment_point(int ui, int vi, PN_stdfloat u, PN_stdfloat v, LVecBase3 &point) const
Evaluates the point on the surface corresponding to the indicated value in parametric time within the...
int get_num_u_segments() const
Returns the number of piecewise continuous segments within the surface in the U direction.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:53
void register_factory(TypeHandle handle, CreateFunc *func)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:90
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:213
void eval_segment_normal(int ui, int vi, PN_stdfloat u, PN_stdfloat v, LVecBase3 &normal) const
As eval_segment_point, but computes the normal to the surface at the indicated point.
static void register_with_read_factory()
Tells the BamReader how to create objects of type SheetNode.
Definition: sheetNode.cxx:389
A thread; that is, a lightweight process.
Definition: thread.h:51
virtual bool is_renderable() const
Returns true if there is some value to visiting this particular node during the cull traversal for an...
Definition: sheetNode.cxx:179
A class to retrieve the individual data elements previously stored in a Datagram. ...
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
int get_num_v_subdiv() const
Returns the number of subdivisions per cubic segment to draw in the V direction.
Definition: sheetNode.I:143
void reset_bound(const NodePath &rel_to)
Recomputes the bounding volume.
Definition: sheetNode.cxx:224
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:43
bool around(const GeometricBoundingVolume **first, const GeometricBoundingVolume **last)
Resets the volume to enclose only the volumes indicated.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:165
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling...
Definition: cullTraverser.h:48
void eval_segment_extended_points(int ui, int vi, PN_stdfloat u, PN_stdfloat v, int d, PN_stdfloat result[], int num_values) const
Simultaneously performs eval_extended_point on a contiguous sequence of dimensions.
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
Definition: bamWriter.cxx:279
bool get_use_vertex_color() const
Returns the "use vertex color" flag.
Definition: sheetNode.I:89