Panda3D
occluderNode.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 occluderNode.cxx
10  * @author jenes
11  * @date 2011-03-11
12  */
13 
14 #include "occluderNode.h"
15 
16 #include "geomNode.h"
17 #include "cullTraverserData.h"
18 #include "cullTraverser.h"
19 #include "renderState.h"
20 #include "plane.h"
21 #include "pnmImage.h"
22 #include "textureAttrib.h"
23 #include "colorAttrib.h"
24 #include "depthOffsetAttrib.h"
25 #include "cullFaceAttrib.h"
26 #include "transparencyAttrib.h"
27 #include "transformState.h"
28 #include "cullableObject.h"
29 #include "cullHandler.h"
30 #include "boundingSphere.h"
31 #include "geomVertexData.h"
32 #include "geomTriangles.h"
33 #include "geomLinestrips.h"
34 #include "geomVertexWriter.h"
35 #include "geom.h"
36 #include "datagram.h"
37 #include "datagramIterator.h"
38 #include "bamReader.h"
39 #include "bamWriter.h"
40 
41 #include "plane.h"
42 
43 TypeHandle OccluderNode::_type_handle;
44 PT(Texture) OccluderNode::_viz_tex;
45 
46 
47 /**
48  * The default constructor creates a default occlusion polygon in the XZ plane
49  * (or XY plane in a y-up coordinate system). Use the normal Panda set_pos(),
50  * set_hpr(), set_scale() to position it appropriately, or replace the
51  * vertices with set_vertices().
52  */
53 OccluderNode::
54 OccluderNode(const std::string &name) :
55  PandaNode(name)
56 {
57  set_cull_callback();
58  // OccluderNodes are hidden by default.
59  set_overall_hidden(true);
60  set_double_sided(false);
61  set_min_coverage(0.0);
62  set_vertices(LPoint3::rfu(-1.0, 0.0, -1.0),
63  LPoint3::rfu(1.0, 0.0, -1.0),
64  LPoint3::rfu(1.0, 0.0, 1.0),
65  LPoint3::rfu(-1.0, 0.0, 1.0));
66 }
67 
68 /**
69  *
70  */
71 OccluderNode::
72 OccluderNode(const OccluderNode &copy) :
73  PandaNode(copy),
74  _double_sided(copy._double_sided),
75  _min_coverage(copy._min_coverage),
76  _vertices(copy._vertices)
77 {
78 }
79 
80 /**
81  *
82  */
83 OccluderNode::
84 ~OccluderNode() {
85 }
86 
87 /**
88  * Returns a newly-allocated Node that is a shallow copy of this one. It will
89  * be a different Node pointer, but its internal data may or may not be shared
90  * with that of the original Node.
91  */
93 make_copy() const {
94  return new OccluderNode(*this);
95 }
96 
97 /**
98  * Returns true if the node's name has extrinsic meaning and must be preserved
99  * across a flatten operation, false otherwise.
100  */
101 bool OccluderNode::
102 preserve_name() const {
103  return true;
104 }
105 
106 /**
107  * Transforms the contents of this node by the indicated matrix, if it means
108  * anything to do so. For most kinds of nodes, this does nothing.
109  */
110 void OccluderNode::
111 xform(const LMatrix4 &mat) {
112  nassertv(!mat.is_nan());
113 
114  for (Vertices::iterator vi = _vertices.begin();
115  vi != _vertices.end();
116  ++vi) {
117  (*vi) = (*vi) * mat;
118  }
119 }
120 
121 /**
122  * This function will be called during the cull traversal to perform any
123  * additional operations that should be performed at cull time. This may
124  * include additional manipulation of render state or additional
125  * visible/invisible decisions, or any other arbitrary operation.
126  *
127  * Note that this function will *not* be called unless set_cull_callback() is
128  * called in the constructor of the derived class. It is necessary to call
129  * set_cull_callback() to indicated that we require cull_callback() to be
130  * called.
131  *
132  * By the time this function is called, the node has already passed the
133  * bounding-volume test for the viewing frustum, and the node's transform and
134  * state have already been applied to the indicated CullTraverserData object.
135  *
136  * The return value is true if this node should be visible, or false if it
137  * should be culled.
138  */
139 bool OccluderNode::
141  // Normally, an OccluderNode is invisible. But if someone shows it, we will
142  // draw a visualization, a checkerboard-textured polygon.
143  CullableObject *occluder_viz =
144  new CullableObject(get_occluder_viz(trav, data), get_occluder_viz_state(trav, data),
145  data.get_internal_transform(trav));
146  trav->get_cull_handler()->record_object(occluder_viz, trav);
147 
148  // Also get the frame.
149  nassertr(_frame_viz != nullptr, false);
150  CullableObject *frame_viz =
151  new CullableObject(_frame_viz, get_frame_viz_state(trav, data),
152  data.get_internal_transform(trav));
153  trav->get_cull_handler()->record_object(frame_viz, trav);
154 
155  // Now carry on to render our child nodes.
156  return true;
157 }
158 
159 /**
160  * Returns true if there is some value to visiting this particular node during
161  * the cull traversal for any camera, false otherwise. This will be used to
162  * optimize the result of get_net_draw_show_mask(), so that any subtrees that
163  * contain only nodes for which is_renderable() is false need not be visited.
164  */
165 bool OccluderNode::
166 is_renderable() const {
167  return true;
168 }
169 
170 
171 /**
172  * Writes a brief description of the node to the indicated output stream.
173  * This is invoked by the << operator. It may be overridden in derived
174  * classes to include some information relevant to the class.
175  */
176 void OccluderNode::
177 output(std::ostream &out) const {
178  PandaNode::output(out);
179 }
180 
181 /**
182  * Called when needed to recompute the node's _internal_bound object. Nodes
183  * that contain anything of substance should redefine this to do the right
184  * thing.
185  */
186 void OccluderNode::
187 compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
188  int &internal_vertices,
189  int pipeline_stage,
190  Thread *current_thread) const {
191  // First, get ourselves a fresh, empty bounding volume.
192  PT(BoundingVolume) bound = new BoundingSphere;
194 
195  // Now actually compute the bounding volume by putting it around all of our
196  // vertices.
197  if (!_vertices.empty()) {
198  const LPoint3 *vertices_begin = &_vertices[0];
199  const LPoint3 *vertices_end = vertices_begin + _vertices.size();
200  gbv->around(vertices_begin, vertices_end);
201  }
202 
203  internal_bounds = bound;
204  internal_vertices = 0;
205 }
206 
207 /**
208  * Returns a Geom that represents the visualization of the OccluderNode, as
209  * seen from the front.
210  */
211 PT(Geom) OccluderNode::
212 get_occluder_viz(CullTraverser *trav, CullTraverserData &data) {
213  if (_occluder_viz == nullptr) {
214  nassertr(_vertices.size() == 4, nullptr);
215 
216  if (pgraph_cat.is_debug()) {
217  pgraph_cat.debug()
218  << "Recomputing viz for " << *this << "\n";
219  }
220 
221  PT(GeomVertexData) vdata = new GeomVertexData
222  (get_name(), GeomVertexFormat::get_v3n3t2(), Geom::UH_static);
223 
224  // Compute the polygon normal from the first three vertices.
225  LPlane plane(_vertices[0], _vertices[1], _vertices[2]);
226  LVector3 poly_normal = plane.get_normal();
227 
228  GeomVertexWriter vertex(vdata, InternalName::get_vertex());
229  GeomVertexWriter normal(vdata, InternalName::get_normal());
230  GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
231  vertex.add_data3(_vertices[0]);
232  normal.add_data3(poly_normal);
233  texcoord.add_data2(0.0, 0.0);
234 
235  vertex.add_data3(_vertices[1]);
236  normal.add_data3(poly_normal);
237  texcoord.add_data2(8.0, 0.0);
238 
239  vertex.add_data3(_vertices[2]);
240  normal.add_data3(poly_normal);
241  texcoord.add_data2(8.0, 8.0);
242 
243  vertex.add_data3(_vertices[3]);
244  normal.add_data3(poly_normal);
245  texcoord.add_data2(0.0, 8.0);
246 
247  PT(GeomTriangles) triangles = new GeomTriangles(Geom::UH_static);
248  triangles->add_vertices(0, 1, 2);
249  triangles->close_primitive();
250  triangles->add_vertices(0, 2, 3);
251  triangles->close_primitive();
252 
253  _occluder_viz = new Geom(vdata);
254  _occluder_viz->add_primitive(triangles);
255 
256  PT(GeomLinestrips) lines = new GeomLinestrips(Geom::UH_static);
257  lines->add_vertices(0, 1, 2, 3);
258  lines->add_vertex(0);
259  lines->close_primitive();
260 
261  _frame_viz = new Geom(vdata);
262  _frame_viz->add_primitive(lines);
263  }
264 
265  return _occluder_viz;
266 }
267 
268 /**
269  * Returns the RenderState to apply to the visualization.
270  */
271 CPT(RenderState) OccluderNode::
272 get_occluder_viz_state(CullTraverser *trav, CullTraverserData &data) {
273  if (_viz_tex == nullptr) {
274  // Create a default texture. We set it up as a 2x2 graytone checkerboard,
275  // since that's real easy, and it doesn't look like a CollisionPolygon.
276  _viz_tex = new Texture("occluder_viz");
277  _viz_tex->setup_2d_texture(2, 2, Texture::T_unsigned_byte, Texture::F_luminance);
278  PTA_uchar image;
279  image.set_data("\x20\x80\x80\x20");
280  _viz_tex->set_ram_image(image);
281  _viz_tex->set_minfilter(SamplerState::FT_nearest);
282  _viz_tex->set_magfilter(SamplerState::FT_nearest);
283  }
284 
285  static CPT(RenderState) viz_state;
286  if (viz_state == nullptr) {
287  viz_state = RenderState::make
288  (ColorAttrib::make_flat(LVecBase4(1.0f, 1.0f, 1.0f, 0.5f)),
289  TransparencyAttrib::make(TransparencyAttrib::M_alpha),
290  DepthOffsetAttrib::make(),
291  TextureAttrib::make(_viz_tex));
292  viz_state = viz_state->adjust_all_priorities(1);
293  }
294 
295  CPT(RenderState) state = viz_state;
296  if (is_double_sided()) {
297  state = viz_state->set_attrib(CullFaceAttrib::make(CullFaceAttrib::M_cull_none), 1);
298  } else {
299  state = viz_state->set_attrib(CullFaceAttrib::make(CullFaceAttrib::M_cull_clockwise), 1);
300  }
301 
302  return state->compose(viz_state);
303 }
304 
305 /**
306  * Returns the RenderState to apply to the frame.
307  */
308 CPT(RenderState) OccluderNode::
309 get_frame_viz_state(CullTraverser *trav, CullTraverserData &data) {
310  static CPT(RenderState) viz_state;
311  if (viz_state == nullptr) {
312  viz_state = RenderState::make
313  (ColorAttrib::make_flat(LVecBase4(0.0f, 0.0f, 0.0f, 1.0f)),
314  TextureAttrib::make_off());
315  viz_state = viz_state->adjust_all_priorities(1);
316  }
317 
318  return data._state->compose(viz_state);
319 }
320 
321 /**
322  * Tells the BamReader how to create objects of type OccluderNode.
323  */
324 void OccluderNode::
326  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
327 }
328 
329 /**
330  * Writes the contents of this object to the datagram for shipping out to a
331  * Bam file.
332  */
333 void OccluderNode::
335  PandaNode::write_datagram(manager, dg);
336 
337  dg.add_uint16(_vertices.size());
338  for (Vertices::const_iterator vi = _vertices.begin();
339  vi != _vertices.end();
340  ++vi) {
341  (*vi).write_datagram(dg);
342  }
343 }
344 
345 /**
346  * Receives an array of pointers, one for each time manager->read_pointer()
347  * was called in fillin(). Returns the number of pointers processed.
348  */
349 int OccluderNode::
351  int pi = PandaNode::complete_pointers(p_list, manager);
352 
353  return pi;
354 }
355 
356 /**
357  * This function is called by the BamReader's factory when a new object of
358  * type OccluderNode is encountered in the Bam file. It should create the
359  * OccluderNode and extract its information from the file.
360  */
361 TypedWritable *OccluderNode::
362 make_from_bam(const FactoryParams &params) {
363  OccluderNode *node = new OccluderNode("");
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 OccluderNode.
376  */
377 void OccluderNode::
378 fillin(DatagramIterator &scan, BamReader *manager) {
379  PandaNode::fillin(scan, manager);
380 
381  int num_vertices = scan.get_uint16();
382  _vertices.clear();
383  _vertices.reserve(num_vertices);
384  for (int i = 0; i < num_vertices; i++) {
385  LPoint3 vertex;
386  vertex.read_datagram(scan);
387  _vertices.push_back(vertex);
388  }
389 }
GeomVertexFormat::get_v3n3t2
static const GeomVertexFormat * get_v3n3t2()
Returns a standard vertex format with a 2-component texture coordinate pair, a 3-component normal,...
Definition: geomVertexFormat.I:278
Geom
A container for geometry primitives.
Definition: geom.h:54
geomVertexData.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
cullTraverser.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
geomVertexWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
occluderNode.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
DatagramIterator::get_uint16
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
Definition: datagramIterator.I:145
CullableObject
The smallest atom of cull.
Definition: cullableObject.h:41
GeomVertexData
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
Definition: geomVertexData.h:68
BoundingSphere
This defines a bounding sphere, consisting of a center and a radius.
Definition: boundingSphere.h:25
OccluderNode::preserve_name
virtual bool preserve_name() const
Returns true if the node's name has extrinsic meaning and must be preserved across a flatten operatio...
Definition: occluderNode.cxx:102
OccluderNode::write_datagram
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: occluderNode.cxx:334
pnmImage.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
DatagramIterator
A class to retrieve the individual data elements previously stored in a Datagram.
Definition: datagramIterator.h:27
cullableObject.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypedWritable::complete_pointers
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
Definition: typedWritable.cxx:81
BamReader
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
OccluderNode
A node in the scene graph that can hold an occluder polygon, which must be a rectangle.
Definition: occluderNode.h:31
GeomVertexWriter::add_data3
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.
Definition: geomVertexWriter.I:1132
BamWriter
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
colorAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexWriter
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
Definition: geomVertexWriter.h:55
CullTraverser
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Definition: cullTraverser.h:45
BamReader::get_factory
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
Texture
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:71
bamReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomLinestrips
Defines a series of line strips.
Definition: geomLinestrips.h:23
OccluderNode::cull_callback
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: occluderNode.cxx:140
plane.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypedWritable
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
RenderState
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
renderState.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
OccluderNode::make_copy
virtual PandaNode * make_copy() const
Returns a newly-allocated Node that is a shallow copy of this one.
Definition: occluderNode.cxx:93
Datagram::add_uint16
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
cullTraverserData.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PandaNode::write_datagram
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:3583
depthOffsetAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
FactoryParams
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
transformState.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
OccluderNode::complete_pointers
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
Definition: occluderNode.cxx:350
CullHandler::record_object
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
OccluderNode::xform
virtual void xform(const LMatrix4 &mat)
Transforms the contents of this node by the indicated matrix, if it means anything to do so.
Definition: occluderNode.cxx:111
GeometricBoundingVolume
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
Definition: geometricBoundingVolume.h:29
boundingSphere.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CullTraverserData
This collects together the pieces of data that are accumulated for each node while walking the scene ...
Definition: cullTraverserData.h:40
CPT
CPT(RenderState) OccluderNode
Returns the RenderState to apply to the visualization.
Definition: occluderNode.cxx:271
transparencyAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
cullFaceAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
geomTriangles.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexWriter::add_data2
void add_data2(PN_stdfloat x, PN_stdfloat y)
Sets the write row to a particular 2-component value, and advances the write row.
Definition: geomVertexWriter.I:1100
datagram.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
geom.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Factory::register_factory
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
GeomTriangles
Defines a series of disconnected triangles.
Definition: geomTriangles.h:23
OccluderNode::is_renderable
virtual bool is_renderable() const
Returns true if there is some value to visiting this particular node during the cull traversal for an...
Definition: occluderNode.cxx:166
OccluderNode::register_with_read_factory
static void register_with_read_factory()
Tells the BamReader how to create objects of type OccluderNode.
Definition: occluderNode.cxx:325
textureAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
geomLinestrips.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeometricBoundingVolume::around
bool around(const GeometricBoundingVolume **first, const GeometricBoundingVolume **last)
Resets the volume to enclose only the volumes indicated.
Definition: geometricBoundingVolume.I:44
OccluderNode::is_double_sided
is_double_sided
Is this occluder double-sided.
Definition: occluderNode.h:61
datagramIterator.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
geomNode.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
OccluderNode::output
virtual void output(std::ostream &out) const
Writes a brief description of the node to the indicated output stream.
Definition: occluderNode.cxx:177
PT
PT(Geom) OccluderNode
Returns a Geom that represents the visualization of the OccluderNode, as seen from the front.
Definition: occluderNode.cxx:211
BoundingVolume
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
Definition: boundingVolume.h:41
bamWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:64
Thread
A thread; that is, a lightweight process.
Definition: thread.h:46
CullTraverser::get_cull_handler
CullHandler * get_cull_handler() const
Returns the object that will receive the culled Geoms.
Definition: cullTraverser.I:152
cullHandler.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
parse_params
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