Forráskód Böngészése

ScissorAttrib, ScissorEffect

David Rose 17 éve
szülő
commit
8537bd7320

+ 0 - 17
panda/src/glstuff/glGraphicsStateGuardian_src.I

@@ -386,23 +386,6 @@ enable_stencil_test(bool val) {
   }
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::enable_scissor
-//       Access:
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE void CLP(GraphicsStateGuardian)::
-enable_scissor(bool val)
-{
-    if ( _scissor_enabled != val ) {
-        _scissor_enabled = val;
-        if ( val )
-            GLP(Enable)( GL_SCISSOR_TEST );
-        else
-            GLP(Disable)( GL_SCISSOR_TEST );
-    }
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: CLP(GraphicsStateGuardian)::enable_blend
 //       Access:

+ 26 - 2
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -1154,7 +1154,6 @@ reset() {
   _line_smooth_enabled = false;
   _point_smooth_enabled = false;
   _polygon_smooth_enabled = false;
-  _scissor_enabled = false;
   _stencil_test_enabled = false;
   _blend_enabled = false;
   _depth_test_enabled = false;
@@ -1454,6 +1453,8 @@ prepare_display_region(DisplayRegionPipelineReader *dr,
 
   int l, b, w, h;
   dr->get_region_pixels(l, b, w, h);
+  _viewport_x = l;
+  _viewport_y = b;
   _viewport_width = w;
   _viewport_height = h;
   GLint x = GLint(l);
@@ -1465,7 +1466,7 @@ prepare_display_region(DisplayRegionPipelineReader *dr,
   _draw_buffer_type |= _current_properties->get_aux_mask();
   set_draw_buffer(_draw_buffer_type);
   
-  enable_scissor(true);
+  GLP(Enable)(GL_SCISSOR_TEST);
   GLP(Scissor)(x, y, width, height);
   GLP(Viewport)(x, y, width, height);
 
@@ -6235,6 +6236,11 @@ set_state_and_transform(const RenderState *target,
     }
   }
 
+  if (_target._scissor != _state._scissor) {
+    do_issue_scissor();
+    _state._scissor = _target._scissor;
+  }
+
   _state_rs = _target_rs;
   maybe_gl_finish();
   report_my_gl_errors();
@@ -7952,3 +7958,21 @@ do_issue_stencil() {
     stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_back_enable, 0);
   }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::do_issue_scissor
+//       Access: Protected
+//  Description: Set stencil render states.
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsStateGuardian)::
+do_issue_scissor() {
+  const LVecBase4f &frame = _target._scissor->get_frame();
+
+  int x = _viewport_x + _viewport_width * frame[0];
+  int y = _viewport_y + _viewport_height * frame[2];
+  int width = _viewport_width * (frame[1] - frame[0]);
+  int height = _viewport_height * (frame[3] - frame[2]);
+
+  GLP(Enable)(GL_SCISSOR_TEST);
+  GLP(Scissor)(x, y, width, height);
+}

+ 3 - 2
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -239,6 +239,7 @@ protected:
   void do_issue_tex_gen();
   void do_issue_tex_matrix();
   void do_issue_stencil();
+  void do_issue_scissor();
 
   virtual void gl_flush() const;
   INLINE void maybe_gl_finish() const;
@@ -279,7 +280,6 @@ protected:
   INLINE void setup_antialias_point();
   INLINE void setup_antialias_polygon();
 
-  INLINE void enable_scissor(bool val);
   INLINE void enable_stencil_test(bool val);
   INLINE void enable_blend(bool val);
   INLINE void enable_depth_test(bool val);
@@ -358,7 +358,6 @@ protected:
   bool _line_smooth_enabled;
   bool _point_smooth_enabled;
   bool _polygon_smooth_enabled;
-  bool _scissor_enabled;
   bool _stencil_test_enabled;
   bool _blend_enabled;
   bool _depth_test_enabled;
@@ -370,6 +369,8 @@ protected:
 
   bool _dithering_enabled;
 
+  int _viewport_x;
+  int _viewport_y;
   int _viewport_width;
   int _viewport_height;
   int _draw_buffer_type;

+ 5 - 0
panda/src/gobj/lens.cxx

@@ -72,6 +72,10 @@ operator = (const Lens &copy) {
   _user_flags = copy._user_flags;
   _comp_flags = 0;
 
+  _focal_length_seq = copy._focal_length_seq;
+  _fov_seq = copy._fov_seq;
+  _film_size_seq = copy._film_size_seq;
+
   // We don't copy the _geom_data.  That's unique to each Lens.
 }
 
@@ -1760,6 +1764,7 @@ film_to_fov(float, float, bool) const {
 ////////////////////////////////////////////////////////////////////
 void Lens::
 resequence_fov_triad(char &newest, char &older_a, char &older_b) {
+  nassertv(newest + older_a + older_b == 3);
   switch (newest) {
   case 0:
     newest = 2;

+ 6 - 0
panda/src/pgraph/Sources.pp

@@ -100,6 +100,8 @@
     sceneGraphAnalyzer.h sceneGraphAnalyzer.I \
     sceneGraphReducer.I sceneGraphReducer.h \
     sceneSetup.I sceneSetup.h \
+    scissorAttrib.I scissorAttrib.h \
+    scissorEffect.I scissorEffect.h \
     selectiveChildNode.I selectiveChildNode.h \
     sequenceNode.I sequenceNode.h \
     shadeModelAttrib.I shadeModelAttrib.h \
@@ -211,6 +213,8 @@
     sceneGraphAnalyzer.cxx \
     sceneGraphReducer.cxx \
     sceneSetup.cxx \
+    scissorAttrib.cxx \
+    scissorEffect.cxx \
     selectiveChildNode.cxx \
     sequenceNode.cxx \
     shadeModelAttrib.cxx \
@@ -320,6 +324,8 @@
     sceneGraphAnalyzer.h sceneGraphAnalyzer.I \
     sceneGraphReducer.I sceneGraphReducer.h \
     sceneSetup.I sceneSetup.h \
+    scissorAttrib.I scissorAttrib.h \
+    scissorEffect.I scissorEffect.h \
     selectiveChildNode.I selectiveChildNode.h \
     sequenceNode.I sequenceNode.h \
     shadeModelAttrib.I shadeModelAttrib.h \

+ 1 - 0
panda/src/pgraph/attribSlots.I

@@ -46,6 +46,7 @@ clear_to_zero() {
   _tex_matrix     = NULL;
   _texture        = NULL;
   _transparency   = NULL;
+  _scissor        = NULL;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 33 - 28
panda/src/pgraph/attribSlots.cxx

@@ -55,6 +55,7 @@ initialize_defvals() {
   _defvals._tex_matrix     = DCAST(TexMatrixAttrib,TexMatrixAttrib::make());
   _defvals._texture        = DCAST(TextureAttrib,TextureAttrib::make_all_off());
   _defvals._transparency   = DCAST(TransparencyAttrib,TransparencyAttrib::make(TransparencyAttrib::M_none));
+  _defvals._scissor        = DCAST(ScissorAttrib, ScissorAttrib::make_off());
 
   // Step two. Replace each with make_default_impl.
 
@@ -85,6 +86,7 @@ initialize_defvals() {
   _defvals._tex_matrix     = DCAST(TexMatrixAttrib,_defvals._tex_matrix->make_default());
   _defvals._texture        = DCAST(TextureAttrib,_defvals._texture->make_default());
   _defvals._transparency   = DCAST(TransparencyAttrib,_defvals._transparency->make_default());
+  _defvals._scissor        = DCAST(ScissorAttrib,_defvals._scissor->make_default());
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -129,7 +131,8 @@ AttribSlots(const AttribSlots &copy) :
   _tex_gen(copy._tex_gen),
   _tex_matrix(copy._tex_matrix),
   _texture(copy._texture),
-  _transparency(copy._transparency)
+  _transparency(copy._transparency),
+  _scissor(copy._scissor)
 {
 }
 
@@ -167,6 +170,7 @@ operator =(const AttribSlots &src) {
   _tex_matrix     = src._tex_matrix;
   _texture        = src._texture;
   _transparency   = src._transparency;
+  _scissor        = src._scissor;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -177,33 +181,34 @@ operator =(const AttribSlots &src) {
 const RenderAttrib *AttribSlots::
 get_slot(int n) const {
   switch(n) {
-  case  0: return DCAST(RenderAttrib, _alpha_test);
-  case  1: return DCAST(RenderAttrib, _antialias);
-  case  2: return DCAST(RenderAttrib, _audio_volume);
-  case  3: return DCAST(RenderAttrib, _aux_bitplane);
-  case  4: return DCAST(RenderAttrib, _clip_plane);
-  case  5: return DCAST(RenderAttrib, _color);
-  case  6: return DCAST(RenderAttrib, _color_blend);
-  case  7: return DCAST(RenderAttrib, _color_scale);
-  case  8: return DCAST(RenderAttrib, _color_write);
-  case  9: return DCAST(RenderAttrib, _cull_bin);
-  case 10: return DCAST(RenderAttrib, _cull_face);
-  case 11: return DCAST(RenderAttrib, _depth_offset);
-  case 12: return DCAST(RenderAttrib, _depth_test);
-  case 13: return DCAST(RenderAttrib, _depth_write);
-  case 14: return DCAST(RenderAttrib, _fog);
-  case 15: return DCAST(RenderAttrib, _light);
-  case 16: return DCAST(RenderAttrib, _light_ramp);
-  case 17: return DCAST(RenderAttrib, _material);
-  case 18: return DCAST(RenderAttrib, _render_mode);
-  case 19: return DCAST(RenderAttrib, _rescale_normal);
-  case 20: return DCAST(RenderAttrib, _shade_model);
-  case 21: return DCAST(RenderAttrib, _shader);
-  case 22: return DCAST(RenderAttrib, _stencil);
-  case 23: return DCAST(RenderAttrib, _tex_gen);
-  case 24: return DCAST(RenderAttrib, _tex_matrix);
-  case 25: return DCAST(RenderAttrib, _texture);
-  case 26: return DCAST(RenderAttrib, _transparency);
+  case  0: return _alpha_test;
+  case  1: return _antialias;
+  case  2: return _audio_volume;
+  case  3: return _aux_bitplane;
+  case  4: return _clip_plane;
+  case  5: return _color;
+  case  6: return _color_blend;
+  case  7: return _color_scale;
+  case  8: return _color_write;
+  case  9: return _cull_bin;
+  case 10: return _cull_face;
+  case 11: return _depth_offset;
+  case 12: return _depth_test;
+  case 13: return _depth_write;
+  case 14: return _fog;
+  case 15: return _light;
+  case 16: return _light_ramp;
+  case 17: return _material;
+  case 18: return _render_mode;
+  case 19: return _rescale_normal;
+  case 20: return _shade_model;
+  case 21: return _shader;
+  case 22: return _stencil;
+  case 23: return _tex_gen;
+  case 24: return _tex_matrix;
+  case 25: return _texture;
+  case 26: return _transparency;
+  case 27: return _scissor;
   default:
     nassertr(false, NULL);
     return NULL;

+ 3 - 2
panda/src/pgraph/attribSlots.h

@@ -40,6 +40,7 @@
 #include "materialAttrib.h"
 #include "renderModeAttrib.h"
 #include "rescaleNormalAttrib.h"
+#include "scissorAttrib.h"
 #include "shadeModelAttrib.h"
 #include "shaderAttrib.h"
 #include "stencilAttrib.h"
@@ -84,6 +85,7 @@ class EXPCL_PANDA_PGRAPH AttribSlots
   CPT(TexMatrixAttrib)       _tex_matrix;
   CPT(TextureAttrib)         _texture;
   CPT(TransparencyAttrib)    _transparency;
+  CPT(ScissorAttrib)         _scissor;
 
  public:
   AttribSlots();
@@ -94,8 +96,7 @@ class EXPCL_PANDA_PGRAPH AttribSlots
   INLINE static const AttribSlots &get_defaults();
 
  public:
-  // Each "array" reference requires a switch and a DCAST, so it's not overly fast.
-  enum { slot_count=27 };
+  enum { slot_count=28 };
   const RenderAttrib *get_slot(int n) const;
 
  private:

+ 6 - 0
panda/src/pgraph/config_pgraph.cxx

@@ -80,6 +80,8 @@
 #include "rescaleNormalAttrib.h"
 #include "selectiveChildNode.h"
 #include "sequenceNode.h"
+#include "scissorAttrib.h"
+#include "scissorEffect.h"
 #include "shadeModelAttrib.h"
 #include "shaderInput.h"
 #include "shaderAttrib.h"
@@ -432,6 +434,8 @@ init_libpgraph() {
   RescaleNormalAttrib::init_type();
   SelectiveChildNode::init_type();
   SequenceNode::init_type();
+  ScissorAttrib::init_type();
+  ScissorEffect::init_type();
   ShadeModelAttrib::init_type();
   ShaderInput::init_type();
   ShaderAttrib::init_type();
@@ -498,6 +502,8 @@ init_libpgraph() {
   RenderState::register_with_read_factory();
   RescaleNormalAttrib::register_with_read_factory();
   SequenceNode::register_with_read_factory();
+  ScissorAttrib::register_with_read_factory();
+  ScissorEffect::register_with_read_factory();
   ShadeModelAttrib::register_with_read_factory();
   ShaderInput::register_with_read_factory();
   ShaderAttrib::register_with_read_factory();

+ 2 - 0
panda/src/pgraph/pgraph_composite4.cxx

@@ -8,6 +8,8 @@
 #include "sceneGraphReducer.cxx"
 #include "selectiveChildNode.cxx"
 #include "sequenceNode.cxx"
+#include "scissorAttrib.cxx"
+#include "scissorEffect.cxx"
 #include "shadeModelAttrib.cxx"
 #include "shaderInput.cxx"
 #include "shaderAttrib.cxx"

+ 41 - 0
panda/src/pgraph/scissorAttrib.I

@@ -0,0 +1,41 @@
+// Filename: scissorAttrib.I
+// Created by:  drose (29Jul08)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorAttrib::make
+//       Access: Published, Static
+//  Description: Constructs a ScissorAttrib that restricts rendering
+//               to the indicated frame within the current
+//               DisplayRegion.  (0,0) is the lower-left corner of the
+//               DisplayRegion, and (1,1) is the upper-right corner.
+////////////////////////////////////////////////////////////////////
+INLINE CPT(RenderAttrib) ScissorAttrib::
+make(float left, float right, float bottom, float top) {
+  return make(LVecBase4f(left, right, bottom, top));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorAttrib::get_frame
+//       Access: Published
+//  Description: Returns the left, right, bottom, top coordinates of
+//               the scissor frame.  This defines a frame within the
+//               current DisplayRegion, where 0,0 is the lower-left
+//               corner of the DisplayRegion, and 1,1 is the
+//               upper-right corner.
+////////////////////////////////////////////////////////////////////
+INLINE const LVecBase4f &ScissorAttrib::
+get_frame() const {
+  return _frame;
+}

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

@@ -0,0 +1,189 @@
+// Filename: scissorAttrib.cxx
+// Created by:  drose (29Jul08)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "scissorAttrib.h"
+#include "attribSlots.h"
+#include "graphicsStateGuardianBase.h"
+#include "dcast.h"
+#include "bamReader.h"
+#include "bamWriter.h"
+#include "datagram.h"
+#include "datagramIterator.h"
+
+TypeHandle ScissorAttrib::_type_handle;
+CPT(RenderAttrib) ScissorAttrib::_off;
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorAttrib::Constructor
+//       Access: Private
+//  Description: Use ScissorAttrib::make() to construct a new
+//               ScissorAttrib object.
+////////////////////////////////////////////////////////////////////
+ScissorAttrib::
+ScissorAttrib(const LVecBase4f &frame) :
+  _frame(frame)
+{
+  // Impose sensible bounds.
+  _frame[0] = max(min(_frame[0], 1.0f), 0.0f);
+  _frame[1] = max(min(_frame[1], 1.0f), _frame[0]);
+  _frame[2] = max(min(_frame[2], 1.0f), 0.0f);
+  _frame[3] = max(min(_frame[3], 1.0f), _frame[2]);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorAttrib::make_off
+//       Access: Published, Static
+//  Description: Constructs a new ScissorAttrib object that removes
+//               the scissor region and fills the DisplayRegion.
+////////////////////////////////////////////////////////////////////
+CPT(RenderAttrib) ScissorAttrib::
+make_off() {
+  if (_off != 0) {
+    return _off;
+  }
+  ScissorAttrib *attrib = new ScissorAttrib(LVecBase4f(0.0f, 1.0f, 0.0f, 1.0f));
+  _off = return_new(attrib);
+  return _off;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorAttrib::make
+//       Access: Published, Static
+//  Description: Constructs a ScissorAttrib that restricts rendering
+//               to the indicated frame within the current
+//               DisplayRegion.  (0,0) is the lower-left corner of the
+//               DisplayRegion, and (1,1) is the upper-right corner.
+////////////////////////////////////////////////////////////////////
+CPT(RenderAttrib) ScissorAttrib::
+make(const LVecBase4f &frame) {
+  ScissorAttrib *attrib = new ScissorAttrib(frame);
+  return return_new(attrib);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorAttrib::output
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void ScissorAttrib::
+output(ostream &out) const {
+  out << get_type() << ":[" << _frame << "]";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorAttrib::compare_to_impl
+//       Access: Protected, Virtual
+//  Description: Intended to be overridden by derived ScissorAttrib
+//               types to return a unique number indicating whether
+//               this ScissorAttrib is equivalent to the other one.
+//
+//               This should return 0 if the two ScissorAttrib objects
+//               are equivalent, a number less than zero if this one
+//               should be sorted before the other one, and a number
+//               greater than zero otherwise.
+//
+//               This will only be called with two ScissorAttrib
+//               objects whose get_type() functions return the same.
+////////////////////////////////////////////////////////////////////
+int ScissorAttrib::
+compare_to_impl(const RenderAttrib *other) const {
+  const ScissorAttrib *ta;
+  DCAST_INTO_R(ta, other, 0);
+  return _frame.compare_to(ta->_frame);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorAttrib::make_default_impl
+//       Access: Protected, Virtual
+//  Description: Intended to be overridden by derived ScissorAttrib
+//               types to specify what the default property for a
+//               ScissorAttrib of this type should be.
+//
+//               This should return a newly-allocated ScissorAttrib of
+//               the same type that corresponds to whatever the
+//               standard default for this kind of ScissorAttrib is.
+////////////////////////////////////////////////////////////////////
+RenderAttrib *ScissorAttrib::
+make_default_impl() const {
+  return new ScissorAttrib(LVecBase4f(0.0f, 1.0f, 0.0f, 1.0f));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorAttrib::store_into_slot
+//       Access: Public, Virtual
+//  Description: Stores this attrib into the appropriate slot of
+//               an object of class AttribSlots.
+////////////////////////////////////////////////////////////////////
+void ScissorAttrib::
+store_into_slot(AttribSlots *slots) const {
+  slots->_scissor = this;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorAttrib::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               ScissorAttrib.
+////////////////////////////////////////////////////////////////////
+void ScissorAttrib::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorAttrib::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void ScissorAttrib::
+write_datagram(BamWriter *manager, Datagram &dg) {
+  RenderAttrib::write_datagram(manager, dg);
+
+  _frame.write_datagram(dg);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorAttrib::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of type ScissorAttrib is encountered
+//               in the Bam file.  It should create the ScissorAttrib
+//               and extract its information from the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *ScissorAttrib::
+make_from_bam(const FactoryParams &params) {
+  ScissorAttrib *attrib = new ScissorAttrib(LVecBase4f(0.0f, 1.0f, 0.0f, 1.0f));
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  attrib->fillin(scan, manager);
+
+  return attrib;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorAttrib::fillin
+//       Access: Protected
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new ScissorAttrib.
+////////////////////////////////////////////////////////////////////
+void ScissorAttrib::
+fillin(DatagramIterator &scan, BamReader *manager) {
+  RenderAttrib::fillin(scan, manager);
+
+  _frame.read_datagram(scan);
+}

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

@@ -0,0 +1,93 @@
+// Filename: scissorAttrib.h
+// Created by:  drose (29Jul08)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef SCISSORATTRIB_H
+#define SCISSORATTRIB_H
+
+#include "pandabase.h"
+
+#include "renderAttrib.h"
+#include "luse.h"
+
+class FactoryParams;
+
+////////////////////////////////////////////////////////////////////
+//       Class : ScissorAttrib
+// Description : This restricts rendering to within a rectangular
+//               region of the scene, without otherwise affecting the
+//               viewport or lens properties.  Geometry that falls
+//               outside the scissor region is not rendered.  It is
+//               akin to the OpenGL glScissor() function.
+//
+//               The ScissorAttrib always specifies its region
+//               relative to its enclosing DisplayRegion, in screen
+//               space, and performs no culling.
+//
+//               See ScissorEffect if you wish to define a
+//               region relative to 2-D or 3-D coordinates in the
+//               scene graph, with culling.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA_PGRAPH ScissorAttrib : public RenderAttrib {
+private:
+  ScissorAttrib(const LVecBase4f &frame);
+
+PUBLISHED:
+  static CPT(RenderAttrib) make_off();
+  INLINE static CPT(RenderAttrib) make(float left, float right, float bottom, float top);
+  static CPT(RenderAttrib) make(const LVecBase4f &frame);
+
+  INLINE const LVecBase4f &get_frame() const;
+
+public:
+  virtual void output(ostream &out) const;
+  virtual void store_into_slot(AttribSlots *slots) const;
+
+protected:
+  virtual int compare_to_impl(const RenderAttrib *other) const;
+  virtual RenderAttrib *make_default_impl() const;
+
+private:
+  LVecBase4f _frame;
+  static CPT(RenderAttrib) _off;
+
+public:
+  static void register_with_read_factory();
+  virtual void write_datagram(BamWriter *manager, Datagram &dg);
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+  void fillin(DatagramIterator &scan, BamReader *manager);
+  
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    RenderAttrib::init_type();
+    register_type(_type_handle, "ScissorAttrib",
+                  RenderAttrib::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "scissorAttrib.I"
+
+#endif
+

+ 78 - 0
panda/src/pgraph/scissorEffect.I

@@ -0,0 +1,78 @@
+// Filename: scissorEffect.I
+// Created by:  drose (30Jul08)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorEffect::is_screen
+//       Access: Published
+//  Description: Returns true if the ScissorEffect is a screen-based
+//               effect, meaning get_frame() has a meaningful value,
+//               but get_a() and get_b() do not.
+////////////////////////////////////////////////////////////////////
+INLINE bool ScissorEffect::
+is_screen() const {
+  return _screen;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorEffect::get_frame
+//       Access: Published
+//  Description: If is_screen() returns true, this method may be
+//               called to query the screen-based scissor frame.  This
+//               is a series of left, right, bottom, top, representing
+//               the scissor frame relative to the current
+//               DisplayRegion.  See ScissorAttrib.
+////////////////////////////////////////////////////////////////////
+INLINE const LVecBase4f &ScissorEffect::
+get_frame() const {
+  return _frame;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorEffect::get_num_points
+//       Access: Published
+//  Description: Returns the number of node-based scissor points.  See
+//               get_point().
+////////////////////////////////////////////////////////////////////
+INLINE int ScissorEffect::
+get_num_points() const {
+  return (int)_points.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorEffect::get_point
+//       Access: Published
+//  Description: If is_screen() returns false, then get_num_points() and
+//               get_point() may be called to query the node-based scissor
+//               frame.  These return n points (at least two), which
+//               are understood to be in the space of this node, and
+//               which define any opposite corners of the scissor
+//               frame.
+////////////////////////////////////////////////////////////////////
+INLINE const LPoint3f &ScissorEffect::
+get_point(int n) const {
+  nassertr(n >= 0 && n < (int)_points.size(), LPoint3f::zero());
+  return _points[n];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorEffect::get_clip
+//       Access: Published
+//  Description: Returns true if this ScissorEffect actually enables
+//               scissoring, or false if it culls only.
+////////////////////////////////////////////////////////////////////
+INLINE bool ScissorEffect::
+get_clip() const {
+  return _clip;
+}

+ 403 - 0
panda/src/pgraph/scissorEffect.cxx

@@ -0,0 +1,403 @@
+// Filename: scissorEffect.cxx
+// Created by:  drose (30Jul08)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "scissorEffect.h"
+#include "scissorAttrib.h"
+#include "cullTraverser.h"
+#include "cullTraverserData.h"
+#include "nodePath.h"
+#include "bamReader.h"
+#include "bamWriter.h"
+#include "datagram.h"
+#include "datagramIterator.h"
+#include "boundingHexahedron.h"
+
+TypeHandle ScissorEffect::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorEffect::Constructor
+//       Access: Private
+//  Description: Use ScissorEffect::make() to construct a new
+//               ScissorEffect object.
+////////////////////////////////////////////////////////////////////
+ScissorEffect::
+ScissorEffect(bool screen, const LVecBase4f &frame,
+              const LPoint3f *points, int num_points, bool clip) :
+  _screen(screen), _frame(frame), _clip(clip) 
+{
+  _points.reserve(num_points);
+  for (int i = 0; i < num_points; ++i) {
+    _points.push_back(points[i]);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorEffect::make_screen
+//       Access: Published, Static
+//  Description: Constructs a new screen-relative ScissorEffect.  The
+//               frame defines a left, right, bottom, top region,
+//               relative to the DisplayRegion.  See ScissorAttrib.
+////////////////////////////////////////////////////////////////////
+CPT(RenderEffect) ScissorEffect::
+make_screen(const LVecBase4f &frame, bool clip) {
+  ScissorEffect *effect = new ScissorEffect(true, frame, 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
+//               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);
+  return return_new(effect);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorEffect::make_node
+//       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.
+////////////////////////////////////////////////////////////////////
+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);
+  return return_new(effect);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorEffect::safe_to_transform
+//       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.
+////////////////////////////////////////////////////////////////////
+bool ScissorEffect::
+safe_to_transform() const {
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorEffect::output
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void ScissorEffect::
+output(ostream &out) const {
+  out << get_type() << ":";
+  if (is_screen()) {
+    out << "screen [" << _frame << "]";
+  } else {
+    out << "node";
+    Points::const_iterator pi;
+    for (pi = _points.begin(); pi != _points.end(); ++pi) {
+      out << " [" << (*pi) << "]";
+    }
+  }
+  if (!get_clip()) {
+    out << " !clip";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorEffect::has_cull_callback
+//       Access: Public, Virtual
+//  Description: Should be overridden by derived classes to return
+//               true if cull_callback() has been defined.  Otherwise,
+//               returns false to indicate cull_callback() does not
+//               need to be called for this effect during the cull
+//               traversal.
+////////////////////////////////////////////////////////////////////
+bool ScissorEffect::
+has_cull_callback() const {
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorEffect::cull_callback
+//       Access: Public, Virtual
+//  Description: If has_cull_callback() returns true, this function
+//               will be called during the cull traversal to perform
+//               any additional operations that should be performed at
+//               cull time.  This may include additional manipulation
+//               of render state or additional visible/invisible
+//               decisions, or any other arbitrary operation.
+//
+//               At the time this function is called, the current
+//               node's transform and state have not yet been applied
+//               to the net_transform and net_state.  This callback
+//               may modify the node_transform and node_state to apply
+//               an effective change to the render state at this
+//               level.
+////////////////////////////////////////////////////////////////////
+void ScissorEffect::
+cull_callback(CullTraverser *trav, CullTraverserData &data,
+              CPT(TransformState) &node_transform,
+              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()) {
+    // If we're under a singular transform, never mind.
+    return;
+  }
+
+  if (is_screen()) {
+    frame = _frame;
+  } else {
+    const LMatrix4f &proj_mat = lens->get_projection_mat();
+    LMatrix4f net_mat = modelview_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;
+      if (pv[3] == 0) {
+        continue;
+      }
+      LPoint3f pr(pv[0] / pv[3], pv[1] / pv[3], pv[2] / pv[3]);
+      if (!any_points) {
+        frame[0] = pr[0];
+        frame[1] = pr[0];
+        frame[2] = pr[1];
+        frame[3] = pr[1];
+        any_points = true;
+      } else {
+        frame[0] = min(frame[0], pr[0]);
+        frame[1] = max(frame[1], pr[0]);
+        frame[2] = min(frame[2], pr[1]);
+        frame[3] = max(frame[3], pr[1]);
+      }
+    }
+    
+    // Scale from -1..1 to 0..1.
+    frame[0] = (frame[0] + 1.0f) * 0.5f;
+    frame[1] = (frame[1] + 1.0f) * 0.5f;
+    frame[2] = (frame[2] + 1.0f) * 0.5f;
+    frame[3] = (frame[3] + 1.0f) * 0.5f;
+  }
+
+  // Impose bounding volumes.
+  frame[0] = max(min(frame[0], 1.0f), 0.0f);
+  frame[1] = max(min(frame[1], 1.0f), frame[0]);
+  frame[2] = max(min(frame[2], 1.0f), 0.0f);
+  frame[3] = max(min(frame[3], 1.0f), frame[2]);
+
+  if (_clip) {
+    CPT(RenderAttrib) scissor_attrib = ScissorAttrib::make(frame);
+    CPT(RenderState) state = RenderState::make(scissor_attrib);
+    node_state = node_state->compose(state); 
+  }
+
+  // Set up the culling.  We do this by extruding the four corners of
+  // the frame into the eight corners of the bounding frustum.
+  PT(GeometricBoundingVolume) frustum = make_frustum(lens, frame);
+  if (frustum != (GeometricBoundingVolume *)NULL) {
+    frustum->xform(modelview_transform->get_inverse()->get_mat());
+    data._view_frustum = frustum;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorEffect::compare_to_impl
+//       Access: Protected, Virtual
+//  Description: Intended to be overridden by derived ScissorEffect
+//               types to return a unique number indicating whether
+//               this ScissorEffect is equivalent to the other one.
+//
+//               This should return 0 if the two ScissorEffect objects
+//               are equivalent, a number less than zero if this one
+//               should be sorted before the other one, and a number
+//               greater than zero otherwise.
+//
+//               This will only be called with two ScissorEffect
+//               objects whose get_type() functions return the same.
+////////////////////////////////////////////////////////////////////
+int ScissorEffect::
+compare_to_impl(const RenderEffect *other) const {
+  const ScissorEffect *ta;
+  DCAST_INTO_R(ta, other, 0);
+
+  if (_screen != ta->_screen) {
+    return (int)_screen - (int)ta->_screen;
+  }
+  if (_clip != ta->_clip) {
+    return (int)_clip - (int)ta->_clip;
+  }
+  if (_screen) {
+    int compare = _frame.compare_to(ta->_frame);
+    if (compare != 0) {
+      return compare;
+    }
+  } else {
+    int compare = (int)_points.size() - (int)ta->_points.size();
+    if (compare != 0) {
+      return compare;
+    }
+    for (size_t i = 0; i < _points.size(); ++i) {
+      compare = _points[i].compare_to(ta->_points[i]);
+      if (compare != 0) {
+        return compare;
+      }
+    }
+  }
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorEffect::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               ScissorEffect.
+////////////////////////////////////////////////////////////////////
+void ScissorEffect::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorEffect::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void ScissorEffect::
+write_datagram(BamWriter *manager, Datagram &dg) {
+  RenderEffect::write_datagram(manager, dg);
+
+  dg.add_bool(_screen);
+  if (_screen) {
+    _frame.write_datagram(dg);
+  } else {
+    dg.add_uint16(_points.size());
+    Points::const_iterator pi;
+    for (pi = _points.begin(); pi != _points.end(); ++pi) {
+      (*pi).write_datagram(dg);
+    }
+  }
+  dg.add_bool(_clip);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorEffect::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of type ScissorEffect is encountered
+//               in the Bam file.  It should create the ScissorEffect
+//               and extract its information from the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *ScissorEffect::
+make_from_bam(const FactoryParams &params) {
+  ScissorEffect *effect = new ScissorEffect(true, LVecBase4f::zero(), NULL, 0, false);
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  effect->fillin(scan, manager);
+
+  return effect;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorEffect::fillin
+//       Access: Protected
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new ScissorEffect.
+////////////////////////////////////////////////////////////////////
+void ScissorEffect::
+fillin(DatagramIterator &scan, BamReader *manager) {
+  RenderEffect::fillin(scan, manager);
+
+  _screen = scan.get_bool();
+  if (_screen) {
+    _frame.read_datagram(scan);
+  } else {
+    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);
+    }
+  }
+  _clip = scan.get_bool();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ScissorEffect::make_frustum
+//       Access: Private
+//  Description: Constructs a new bounding frustum from the lens
+//               properties, given the indicated scissor frame.
+////////////////////////////////////////////////////////////////////
+PT(GeometricBoundingVolume) ScissorEffect::
+make_frustum(const Lens *lens, const LVecBase4f &frame) const{
+  // Scale the frame from 0 .. 1 into -1 .. 1.
+  LVecBase4f f2(frame[0] * 2.0f - 1.0f,
+                frame[1] * 2.0f - 1.0f,
+                frame[2] * 2.0f - 1.0f,
+                frame[3] * 2.0f - 1.0f);
+
+  LPoint3f fll, flr, ful, fur;
+  LPoint3f nll, nlr, nul, nur;
+  LPoint2f corner;
+
+  corner[0] = f2[0]; corner[1] = f2[3];
+
+  // Upper left.
+  if (!lens->extrude(corner, nul, ful)) {
+    return (GeometricBoundingVolume *)NULL;
+  }
+
+  corner[0] = f2[1]; corner[1] = f2[3];
+
+  // Upper right.
+  if (!lens->extrude(corner, nur, fur)) {
+    return (GeometricBoundingVolume *)NULL;
+  }
+
+  corner[0] = f2[1]; corner[1] = f2[2];
+
+  // Lower right.
+  if (!lens->extrude(corner, nlr, flr)) {
+    return (GeometricBoundingVolume *)NULL;
+  }
+
+  corner[0] = f2[0]; corner[1] = f2[2];
+
+  // Lower left.
+  if (!lens->extrude(corner, nll, fll)) {
+    return (GeometricBoundingVolume *)NULL;
+  }
+
+  return new BoundingHexahedron(fll, flr, fur, ful, nll, nlr, nur, nul);
+}

+ 101 - 0
panda/src/pgraph/scissorEffect.h

@@ -0,0 +1,101 @@
+// Filename: scissorEffect.h
+// Created by:  drose (30Jul08)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef SCISSOREFFECT_H
+#define SCISSOREFFECT_H
+
+#include "pandabase.h"
+
+#include "renderEffect.h"
+#include "luse.h"
+#include "nodePath.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : ScissorEffect
+// Description : This provides a higher-level wrapper around
+//               ScissorAttrib.  It allows for the scissor region to
+//               be defined via points relative to the current node,
+//               and also performs culling based on the scissor
+//               region.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA_PGRAPH ScissorEffect : public RenderEffect {
+private:
+  ScissorEffect(bool screen, const LVecBase4f &frame,
+                const LPoint3f *points, int num_points, bool clip);
+
+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);
+
+  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 bool get_clip() const;
+
+public:
+  virtual bool safe_to_transform() const;
+  virtual void output(ostream &out) const;
+
+  virtual bool has_cull_callback() const;
+  virtual void cull_callback(CullTraverser *trav, CullTraverserData &data,
+                             CPT(TransformState) &node_transform,
+                             CPT(RenderState) &node_state) const;
+
+protected:
+  virtual int compare_to_impl(const RenderEffect *other) const;
+
+private:
+  PT(GeometricBoundingVolume) make_frustum(const Lens *lens, const LVecBase4f &frame) const;
+
+private:
+  bool _screen;
+  LVecBase4f _frame;
+  typedef pvector<LPoint3f> Points;
+  Points _points;
+  bool _clip;
+
+public:
+  static void register_with_read_factory();
+  virtual void write_datagram(BamWriter *manager, Datagram &dg);
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+  void fillin(DatagramIterator &scan, BamReader *manager);
+  
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    RenderEffect::init_type();
+    register_type(_type_handle, "ScissorEffect",
+                  RenderEffect::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "scissorEffect.I"
+
+#endif
+

+ 44 - 7
panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx

@@ -255,9 +255,7 @@ prepare_display_region(DisplayRegionPipelineReader *dr,
   _c->viewport.ymin = ymin;
   _c->viewport.xsize = xsize;
   _c->viewport.ysize = ysize;
-  gl_eval_viewport(_c);
-
-  GLViewport *v = &_c->viewport;
+  set_scissor(0.0f, 1.0f, 0.0f, 1.0f);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -467,21 +465,23 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader,
     // matrix (so we don't attempt to transform it again).
     const TransformState *ident = TransformState::make_identity();
     load_matrix(&_c->matrix_model_view, ident);
-    load_matrix(&_c->matrix_projection, ident);
+    load_matrix(&_c->matrix_projection, _scissor_mat);
     load_matrix(&_c->matrix_model_view_inv, ident);
-    load_matrix(&_c->matrix_model_projection, ident);
+    load_matrix(&_c->matrix_model_projection, _scissor_mat);
     _c->matrix_model_projection_no_w_transform = 1;
     _transform_stale = true;
 
   } else if (_transform_stale) {
     // Load the actual transform.
 
+    CPT(TransformState) scissor_proj_mat = _scissor_mat->compose(_projection_mat);
+
     if (_c->lighting_enabled) {
       // With the lighting equation, we need to keep the modelview and
       // projection matrices separate.
 
       load_matrix(&_c->matrix_model_view, _internal_transform);
-      load_matrix(&_c->matrix_projection, _projection_mat);
+      load_matrix(&_c->matrix_projection, scissor_proj_mat);
 
       /* precompute inverse modelview */
       M4 tmp;
@@ -492,7 +492,7 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader,
 
     // Compose the modelview and projection matrices.
     load_matrix(&_c->matrix_model_projection, 
-                _projection_mat->compose(_internal_transform));
+                scissor_proj_mat->compose(_internal_transform));
 
     /* test to accelerate computation */
     _c->matrix_model_projection_no_w_transform = 0;
@@ -1219,6 +1219,11 @@ set_state_and_transform(const RenderState *target,
     _state._light = _target._light;
   }
 
+  if (_target._scissor != _state._scissor) {
+    do_issue_scissor();
+    _state._scissor = _target._scissor;
+  }
+
   _state_rs = _target_rs;
 }
 
@@ -1706,6 +1711,38 @@ do_issue_texture() {
   _texture_replace = (stage->get_mode() == TextureStage::M_replace);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TinyGraphicsStateGuardian::do_issue_scissor
+//       Access: Protected
+//  Description:
+////////////////////////////////////////////////////////////////////
+void TinyGraphicsStateGuardian::
+do_issue_scissor() {
+  const LVecBase4f &frame = _target._scissor->get_frame();
+  set_scissor(frame[0], frame[1], frame[2], frame[3]);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TinyGraphicsStateGuardian::set_scissor
+//       Access: Private
+//  Description: Sets up the scissor region, as a set of coordinates
+//               relative to the current viewport.
+////////////////////////////////////////////////////////////////////
+void TinyGraphicsStateGuardian::
+set_scissor(float left, float right, float bottom, float top) {
+  _c->scissor.left = left;
+  _c->scissor.right = right;
+  _c->scissor.bottom = bottom;
+  _c->scissor.top = top;
+  gl_eval_viewport(_c);
+
+  float xsize = right - left;
+  float ysize = top - bottom;
+  float xcenter = (left + right) - 1.0f;
+  float ycenter = (bottom + top) - 1.0f;
+  _scissor_mat = TransformState::make_scale(LVecBase3f(1.0f / xsize, 1.0f / ysize, 1.0f))->compose(TransformState::make_pos(LPoint3f(-xcenter, -ycenter, 0.0f)));
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TinyGraphicsStateGuardian::apply_texture
 //       Access: Protected

+ 5 - 0
panda/src/tinydisplay/tinyGraphicsStateGuardian.h

@@ -99,6 +99,9 @@ private:
   void do_issue_cull_face();
   void do_issue_material();
   void do_issue_texture();
+  void do_issue_scissor();
+
+  void set_scissor(float left, float right, float bottom, float top);
 
   bool apply_texture(TextureContext *tc);
   bool upload_texture(TinyTextureContext *gtc);
@@ -139,6 +142,8 @@ private:
 
   SimpleLru _textures_lru;
 
+  CPT(TransformState) _scissor_mat;
+
   // Used during being_draw_primitives() .. end_draw_primitives().
   int _min_vertex;
   int _max_vertex;

+ 16 - 13
panda/src/tinydisplay/vertex.cxx

@@ -1,20 +1,23 @@
 #include "zgl.h"
 #include "string.h"
 
-void gl_eval_viewport(GLContext * c)
-{
-    GLViewport *v;
-    float zsize = (1 << (ZB_Z_BITS + ZB_POINT_Z_FRAC_BITS));
-
-    v = &c->viewport;
-
-    v->trans.X = ((v->xsize - 0.5f) / 2.0f) + v->xmin;
-    v->trans.Y = ((v->ysize - 0.5f) / 2.0f) + v->ymin;
-    v->trans.Z = ((zsize - 0.5f) / 2.0f) + ((1 << ZB_POINT_Z_FRAC_BITS)) / 2;
+void gl_eval_viewport(GLContext * c) {
+  GLViewport *v = &c->viewport;
+  GLScissor *s = &c->scissor;
+  
+  float xsize = v->xsize * (s->right - s->left);
+  float xmin = v->xmin + v->xsize * s->left;
+  float ysize = v->ysize * (s->top - s->bottom);
+  float ymin = v->ymin + v->ysize * (1.0f - s->top);
+  float zsize = (1 << (ZB_Z_BITS + ZB_POINT_Z_FRAC_BITS));
 
-    v->scale.X = (v->xsize - 0.5f) / 2.0f;
-    v->scale.Y = -(v->ysize - 0.5f) / 2.0f;
-    v->scale.Z = -((zsize - 0.5f) / 2.0f);
+  v->trans.X = ((xsize - 0.5f) / 2.0f) + xmin;
+  v->trans.Y = ((ysize - 0.5f) / 2.0f) + ymin;
+  v->trans.Z = ((zsize - 0.5f) / 2.0f) + ((1 << ZB_POINT_Z_FRAC_BITS)) / 2;
+  
+  v->scale.X = (xsize - 0.5f) / 2.0f;
+  v->scale.Y = -(ysize - 0.5f) / 2.0f;
+  v->scale.Z = -((zsize - 0.5f) / 2.0f);
 }
 
 /* coords, tranformation , clip code and projection */

+ 5 - 0
panda/src/tinydisplay/zgl.h

@@ -79,6 +79,10 @@ typedef struct GLViewport {
   int updated;
 } GLViewport;
 
+typedef struct GLScissor {
+  float left, right, bottom, top;
+} GLScissor;
+
 typedef union {
   int op;
   float f;
@@ -161,6 +165,7 @@ typedef struct GLContext {
 
   /* viewport */
   GLViewport viewport;
+  GLScissor scissor;
 
   /* current state */
   int smooth_shade_model;