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