Panda3D
Loading...
Searching...
No Matches
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
26using std::max;
27using std::min;
28
29TypeHandle ScissorEffect::_type_handle;
30
31/**
32 * Use ScissorEffect::make() to construct a new ScissorEffect object.
33 */
34ScissorEffect::
35ScissorEffect(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 */
48ScissorEffect::
49ScissorEffect(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 */
62CPT(RenderEffect) ScissorEffect::
63make_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 */
73CPT(RenderEffect) ScissorEffect::
74make_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 */
85CPT(RenderEffect) ScissorEffect::
86make_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 */
102CPT(RenderEffect) ScissorEffect::
103make_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 */
125CPT(RenderEffect) ScissorEffect::
126add_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 */
139CPT(RenderEffect) ScissorEffect::
140xform(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 */
160void ScissorEffect::
161output(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 */
187bool ScissorEffect::
188has_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 */
204void ScissorEffect::
205cull_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 */
297int ScissorEffect::
298compare_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 */
335void ScissorEffect::
336register_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 */
345write_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 */
366TypedWritable *ScissorEffect::
367make_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 */
382void ScissorEffect::
383fillin(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 */
405PT(GeometricBoundingVolume) ScissorEffect::
406make_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,...
SceneSetup * get_scene() const
Returns the SceneSetup object.
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...
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...
This is the base class for a number of special render effects that may be set on scene graph nodes to...
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.
bool is_screen() const
Returns true if the ScissorEffect is a screen-based effect, meaning get_frame() has a meaningful valu...
bool get_clip() const
Returns true if this ScissorEffect actually enables scissoring, or false if it culls only.
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.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.