Panda3D
scissorEffect.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 scissorEffect.cxx
10  * @author drose
11  * @date 2008-07-30
12  */
13 
14 #include "scissorEffect.h"
15 #include "scissorAttrib.h"
16 #include "cullTraverser.h"
17 #include "cullTraverserData.h"
18 #include "nodePath.h"
19 #include "bamReader.h"
20 #include "bamWriter.h"
21 #include "datagram.h"
22 #include "datagramIterator.h"
23 #include "boundingHexahedron.h"
24 #include "lens.h"
25 
26 using std::max;
27 using std::min;
28 
29 TypeHandle ScissorEffect::_type_handle;
30 
31 /**
32  * Use ScissorEffect::make() to construct a new ScissorEffect object.
33  */
34 ScissorEffect::
35 ScissorEffect(bool screen, const LVecBase4 &frame,
36  const PointDef *points, int num_points, bool clip) :
37  _screen(screen), _frame(frame), _clip(clip)
38 {
39  _points.reserve(num_points);
40  for (int i = 0; i < num_points; ++i) {
41  _points.push_back(points[i]);
42  }
43 }
44 
45 /**
46  * Use ScissorEffect::make() to construct a new ScissorEffect object.
47  */
48 ScissorEffect::
49 ScissorEffect(const ScissorEffect &copy) :
50  _screen(copy._screen),
51  _frame(copy._frame),
52  _points(copy._points),
53  _clip(copy._clip)
54 {
55 }
56 
57 /**
58  * Constructs a new screen-relative ScissorEffect. The frame defines a left,
59  * right, bottom, top region, relative to the DisplayRegion. See
60  * ScissorAttrib.
61  */
62 CPT(RenderEffect) ScissorEffect::
63 make_screen(const LVecBase4 &frame, bool clip) {
64  ScissorEffect *effect = new ScissorEffect(true, frame, nullptr, 0, clip);
65  return return_new(effect);
66 }
67 
68 /**
69  * Constructs a new node-relative ScissorEffect, with no points. This empty
70  * ScissorEffect does nothing. You must then call add_point a number of times
71  * to add the points you require.
72  */
73 CPT(RenderEffect) ScissorEffect::
74 make_node(bool clip) {
75  ScissorEffect *effect = new ScissorEffect(false, LVecBase4::zero(), nullptr, 0, clip);
76  return return_new(effect);
77 }
78 
79 /**
80  * Constructs a new node-relative ScissorEffect. The two points are
81  * understood to be relative to the indicated node, or the current node if the
82  * NodePath is empty, and determine the diagonally opposite corners of the
83  * scissor region.
84  */
85 CPT(RenderEffect) ScissorEffect::
86 make_node(const LPoint3 &a, const LPoint3 &b, const NodePath &node) {
87  PointDef points[2];
88  points[0]._p = a;
89  points[0]._node = node;
90  points[1]._p = b;
91  points[1]._node = node;
92  ScissorEffect *effect = new ScissorEffect(false, LVecBase4::zero(), points, 2, true);
93  return return_new(effect);
94 }
95 
96 /**
97  * Constructs a new node-relative ScissorEffect. The four points are
98  * understood to be relative to the indicated node, or the current node if the
99  * indicated NodePath is empty, and determine four points surrounding the
100  * scissor region.
101  */
102 CPT(RenderEffect) ScissorEffect::
103 make_node(const LPoint3 &a, const LPoint3 &b, const LPoint3 &c, const LPoint3 &d, const NodePath &node) {
104  PointDef points[4];
105  points[0]._p = a;
106  points[0]._node = node;
107  points[1]._p = b;
108  points[1]._node = node;
109  points[2]._p = c;
110  points[2]._node = node;
111  points[3]._p = d;
112  points[3]._node = node;
113  ScissorEffect *effect = new ScissorEffect(false, LVecBase4::zero(), points, 4, true);
114  return return_new(effect);
115 }
116 
117 /**
118  * Returns a new ScissorEffect with the indicated point added. It is only
119  * valid to call this on a "node" type ScissorEffect. The full set of points,
120  * projected into screen space, defines the bounding volume of the rectangular
121  * scissor region.
122  *
123  * Each point may be relative to a different node, if desired.
124  */
125 CPT(RenderEffect) ScissorEffect::
126 add_point(const LPoint3 &p, const NodePath &node) const {
127  nassertr(!is_screen(), this);
128  ScissorEffect *effect = new ScissorEffect(*this);
129  PointDef point;
130  point._p = p;
131  point._node = node;
132  effect->_points.push_back(point);
133  return return_new(effect);
134 }
135 
136 /**
137  * Returns a new RenderEffect transformed by the indicated matrix.
138  */
139 CPT(RenderEffect) ScissorEffect::
140 xform(const LMatrix4 &mat) const {
141  if (is_screen()) {
142  return this;
143  }
144  ScissorEffect *effect = new ScissorEffect(*this);
145  Points::iterator pi;
146  for (pi = effect->_points.begin();
147  pi != effect->_points.end();
148  ++pi) {
149  PointDef &point = (*pi);
150  if (point._node.is_empty()) {
151  point._p = point._p * mat;
152  }
153  }
154  return return_new(effect);
155 }
156 
157 /**
158  *
159  */
160 void ScissorEffect::
161 output(std::ostream &out) const {
162  out << get_type() << ":";
163  if (is_screen()) {
164  out << "screen [" << _frame << "]";
165  } else {
166  out << "node";
167  Points::const_iterator pi;
168  for (pi = _points.begin(); pi != _points.end(); ++pi) {
169  const PointDef &point = (*pi);
170  if (point._node.is_empty()) {
171  out << " (" << point._p << ")";
172  } else {
173  out << " (" << point._node << ":" << point._p << ")";
174  }
175  }
176  }
177  if (!get_clip()) {
178  out << " !clip";
179  }
180 }
181 
182 /**
183  * Should be overridden by derived classes to return true if cull_callback()
184  * has been defined. Otherwise, returns false to indicate cull_callback()
185  * does not need to be called for this effect during the cull traversal.
186  */
187 bool ScissorEffect::
188 has_cull_callback() const {
189  return true;
190 }
191 
192 /**
193  * If has_cull_callback() returns true, this function will be called during
194  * the cull traversal to perform any additional operations that should be
195  * performed at cull time. This may include additional manipulation of render
196  * state or additional visible/invisible decisions, or any other arbitrary
197  * operation.
198  *
199  * At the time this function is called, the current node's transform and state
200  * have not yet been applied to the net_transform and net_state. This
201  * callback may modify the node_transform and node_state to apply an effective
202  * change to the render state at this level.
203  */
204 void ScissorEffect::
205 cull_callback(CullTraverser *trav, CullTraverserData &data,
206  CPT(TransformState) &node_transform,
207  CPT(RenderState) &node_state) const {
208  LVecBase4 frame;
209  const Lens *lens = trav->get_scene()->get_lens();
210  CPT(TransformState) modelview_transform = data.get_modelview_transform(trav);
211  CPT(TransformState) net_transform = modelview_transform->compose(node_transform);
212  if (net_transform->is_singular()) {
213  // If we're under a singular transform, never mind.
214  return;
215  }
216 
217  if (is_screen()) {
218  frame = _frame;
219  } else {
220  const LMatrix4 &proj_mat = lens->get_projection_mat();
221  LMatrix4 net_mat = net_transform->get_mat() * proj_mat;
222 
223  bool any_points = false;
224 
225  Points::const_iterator pi;
226  for (pi = _points.begin(); pi != _points.end(); ++pi) {
227  const PointDef &point = (*pi);
228  LVecBase4 pv(point._p[0], point._p[1], point._p[2], 1.0f);
229  if (point._node.is_empty()) {
230  // Relative to this node.
231  pv = pv * net_mat;
232 
233  } else {
234  // Relative to some other node.
235  LMatrix4 other_mat = point._node.get_net_transform()->get_mat() * proj_mat;
236  pv = pv * other_mat;
237  }
238 
239  if (pv[3] == 0) {
240  continue;
241  }
242  LPoint3 pr(pv[0] / pv[3], pv[1] / pv[3], pv[2] / pv[3]);
243  if (!any_points) {
244  frame[0] = pr[0];
245  frame[1] = pr[0];
246  frame[2] = pr[1];
247  frame[3] = pr[1];
248  any_points = true;
249  } else {
250  frame[0] = min(frame[0], pr[0]);
251  frame[1] = max(frame[1], pr[0]);
252  frame[2] = min(frame[2], pr[1]);
253  frame[3] = max(frame[3], pr[1]);
254  }
255  }
256 
257  // Scale from -1..1 to 0..1.
258  frame[0] = (frame[0] + 1.0f) * 0.5f;
259  frame[1] = (frame[1] + 1.0f) * 0.5f;
260  frame[2] = (frame[2] + 1.0f) * 0.5f;
261  frame[3] = (frame[3] + 1.0f) * 0.5f;
262  }
263 
264  // Impose bounding volumes.
265  frame[0] = max(min(frame[0], (PN_stdfloat)1.0), (PN_stdfloat)0.0);
266  frame[1] = max(min(frame[1], (PN_stdfloat)1.0), frame[0]);
267  frame[2] = max(min(frame[2], (PN_stdfloat)1.0), (PN_stdfloat)0.0);
268  frame[3] = max(min(frame[3], (PN_stdfloat)1.0), frame[2]);
269 
270  if (_clip) {
271  CPT(RenderAttrib) scissor_attrib = ScissorAttrib::make(frame);
272  CPT(RenderState) state = RenderState::make(scissor_attrib);
273  node_state = node_state->compose(state);
274  }
275 
276  // Set up the culling. We do this by extruding the four corners of the
277  // frame into the eight corners of the bounding frustum.
278  PT(GeometricBoundingVolume) frustum = make_frustum(lens, frame);
279  if (frustum != nullptr) {
280  frustum->xform(modelview_transform->get_inverse()->get_mat());
281  data._view_frustum = frustum;
282  }
283 }
284 
285 /**
286  * Intended to be overridden by derived ScissorEffect types to return a unique
287  * number indicating whether this ScissorEffect is equivalent to the other
288  * one.
289  *
290  * This should return 0 if the two ScissorEffect objects are equivalent, a
291  * number less than zero if this one should be sorted before the other one,
292  * and a number greater than zero otherwise.
293  *
294  * This will only be called with two ScissorEffect objects whose get_type()
295  * functions return the same.
296  */
297 int ScissorEffect::
298 compare_to_impl(const RenderEffect *other) const {
299  const ScissorEffect *ta;
300  DCAST_INTO_R(ta, other, 0);
301 
302  if (_screen != ta->_screen) {
303  return (int)_screen - (int)ta->_screen;
304  }
305  if (_clip != ta->_clip) {
306  return (int)_clip - (int)ta->_clip;
307  }
308  if (_screen) {
309  int compare = _frame.compare_to(ta->_frame);
310  if (compare != 0) {
311  return compare;
312  }
313  } else {
314  int compare = (int)_points.size() - (int)ta->_points.size();
315  if (compare != 0) {
316  return compare;
317  }
318  for (size_t i = 0; i < _points.size(); ++i) {
319  compare = _points[i]._p.compare_to(ta->_points[i]._p);
320  if (compare != 0) {
321  return compare;
322  }
323  compare = _points[i]._node.compare_to(ta->_points[i]._node);
324  if (compare != 0) {
325  return compare;
326  }
327  }
328  }
329  return 0;
330 }
331 
332 /**
333  * Tells the BamReader how to create objects of type ScissorEffect.
334  */
335 void ScissorEffect::
336 register_with_read_factory() {
337  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
338 }
339 
340 /**
341  * Writes the contents of this object to the datagram for shipping out to a
342  * Bam file.
343  */
345 write_datagram(BamWriter *manager, Datagram &dg) {
346  RenderEffect::write_datagram(manager, dg);
347 
348  dg.add_bool(_screen);
349  if (_screen) {
350  _frame.write_datagram(dg);
351  } else {
352  dg.add_uint16(_points.size());
353  Points::const_iterator pi;
354  for (pi = _points.begin(); pi != _points.end(); ++pi) {
355  (*pi)._p.write_datagram(dg);
356  }
357  }
358  dg.add_bool(_clip);
359 }
360 
361 /**
362  * This function is called by the BamReader's factory when a new object of
363  * type ScissorEffect is encountered in the Bam file. It should create the
364  * ScissorEffect and extract its information from the file.
365  */
366 TypedWritable *ScissorEffect::
367 make_from_bam(const FactoryParams &params) {
368  ScissorEffect *effect = new ScissorEffect(true, LVecBase4::zero(), nullptr, 0, false);
369  DatagramIterator scan;
370  BamReader *manager;
371 
372  parse_params(params, scan, manager);
373  effect->fillin(scan, manager);
374 
375  return effect;
376 }
377 
378 /**
379  * This internal function is called by make_from_bam to read in all of the
380  * relevant data from the BamFile for the new ScissorEffect.
381  */
382 void ScissorEffect::
383 fillin(DatagramIterator &scan, BamReader *manager) {
384  RenderEffect::fillin(scan, manager);
385 
386  _screen = scan.get_bool();
387  if (_screen) {
388  _frame.read_datagram(scan);
389  } else {
390  int num_points = scan.get_uint16();
391  _points.reserve(num_points);
392  for (int i = 0; i < num_points; ++i) {
393  PointDef point;
394  point._p.read_datagram(scan);
395  _points.push_back(point);
396  }
397  }
398  _clip = scan.get_bool();
399 }
400 
401 /**
402  * Constructs a new bounding frustum from the lens properties, given the
403  * indicated scissor frame.
404  */
405 PT(GeometricBoundingVolume) ScissorEffect::
406 make_frustum(const Lens *lens, const LVecBase4 &frame) const{
407  // Scale the frame from 0 .. 1 into -1 .. 1.
408  LVecBase4 f2(frame[0] * 2.0f - 1.0f,
409  frame[1] * 2.0f - 1.0f,
410  frame[2] * 2.0f - 1.0f,
411  frame[3] * 2.0f - 1.0f);
412 
413  LPoint3 fll, flr, ful, fur;
414  LPoint3 nll, nlr, nul, nur;
415  LPoint2 corner;
416 
417  corner[0] = f2[0]; corner[1] = f2[3];
418 
419  // Upper left.
420  if (!lens->extrude(corner, nul, ful)) {
421  return nullptr;
422  }
423 
424  corner[0] = f2[1]; corner[1] = f2[3];
425 
426  // Upper right.
427  if (!lens->extrude(corner, nur, fur)) {
428  return nullptr;
429  }
430 
431  corner[0] = f2[1]; corner[1] = f2[2];
432 
433  // Lower right.
434  if (!lens->extrude(corner, nlr, flr)) {
435  return nullptr;
436  }
437 
438  corner[0] = f2[0]; corner[1] = f2[2];
439 
440  // Lower left.
441  if (!lens->extrude(corner, nll, fll)) {
442  return nullptr;
443  }
444 
445  return new BoundingHexahedron(fll, flr, fur, ful, nll, nlr, nur, nul);
446 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
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
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
This defines a bounding convex hexahedron.
This collects together the pieces of data that are accumulated for each node while walking the scene ...
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Definition: cullTraverser.h:45
SceneSetup * get_scene() const
Returns the SceneSetup object.
Definition: cullTraverser.I:35
A class to retrieve the individual data elements previously stored in a Datagram.
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
bool get_bool()
Extracts a boolean value.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:34
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
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
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
A base class for any number of different kinds of lenses, linear and otherwise.
Definition: lens.h:41
bool extrude(const LPoint2 &point2d, LPoint3 &near_point, LPoint3 &far_point) const
Given a 2-d point in the range (-1,1) in both dimensions, where (0,0) is the center of the lens and (...
Definition: lens.I:24
const LMatrix4 & get_projection_mat(StereoChannel channel=SC_mono) const
Returns the complete transformation matrix from a 3-d point in space to a point on the film,...
Definition: lens.I:563
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
This is the base class for a number of render attributes (other than transform) that may be set on sc...
Definition: renderAttrib.h:51
This is the base class for a number of special render effects that may be set on scene graph nodes to...
Definition: renderEffect.h:48
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
const Lens * get_lens() const
Returns the particular Lens used for rendering.
Definition: sceneSetup.I:131
This provides a higher-level wrapper around ScissorAttrib.
Definition: scissorEffect.h:31
bool is_screen() const
Returns true if the ScissorEffect is a screen-based effect, meaning get_frame() has a meaningful valu...
Definition: scissorEffect.I:19
bool get_clip() const
Returns true if this ScissorEffect actually enables scissoring, or false if it culls only.
Definition: scissorEffect.I:69
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Indicates a coordinate-system transform on vertices.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CPT(RenderEffect) ScissorEffect
Constructs a new screen-relative ScissorEffect.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.