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 }
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.
virtual void xform(const LMatrix4 &mat)
Transforms the contents of this node by the indicated matrix, if it means anything to do so.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
virtual bool is_renderable() const
Returns true if there is some value to visiting this particular node during the cull traversal for an...
static void register_with_read_factory()
Tells the BamReader how to create objects of type OccluderNode.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This defines a bounding sphere, consisting of a center and a radius.
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
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
void add_data2(PN_stdfloat x, PN_stdfloat y)
Sets the write row to a particular 2-component value, and advances the write row.
This collects together the pieces of data that are accumulated for each node while walking the scene ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static const GeomVertexFormat * get_v3n3t2()
Returns a standard vertex format with a 2-component texture coordinate pair, a 3-component normal,...
A node in the scene graph that can hold an occluder polygon, which must be a rectangle.
Definition: occluderNode.h:31
PT(Geom) OccluderNode
Returns a Geom that represents the visualization of the OccluderNode, as seen from the front.
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.
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
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data)
This function will be called during the cull traversal to perform any additional operations that shou...
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The smallest atom of cull.
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().
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
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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 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 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.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
virtual bool preserve_name() const
Returns true if the node's name has extrinsic meaning and must be preserved across a flatten operatio...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A thread; that is, a lightweight process.
Definition: thread.h:46
CPT(RenderState) OccluderNode
Returns the RenderState to apply to the visualization.
Defines a series of line strips.
Defines a series of disconnected triangles.
Definition: geomTriangles.h:23
virtual PandaNode * make_copy() const
Returns a newly-allocated Node that is a shallow copy of this one.
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
virtual void output(std::ostream &out) const
Writes a brief description of the node to the indicated output stream.
bool around(const GeometricBoundingVolume **first, const GeometricBoundingVolume **last)
Resets the volume to enclose only the volumes indicated.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().