Răsfoiți Sursa

scissor MouseWatcherRegions too

David Rose 17 ani în urmă
părinte
comite
4d59f04134

+ 19 - 0
panda/src/pgraph/renderState.I

@@ -366,6 +366,25 @@ get_clip_plane() const {
   return _clip_plane;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::get_scissor
+//       Access: Published
+//  Description: This function is provided as an optimization, to
+//               speed up the render-time checking for the existance
+//               of a ScissorAttrib on this state.  It returns a
+//               pointer to the ScissorAttrib, if there is one, or
+//               NULL if there is not.
+////////////////////////////////////////////////////////////////////
+INLINE const ScissorAttrib *RenderState::
+get_scissor() const {
+  if ((_flags & F_checked_scissor) == 0) {
+    // We pretend this function is const, even though it transparently
+    // modifies the internal scissor cache.
+    ((RenderState *)this)->determine_scissor();
+  }
+  return _scissor;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::get_shader
 //       Access: Published

+ 22 - 0
panda/src/pgraph/renderState.cxx

@@ -18,6 +18,7 @@
 #include "cullBinManager.h"
 #include "fogAttrib.h"
 #include "clipPlaneAttrib.h"
+#include "scissorAttrib.h"
 #include "transparencyAttrib.h"
 #include "colorAttrib.h"
 #include "colorScaleAttrib.h"
@@ -1972,6 +1973,27 @@ determine_clip_plane() {
   _flags |= F_checked_clip_plane;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::determine_scissor
+//       Access: Private
+//  Description: This is the private implementation of get_scissor().
+////////////////////////////////////////////////////////////////////
+void RenderState::
+determine_scissor() {
+  MutexHolder holder(_lock);
+  if ((_flags & F_checked_scissor) != 0) {
+    // Someone else checked it first.
+    return;
+  }
+
+  const RenderAttrib *attrib = get_attrib(ScissorAttrib::get_class_type());
+  _scissor = (const ScissorAttrib *)NULL;
+  if (attrib != (const RenderAttrib *)NULL) {
+    _scissor = DCAST(ScissorAttrib, attrib);
+  }
+  _flags |= F_checked_scissor;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::determine_shader
 //       Access: Private

+ 22 - 17
panda/src/pgraph/renderState.h

@@ -42,6 +42,7 @@ class ColorScaleAttrib;
 class TextureAttrib;
 class TexGenAttrib;
 class ClipPlaneAttrib;
+class ScissorAttrib;
 class ShaderAttrib;
 class FactoryParams;
 class AudioVolumeAttrib;
@@ -147,6 +148,7 @@ PUBLISHED:
   INLINE const TexMatrixAttrib *get_tex_matrix() const;
   INLINE const RenderModeAttrib *get_render_mode() const;
   INLINE const ClipPlaneAttrib *get_clip_plane() const;
+  INLINE const ScissorAttrib *get_scissor() const;
   INLINE const ShaderAttrib *get_shader() const;
   INLINE const AudioVolumeAttrib *get_audio_volume() const;
   
@@ -201,6 +203,7 @@ private:
   void determine_tex_matrix();
   void determine_render_mode();
   void determine_clip_plane();
+  void determine_scissor();
   void determine_shader();
   void determine_cull_callback();
   void determine_audio_volume();
@@ -315,28 +318,30 @@ private:
   const TexMatrixAttrib *_tex_matrix;
   const RenderModeAttrib *_render_mode;
   const ClipPlaneAttrib *_clip_plane;
+  const ScissorAttrib *_scissor;
   const ShaderAttrib *_shader;
   const AudioVolumeAttrib *_audio_volume;
   
   enum Flags {
-    F_checked_bin_index     = 0x0001,
-    F_checked_fog           = 0x0002,
-    F_checked_bin           = 0x0004,
-    F_checked_transparency  = 0x0008,
-    F_checked_color         = 0x0010,
-    F_checked_color_scale   = 0x0020,
-    F_checked_texture       = 0x0040,
-    F_checked_tex_gen       = 0x0080,
-    F_checked_tex_matrix    = 0x0100,
-    F_checked_render_mode   = 0x0200,
-    F_checked_clip_plane    = 0x0400,
-    F_checked_shader        = 0x0800,
-    F_checked_cull_callback = 0x1000,
-    F_checked_audio_volume  = 0x2000,
-    F_has_cull_callback     = 0x4000,
-    F_is_destructing        = 0x8000,
+    F_checked_bin_index     = 0x000001,
+    F_checked_fog           = 0x000002,
+    F_checked_bin           = 0x000004,
+    F_checked_transparency  = 0x000008,
+    F_checked_color         = 0x000010,
+    F_checked_color_scale   = 0x000020,
+    F_checked_texture       = 0x000040,
+    F_checked_tex_gen       = 0x000080,
+    F_checked_tex_matrix    = 0x000100,
+    F_checked_render_mode   = 0x000200,
+    F_checked_clip_plane    = 0x000400,
+    F_checked_shader        = 0x000800,
+    F_checked_cull_callback = 0x001000,
+    F_checked_audio_volume  = 0x002000,
+    F_has_cull_callback     = 0x004000,
+    F_is_destructing        = 0x008000,
+    F_checked_scissor       = 0x010000,
   };
-  unsigned short _flags;
+  unsigned int _flags;
 
   // This mutex protects _flags, and all of the above computed values.
   Mutex _lock;

+ 31 - 12
panda/src/pgui/pgItem.cxx

@@ -26,6 +26,7 @@
 #include "cullTraverserData.h"
 #include "cullBinManager.h"
 #include "clipPlaneAttrib.h"
+#include "scissorAttrib.h"
 #include "dcast.h"
 #include "boundingSphere.h"
 #include "boundingBox.h"
@@ -252,7 +253,8 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
       // which only provides one.
       sort = (bin_sort << 16) | ((sort + 0x8000) & 0xffff);
 
-      if (activate_region(transform, sort, data._state->get_clip_plane())) {
+      if (activate_region(transform, sort, data._state->get_clip_plane(),
+                          data._state->get_scissor())) {
         pg_trav->_top->add_region(get_region());
       }
     }
@@ -379,7 +381,8 @@ xform(const LMatrix4f &mat) {
 ////////////////////////////////////////////////////////////////////
 bool PGItem::
 activate_region(const LMatrix4f &transform, int sort,
-                const ClipPlaneAttrib *cpa) {
+                const ClipPlaneAttrib *cpa,
+                const ScissorAttrib *sa) {
   // Transform all four vertices, and get the new bounding box.  This
   // way the region works (mostly) even if has been rotated.
   LPoint3f ll(_frame[0], 0.0f, _frame[2]);
@@ -391,8 +394,10 @@ activate_region(const LMatrix4f &transform, int sort,
   ul = ul * transform;
   ur = ur * transform;
 
+  LVecBase4f frame;
   if (cpa != (ClipPlaneAttrib *)NULL && cpa->get_num_on_planes() != 0) {
-    // Apply the clip plane(s) now that we are here in world space.
+    // Apply the clip plane(s) and/or scissor region now that we are
+    // here in world space.
     
     pvector<LPoint2f> points;
     points.reserve(4);
@@ -406,13 +411,13 @@ activate_region(const LMatrix4f &transform, int sort,
       NodePath plane_path = cpa->get_on_plane(i);
       Planef plane = DCAST(PlaneNode, plane_path.node())->get_plane();
       plane.xform(plane_path.get_net_transform()->get_mat());
-
+      
       // We ignore the y coordinate, assuming the frame is still in
       // the X-Z plane after being transformed.  Not sure if we really
       // need to support general 3-D transforms on 2-D objects.
       clip_frame(points, plane);
     }
-
+    
     if (points.empty()) {
       // Turns out it's completely clipped after all.
       return false;
@@ -420,7 +425,7 @@ activate_region(const LMatrix4f &transform, int sort,
 
     pvector<LPoint2f>::iterator pi;
     pi = points.begin();
-    LVecBase4f frame((*pi)[0], (*pi)[0], (*pi)[1], (*pi)[1]);
+    frame.set((*pi)[0], (*pi)[0], (*pi)[1], (*pi)[1]);
     ++pi;
     while (pi != points.end()) {
       frame[0] = min(frame[0], (*pi)[0]);
@@ -429,15 +434,29 @@ activate_region(const LMatrix4f &transform, int sort,
       frame[3] = max(frame[3], (*pi)[1]);
       ++pi;
     }
-    _region->set_frame(frame);
-
   } else {
     // Since there are no clip planes involved, just set the frame.
-    _region->set_frame(min(min(ll[0], lr[0]), min(ul[0], ur[0])),
-                       max(max(ll[0], lr[0]), max(ul[0], ur[0])),
-                       min(min(ll[2], lr[2]), min(ul[2], ur[2])),
-                       max(max(ll[2], lr[2]), max(ul[2], ur[2])));
+    frame.set(min(min(ll[0], lr[0]), min(ul[0], ur[0])),
+              max(max(ll[0], lr[0]), max(ul[0], ur[0])),
+              min(min(ll[2], lr[2]), min(ul[2], ur[2])),
+              max(max(ll[2], lr[2]), max(ul[2], ur[2])));
   }
+
+  if (sa != (ScissorAttrib *)NULL) {
+    // Also restrict it to within the scissor region.
+    const LVecBase4f &sf = sa->get_frame();
+    // Expand sf from 0..1 to -1..1.
+    frame.set(max(frame[0], sf[0] * 2.0f - 1.0f),
+              min(frame[1], sf[1] * 2.0f - 1.0f),
+              max(frame[2], sf[2] * 2.0f - 1.0f),
+              min(frame[3], sf[3] * 2.0f - 1.0f));
+    if (frame[1] <= frame[0] || frame[3] <= frame[2]) {
+      // Completely outside the scissor region.
+      return false;
+    }
+  }
+
+  _region->set_frame(frame);
                      
   _region->set_sort(sort);
   _region->set_active(true);

+ 3 - 1
panda/src/pgui/pgItem.h

@@ -34,6 +34,7 @@ class PGTop;
 class MouseWatcherParameter;
 class AudioSound;
 class ClipPlaneAttrib;
+class ScissorAttrib;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : PGItem
@@ -70,7 +71,8 @@ protected:
 public:
   virtual void xform(const LMatrix4f &mat);
   bool activate_region(const LMatrix4f &transform, int sort,
-                       const ClipPlaneAttrib *cpa);
+                       const ClipPlaneAttrib *cpa,
+                       const ScissorAttrib *sa);
   INLINE PGMouseWatcherRegion *get_region() const;
 
   virtual void enter_region(const MouseWatcherParameter &param);