Ver código fonte

higher-level ScissorEffect fixes

David Rose 17 anos atrás
pai
commit
ab6e8bbc3c

+ 108 - 0
panda/src/pgraph/nodePath.cxx

@@ -43,6 +43,7 @@
 #include "antialiasAttrib.h"
 #include "audioVolumeAttrib.h"
 #include "texProjectorEffect.h"
+#include "scissorEffect.h"
 #include "texturePool.h"
 #include "planeNode.h"
 #include "lensNode.h"
@@ -2796,6 +2797,113 @@ has_clip_plane_off(const NodePath &clip_plane) const {
   return false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::set_scissor
+//       Access: Published
+//  Description: Sets up a scissor region on the nodes rendered at
+//               this level and below.  The four coordinates are
+//               understood to define a rectangle in screen space.
+//               These numbers are relative to the current
+//               DisplayRegion, where (0,0) is the lower-left corner
+//               of the DisplayRegion, and (1,1) is the upper-right
+//               corner.
+////////////////////////////////////////////////////////////////////
+void NodePath::
+set_scissor(float left, float right, float bottom, float top) {
+  set_effect(ScissorEffect::make_screen(LVecBase4f(left, right, bottom, top)));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::set_scissor
+//       Access: Published
+//  Description: Sets up a scissor region on the nodes rendered at
+//               this level and below.  The two points are understood
+//               to be relative to this node.  When these points are
+//               projected into screen space, they define the
+//               diagonally-opposite points that determine the scissor
+//               region.
+////////////////////////////////////////////////////////////////////
+void NodePath::
+set_scissor(const LPoint3f &a, const LPoint3f &b) {
+  set_effect(ScissorEffect::make_node(a, b));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::set_scissor
+//       Access: Published
+//  Description: Sets up a scissor region on the nodes rendered at
+//               this level and below.  The four points are understood
+//               to be relative to this node.  When these points are
+//               projected into screen space, they define the
+//               bounding volume of the scissor region (the scissor
+//               region is the smallest onscreen rectangle that
+//               encloses all four points).
+////////////////////////////////////////////////////////////////////
+void NodePath::
+set_scissor(const LPoint3f &a, const LPoint3f &b,
+            const LPoint3f &c, const LPoint3f &d) {
+  set_effect(ScissorEffect::make_node(a, b, c, d));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::set_scissor
+//       Access: Published
+//  Description: Sets up a scissor region on the nodes rendered at
+//               this level and below.  The two points are understood
+//               to be relative to the indicated other node.  When
+//               these points are projected into screen space, they
+//               define the diagonally-opposite points that determine
+//               the scissor region.
+////////////////////////////////////////////////////////////////////
+void NodePath::
+set_scissor(const NodePath &other, const LPoint3f &a, const LPoint3f &b) {
+  set_effect(ScissorEffect::make_node(a, b, other));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::set_scissor
+//       Access: Published
+//  Description: Sets up a scissor region on the nodes rendered at
+//               this level and below.  The four points are understood
+//               to be relative to the indicated other node.  When
+//               these points are projected into screen space, they
+//               define the bounding volume of the scissor region (the
+//               scissor region is the smallest onscreen rectangle
+//               that encloses all four points).
+////////////////////////////////////////////////////////////////////
+void NodePath::
+set_scissor(const NodePath &other,
+            const LPoint3f &a, const LPoint3f &b,
+            const LPoint3f &c, const LPoint3f &d) {
+  set_effect(ScissorEffect::make_node(a, b, c, d, other));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::clear_scissor
+//       Access: Published
+//  Description: Removes the scissor region that was defined at this
+//               node level by a previous call to set_scissor().
+////////////////////////////////////////////////////////////////////
+void NodePath::
+clear_scissor() {
+  clear_effect(ScissorEffect::get_class_type());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::has_scissor
+//       Access: Published
+//  Description: Returns true if a scissor region was defined at this
+//               node by a previous call to set_scissor().  This does
+//               not check for scissor regions inherited from a parent
+//               class.  It also does not check for the presence of a
+//               low-level ScissorAttrib, which is different from the
+//               ScissorEffect added by set_scissor.
+////////////////////////////////////////////////////////////////////
+bool NodePath::
+has_scissor() const {
+  return has_effect(ScissorEffect::get_class_type());
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePath::set_bin
 //       Access: Published

+ 12 - 0
panda/src/pgraph/nodePath.h

@@ -547,6 +547,18 @@ PUBLISHED:
   bool has_clip_plane_off() const;
   bool has_clip_plane_off(const NodePath &clip_plane) const;
 
+  void set_scissor(float left, float right, float bottom, float top);
+  void set_scissor(const LPoint3f &a, const LPoint3f &b);
+  void set_scissor(const LPoint3f &a, const LPoint3f &b, 
+                   const LPoint3f &c, const LPoint3f &d);
+  void set_scissor(const NodePath &other, 
+                   const LPoint3f &a, const LPoint3f &b);
+  void set_scissor(const NodePath &other,
+                   const LPoint3f &a, const LPoint3f &b, 
+                   const LPoint3f &c, const LPoint3f &d);
+  void clear_scissor();
+  bool has_scissor() const;
+
   void set_bin(const string &bin_name, int draw_order, int priority = 0);
   void clear_bin();
   bool has_bin() const;

+ 10 - 1
panda/src/pgraph/pandaNode.cxx

@@ -344,7 +344,16 @@ void PandaNode::
 apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types,
                           GeomTransformer &transformer) {
   if ((attrib_types & SceneGraphReducer::TT_transform) != 0) {
-    xform(attribs._transform->get_mat());
+    const LMatrix4f &mat = attribs._transform->get_mat();
+    xform(mat);
+
+    Thread *current_thread = Thread::get_current_thread();
+    OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
+      CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
+      cdata->_effects = cdata->_effects->xform(mat);
+      cdata->set_fancy_bit(FB_effects, !cdata->_effects->is_empty());
+    }
+    CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
   }
 }
 

+ 31 - 0
panda/src/pgraph/scissorAttrib.cxx

@@ -103,6 +103,37 @@ compare_to_impl(const RenderAttrib *other) const {
   return _frame.compare_to(ta->_frame);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorAttrib::compose_impl
+//       Access: Protected, Virtual
+//  Description: Intended to be overridden by derived RenderAttrib
+//               types to specify how two consecutive RenderAttrib
+//               objects of the same type interact.
+//
+//               This should return the result of applying the other
+//               RenderAttrib to a node in the scene graph below this
+//               RenderAttrib, which was already applied.  In most
+//               cases, the result is the same as the other
+//               RenderAttrib (that is, a subsequent RenderAttrib
+//               completely replaces the preceding one).  On the other
+//               hand, some kinds of RenderAttrib (for instance,
+//               ColorTransformAttrib) might combine in meaningful
+//               ways.
+////////////////////////////////////////////////////////////////////
+CPT(RenderAttrib) ScissorAttrib::
+compose_impl(const RenderAttrib *other) const {
+  const ScissorAttrib *ta;
+  DCAST_INTO_R(ta, other, 0);
+
+  LVecBase4f new_frame(max(ta->_frame[0], _frame[0]),
+                       min(ta->_frame[1], _frame[1]),
+                       max(ta->_frame[2], _frame[2]),
+                       min(ta->_frame[3], _frame[3]));
+  
+  ScissorAttrib *attrib = new ScissorAttrib(new_frame);
+  return return_new(attrib);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ScissorAttrib::make_default_impl
 //       Access: Protected, Virtual

+ 1 - 0
panda/src/pgraph/scissorAttrib.h

@@ -55,6 +55,7 @@ public:
 
 protected:
   virtual int compare_to_impl(const RenderAttrib *other) const;
+  virtual CPT(RenderAttrib) compose_impl(const RenderAttrib *other) const;
   virtual RenderAttrib *make_default_impl() const;
 
 private:

+ 13 - 1
panda/src/pgraph/scissorEffect.I

@@ -63,7 +63,19 @@ get_num_points() const {
 INLINE const LPoint3f &ScissorEffect::
 get_point(int n) const {
   nassertr(n >= 0 && n < (int)_points.size(), LPoint3f::zero());
-  return _points[n];
+  return _points[n]._p;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorEffect::get_node
+//       Access: Published
+//  Description: Returns the node to which the nth point is relative,
+//               or empty NodePath to indicate the current node.
+////////////////////////////////////////////////////////////////////
+INLINE NodePath ScissorEffect::
+get_node(int n) const {
+  nassertr(n >= 0 && n < (int)_points.size(), NodePath());
+  return _points[n]._node;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 126 - 35
panda/src/pgraph/scissorEffect.cxx

@@ -33,7 +33,7 @@ TypeHandle ScissorEffect::_type_handle;
 ////////////////////////////////////////////////////////////////////
 ScissorEffect::
 ScissorEffect(bool screen, const LVecBase4f &frame,
-              const LPoint3f *points, int num_points, bool clip) :
+              const PointDef *points, int num_points, bool clip) :
   _screen(screen), _frame(frame), _clip(clip) 
 {
   _points.reserve(num_points);
@@ -42,6 +42,21 @@ ScissorEffect(bool screen, const LVecBase4f &frame,
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorEffect::Copy Constructor
+//       Access: Private
+//  Description: Use ScissorEffect::make() to construct a new
+//               ScissorEffect object.
+////////////////////////////////////////////////////////////////////
+ScissorEffect::
+ScissorEffect(const ScissorEffect &copy) :
+  _screen(copy._screen), 
+  _frame(copy._frame),
+  _points(copy._points),
+  _clip(copy._clip)
+{
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ScissorEffect::make_screen
 //       Access: Published, Static
@@ -55,20 +70,37 @@ make_screen(const LVecBase4f &frame, bool clip) {
   return return_new(effect);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorEffect::make_node
+//       Access: Published, Static
+//  Description: Constructs a new node-relative ScissorEffect, with no
+//               points.  This empty ScissorEffect does nothing.  You
+//               must then call add_point a number of times to add the
+//               points you require.
+////////////////////////////////////////////////////////////////////
+CPT(RenderEffect) ScissorEffect::
+make_node(bool clip) {
+  ScissorEffect *effect = new ScissorEffect(false, LVecBase4f::zero(), NULL, 0, clip);
+  return return_new(effect);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ScissorEffect::make_node
 //       Access: Published, Static
 //  Description: Constructs a new node-relative ScissorEffect.  The
 //               two points are understood to be relative to the
-//               current node, and determine the diagonally opposite
+//               indicated node, or the current node if the NodePath
+//               is empty, and determine the diagonally opposite
 //               corners of the scissor region.
 ////////////////////////////////////////////////////////////////////
 CPT(RenderEffect) ScissorEffect::
-make_node(const LPoint3f &a, const LPoint3f &b, bool clip) {
-  LPoint3f points[2];
-  points[0] = a;
-  points[1] = b;
-  ScissorEffect *effect = new ScissorEffect(false, LVecBase4f::zero(), points, 2, clip);
+make_node(const LPoint3f &a, const LPoint3f &b, const NodePath &node) {
+  PointDef points[2];
+  points[0]._p = a;
+  points[0]._node = node;
+  points[1]._p = b;
+  points[1]._node = node;
+  ScissorEffect *effect = new ScissorEffect(false, LVecBase4f::zero(), points, 2, true);
   return return_new(effect);
 }
 
@@ -77,30 +109,70 @@ make_node(const LPoint3f &a, const LPoint3f &b, bool clip) {
 //       Access: Published, Static
 //  Description: Constructs a new node-relative ScissorEffect.  The
 //               four points are understood to be relative to the
-//               current node, and determine four points surrounding
-//               the scissor region.
+//               indicated node, or the current node if the indicated
+//               NodePath is empty, and determine four points
+//               surrounding the scissor region.
+////////////////////////////////////////////////////////////////////
+CPT(RenderEffect) ScissorEffect::
+make_node(const LPoint3f &a, const LPoint3f &b, const LPoint3f &c, const LPoint3f &d, const NodePath &node) {
+  PointDef points[4];
+  points[0]._p = a;
+  points[0]._node = node;
+  points[1]._p = b;
+  points[1]._node = node;
+  points[2]._p = c;
+  points[2]._node = node;
+  points[3]._p = d;
+  points[3]._node = node;
+  ScissorEffect *effect = new ScissorEffect(false, LVecBase4f::zero(), points, 4, true);
+  return return_new(effect);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorEffect::add_point
+//       Access: Published
+//  Description: Returns a new ScissorEffect with the indicated point
+//               added.  It is only valid to call this on a "node"
+//               type ScissorEffect.  The full set of points,
+//               projected into screen space, defines the bounding
+//               volume of the rectangular scissor region.
+//
+//               Each point may be relative to a different node, if
+//               desired.
 ////////////////////////////////////////////////////////////////////
 CPT(RenderEffect) ScissorEffect::
-make_node(const LPoint3f &a, const LPoint3f &b, const LPoint3f &c, const LPoint3f &d, bool clip) {
-  LPoint3f points[4];
-  points[0] = a;
-  points[1] = b;
-  points[2] = c;
-  points[3] = d;
-  ScissorEffect *effect = new ScissorEffect(false, LVecBase4f::zero(), points, 4, clip);
+add_point(const LPoint3f &p, const NodePath &node) const {
+  nassertr(!is_screen(), this);
+  ScissorEffect *effect = new ScissorEffect(*this);
+  PointDef point;
+  point._p = p;
+  point._node = node;
+  effect->_points.push_back(point);
   return return_new(effect);
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: ScissorEffect::safe_to_transform
+//     Function: ScissorEffect::xform
 //       Access: Public, Virtual
-//  Description: Returns true if it is generally safe to transform
-//               this particular kind of RenderEffect by calling the
-//               xform() method, false otherwise.
+//  Description: Returns a new RenderEffect transformed by the
+//               indicated matrix.
 ////////////////////////////////////////////////////////////////////
-bool ScissorEffect::
-safe_to_transform() const {
-  return false;
+CPT(RenderEffect) ScissorEffect::
+xform(const LMatrix4f &mat) const {
+  if (is_screen()) {
+    return this;
+  }
+  ScissorEffect *effect = new ScissorEffect(*this);
+  Points::iterator pi;
+  for (pi = effect->_points.begin();
+       pi != effect->_points.end();
+       ++pi) {
+    PointDef &point = (*pi);
+    if (point._node.is_empty()) {
+      point._p = point._p * mat;
+    }
+  }
+  return return_new(effect);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -117,7 +189,12 @@ output(ostream &out) const {
     out << "node";
     Points::const_iterator pi;
     for (pi = _points.begin(); pi != _points.end(); ++pi) {
-      out << " [" << (*pi) << "]";
+      const PointDef &point = (*pi);
+      if (point._node.is_empty()) {
+        out << " (" << point._p << ")";
+      } else {
+        out << " (" << point._node << ":" << point._p << ")";
+      }
     }
   }
   if (!get_clip()) {
@@ -162,8 +239,9 @@ cull_callback(CullTraverser *trav, CullTraverserData &data,
               CPT(RenderState) &node_state) const {
   LVecBase4f frame;
   const Lens *lens = trav->get_scene()->get_lens();
-  CPT(TransformState) modelview_transform = data.get_modelview_transform(trav)->compose(node_transform);
-  if (modelview_transform->is_singular()) {
+  CPT(TransformState) modelview_transform = data.get_modelview_transform(trav);
+  CPT(TransformState) net_transform = modelview_transform->compose(node_transform);
+  if (net_transform->is_singular()) {
     // If we're under a singular transform, never mind.
     return;
   }
@@ -172,15 +250,24 @@ cull_callback(CullTraverser *trav, CullTraverserData &data,
     frame = _frame;
   } else {
     const LMatrix4f &proj_mat = lens->get_projection_mat();
-    LMatrix4f net_mat = modelview_transform->get_mat() * proj_mat;
+    LMatrix4f net_mat = net_transform->get_mat() * proj_mat;
 
     bool any_points = false;
 
     Points::const_iterator pi;
     for (pi = _points.begin(); pi != _points.end(); ++pi) {
-      const LPoint3f &p = (*pi);
-      LVecBase4f pv(p[0], p[1], p[2], 1.0f);
-      pv = pv * net_mat;
+      const PointDef &point = (*pi);
+      LVecBase4f pv(point._p[0], point._p[1], point._p[2], 1.0f);
+      if (point._node.is_empty()) {
+        // Relative to this node.
+        pv = pv * net_mat;
+
+      } else {
+        // Relative to some other node.
+        LMatrix4f other_mat = point._node.get_net_transform()->get_mat() * proj_mat;
+        pv = pv * other_mat;
+      }
+
       if (pv[3] == 0) {
         continue;
       }
@@ -264,7 +351,11 @@ compare_to_impl(const RenderEffect *other) const {
       return compare;
     }
     for (size_t i = 0; i < _points.size(); ++i) {
-      compare = _points[i].compare_to(ta->_points[i]);
+      compare = _points[i]._p.compare_to(ta->_points[i]._p);
+      if (compare != 0) {
+        return compare;
+      }
+      compare = _points[i]._node.compare_to(ta->_points[i]._node);
       if (compare != 0) {
         return compare;
       }
@@ -301,7 +392,7 @@ write_datagram(BamWriter *manager, Datagram &dg) {
     dg.add_uint16(_points.size());
     Points::const_iterator pi;
     for (pi = _points.begin(); pi != _points.end(); ++pi) {
-      (*pi).write_datagram(dg);
+      (*pi)._p.write_datagram(dg);
     }
   }
   dg.add_bool(_clip);
@@ -345,9 +436,9 @@ fillin(DatagramIterator &scan, BamReader *manager) {
     int num_points = scan.get_uint16();
     _points.reserve(num_points);
     for (int i = 0; i < num_points; ++i) {
-      LPoint3f p;
-      p.read_datagram(scan);
-      _points.push_back(p);
+      PointDef point;
+      point._p.read_datagram(scan);
+      _points.push_back(point);
     }
   }
   _clip = scan.get_bool();

+ 15 - 5
panda/src/pgraph/scissorEffect.h

@@ -31,24 +31,34 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_PGRAPH ScissorEffect : public RenderEffect {
 private:
+  class PointDef {
+  public:
+    LPoint3f _p;
+    NodePath _node;
+  };
+
   ScissorEffect(bool screen, const LVecBase4f &frame,
-                const LPoint3f *points, int num_points, bool clip);
+                const PointDef *points, int num_points, bool clip);
+  ScissorEffect(const ScissorEffect &copy);
 
 PUBLISHED:
   static CPT(RenderEffect) make_screen(const LVecBase4f &frame, bool clip = true);
-  static CPT(RenderEffect) make_node(const LPoint3f &a, const LPoint3f &b, bool clip = true);
-  static CPT(RenderEffect) make_node(const LPoint3f &a, const LPoint3f &b, const LPoint3f &c, const LPoint3f &d, bool clip = true);
+  static CPT(RenderEffect) make_node(bool clip = true);
+  static CPT(RenderEffect) make_node(const LPoint3f &a, const LPoint3f &b, const NodePath &node = NodePath());
+  static CPT(RenderEffect) make_node(const LPoint3f &a, const LPoint3f &b, const LPoint3f &c, const LPoint3f &d, const NodePath &node = NodePath());
+  CPT(RenderEffect) add_point(const LPoint3f &point, const NodePath &node = NodePath()) const;
 
   INLINE bool is_screen() const;
   INLINE const LVecBase4f &get_frame() const;
 
   INLINE int get_num_points() const;
   INLINE const LPoint3f &get_point(int n) const;
+  INLINE NodePath get_node(int n) const;
 
   INLINE bool get_clip() const;
 
 public:
-  virtual bool safe_to_transform() const;
+  virtual CPT(RenderEffect) xform(const LMatrix4f &mat) const;
   virtual void output(ostream &out) const;
 
   virtual bool has_cull_callback() const;
@@ -65,7 +75,7 @@ private:
 private:
   bool _screen;
   LVecBase4f _frame;
-  typedef pvector<LPoint3f> Points;
+  typedef pvector<PointDef> Points;
   Points _points;
   bool _clip;
 

+ 4 - 6
panda/src/pgui/pgVirtualFrame.I

@@ -88,13 +88,11 @@ get_canvas_node() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: PGVirtualFrame::get_clip_plane_node
+//     Function: PGVirtualFrame::get_canvas_parent
 //       Access: Published
-//  Description: Returns the special node that holds all of PlaneNodes
-//               that are used for applying the clip planes to the
-//               canvas_node.
+//  Description: Returns the parent node of the canvas_node.
 ////////////////////////////////////////////////////////////////////
 INLINE PandaNode *PGVirtualFrame::
-get_clip_plane_node() const {
-  return _clip_plane_node;
+get_canvas_parent() const {
+  return _canvas_parent;
 }

+ 19 - 40
panda/src/pgui/pgVirtualFrame.cxx

@@ -13,8 +13,7 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "pgVirtualFrame.h"
-#include "clipPlaneAttrib.h"
-#include "planeNode.h"
+#include "scissorEffect.h"
 #include "sceneGraphReducer.h"
 
 TypeHandle PGVirtualFrame::_type_handle;
@@ -99,7 +98,7 @@ r_copy_children(const PandaNode *from, PandaNode::InstanceMap &inst_map,
   // Reassign the canvas_node to point to the new copy, if it's there.
   const PGVirtualFrame *from_frame = DCAST(PGVirtualFrame, from);
   PandaNode *from_canvas_node = from_frame->get_canvas_node();
-  PandaNode *from_clip_plane_node = from_frame->get_clip_plane_node();
+  PandaNode *from_canvas_parent = from_frame->get_canvas_parent();
 
   InstanceMap::const_iterator ci;
   ci = inst_map.find(from_canvas_node);
@@ -108,10 +107,10 @@ r_copy_children(const PandaNode *from, PandaNode::InstanceMap &inst_map,
     _canvas_node = DCAST(ModelNode, (*ci).second);
   }
 
-  ci = inst_map.find(from_clip_plane_node);
+  ci = inst_map.find(from_canvas_parent);
   if (ci != inst_map.end()) {
-    remove_child(_clip_plane_node);
-    _clip_plane_node = (*ci).second;
+    remove_child(_canvas_parent);
+    _canvas_parent = DCAST(ModelNode, (*ci).second);
   }
 
   // Reassign the clip planes according to the clip frame.
@@ -163,33 +162,14 @@ set_clip_frame(const LVecBase4f &frame) {
   if (!_has_clip_frame || _clip_frame != frame) {
     _has_clip_frame = true;
     _clip_frame = frame;
+
+    CPT(RenderEffect) scissor_effect = ScissorEffect::make_node
+      (LPoint3f(_clip_frame[0], _clip_frame[2], _clip_frame[2]),
+       LPoint3f(_clip_frame[1], _clip_frame[2], _clip_frame[2]),
+       LPoint3f(_clip_frame[1], _clip_frame[3], _clip_frame[3]),
+       LPoint3f(_clip_frame[0], _clip_frame[3], _clip_frame[3]));
     
-    const LVector3f r = LVector3f::right();
-    const LVector3f u = LVector3f::up();
-    
-    PT(PlaneNode) left_clip = 
-      new PlaneNode("left_clip", Planef(r, r * _clip_frame[0]));
-    PT(PlaneNode) right_clip = 
-      new PlaneNode("right_clip", Planef(-r, r * _clip_frame[1]));
-    
-    PT(PlaneNode) bottom_clip = 
-      new PlaneNode("bottom_clip", Planef(u, u * _clip_frame[2]));
-    PT(PlaneNode) top_clip = 
-      new PlaneNode("top_clip", Planef(-u, u * _clip_frame[3]));
-    
-    _clip_plane_node->remove_all_children();
-    _clip_plane_node->add_child(left_clip);
-    _clip_plane_node->add_child(right_clip);
-    _clip_plane_node->add_child(bottom_clip);
-    _clip_plane_node->add_child(top_clip);
-    
-    CPT(ClipPlaneAttrib) plane_attrib = DCAST(ClipPlaneAttrib, ClipPlaneAttrib::make());
-    plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib->add_on_plane(NodePath::any_path(left_clip)));
-    plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib->add_on_plane(NodePath::any_path(right_clip)));
-    plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib->add_on_plane(NodePath::any_path(bottom_clip)));
-    plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib->add_on_plane(NodePath::any_path(top_clip)));
-    
-    _canvas_node->set_attrib(plane_attrib);
+    _canvas_parent->set_effect(scissor_effect);
     clip_frame_changed();
   }
 }
@@ -205,7 +185,7 @@ clear_clip_frame() {
   if (_has_clip_frame) {
     _has_clip_frame = false;
     
-    _canvas_node->clear_attrib(ClipPlaneAttrib::get_class_type());
+    _canvas_parent->clear_effect(ScissorEffect::get_class_type());
     clip_frame_changed();
   }
 }
@@ -222,17 +202,16 @@ clip_frame_changed() {
 ////////////////////////////////////////////////////////////////////
 //     Function: PGVirtualFrame::setup_child_nodes
 //       Access: Private
-//  Description: Creates the special canvas_node and clip_plane_node
+//  Description: Creates the special canvas_node and canvas_parent
 //               for this object.
 ////////////////////////////////////////////////////////////////////
 void PGVirtualFrame::
 setup_child_nodes() {
+  _canvas_parent = new ModelNode("canvas_parent");
+  _canvas_parent->set_preserve_transform(ModelNode::PT_local);
+  add_child(_canvas_parent);
+
   _canvas_node = new ModelNode("canvas");
   _canvas_node->set_preserve_transform(ModelNode::PT_local);
-  // We have to preserve the clip plane attribute.
-  _canvas_node->set_preserve_attributes(SceneGraphReducer::TT_other);
-  add_child(_canvas_node);
-
-  _clip_plane_node = new PandaNode("clip_planes");
-  add_child(_clip_plane_node);
+  _canvas_parent->add_child(_canvas_node);
 }

+ 9 - 9
panda/src/pgui/pgVirtualFrame.h

@@ -29,19 +29,19 @@ class TransformState;
 //               only see the portion of the canvas that is below the
 //               window at any given time.
 //
-//               This works simply by automatically defining clipping
-//               planes to be applied to a special child node, called
+//               This works simply by automatically defining a scissor
+//               effect to be applied to a special child node, called
 //               the canvas_node, of the PGVirtualFrame node.  Every
 //               object that is parented to the canvas_node will be
-//               clipped by the clip_frame.  Also, you can modify the
-//               canvas_transform through convenience methods here,
-//               which actually modifies the transform on the
+//               clipped by the scissor effect.  Also, you can modify
+//               the canvas_transform through convenience methods
+//               here, which actually modifies the transform on the
 //               canvas_node.
 //
 //               The net effect is that the virtual canvas is
 //               arbitrarily large, and we can peek at it through the
-//               clip_frame, and scroll through different parts of it
-//               by modifying the canvas_transform.
+//               scissor region, and scroll through different parts of
+//               it by modifying the canvas_transform.
 //
 //               See PGScrollFrame for a specialization of this class
 //               that handles the traditional scrolling canvas, with
@@ -71,7 +71,7 @@ PUBLISHED:
   INLINE const TransformState *get_canvas_transform() const;
 
   INLINE PandaNode *get_canvas_node() const;
-  INLINE PandaNode *get_clip_plane_node() const;
+  INLINE PandaNode *get_canvas_parent() const;
 
 protected:
   virtual void clip_frame_changed();
@@ -84,7 +84,7 @@ private:
   LVecBase4f _clip_frame;
 
   PT(ModelNode) _canvas_node;
-  PT(PandaNode) _clip_plane_node;
+  PT(ModelNode) _canvas_parent;
 
 public:
   static TypeHandle get_class_type() {