Panda3D
 All Classes Functions Variables Enumerations
scissorEffect.cxx
00001 // Filename: scissorEffect.cxx
00002 // Created by:  drose (30Jul08)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "scissorEffect.h"
00016 #include "scissorAttrib.h"
00017 #include "cullTraverser.h"
00018 #include "cullTraverserData.h"
00019 #include "nodePath.h"
00020 #include "bamReader.h"
00021 #include "bamWriter.h"
00022 #include "datagram.h"
00023 #include "datagramIterator.h"
00024 #include "boundingHexahedron.h"
00025 
00026 TypeHandle ScissorEffect::_type_handle;
00027 
00028 ////////////////////////////////////////////////////////////////////
00029 //     Function: ScissorEffect::Constructor
00030 //       Access: Private
00031 //  Description: Use ScissorEffect::make() to construct a new
00032 //               ScissorEffect object.
00033 ////////////////////////////////////////////////////////////////////
00034 ScissorEffect::
00035 ScissorEffect(bool screen, const LVecBase4 &frame,
00036               const PointDef *points, int num_points, bool clip) :
00037   _screen(screen), _frame(frame), _clip(clip) 
00038 {
00039   _points.reserve(num_points);
00040   for (int i = 0; i < num_points; ++i) {
00041     _points.push_back(points[i]);
00042   }
00043 }
00044 
00045 ////////////////////////////////////////////////////////////////////
00046 //     Function: ScissorEffect::Copy Constructor
00047 //       Access: Private
00048 //  Description: Use ScissorEffect::make() to construct a new
00049 //               ScissorEffect object.
00050 ////////////////////////////////////////////////////////////////////
00051 ScissorEffect::
00052 ScissorEffect(const ScissorEffect &copy) :
00053   _screen(copy._screen), 
00054   _frame(copy._frame),
00055   _points(copy._points),
00056   _clip(copy._clip)
00057 {
00058 }
00059 
00060 ////////////////////////////////////////////////////////////////////
00061 //     Function: ScissorEffect::make_screen
00062 //       Access: Published, Static
00063 //  Description: Constructs a new screen-relative ScissorEffect.  The
00064 //               frame defines a left, right, bottom, top region,
00065 //               relative to the DisplayRegion.  See ScissorAttrib.
00066 ////////////////////////////////////////////////////////////////////
00067 CPT(RenderEffect) ScissorEffect::
00068 make_screen(const LVecBase4 &frame, bool clip) {
00069   ScissorEffect *effect = new ScissorEffect(true, frame, NULL, 0, clip);
00070   return return_new(effect);
00071 }
00072 
00073 ////////////////////////////////////////////////////////////////////
00074 //     Function: ScissorEffect::make_node
00075 //       Access: Published, Static
00076 //  Description: Constructs a new node-relative ScissorEffect, with no
00077 //               points.  This empty ScissorEffect does nothing.  You
00078 //               must then call add_point a number of times to add the
00079 //               points you require.
00080 ////////////////////////////////////////////////////////////////////
00081 CPT(RenderEffect) ScissorEffect::
00082 make_node(bool clip) {
00083   ScissorEffect *effect = new ScissorEffect(false, LVecBase4::zero(), NULL, 0, clip);
00084   return return_new(effect);
00085 }
00086 
00087 ////////////////////////////////////////////////////////////////////
00088 //     Function: ScissorEffect::make_node
00089 //       Access: Published, Static
00090 //  Description: Constructs a new node-relative ScissorEffect.  The
00091 //               two points are understood to be relative to the
00092 //               indicated node, or the current node if the NodePath
00093 //               is empty, and determine the diagonally opposite
00094 //               corners of the scissor region.
00095 ////////////////////////////////////////////////////////////////////
00096 CPT(RenderEffect) ScissorEffect::
00097 make_node(const LPoint3 &a, const LPoint3 &b, const NodePath &node) {
00098   PointDef points[2];
00099   points[0]._p = a;
00100   points[0]._node = node;
00101   points[1]._p = b;
00102   points[1]._node = node;
00103   ScissorEffect *effect = new ScissorEffect(false, LVecBase4::zero(), points, 2, true);
00104   return return_new(effect);
00105 }
00106 
00107 ////////////////////////////////////////////////////////////////////
00108 //     Function: ScissorEffect::make_node
00109 //       Access: Published, Static
00110 //  Description: Constructs a new node-relative ScissorEffect.  The
00111 //               four points are understood to be relative to the
00112 //               indicated node, or the current node if the indicated
00113 //               NodePath is empty, and determine four points
00114 //               surrounding the scissor region.
00115 ////////////////////////////////////////////////////////////////////
00116 CPT(RenderEffect) ScissorEffect::
00117 make_node(const LPoint3 &a, const LPoint3 &b, const LPoint3 &c, const LPoint3 &d, const NodePath &node) {
00118   PointDef points[4];
00119   points[0]._p = a;
00120   points[0]._node = node;
00121   points[1]._p = b;
00122   points[1]._node = node;
00123   points[2]._p = c;
00124   points[2]._node = node;
00125   points[3]._p = d;
00126   points[3]._node = node;
00127   ScissorEffect *effect = new ScissorEffect(false, LVecBase4::zero(), points, 4, true);
00128   return return_new(effect);
00129 }
00130 
00131 ////////////////////////////////////////////////////////////////////
00132 //     Function: ScissorEffect::add_point
00133 //       Access: Published
00134 //  Description: Returns a new ScissorEffect with the indicated point
00135 //               added.  It is only valid to call this on a "node"
00136 //               type ScissorEffect.  The full set of points,
00137 //               projected into screen space, defines the bounding
00138 //               volume of the rectangular scissor region.
00139 //
00140 //               Each point may be relative to a different node, if
00141 //               desired.
00142 ////////////////////////////////////////////////////////////////////
00143 CPT(RenderEffect) ScissorEffect::
00144 add_point(const LPoint3 &p, const NodePath &node) const {
00145   nassertr(!is_screen(), this);
00146   ScissorEffect *effect = new ScissorEffect(*this);
00147   PointDef point;
00148   point._p = p;
00149   point._node = node;
00150   effect->_points.push_back(point);
00151   return return_new(effect);
00152 }
00153 
00154 ////////////////////////////////////////////////////////////////////
00155 //     Function: ScissorEffect::xform
00156 //       Access: Public, Virtual
00157 //  Description: Returns a new RenderEffect transformed by the
00158 //               indicated matrix.
00159 ////////////////////////////////////////////////////////////////////
00160 CPT(RenderEffect) ScissorEffect::
00161 xform(const LMatrix4 &mat) const {
00162   if (is_screen()) {
00163     return this;
00164   }
00165   ScissorEffect *effect = new ScissorEffect(*this);
00166   Points::iterator pi;
00167   for (pi = effect->_points.begin();
00168        pi != effect->_points.end();
00169        ++pi) {
00170     PointDef &point = (*pi);
00171     if (point._node.is_empty()) {
00172       point._p = point._p * mat;
00173     }
00174   }
00175   return return_new(effect);
00176 }
00177 
00178 ////////////////////////////////////////////////////////////////////
00179 //     Function: ScissorEffect::output
00180 //       Access: Public, Virtual
00181 //  Description: 
00182 ////////////////////////////////////////////////////////////////////
00183 void ScissorEffect::
00184 output(ostream &out) const {
00185   out << get_type() << ":";
00186   if (is_screen()) {
00187     out << "screen [" << _frame << "]";
00188   } else {
00189     out << "node";
00190     Points::const_iterator pi;
00191     for (pi = _points.begin(); pi != _points.end(); ++pi) {
00192       const PointDef &point = (*pi);
00193       if (point._node.is_empty()) {
00194         out << " (" << point._p << ")";
00195       } else {
00196         out << " (" << point._node << ":" << point._p << ")";
00197       }
00198     }
00199   }
00200   if (!get_clip()) {
00201     out << " !clip";
00202   }
00203 }
00204 
00205 ////////////////////////////////////////////////////////////////////
00206 //     Function: ScissorEffect::has_cull_callback
00207 //       Access: Public, Virtual
00208 //  Description: Should be overridden by derived classes to return
00209 //               true if cull_callback() has been defined.  Otherwise,
00210 //               returns false to indicate cull_callback() does not
00211 //               need to be called for this effect during the cull
00212 //               traversal.
00213 ////////////////////////////////////////////////////////////////////
00214 bool ScissorEffect::
00215 has_cull_callback() const {
00216   return true;
00217 }
00218 
00219 ////////////////////////////////////////////////////////////////////
00220 //     Function: ScissorEffect::cull_callback
00221 //       Access: Public, Virtual
00222 //  Description: If has_cull_callback() returns true, this function
00223 //               will be called during the cull traversal to perform
00224 //               any additional operations that should be performed at
00225 //               cull time.  This may include additional manipulation
00226 //               of render state or additional visible/invisible
00227 //               decisions, or any other arbitrary operation.
00228 //
00229 //               At the time this function is called, the current
00230 //               node's transform and state have not yet been applied
00231 //               to the net_transform and net_state.  This callback
00232 //               may modify the node_transform and node_state to apply
00233 //               an effective change to the render state at this
00234 //               level.
00235 ////////////////////////////////////////////////////////////////////
00236 void ScissorEffect::
00237 cull_callback(CullTraverser *trav, CullTraverserData &data,
00238               CPT(TransformState) &node_transform,
00239               CPT(RenderState) &node_state) const {
00240   LVecBase4 frame;
00241   const Lens *lens = trav->get_scene()->get_lens();
00242   CPT(TransformState) modelview_transform = data.get_modelview_transform(trav);
00243   CPT(TransformState) net_transform = modelview_transform->compose(node_transform);
00244   if (net_transform->is_singular()) {
00245     // If we're under a singular transform, never mind.
00246     return;
00247   }
00248 
00249   if (is_screen()) {
00250     frame = _frame;
00251   } else {
00252     const LMatrix4 &proj_mat = lens->get_projection_mat();
00253     LMatrix4 net_mat = net_transform->get_mat() * proj_mat;
00254 
00255     bool any_points = false;
00256 
00257     Points::const_iterator pi;
00258     for (pi = _points.begin(); pi != _points.end(); ++pi) {
00259       const PointDef &point = (*pi);
00260       LVecBase4 pv(point._p[0], point._p[1], point._p[2], 1.0f);
00261       if (point._node.is_empty()) {
00262         // Relative to this node.
00263         pv = pv * net_mat;
00264 
00265       } else {
00266         // Relative to some other node.
00267         LMatrix4 other_mat = point._node.get_net_transform()->get_mat() * proj_mat;
00268         pv = pv * other_mat;
00269       }
00270 
00271       if (pv[3] == 0) {
00272         continue;
00273       }
00274       LPoint3 pr(pv[0] / pv[3], pv[1] / pv[3], pv[2] / pv[3]);
00275       if (!any_points) {
00276         frame[0] = pr[0];
00277         frame[1] = pr[0];
00278         frame[2] = pr[1];
00279         frame[3] = pr[1];
00280         any_points = true;
00281       } else {
00282         frame[0] = min(frame[0], pr[0]);
00283         frame[1] = max(frame[1], pr[0]);
00284         frame[2] = min(frame[2], pr[1]);
00285         frame[3] = max(frame[3], pr[1]);
00286       }
00287     }
00288     
00289     // Scale from -1..1 to 0..1.
00290     frame[0] = (frame[0] + 1.0f) * 0.5f;
00291     frame[1] = (frame[1] + 1.0f) * 0.5f;
00292     frame[2] = (frame[2] + 1.0f) * 0.5f;
00293     frame[3] = (frame[3] + 1.0f) * 0.5f;
00294   }
00295 
00296   // Impose bounding volumes.
00297   frame[0] = max(min(frame[0], (PN_stdfloat)1.0), (PN_stdfloat)0.0);
00298   frame[1] = max(min(frame[1], (PN_stdfloat)1.0), frame[0]);
00299   frame[2] = max(min(frame[2], (PN_stdfloat)1.0), (PN_stdfloat)0.0);
00300   frame[3] = max(min(frame[3], (PN_stdfloat)1.0), frame[2]);
00301 
00302   if (_clip) {
00303     CPT(RenderAttrib) scissor_attrib = ScissorAttrib::make(frame);
00304     CPT(RenderState) state = RenderState::make(scissor_attrib);
00305     node_state = node_state->compose(state); 
00306   }
00307 
00308   // Set up the culling.  We do this by extruding the four corners of
00309   // the frame into the eight corners of the bounding frustum.
00310   PT(GeometricBoundingVolume) frustum = make_frustum(lens, frame);
00311   if (frustum != (GeometricBoundingVolume *)NULL) {
00312     frustum->xform(modelview_transform->get_inverse()->get_mat());
00313     data._view_frustum = frustum;
00314   }
00315 }
00316 
00317 ////////////////////////////////////////////////////////////////////
00318 //     Function: ScissorEffect::compare_to_impl
00319 //       Access: Protected, Virtual
00320 //  Description: Intended to be overridden by derived ScissorEffect
00321 //               types to return a unique number indicating whether
00322 //               this ScissorEffect is equivalent to the other one.
00323 //
00324 //               This should return 0 if the two ScissorEffect objects
00325 //               are equivalent, a number less than zero if this one
00326 //               should be sorted before the other one, and a number
00327 //               greater than zero otherwise.
00328 //
00329 //               This will only be called with two ScissorEffect
00330 //               objects whose get_type() functions return the same.
00331 ////////////////////////////////////////////////////////////////////
00332 int ScissorEffect::
00333 compare_to_impl(const RenderEffect *other) const {
00334   const ScissorEffect *ta;
00335   DCAST_INTO_R(ta, other, 0);
00336 
00337   if (_screen != ta->_screen) {
00338     return (int)_screen - (int)ta->_screen;
00339   }
00340   if (_clip != ta->_clip) {
00341     return (int)_clip - (int)ta->_clip;
00342   }
00343   if (_screen) {
00344     int compare = _frame.compare_to(ta->_frame);
00345     if (compare != 0) {
00346       return compare;
00347     }
00348   } else {
00349     int compare = (int)_points.size() - (int)ta->_points.size();
00350     if (compare != 0) {
00351       return compare;
00352     }
00353     for (size_t i = 0; i < _points.size(); ++i) {
00354       compare = _points[i]._p.compare_to(ta->_points[i]._p);
00355       if (compare != 0) {
00356         return compare;
00357       }
00358       compare = _points[i]._node.compare_to(ta->_points[i]._node);
00359       if (compare != 0) {
00360         return compare;
00361       }
00362     }
00363   }
00364   return 0;
00365 }
00366 
00367 ////////////////////////////////////////////////////////////////////
00368 //     Function: ScissorEffect::register_with_read_factory
00369 //       Access: Public, Static
00370 //  Description: Tells the BamReader how to create objects of type
00371 //               ScissorEffect.
00372 ////////////////////////////////////////////////////////////////////
00373 void ScissorEffect::
00374 register_with_read_factory() {
00375   BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
00376 }
00377 
00378 ////////////////////////////////////////////////////////////////////
00379 //     Function: ScissorEffect::write_datagram
00380 //       Access: Public, Virtual
00381 //  Description: Writes the contents of this object to the datagram
00382 //               for shipping out to a Bam file.
00383 ////////////////////////////////////////////////////////////////////
00384 void ScissorEffect::
00385 write_datagram(BamWriter *manager, Datagram &dg) {
00386   RenderEffect::write_datagram(manager, dg);
00387 
00388   dg.add_bool(_screen);
00389   if (_screen) {
00390     _frame.write_datagram(dg);
00391   } else {
00392     dg.add_uint16(_points.size());
00393     Points::const_iterator pi;
00394     for (pi = _points.begin(); pi != _points.end(); ++pi) {
00395       (*pi)._p.write_datagram(dg);
00396     }
00397   }
00398   dg.add_bool(_clip);
00399 }
00400 
00401 ////////////////////////////////////////////////////////////////////
00402 //     Function: ScissorEffect::make_from_bam
00403 //       Access: Protected, Static
00404 //  Description: This function is called by the BamReader's factory
00405 //               when a new object of type ScissorEffect is encountered
00406 //               in the Bam file.  It should create the ScissorEffect
00407 //               and extract its information from the file.
00408 ////////////////////////////////////////////////////////////////////
00409 TypedWritable *ScissorEffect::
00410 make_from_bam(const FactoryParams &params) {
00411   ScissorEffect *effect = new ScissorEffect(true, LVecBase4::zero(), NULL, 0, false);
00412   DatagramIterator scan;
00413   BamReader *manager;
00414 
00415   parse_params(params, scan, manager);
00416   effect->fillin(scan, manager);
00417 
00418   return effect;
00419 }
00420 
00421 ////////////////////////////////////////////////////////////////////
00422 //     Function: ScissorEffect::fillin
00423 //       Access: Protected
00424 //  Description: This internal function is called by make_from_bam to
00425 //               read in all of the relevant data from the BamFile for
00426 //               the new ScissorEffect.
00427 ////////////////////////////////////////////////////////////////////
00428 void ScissorEffect::
00429 fillin(DatagramIterator &scan, BamReader *manager) {
00430   RenderEffect::fillin(scan, manager);
00431 
00432   _screen = scan.get_bool();
00433   if (_screen) {
00434     _frame.read_datagram(scan);
00435   } else {
00436     int num_points = scan.get_uint16();
00437     _points.reserve(num_points);
00438     for (int i = 0; i < num_points; ++i) {
00439       PointDef point;
00440       point._p.read_datagram(scan);
00441       _points.push_back(point);
00442     }
00443   }
00444   _clip = scan.get_bool();
00445 }
00446 
00447 ////////////////////////////////////////////////////////////////////
00448 //     Function: ScissorEffect::make_frustum
00449 //       Access: Private
00450 //  Description: Constructs a new bounding frustum from the lens
00451 //               properties, given the indicated scissor frame.
00452 ////////////////////////////////////////////////////////////////////
00453 PT(GeometricBoundingVolume) ScissorEffect::
00454 make_frustum(const Lens *lens, const LVecBase4 &frame) const{
00455   // Scale the frame from 0 .. 1 into -1 .. 1.
00456   LVecBase4 f2(frame[0] * 2.0f - 1.0f,
00457                frame[1] * 2.0f - 1.0f,
00458                frame[2] * 2.0f - 1.0f,
00459                frame[3] * 2.0f - 1.0f);
00460 
00461   LPoint3 fll, flr, ful, fur;
00462   LPoint3 nll, nlr, nul, nur;
00463   LPoint2 corner;
00464 
00465   corner[0] = f2[0]; corner[1] = f2[3];
00466 
00467   // Upper left.
00468   if (!lens->extrude(corner, nul, ful)) {
00469     return (GeometricBoundingVolume *)NULL;
00470   }
00471 
00472   corner[0] = f2[1]; corner[1] = f2[3];
00473 
00474   // Upper right.
00475   if (!lens->extrude(corner, nur, fur)) {
00476     return (GeometricBoundingVolume *)NULL;
00477   }
00478 
00479   corner[0] = f2[1]; corner[1] = f2[2];
00480 
00481   // Lower right.
00482   if (!lens->extrude(corner, nlr, flr)) {
00483     return (GeometricBoundingVolume *)NULL;
00484   }
00485 
00486   corner[0] = f2[0]; corner[1] = f2[2];
00487 
00488   // Lower left.
00489   if (!lens->extrude(corner, nll, fll)) {
00490     return (GeometricBoundingVolume *)NULL;
00491   }
00492 
00493   return new BoundingHexahedron(fll, flr, fur, ful, nll, nlr, nur, nul);
00494 }
 All Classes Functions Variables Enumerations