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  */
344 void ScissorEffect::
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 }
This provides a higher-level wrapper around ScissorAttrib.
Definition: scissorEffect.h:31
Indicates a coordinate-system transform on vertices.
bool get_bool()
Extracts a boolean value.
This is the base class for a number of render attributes (other than transform) that may be set on sc...
Definition: renderAttrib.h:51
A base class for any number of different kinds of lenses, linear and otherwise.
Definition: lens.h:41
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
This collects together the pieces of data that are accumulated for each node while walking the scene ...
const Lens * get_lens() const
Returns the particular Lens used for rendering.
Definition: sceneSetup.I:131
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
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
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
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:34
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.
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
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.
SceneSetup * get_scene() const
Returns the SceneSetup object.
Definition: cullTraverser.I:35
bool get_clip() const
Returns true if this ScissorEffect actually enables scissoring, or false if it culls only.
Definition: scissorEffect.I:69
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
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
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:161
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
CPT(RenderEffect) ScissorEffect
Constructs a new screen-relative ScissorEffect.
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.
This defines a bounding convex hexahedron.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.