Panda3D
 All Classes Functions Variables Enumerations
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 ////////////////////////////////////////////////////////////////////
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 }
void get_vertices(Vert4Array &verts, const NodePath &rel_to) const
Fills the indicated vector with the set of vertices in the surface, transformed to the given space...
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...
bool get_use_vertex_color() const
Returns the &quot;use vertex color&quot; flag.
Definition: sheetNode.I:89
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
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:122
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler)
Reads in the indicated CycleData object.
Definition: bamReader.cxx:747
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...
This defines a bounding sphere, consisting of a center and a radius.
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...
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 skip_pointer(DatagramIterator &scan)
Reads and discards a pointer value from the Bam file.
Definition: bamReader.cxx:709
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.
This collects together the pieces of data that are accumulated for each node while walking the scene ...
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
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
This class is an abstraction for evaluating NURBS surfaces.
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 ...
void add_vertex(int vertex)
Adds the indicated vertex to the list of vertex indices used by the graphics primitive type...
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 mark_internal_bounds_stale(Thread *current_thread=Thread::get_current_thread())
Should be called by a derived class to mark the internal bounding volume stale, so that compute_inter...
Definition: pandaNode.cxx:2467
This class draws a visible representation of the NURBS surface stored in its NurbsSurfaceEvaluator.
Definition: sheetNode.h:36
NurbsSurfaceEvaluator * get_surface() const
Returns the surface represented by the SheetNode.
Definition: sheetNode.I:61
The smallest atom of cull.
NodePath get_node_path() const
Constructs and returns an actual NodePath that represents the same path we have just traversed...
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
virtual PandaNode * make_copy() const
Returns a newly-allocated Node that is a shallow copy of this one.
Definition: sheetNode.cxx:106
CullHandler * get_cull_handler() const
Returns the object that will receive the culled Geoms.
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.
int get_num_u_segments() const
Returns the number of piecewise continuous segments within the surface in the U direction.
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
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 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_subdiv() const
Returns the number of subdivisions per cubic segment to draw in the U direction.
Definition: sheetNode.I:116
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
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
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
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
int get_num_v_segments() const
Returns the number of piecewise continuous segments within the surface in the V direction.
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
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 write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
Definition: bamWriter.cxx:279
int get_pipeline_stage() const
Returns the Pipeline stage number associated with this thread.
Definition: thread.I:84