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