Browse Source

StereoDisplayRegion

David Rose 17 years ago
parent
commit
cd48a64f86

+ 3 - 0
panda/src/display/Sources.pp

@@ -33,6 +33,7 @@
     windowProperties.I windowProperties.h \
     windowProperties.I windowProperties.h \
     renderBuffer.h \
     renderBuffer.h \
     stencilRenderStates.h \
     stencilRenderStates.h \
+    stereoDisplayRegion.I stereoDisplayRegion.h \
     displaySearchParameters.h \
     displaySearchParameters.h \
     displayInformation.h    
     displayInformation.h    
     
     
@@ -55,6 +56,7 @@
     windowProperties.cxx \
     windowProperties.cxx \
     lru.cxx \
     lru.cxx \
     stencilRenderStates.cxx \
     stencilRenderStates.cxx \
+    stereoDisplayRegion.cxx \
     displaySearchParameters.cxx \
     displaySearchParameters.cxx \
     displayInformation.cxx    
     displayInformation.cxx    
 
 
@@ -80,6 +82,7 @@
     windowProperties.I windowProperties.h \
     windowProperties.I windowProperties.h \
     renderBuffer.h \
     renderBuffer.h \
     stencilRenderStates.h \
     stencilRenderStates.h \
+    stereoDisplayRegion.I stereoDisplayRegion.h \
     displaySearchParameters.h \
     displaySearchParameters.h \
     displayInformation.h    
     displayInformation.h    
 
 

+ 10 - 0
panda/src/display/config_display.cxx

@@ -24,6 +24,7 @@
 #include "graphicsDevice.h"
 #include "graphicsDevice.h"
 #include "parasiteBuffer.h"
 #include "parasiteBuffer.h"
 #include "pandaSystem.h"
 #include "pandaSystem.h"
+#include "stereoDisplayRegion.h"
 
 
 ConfigureDef(config_display);
 ConfigureDef(config_display);
 NotifyCategoryDef(display, "");
 NotifyCategoryDef(display, "");
@@ -197,6 +198,14 @@ ConfigVariableString red_blue_stereo_colors
           "'green', 'cyan', 'magenta', 'yellow', or 'alpha', or a union "
           "'green', 'cyan', 'magenta', 'yellow', or 'alpha', or a union "
           "of two or more words separated by a vertical pipe (|)."));
           "of two or more words separated by a vertical pipe (|)."));
 
 
+ConfigVariableBool default_stereo_camera
+("default-stereo-camera", true,
+ PRC_DESC("When this is true, the default DisplayRegion created for "
+          "a window or buffer with the stereo property will be a "
+          "StereoDisplayRegion, which activates the stereo properties of "
+          "the camera lens, and enables stereo.  Set this false to "
+          "require StereoDisplayRegions to be created explicitly."));
+
 ConfigVariableBool color_scale_via_lighting
 ConfigVariableBool color_scale_via_lighting
 ("color-scale-via-lighting", true,
 ("color-scale-via-lighting", true,
  PRC_DESC("When this is true, Panda will try to implement ColorAttribs and "
  PRC_DESC("When this is true, Panda will try to implement ColorAttribs and "
@@ -369,6 +378,7 @@ init_libdisplay() {
   GraphicsWindow::init_type();
   GraphicsWindow::init_type();
   ParasiteBuffer::init_type();
   ParasiteBuffer::init_type();
   StandardMunger::init_type();
   StandardMunger::init_type();
+  StereoDisplayRegion::init_type();
 
 
 #if defined(HAVE_THREADS) && defined(DO_PIPELINING)
 #if defined(HAVE_THREADS) && defined(DO_PIPELINING)
   PandaSystem *ps = PandaSystem::get_global_ptr();
   PandaSystem *ps = PandaSystem::get_global_ptr();

+ 1 - 0
panda/src/display/config_display.h

@@ -57,6 +57,7 @@ extern EXPCL_PANDA_DISPLAY ConfigVariableBool copy_texture_inverted;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool window_inverted;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool window_inverted;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool red_blue_stereo;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool red_blue_stereo;
 extern EXPCL_PANDA_DISPLAY ConfigVariableString red_blue_stereo_colors;
 extern EXPCL_PANDA_DISPLAY ConfigVariableString red_blue_stereo_colors;
+extern EXPCL_PANDA_DISPLAY ConfigVariableBool default_stereo_camera;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool color_scale_via_lighting;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool color_scale_via_lighting;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool alpha_scale_via_texture;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool alpha_scale_via_texture;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool allow_incomplete_render;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool allow_incomplete_render;

+ 23 - 148
panda/src/display/displayRegion.I

@@ -155,63 +155,9 @@ get_stereo_channel() {
   return cdata->_stereo_channel;
   return cdata->_stereo_channel;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: DisplayRegion::set_clear_depth_between_eyes
-//       Access: Published
-//  Description: Specifies whether the depth buffer is cleared again
-//               between the left and right eyes of a stereo
-//               DisplayRegion.  This has an effect only when
-//               get_stereo_channel() returns Lens::SC_stereo; other
-//               kinds of DisplayRegions are monocular and do not
-//               render two different eyes.
-//
-//               Normally, you want this to be true, since if you're
-//               using a depth buffer you normally need to clear it
-//               between the left and right eyes.
-////////////////////////////////////////////////////////////////////
-INLINE void DisplayRegion::
-set_clear_depth_between_eyes(bool clear_depth_between_eyes) {
-  _clear_depth_between_eyes = clear_depth_between_eyes;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DisplayRegion::get_clear_depth_between_eyes
-//       Access: Published
-//  Description: Returns whether the depth buffer is cleared again
-//               between the left and right eyes of a stereo
-//               DisplayRegion.  See set_clear_depth_between_eyes().
-////////////////////////////////////////////////////////////////////
-INLINE bool DisplayRegion::
-get_clear_depth_between_eyes() const {
-  return _clear_depth_between_eyes;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DisplayRegion::set_incomplete_render
-//       Access: Public
-//  Description: Sets the incomplete_render flag.  When this is
-//               true, the frame will be rendered even if some of the
-//               geometry or textures in the scene are not available
-//               (e.g. they have been temporarily paged out).  When
-//               this is false, the frame will be held up while this
-//               data is reloaded.
-//
-//               This flag may also be set on the
-//               GraphicsStateGuardian.  It will be considered true
-//               for a given DisplayRegion only if it is true on both
-//               the GSG and on the DisplayRegion.
-//
-//               See GraphicsStateGuardian::set_incomplete_render()
-//               for more detail.
-////////////////////////////////////////////////////////////////////
-INLINE void DisplayRegion::
-set_incomplete_render(bool incomplete_render) {
-  _incomplete_render = incomplete_render;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegion::get_incomplete_render
 //     Function: DisplayRegion::get_incomplete_render
-//       Access: Public, Virtual
+//       Access: Published
 //  Description: Returns the incomplete_render flag.  See
 //  Description: Returns the incomplete_render flag.  See
 //               set_incomplete_render().
 //               set_incomplete_render().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -220,28 +166,6 @@ get_incomplete_render() const {
   return _incomplete_render;
   return _incomplete_render;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: DisplayRegion::set_texture_reload_priority
-//       Access: Published
-//  Description: Specifies an integer priority which is assigned to
-//               any asynchronous texture reload requests spawned
-//               while processing this DisplayRegion.  This controls
-//               which textures are loaded first when multiple
-//               textures need to be reloaded at once; it also
-//               controls the relative priority between asynchronous
-//               texture loads and asynchronous model or animation
-//               loads.
-//
-//               Specifying a larger number here makes the textures
-//               rendered by this DisplayRegion load up first.  This
-//               may be particularly useful to do, for instance, for
-//               the DisplayRegion that renders the gui.
-////////////////////////////////////////////////////////////////////
-INLINE void DisplayRegion::
-set_texture_reload_priority(int texture_reload_priority) {
-  _texture_reload_priority = texture_reload_priority;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegion::get_texture_reload_priority
 //     Function: DisplayRegion::get_texture_reload_priority
 //       Access: Published
 //       Access: Published
@@ -255,54 +179,44 @@ get_texture_reload_priority() const {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: DisplayRegion::set_cull_traverser
+//     Function: DisplayRegion::get_cube_map_index
 //       Access: Published
 //       Access: Published
-//  Description: Specifies the CullTraverser that will be used to draw
-//               the contents of this DisplayRegion.  Normally the
-//               default CullTraverser is sufficient, but this may be
-//               changed to change the default cull behavior.
+//  Description: Returns the cube map face index associated with this
+//               particular DisplayRegion, or -1 if it is not
+//               associated with a cube map.  See
+//               set_cube_map_index().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE void DisplayRegion::
-set_cull_traverser(CullTraverser *trav) {
-  _trav = trav;
+INLINE int DisplayRegion::
+get_cube_map_index() const {
+  CDReader cdata(_cycler);
+  return cdata->_cube_map_index;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: DisplayRegion::set_cube_map_index
+//     Function: DisplayRegion::get_pixel_width
 //       Access: Published
 //       Access: Published
-//  Description: This is a special parameter that is only used when
-//               rendering the faces of a cube map.  Normally you
-//               should not need to set it directly.  This sets up the
-//               DisplayRegion to render to the nth cube map face; the
-//               value must be between 0 and 5, inclusive.  A normal
-//               DisplayRegion that is not associated with any
-//               particular cube map should be set to -1.
+//  Description: Returns the width of the DisplayRegion in pixels.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE void DisplayRegion::
-set_cube_map_index(int cube_map_index) {
-  int pipeline_stage = Thread::get_current_pipeline_stage();
-  nassertv(pipeline_stage == 0);
-  CDWriter cdata(_cycler);
-  cdata->_cube_map_index = cube_map_index;
+INLINE int DisplayRegion::
+get_pixel_width() const {
+  CDReader cdata(_cycler);
+  return cdata->_pr - cdata->_pl;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: DisplayRegion::get_cube_map_index
+//     Function: DisplayRegion::get_pixel_height
 //       Access: Published
 //       Access: Published
-//  Description: Returns the cube map face index associated with this
-//               particular DisplayRegion, or -1 if it is not
-//               associated with a cube map.  See
-//               set_cube_map_index().
+//  Description: Returns the height of the DisplayRegion in pixels.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE int DisplayRegion::
 INLINE int DisplayRegion::
-get_cube_map_index() const {
+get_pixel_height() const {
   CDReader cdata(_cycler);
   CDReader cdata(_cycler);
-  return cdata->_cube_map_index;
+  return cdata->_pt - cdata->_pb;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegion::get_pixels
 //     Function: DisplayRegion::get_pixels
-//       Access: Published
+//       Access: Public
 //  Description: Retrieves the coordinates of the DisplayRegion within
 //  Description: Retrieves the coordinates of the DisplayRegion within
 //               its window, in pixels.
 //               its window, in pixels.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -317,7 +231,7 @@ get_pixels(int &pl, int &pr, int &pb, int &pt) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegion::get_region_pixels
 //     Function: DisplayRegion::get_region_pixels
-//       Access: Published
+//       Access: Public
 //  Description: Retrieves the coordinates of the DisplayRegion within
 //  Description: Retrieves the coordinates of the DisplayRegion within
 //               its window, as the pixel location of its bottom-left
 //               its window, as the pixel location of its bottom-left
 //               corner, along with a pixel width and height.
 //               corner, along with a pixel width and height.
@@ -333,7 +247,7 @@ get_region_pixels(int &xo, int &yo, int &w, int &h) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegion::get_region_pixels_i
 //     Function: DisplayRegion::get_region_pixels_i
-//       Access: Published
+//       Access: Public
 //  Description: Similar to get_region_pixels(), but returns the upper
 //  Description: Similar to get_region_pixels(), but returns the upper
 //               left corner, and the pixel numbers are numbered from
 //               left corner, and the pixel numbers are numbered from
 //               the top-left corner down, in the DirectX way of
 //               the top-left corner down, in the DirectX way of
@@ -348,28 +262,6 @@ get_region_pixels_i(int &xo, int &yo, int &w, int &h) const {
   h = cdata->_pbi - cdata->_pti;
   h = cdata->_pbi - cdata->_pti;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: DisplayRegion::get_pixel_width
-//       Access: Published
-//  Description: Returns the width of the DisplayRegion in pixels.
-////////////////////////////////////////////////////////////////////
-INLINE int DisplayRegion::
-get_pixel_width() const {
-  CDReader cdata(_cycler);
-  return cdata->_pr - cdata->_pl;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DisplayRegion::get_pixel_height
-//       Access: Published
-//  Description: Returns the height of the DisplayRegion in pixels.
-////////////////////////////////////////////////////////////////////
-INLINE int DisplayRegion::
-get_pixel_height() const {
-  CDReader cdata(_cycler);
-  return cdata->_pt - cdata->_pb;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegion::set_cull_result
 //     Function: DisplayRegion::set_cull_result
 //       Access: Public
 //       Access: Public
@@ -674,18 +566,6 @@ get_stereo_channel() {
   return _cdata->_stereo_channel;
   return _cdata->_stereo_channel;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: DisplayRegionPipelineReader::get_clear_depth_between_eyes
-//       Access: Public
-//  Description: Returns whether the depth buffer is cleared again
-//               between the left and right eyes of a stereo
-//               DisplayRegion.  See set_clear_depth_between_eyes().
-////////////////////////////////////////////////////////////////////
-INLINE bool DisplayRegionPipelineReader::
-get_clear_depth_between_eyes() const {
-  return _object->_clear_depth_between_eyes;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegionPipelineReader::get_cube_map_index
 //     Function: DisplayRegionPipelineReader::get_cube_map_index
 //       Access: Public
 //       Access: Public
@@ -763,8 +643,3 @@ INLINE int DisplayRegionPipelineReader::
 get_pixel_height() const {
 get_pixel_height() const {
   return _cdata->_pt - _cdata->_pb;
   return _cdata->_pt - _cdata->_pb;
 }
 }
-
-INLINE ostream &operator << (ostream &out, const DisplayRegion &dr) {
-  dr.output(out);
-  return out;
-}

+ 180 - 106
panda/src/display/displayRegion.cxx

@@ -13,6 +13,7 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 #include "displayRegion.h"
 #include "displayRegion.h"
+#include "stereoDisplayRegion.h"
 #include "graphicsOutput.h"
 #include "graphicsOutput.h"
 #include "config_display.h"
 #include "config_display.h"
 #include "texture.h"
 #include "texture.h"
@@ -25,32 +26,12 @@ TypeHandle DisplayRegionPipelineReader::_type_handle;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegion::Constructor
 //     Function: DisplayRegion::Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-DisplayRegion::
-DisplayRegion(GraphicsOutput *window) :
-  _window(window),
-  _clear_depth_between_eyes(true),
-  _incomplete_render(true),
-  _texture_reload_priority(0),
-  _cull_region_pcollector("Cull:Invalid"),
-  _draw_region_pcollector("Draw:Invalid")
-{
-  _screenshot_buffer_type = window->get_draw_buffer_type();
-  _draw_buffer_type = window->get_draw_buffer_type();
-  compute_pixels_all_stages();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DisplayRegion::Constructor
-//       Access: Public
+//       Access: Protected
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 DisplayRegion::
 DisplayRegion::
 DisplayRegion(GraphicsOutput *window, float l, float r, float b, float t) :
 DisplayRegion(GraphicsOutput *window, float l, float r, float b, float t) :
   _window(window),
   _window(window),
-  _clear_depth_between_eyes(true),
   _incomplete_render(true),
   _incomplete_render(true),
   _texture_reload_priority(0),
   _texture_reload_priority(0),
   _cull_region_pcollector("Cull:Invalid"),
   _cull_region_pcollector("Cull:Invalid"),
@@ -68,11 +49,11 @@ DisplayRegion(GraphicsOutput *window, float l, float r, float b, float t) :
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 DisplayRegion::
 DisplayRegion::
-DisplayRegion(const DisplayRegion &) : 
+DisplayRegion(const DisplayRegion &copy) : 
+  _window(NULL),
   _cull_region_pcollector("Cull:Invalid"),
   _cull_region_pcollector("Cull:Invalid"),
   _draw_region_pcollector("Draw:Invalid")
   _draw_region_pcollector("Draw:Invalid")
 {
 {
-  nassertv(false);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -117,7 +98,7 @@ cleanup() {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegion::set_dimensions
 //     Function: DisplayRegion::set_dimensions
-//       Access: Published
+//       Access: Published, Virtual
 //  Description: Changes the portion of the framebuffer this
 //  Description: Changes the portion of the framebuffer this
 //               DisplayRegion corresponds to.  The parameters range
 //               DisplayRegion corresponds to.  The parameters range
 //               from 0 to 1, where 0,0 is the lower left corner and
 //               from 0 to 1, where 0,0 is the lower left corner and
@@ -152,9 +133,20 @@ get_pipe() const {
   return (_window != (GraphicsOutput *)NULL) ? _window->get_pipe() : NULL;
   return (_window != (GraphicsOutput *)NULL) ? _window->get_pipe() : NULL;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: DisplayRegion::is_stereo
+//       Access: Published, Virtual
+//  Description: Returns true if this is a StereoDisplayRegion, false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+bool DisplayRegion::
+is_stereo() const {
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegion::set_camera
 //     Function: DisplayRegion::set_camera
-//       Access: Published
+//       Access: Published, Virtual
 //  Description: Sets the camera that is associated with this
 //  Description: Sets the camera that is associated with this
 //               DisplayRegion.  There is a one-to-many association
 //               DisplayRegion.  There is a one-to-many association
 //               between cameras and DisplayRegions; one camera may be
 //               between cameras and DisplayRegions; one camera may be
@@ -196,7 +188,7 @@ set_camera(const NodePath &camera) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegion::set_active
 //     Function: DisplayRegion::set_active
-//       Access: Published
+//       Access: Published, Virtual
 //  Description: Sets the active flag associated with the
 //  Description: Sets the active flag associated with the
 //               DisplayRegion.  If the DisplayRegion is marked
 //               DisplayRegion.  If the DisplayRegion is marked
 //               inactive, nothing is rendered.
 //               inactive, nothing is rendered.
@@ -216,7 +208,7 @@ set_active(bool active) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegion::set_sort
 //     Function: DisplayRegion::set_sort
-//       Access: Published
+//       Access: Published, Virtual
 //  Description: Sets the sort value associated with the
 //  Description: Sets the sort value associated with the
 //               DisplayRegion.  Within a window, DisplayRegions will
 //               DisplayRegion.  Within a window, DisplayRegions will
 //               be rendered in order from the lowest sort value to
 //               be rendered in order from the lowest sort value to
@@ -236,17 +228,18 @@ set_sort(int sort) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegion::set_stereo_channel
 //     Function: DisplayRegion::set_stereo_channel
-//       Access: Published
+//       Access: Published, Virtual
 //  Description: Specifies whether the DisplayRegion represents the
 //  Description: Specifies whether the DisplayRegion represents the
 //               left or right channel of a stereo pair, or whether it
 //               left or right channel of a stereo pair, or whether it
-//               is a normal, monocular image.  See
-//               set_stereo_channel().
+//               is a normal, monocular image.  This automatically
+//               adjusts the lens that is used to render to this
+//               DisplayRegion to its left or right eye, according to
+//               the lens's stereo properties.
 //
 //
-//               This controls which direction--to the left or the
-//               right--the view from a PerspectiveLens is shifted
-//               when it is used to render into this DisplayRegion.
-//               Also see Lens::set_interocular_distance() and
-//               Lens::set_convergence_distance().
+//               When the DisplayRegion is attached to a stereo window
+//               (one for which is_stereo() returns true), this also
+//               specifies which physical channel the DisplayRegion
+//               renders to.
 //
 //
 //               Normally you would create at least two DisplayRegions
 //               Normally you would create at least two DisplayRegions
 //               for a stereo window, one for each of the left and
 //               for a stereo window, one for each of the left and
@@ -255,13 +248,17 @@ set_sort(int sort) {
 //               is used to control the exact properties of the lens
 //               is used to control the exact properties of the lens
 //               when it is used to render into this DisplayRegion.
 //               when it is used to render into this DisplayRegion.
 //
 //
-//               When the DisplayRegion is attached to a stereo window
-//               (one in which FrameBufferProperties::FM_stereo is
-//               set), this also specifies which physical channel the
-//               DisplayRegion renders to.
+//               Also see the StereoDisplayRegion, which automates
+//               managing a pair of left/right DisplayRegions.
+//
+//               An ordinary DisplayRegion may be set to SC_mono,
+//               SC_left, or SC_right.  You may set SC_stereo only on
+//               a StereoDisplayRegion.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void DisplayRegion::
 void DisplayRegion::
 set_stereo_channel(Lens::StereoChannel stereo_channel) {
 set_stereo_channel(Lens::StereoChannel stereo_channel) {
+  nassertv(is_stereo() || stereo_channel != Lens::SC_stereo);
+
   nassertv(Thread::get_current_pipeline_stage() == 0);
   nassertv(Thread::get_current_pipeline_stage() == 0);
 
 
   CDWriter cdata(_cycler);
   CDWriter cdata(_cycler);
@@ -269,96 +266,99 @@ set_stereo_channel(Lens::StereoChannel stereo_channel) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: DisplayRegion::get_cull_traverser
-//       Access: Published
-//  Description: Returns the CullTraverser that will be used to draw
-//               the contents of this DisplayRegion.
+//     Function: DisplayRegion::set_incomplete_render
+//       Access: Published, Virtual
+//  Description: Sets the incomplete_render flag.  When this is
+//               true, the frame will be rendered even if some of the
+//               geometry or textures in the scene are not available
+//               (e.g. they have been temporarily paged out).  When
+//               this is false, the frame will be held up while this
+//               data is reloaded.
+//
+//               This flag may also be set on the
+//               GraphicsStateGuardian.  It will be considered true
+//               for a given DisplayRegion only if it is true on both
+//               the GSG and on the DisplayRegion.
+//
+//               See GraphicsStateGuardian::set_incomplete_render()
+//               for more detail.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-CullTraverser *DisplayRegion::
-get_cull_traverser() {
-  if (_trav == (CullTraverser *)NULL) {
-    _trav = new CullTraverser;
-  }
-  return _trav;
+void DisplayRegion::
+set_incomplete_render(bool incomplete_render) {
+  _incomplete_render = incomplete_render;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: DisplayRegion::compute_pixels
-//       Access: Published
-//  Description: Computes the pixel locations of the DisplayRegion
-//               within its window.  The DisplayRegion will request
-//               the size from the window.
+//     Function: DisplayRegion::set_texture_reload_priority
+//       Access: Published, Virtual
+//  Description: Specifies an integer priority which is assigned to
+//               any asynchronous texture reload requests spawned
+//               while processing this DisplayRegion.  This controls
+//               which textures are loaded first when multiple
+//               textures need to be reloaded at once; it also
+//               controls the relative priority between asynchronous
+//               texture loads and asynchronous model or animation
+//               loads.
+//
+//               Specifying a larger number here makes the textures
+//               rendered by this DisplayRegion load up first.  This
+//               may be particularly useful to do, for instance, for
+//               the DisplayRegion that renders the gui.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void DisplayRegion::
 void DisplayRegion::
-compute_pixels() {
-  int pipeline_stage = Thread::get_current_pipeline_stage();
-  nassertv(pipeline_stage == 0);
-
-  if (_window != (GraphicsOutput *)NULL) {
-    CDWriter cdata(_cycler);
-    do_compute_pixels(_window->get_fb_x_size(), _window->get_fb_y_size(), 
-                      cdata);
-  }
+set_texture_reload_priority(int texture_reload_priority) {
+  _texture_reload_priority = texture_reload_priority;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: DisplayRegion::compute_pixels_all_stages
-//       Access: Published
-//  Description: Computes the pixel locations of the DisplayRegion
-//               within its window.  The DisplayRegion will request
-//               the size from the window.
+//     Function: DisplayRegion::set_cull_traverser
+//       Access: Published, Virtual
+//  Description: Specifies the CullTraverser that will be used to draw
+//               the contents of this DisplayRegion.  Normally the
+//               default CullTraverser is sufficient, but this may be
+//               changed to change the default cull behavior.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void DisplayRegion::
 void DisplayRegion::
-compute_pixels_all_stages() {
-  int pipeline_stage = Thread::get_current_pipeline_stage();
-  nassertv(pipeline_stage == 0);
-
-  if (_window != (GraphicsOutput *)NULL) {
-    OPEN_ITERATE_ALL_STAGES(_cycler) {
-      CDStageWriter cdata(_cycler, pipeline_stage);
-      do_compute_pixels(_window->get_fb_x_size(), _window->get_fb_y_size(), 
-                        cdata);
-    }
-    CLOSE_ITERATE_ALL_STAGES(_cycler);
-  }
+set_cull_traverser(CullTraverser *trav) {
+  _trav = trav;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: DisplayRegion::compute_pixels
+//     Function: DisplayRegion::get_cull_traverser
 //       Access: Published
 //       Access: Published
-//  Description: Computes the pixel locations of the DisplayRegion
-//               within its window, given the size of the window in
-//               pixels.
+//  Description: Returns the CullTraverser that will be used to draw
+//               the contents of this DisplayRegion.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-void DisplayRegion::
-compute_pixels(int x_size, int y_size) {
-  int pipeline_stage = Thread::get_current_pipeline_stage();
-  nassertv(pipeline_stage == 0);
-  CDWriter cdata(_cycler);
-  do_compute_pixels(x_size, y_size, cdata);
+CullTraverser *DisplayRegion::
+get_cull_traverser() {
+  if (_trav == (CullTraverser *)NULL) {
+    _trav = new CullTraverser;
+  }
+  return _trav;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: DisplayRegion::compute_pixels_all_stages
-//       Access: Published
-//  Description: Performs a compute_pixels() operation for all stages
-//               of the pipeline.  This is appropriate, for instance,
-//               when a window changes sizes, since this is a global
-//               operation; and you want the new window size to be
-//               immediately available even to the downstream stages.
+//     Function: DisplayRegion::set_cube_map_index
+//       Access: Published, Virtual
+//  Description: This is a special parameter that is only used when
+//               rendering the faces of a cube map.  Normally you
+//               should not need to set it directly.  This sets up the
+//               DisplayRegion to render to the nth cube map face; the
+//               value must be between 0 and 5, inclusive.  A normal
+//               DisplayRegion that is not associated with any
+//               particular cube map should be set to -1.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void DisplayRegion::
 void DisplayRegion::
-compute_pixels_all_stages(int x_size, int y_size) {
-  OPEN_ITERATE_ALL_STAGES(_cycler) {
-    CDStageWriter cdata(_cycler, pipeline_stage);
-    do_compute_pixels(x_size, y_size, cdata);
-  } 
-  CLOSE_ITERATE_ALL_STAGES(_cycler);
+set_cube_map_index(int cube_map_index) {
+  int pipeline_stage = Thread::get_current_pipeline_stage();
+  nassertv(pipeline_stage == 0);
+  CDWriter cdata(_cycler);
+  cdata->_cube_map_index = cube_map_index;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegion::output
 //     Function: DisplayRegion::output
-//       Access: Published
+//       Access: Published, Virtual
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void DisplayRegion::
 void DisplayRegion::
@@ -526,7 +526,7 @@ get_screenshot(PNMImage &image) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegion::make_cull_result_graph
 //     Function: DisplayRegion::make_cull_result_graph
-//       Access: Public
+//       Access: Published
 //  Description: Returns a special scene graph constructed to
 //  Description: Returns a special scene graph constructed to
 //               represent the results of the last frame's cull
 //               represent the results of the last frame's cull
 //               operation.
 //               operation.
@@ -554,9 +554,83 @@ make_cull_result_graph() {
   return cull_result->make_result_graph();
   return cull_result->make_result_graph();
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: DisplayRegion::compute_pixels
+//       Access: Public
+//  Description: Computes the pixel locations of the DisplayRegion
+//               within its window.  The DisplayRegion will request
+//               the size from the window.
+////////////////////////////////////////////////////////////////////
+void DisplayRegion::
+compute_pixels() {
+  int pipeline_stage = Thread::get_current_pipeline_stage();
+  nassertv(pipeline_stage == 0);
+
+  if (_window != (GraphicsOutput *)NULL) {
+    CDWriter cdata(_cycler);
+    do_compute_pixels(_window->get_fb_x_size(), _window->get_fb_y_size(), 
+                      cdata);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DisplayRegion::compute_pixels_all_stages
+//       Access: Public
+//  Description: Computes the pixel locations of the DisplayRegion
+//               within its window.  The DisplayRegion will request
+//               the size from the window.
+////////////////////////////////////////////////////////////////////
+void DisplayRegion::
+compute_pixels_all_stages() {
+  int pipeline_stage = Thread::get_current_pipeline_stage();
+  nassertv(pipeline_stage == 0);
+
+  if (_window != (GraphicsOutput *)NULL) {
+    OPEN_ITERATE_ALL_STAGES(_cycler) {
+      CDStageWriter cdata(_cycler, pipeline_stage);
+      do_compute_pixels(_window->get_fb_x_size(), _window->get_fb_y_size(), 
+                        cdata);
+    }
+    CLOSE_ITERATE_ALL_STAGES(_cycler);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DisplayRegion::compute_pixels
+//       Access: Public
+//  Description: Computes the pixel locations of the DisplayRegion
+//               within its window, given the size of the window in
+//               pixels.
+////////////////////////////////////////////////////////////////////
+void DisplayRegion::
+compute_pixels(int x_size, int y_size) {
+  int pipeline_stage = Thread::get_current_pipeline_stage();
+  nassertv(pipeline_stage == 0);
+  CDWriter cdata(_cycler);
+  do_compute_pixels(x_size, y_size, cdata);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DisplayRegion::compute_pixels_all_stages
+//       Access: Public
+//  Description: Performs a compute_pixels() operation for all stages
+//               of the pipeline.  This is appropriate, for instance,
+//               when a window changes sizes, since this is a global
+//               operation; and you want the new window size to be
+//               immediately available even to the downstream stages.
+////////////////////////////////////////////////////////////////////
+void DisplayRegion::
+compute_pixels_all_stages(int x_size, int y_size) {
+  OPEN_ITERATE_ALL_STAGES(_cycler) {
+    CDStageWriter cdata(_cycler, pipeline_stage);
+    do_compute_pixels(x_size, y_size, cdata);
+  } 
+  CLOSE_ITERATE_ALL_STAGES(_cycler);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegion::supports_pixel_zoom
 //     Function: DisplayRegion::supports_pixel_zoom
-//       Access: Published, Virtual
+//       Access: Public, Virtual
 //  Description: Returns true if a call to set_pixel_zoom() will be
 //  Description: Returns true if a call to set_pixel_zoom() will be
 //               respected, false if it will be ignored.  If this
 //               respected, false if it will be ignored.  If this
 //               returns false, then get_pixel_factor() will always
 //               returns false, then get_pixel_factor() will always

+ 31 - 29
panda/src/display/displayRegion.h

@@ -17,6 +17,7 @@
 
 
 #include "pandabase.h"
 #include "pandabase.h"
 
 
+#include "displayRegionBase.h"
 #include "drawableRegion.h"
 #include "drawableRegion.h"
 #include "referenceCount.h"
 #include "referenceCount.h"
 #include "nodePath.h"
 #include "nodePath.h"
@@ -54,11 +55,11 @@ class CullTraverser;
 //               glass, usually for layering 2-d interfaces on top of
 //               glass, usually for layering 2-d interfaces on top of
 //               a 3-d scene.
 //               a 3-d scene.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA_DISPLAY DisplayRegion : public ReferenceCount, public DrawableRegion {
+class EXPCL_PANDA_DISPLAY DisplayRegion : public DisplayRegionBase, public DrawableRegion {
 protected:
 protected:
-  DisplayRegion(GraphicsOutput *window);
   DisplayRegion(GraphicsOutput *window,
   DisplayRegion(GraphicsOutput *window,
                 float l, float r, float b, float t);
                 float l, float r, float b, float t);
+
 private:
 private:
   DisplayRegion(const DisplayRegion &copy);
   DisplayRegion(const DisplayRegion &copy);
   void operator = (const DisplayRegion &copy);
   void operator = (const DisplayRegion &copy);
@@ -75,50 +76,40 @@ PUBLISHED:
   INLINE float get_right() const;
   INLINE float get_right() const;
   INLINE float get_bottom() const;
   INLINE float get_bottom() const;
   INLINE float get_top() const;
   INLINE float get_top() const;
-  void set_dimensions(float l, float r, float b, float t);
+  virtual void set_dimensions(float l, float r, float b, float t);
 
 
   INLINE GraphicsOutput *get_window() const;
   INLINE GraphicsOutput *get_window() const;
   GraphicsPipe *get_pipe() const;
   GraphicsPipe *get_pipe() const;
+  virtual bool is_stereo() const;
 
 
-  void set_camera(const NodePath &camera);
+  virtual void set_camera(const NodePath &camera);
   INLINE NodePath get_camera(Thread *current_thread = Thread::get_current_thread()) const;
   INLINE NodePath get_camera(Thread *current_thread = Thread::get_current_thread()) const;
 
 
-  void set_active(bool active);
+  virtual void set_active(bool active);
   INLINE bool is_active() const;
   INLINE bool is_active() const;
 
 
-  void set_sort(int sort);
+  virtual void set_sort(int sort);
   INLINE int get_sort() const;
   INLINE int get_sort() const;
 
 
-  void set_stereo_channel(Lens::StereoChannel stereo_channel);
+  virtual void set_stereo_channel(Lens::StereoChannel stereo_channel);
   INLINE Lens::StereoChannel get_stereo_channel();
   INLINE Lens::StereoChannel get_stereo_channel();
 
 
-  INLINE void set_clear_depth_between_eyes(bool clear_depth_between_eyes);
-  INLINE bool get_clear_depth_between_eyes() const;
-
-  INLINE void set_incomplete_render(bool incomplete_render);
+  virtual void set_incomplete_render(bool incomplete_render);
   INLINE bool get_incomplete_render() const;
   INLINE bool get_incomplete_render() const;
 
 
-  INLINE void set_texture_reload_priority(int texture_reload_priority);
+  virtual void set_texture_reload_priority(int texture_reload_priority);
   INLINE int get_texture_reload_priority() const;
   INLINE int get_texture_reload_priority() const;
 
 
-  INLINE void set_cull_traverser(CullTraverser *trav);
+  virtual void set_cull_traverser(CullTraverser *trav);
   CullTraverser *get_cull_traverser();
   CullTraverser *get_cull_traverser();
 
 
-  INLINE void set_cube_map_index(int cube_map_index);
+  virtual void set_cube_map_index(int cube_map_index);
   INLINE int get_cube_map_index() const;
   INLINE int get_cube_map_index() const;
 
 
-  void compute_pixels();
-  void compute_pixels_all_stages();
-  void compute_pixels(int x_size, int y_size);
-  void compute_pixels_all_stages(int x_size, int y_size);
-  INLINE void get_pixels(int &pl, int &pr, int &pb, int &pt) const;
-  INLINE void get_region_pixels(int &xo, int &yo, int &w, int &h) const;
-  INLINE void get_region_pixels_i(int &xo, int &yo, int &w, int &h) const;
-
   INLINE int get_pixel_width() const;
   INLINE int get_pixel_width() const;
   INLINE int get_pixel_height() const;
   INLINE int get_pixel_height() const;
 
 
-  void output(ostream &out) const;
+  virtual void output(ostream &out) const;
 
 
   static Filename make_screenshot_filename(
   static Filename make_screenshot_filename(
     const string &prefix = "screenshot");
     const string &prefix = "screenshot");
@@ -127,9 +118,17 @@ PUBLISHED:
     const Filename &filename, const string &image_comment = "");
     const Filename &filename, const string &image_comment = "");
   bool get_screenshot(PNMImage &image);
   bool get_screenshot(PNMImage &image);
 
 
-  PT(PandaNode) make_cull_result_graph();
+  virtual PT(PandaNode) make_cull_result_graph();
 
 
 public:
 public:
+  void compute_pixels();
+  void compute_pixels_all_stages();
+  void compute_pixels(int x_size, int y_size);
+  void compute_pixels_all_stages(int x_size, int y_size);
+  INLINE void get_pixels(int &pl, int &pr, int &pb, int &pt) const;
+  INLINE void get_region_pixels(int &xo, int &yo, int &w, int &h) const;
+  INLINE void get_region_pixels_i(int &xo, int &yo, int &w, int &h) const;
+
   virtual bool supports_pixel_zoom() const;
   virtual bool supports_pixel_zoom() const;
 
 
   INLINE void set_cull_result(CullResult *cull_result, SceneSetup *scene_setup,
   INLINE void set_cull_result(CullResult *cull_result, SceneSetup *scene_setup,
@@ -147,10 +146,10 @@ private:
   void do_compute_pixels(int x_size, int y_size, CData *cdata);
   void do_compute_pixels(int x_size, int y_size, CData *cdata);
   void set_active_index(int index);
   void set_active_index(int index);
 
 
+protected:
   // The associated window is a permanent property of the
   // The associated window is a permanent property of the
   // DisplayRegion.  It doesn't need to be cycled.
   // DisplayRegion.  It doesn't need to be cycled.
   GraphicsOutput *_window;
   GraphicsOutput *_window;
-  bool _clear_depth_between_eyes;
 
 
   bool _incomplete_render;
   bool _incomplete_render;
   int _texture_reload_priority;
   int _texture_reload_priority;
@@ -158,6 +157,7 @@ private:
   // Ditto for the cull traverser.
   // Ditto for the cull traverser.
   PT(CullTraverser) _trav;
   PT(CullTraverser) _trav;
 
 
+private:
   // This is the data that is associated with the DisplayRegion that
   // This is the data that is associated with the DisplayRegion that
   // needs to be cycled every frame, but represents the parameters as
   // needs to be cycled every frame, but represents the parameters as
   // specified by the user, and which probably will not change that
   // specified by the user, and which probably will not change that
@@ -230,10 +230,14 @@ public:
     return _type_handle;
     return _type_handle;
   }
   }
   static void init_type() {
   static void init_type() {
-    ReferenceCount::init_type();
+    DisplayRegionBase::init_type();
     register_type(_type_handle, "DisplayRegion",
     register_type(_type_handle, "DisplayRegion",
-                  ReferenceCount::get_class_type());
+                  DisplayRegionBase::get_class_type());
   }
   }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
 
 
 private:
 private:
   static TypeHandle _type_handle;
   static TypeHandle _type_handle;
@@ -303,8 +307,6 @@ private:
   static TypeHandle _type_handle;
   static TypeHandle _type_handle;
 };
 };
 
 
-INLINE ostream &operator << (ostream &out, const DisplayRegion &dr);
-
 #include "displayRegion.I"
 #include "displayRegion.I"
 
 
 #endif /* DISPLAYREGION_H */
 #endif /* DISPLAYREGION_H */

+ 1 - 0
panda/src/display/display_composite2.cxx

@@ -12,3 +12,4 @@
 #include "stencilRenderStates.cxx"
 #include "stencilRenderStates.cxx"
 #include "displaySearchParameters.cxx"
 #include "displaySearchParameters.cxx"
 #include "displayInformation.cxx"
 #include "displayInformation.cxx"
+#include "stereoDisplayRegion.cxx"

+ 12 - 122
panda/src/display/drawableRegion.I

@@ -93,8 +93,7 @@ copy_clear_settings(const DrawableRegion &copy) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void DrawableRegion::
 INLINE void DrawableRegion::
 set_clear_color_active(bool clear_color_active) {
 set_clear_color_active(bool clear_color_active) {
-  _clear_active[RTP_color] = clear_color_active;
-  update_pixel_factor();
+  set_clear_active(RTP_color, clear_color_active);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -106,7 +105,7 @@ set_clear_color_active(bool clear_color_active) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool DrawableRegion::
 INLINE bool DrawableRegion::
 get_clear_color_active() const {
 get_clear_color_active() const {
-  return _clear_active[RTP_color];
+  return get_clear_active(RTP_color);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -120,8 +119,7 @@ get_clear_color_active() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void DrawableRegion::
 INLINE void DrawableRegion::
 set_clear_depth_active(bool clear_depth_active) {
 set_clear_depth_active(bool clear_depth_active) {
-  _clear_active[RTP_depth] = clear_depth_active;
-  update_pixel_factor();
+  set_clear_active(RTP_depth, clear_depth_active);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -133,7 +131,7 @@ set_clear_depth_active(bool clear_depth_active) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool DrawableRegion::
 INLINE bool DrawableRegion::
 get_clear_depth_active() const {
 get_clear_depth_active() const {
-  return _clear_active[RTP_depth];
+  return get_clear_active(RTP_depth);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -147,7 +145,7 @@ get_clear_depth_active() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void DrawableRegion::
 INLINE void DrawableRegion::
 set_clear_stencil_active(bool clear_stencil_active) {
 set_clear_stencil_active(bool clear_stencil_active) {
-  _clear_active[RTP_stencil] = clear_stencil_active;
+  set_clear_active(RTP_stencil, clear_stencil_active);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -159,30 +157,7 @@ set_clear_stencil_active(bool clear_stencil_active) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool DrawableRegion::
 INLINE bool DrawableRegion::
 get_clear_stencil_active() const {
 get_clear_stencil_active() const {
-  return _clear_active[RTP_stencil];
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DrawableRegion::set_clear_active
-//       Access: Published
-//  Description: Sets the clear-active flag for any bitplane.
-////////////////////////////////////////////////////////////////////
-INLINE void DrawableRegion::
-set_clear_active(int n, bool clear_active) {
-  nassertv((n >= 0)&&(n < RTP_COUNT));
-  _clear_active[n] = clear_active;
-  update_pixel_factor();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DrawableRegion::get_clear_active
-//       Access: Published
-//  Description: Gets the clear-active flag for any bitplane.
-////////////////////////////////////////////////////////////////////
-INLINE bool DrawableRegion::
-get_clear_active(int n) const {
-  nassertr((n >= 0)&&(n < RTP_COUNT), false);
-  return _clear_active[n];
+  return get_clear_active(RTP_stencil);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -196,7 +171,7 @@ get_clear_active(int n) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void DrawableRegion::
 INLINE void DrawableRegion::
 set_clear_color(const Colorf &color) {
 set_clear_color(const Colorf &color) {
-  _clear_value[RTP_color] = color;
+  set_clear_value(RTP_color, color);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -210,7 +185,7 @@ set_clear_color(const Colorf &color) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE const Colorf &DrawableRegion::
 INLINE const Colorf &DrawableRegion::
 get_clear_color() const {
 get_clear_color() const {
-  return _clear_value[RTP_color];
+  return get_clear_value(RTP_color);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -224,7 +199,7 @@ get_clear_color() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void DrawableRegion::
 INLINE void DrawableRegion::
 set_clear_depth(float depth) {
 set_clear_depth(float depth) {
-  _clear_value[RTP_depth] = Colorf(depth,depth,depth,depth);
+  set_clear_value(RTP_depth, Colorf(depth,depth,depth,depth));
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -238,7 +213,7 @@ set_clear_depth(float depth) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE float DrawableRegion::
 INLINE float DrawableRegion::
 get_clear_depth() const {
 get_clear_depth() const {
-  return _clear_value[RTP_depth][0];
+  return get_clear_value(RTP_depth)[0];
 }
 }
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DrawableRegion::set_clear_stencil
 //     Function: DrawableRegion::set_clear_stencil
@@ -251,7 +226,7 @@ get_clear_depth() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void DrawableRegion::
 INLINE void DrawableRegion::
 set_clear_stencil(const unsigned int stencil) {
 set_clear_stencil(const unsigned int stencil) {
-  _clear_value[RTP_stencil] = Colorf(stencil,stencil,stencil,stencil);
+  set_clear_value(RTP_stencil, Colorf(stencil,stencil,stencil,stencil));
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -265,92 +240,7 @@ set_clear_stencil(const unsigned int stencil) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE unsigned int DrawableRegion::
 INLINE unsigned int DrawableRegion::
 get_clear_stencil() const {
 get_clear_stencil() const {
-  return (int)(_clear_value[RTP_stencil][0]);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DrawableRegion::set_clear_value
-//       Access: Published
-//  Description: Sets the clear value for any bitplane.
-////////////////////////////////////////////////////////////////////
-INLINE void DrawableRegion::
-set_clear_value(int n, const Colorf &color) {
-  nassertv((n >= 0) && (n < RTP_COUNT));
-  _clear_value[n] = color;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DrawableRegion::get_clear_value
-//       Access: Published
-//  Description: Returns the clear value for any bitplane.
-////////////////////////////////////////////////////////////////////
-INLINE const Colorf &DrawableRegion::
-get_clear_value(int n) const {
-  static Colorf blank(0.5,0.5,0.5,0.0);
-  nassertr((n >= 0) && (n < RTP_COUNT), blank);
-  return _clear_value[n];
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DrawableRegion::disable_clears
-//       Access: Published
-//  Description: Disables both the color and depth clear.  See
-//               set_clear_color_active and set_clear_depth_active.
-////////////////////////////////////////////////////////////////////
-INLINE void DrawableRegion::
-disable_clears() {
-  for (int i=0; i<RTP_COUNT; i++) {
-    _clear_active[i] = false;
-  }
-  update_pixel_factor();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DrawableRegion::is_any_clear_active
-//       Access: Published
-//  Description: Returns true if any of the clear types (so far there
-//               are just color or depth) have been set active, or
-//               false if none of them are active and there is no need
-//               to clear.
-////////////////////////////////////////////////////////////////////
-INLINE bool DrawableRegion::
-is_any_clear_active() const {
-  for (int i=0; i<RTP_COUNT; i++) {
-    if (_clear_active[i]) return true;
-  }
-  return false;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DrawableRegion::set_pixel_zoom
-//       Access: Published
-//  Description: Sets the amount by which the pixels of the region are
-//               scaled internally when filling the image interally.
-//               Setting this number larger makes the pixels blockier,
-//               but may make the rendering faster, particularly for
-//               software renderers.  Setting this number to 2.0
-//               reduces the number of pixels that have to be filled
-//               by the renderer by a factor of 2.0.  It doesn't make
-//               sense to set this lower than 1.0.
-//
-//               It is possible to set this on either individual
-//               DisplayRegions or on overall GraphicsWindows, but you
-//               will get better performance for setting it on the
-//               window rather than its individual DisplayRegions.
-//               Also, you may not set it on a DisplayRegion that
-//               doesn't have both clear_color() and clear_depth()
-//               enabled.
-//
-//               This property is only supported on renderers for
-//               which it is particularly useful--currently, this is
-//               the tinydisplay software renderer.  Other kinds of
-//               renderers allow you to set this property, but ignore
-//               it.
-////////////////////////////////////////////////////////////////////
-INLINE void DrawableRegion::
-set_pixel_zoom(float pixel_zoom) {
-  _pixel_zoom = pixel_zoom;
-  update_pixel_factor();
+  return (int)(get_clear_value(RTP_stencil)[0]);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 110 - 0
panda/src/display/drawableRegion.cxx

@@ -24,6 +24,116 @@ DrawableRegion::
 ~DrawableRegion() {
 ~DrawableRegion() {
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: DrawableRegion::set_clear_active
+//       Access: Published, Virtual
+//  Description: Sets the clear-active flag for any bitplane.
+////////////////////////////////////////////////////////////////////
+void DrawableRegion::
+set_clear_active(int n, bool clear_active) {
+  nassertv((n >= 0)&&(n < RTP_COUNT));
+  _clear_active[n] = clear_active;
+  update_pixel_factor();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DrawableRegion::get_clear_active
+//       Access: Published, Virtual
+//  Description: Gets the clear-active flag for any bitplane.
+////////////////////////////////////////////////////////////////////
+bool DrawableRegion::
+get_clear_active(int n) const {
+  nassertr((n >= 0)&&(n < RTP_COUNT), false);
+  return _clear_active[n];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DrawableRegion::set_clear_value
+//       Access: Published, Virtual
+//  Description: Sets the clear value for any bitplane.
+////////////////////////////////////////////////////////////////////
+void DrawableRegion::
+set_clear_value(int n, const Colorf &clear_value) {
+  nassertv((n >= 0) && (n < RTP_COUNT));
+  _clear_value[n] = clear_value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DrawableRegion::get_clear_value
+//       Access: Published, Virtual
+//  Description: Returns the clear value for any bitplane.
+////////////////////////////////////////////////////////////////////
+const Colorf &DrawableRegion::
+get_clear_value(int n) const {
+  static Colorf blank(0.5,0.5,0.5,0.0);
+  nassertr((n >= 0) && (n < RTP_COUNT), blank);
+  return _clear_value[n];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DrawableRegion::disable_clears
+//       Access: Published, Virtual
+//  Description: Disables both the color and depth clear.  See
+//               set_clear_color_active and set_clear_depth_active.
+////////////////////////////////////////////////////////////////////
+void DrawableRegion::
+disable_clears() {
+  for (int i = 0; i < RTP_COUNT; ++i) {
+    _clear_active[i] = false;
+  }
+  update_pixel_factor();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DrawableRegion::is_any_clear_active
+//       Access: Published, Virtual
+//  Description: Returns true if any of the clear types (so far there
+//               are just color or depth) have been set active, or
+//               false if none of them are active and there is no need
+//               to clear.
+////////////////////////////////////////////////////////////////////
+bool DrawableRegion::
+is_any_clear_active() const {
+  for (int i = 0; i < RTP_COUNT; ++i) {
+    if (get_clear_active(i)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DrawableRegion::set_pixel_zoom
+//       Access: Published, Virtual
+//  Description: Sets the amount by which the pixels of the region are
+//               scaled internally when filling the image interally.
+//               Setting this number larger makes the pixels blockier,
+//               but may make the rendering faster, particularly for
+//               software renderers.  Setting this number to 2.0
+//               reduces the number of pixels that have to be filled
+//               by the renderer by a factor of 2.0.  It doesn't make
+//               sense to set this lower than 1.0.
+//
+//               It is possible to set this on either individual
+//               DisplayRegions or on overall GraphicsWindows, but you
+//               will get better performance for setting it on the
+//               window rather than its individual DisplayRegions.
+//               Also, you may not set it on a DisplayRegion that
+//               doesn't have both clear_color() and clear_depth()
+//               enabled.
+//
+//               This property is only supported on renderers for
+//               which it is particularly useful--currently, this is
+//               the tinydisplay software renderer.  Other kinds of
+//               renderers allow you to set this property, but ignore
+//               it.
+////////////////////////////////////////////////////////////////////
+void DrawableRegion::
+set_pixel_zoom(float pixel_zoom) {
+  _pixel_zoom = pixel_zoom;
+  update_pixel_factor();
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DrawableRegion::supports_pixel_zoom
 //     Function: DrawableRegion::supports_pixel_zoom
 //       Access: Published, Virtual
 //       Access: Published, Virtual

+ 9 - 10
panda/src/display/drawableRegion.h

@@ -65,10 +65,10 @@ PUBLISHED:
 
 
   INLINE void set_clear_color_active(bool clear_color_active);
   INLINE void set_clear_color_active(bool clear_color_active);
   INLINE bool get_clear_color_active() const;
   INLINE bool get_clear_color_active() const;
-
+  
   INLINE void set_clear_depth_active(bool clear_depth_active);
   INLINE void set_clear_depth_active(bool clear_depth_active);
   INLINE bool get_clear_depth_active() const;
   INLINE bool get_clear_depth_active() const;
-
+ 
   INLINE void set_clear_stencil_active(bool clear_stencil_active);
   INLINE void set_clear_stencil_active(bool clear_stencil_active);
   INLINE bool get_clear_stencil_active() const;
   INLINE bool get_clear_stencil_active() const;
 
 
@@ -81,17 +81,16 @@ PUBLISHED:
   INLINE void set_clear_stencil(unsigned int stencil);
   INLINE void set_clear_stencil(unsigned int stencil);
   INLINE unsigned int get_clear_stencil() const;
   INLINE unsigned int get_clear_stencil() const;
 
 
-  INLINE void set_clear_active(int n, bool clear_aux_active);
-  INLINE bool get_clear_active(int n) const;
+  virtual void set_clear_active(int n, bool clear_aux_active);
+  virtual bool get_clear_active(int n) const;
 
 
-  INLINE void set_clear_value(int n, const Colorf &color);
-  INLINE const Colorf &get_clear_value(int n) const;
+  virtual void set_clear_value(int n, const Colorf &clear_value);
+  virtual const Colorf &get_clear_value(int n) const;
   
   
-  INLINE void disable_clears();
-
-  INLINE bool is_any_clear_active() const;
+  virtual void disable_clears();
+  virtual bool is_any_clear_active() const;
 
 
-  INLINE void set_pixel_zoom(float pixel_zoom);
+  virtual void set_pixel_zoom(float pixel_zoom);
   INLINE float get_pixel_zoom() const;
   INLINE float get_pixel_zoom() const;
   INLINE float get_pixel_factor() const;
   INLINE float get_pixel_factor() const;
   virtual bool supports_pixel_zoom() const;
   virtual bool supports_pixel_zoom() const;

+ 34 - 62
panda/src/display/graphicsEngine.cxx

@@ -1244,20 +1244,23 @@ cull_and_draw_together(GraphicsOutput *win, DisplayRegion *dr,
   win->change_scenes(dr_reader);
   win->change_scenes(dr_reader);
   gsg->prepare_display_region(dr_reader, dr_reader->get_stereo_channel());
   gsg->prepare_display_region(dr_reader, dr_reader->get_stereo_channel());
 
 
+  if (dr_reader->is_any_clear_active()) {
+    gsg->clear(dr);
+  }
+
   PT(SceneSetup) scene_setup = setup_scene(gsg, dr_reader);
   PT(SceneSetup) scene_setup = setup_scene(gsg, dr_reader);
   if (scene_setup == (SceneSetup *)NULL) {
   if (scene_setup == (SceneSetup *)NULL) {
     // Never mind.
     // Never mind.
 
 
+  } else if (dr_reader->get_object()->is_stereo()) {
+    // Don't draw stereo DisplayRegions directly.
+
   } else if (!gsg->set_scene(scene_setup)) {
   } else if (!gsg->set_scene(scene_setup)) {
     // The scene or lens is inappropriate somehow.
     // The scene or lens is inappropriate somehow.
     display_cat.error()
     display_cat.error()
       << gsg->get_type() << " cannot render scene with specified lens.\n";
       << gsg->get_type() << " cannot render scene with specified lens.\n";
 
 
   } else {
   } else {
-    if (dr_reader->is_any_clear_active()) {
-      gsg->clear(dr);
-    }
-
     DrawCullHandler cull_handler(gsg);
     DrawCullHandler cull_handler(gsg);
     if (gsg->begin_scene()) {
     if (gsg->begin_scene()) {
       delete dr_reader;
       delete dr_reader;
@@ -1312,7 +1315,7 @@ cull_to_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
             dr_reader = NULL;
             dr_reader = NULL;
             (*aci).second = dr;
             (*aci).second = dr;
             cull_to_bins(win, dr, current_thread);
             cull_to_bins(win, dr, current_thread);
-
+            
           } else {
           } else {
             // We have already culled a scene using this camera in
             // We have already culled a scene using this camera in
             // this thread, and now we're being asked to cull another
             // this thread, and now we're being asked to cull another
@@ -1326,7 +1329,7 @@ cull_to_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
                                 setup_scene(win->get_gsg(), dr_reader),
                                 setup_scene(win->get_gsg(), dr_reader),
                                 current_thread);
                                 current_thread);
           }
           }
-
+        
           if (dr_reader != (DisplayRegionPipelineReader *)NULL) {
           if (dr_reader != (DisplayRegionPipelineReader *)NULL) {
             delete dr_reader;
             delete dr_reader;
           }
           }
@@ -1462,9 +1465,7 @@ draw_bins(GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread) {
 
 
   PT(CullResult) cull_result = dr->get_cull_result(current_thread);
   PT(CullResult) cull_result = dr->get_cull_result(current_thread);
   PT(SceneSetup) scene_setup = dr->get_scene_setup(current_thread);
   PT(SceneSetup) scene_setup = dr->get_scene_setup(current_thread);
-  if (cull_result != (CullResult *)NULL && scene_setup != (SceneSetup *)NULL) {
-    do_draw(cull_result, scene_setup, win, dr, current_thread);
-  }
+  do_draw(cull_result, scene_setup, win, dr, current_thread);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -1771,62 +1772,33 @@ do_draw(CullResult *cull_result, SceneSetup *scene_setup,
   GraphicsStateGuardian *gsg = win->get_gsg();
   GraphicsStateGuardian *gsg = win->get_gsg();
   win->change_scenes(dr_reader);
   win->change_scenes(dr_reader);
 
 
-  if (dr_reader->get_stereo_channel() == Lens::SC_stereo) {
-    // A special case.  For a stereo DisplayRegion, we render the left
-    // eye, followed by the right eye.
-    if (dr_reader->is_any_clear_active()) {
-      gsg->prepare_display_region(dr_reader, Lens::SC_stereo);
-      gsg->clear(dr_reader->get_object());
-    }
-    gsg->prepare_display_region(dr_reader, Lens::SC_left);
+  gsg->prepare_display_region(dr_reader, dr_reader->get_stereo_channel());
+  if (dr_reader->is_any_clear_active()) {
+    gsg->clear(dr_reader->get_object());
+  }
 
 
-    if (!gsg->set_scene(scene_setup)) {
-      // The scene or lens is inappropriate somehow.
-      display_cat.error()
-        << gsg->get_type() << " cannot render scene with specified lens.\n";
-    } else {
-      if (gsg->begin_scene()) {
-        delete dr_reader;
-        dr_reader = NULL;
-        cull_result->draw(current_thread);
-        gsg->end_scene();
-        dr_reader = new DisplayRegionPipelineReader(dr, current_thread);
-      }
-      if (dr_reader->get_clear_depth_between_eyes()) {
-        DrawableRegion clear_region;
-        clear_region.set_clear_depth_active(true);
-        clear_region.set_clear_depth(dr->get_clear_depth());
-        gsg->clear(&clear_region);
-      }
-      gsg->prepare_display_region(dr_reader, Lens::SC_right);
-      gsg->set_scene(scene_setup);
-      if (gsg->begin_scene()) {
-        delete dr_reader;
-        dr_reader = NULL;
-        cull_result->draw(current_thread);
-        gsg->end_scene();
-      }
-    }
+  if (cull_result == NULL || scene_setup == NULL) {
+    // Nothing to see here.
 
 
-  } else {
-    // For a mono DisplayRegion, or a left/right eye only
-    // DisplayRegion, we just render that.
-    gsg->prepare_display_region(dr_reader, dr_reader->get_stereo_channel());
+  } else if (dr_reader->get_object()->is_stereo()) {
+    // We don't actually draw the stereo DisplayRegions.  These are
+    // just placeholders; we draw the individual left and right eyes
+    // instead.  (We might still clear the stereo DisplayRegions,
+    // though, since it's probably faster to clear right and left
+    // channels in one pass, than to clear them in two separate
+    // passes.)
 
 
-    if (!gsg->set_scene(scene_setup)) {
-      // The scene or lens is inappropriate somehow.
-      display_cat.error()
-        << gsg->get_type() << " cannot render scene with specified lens.\n";
-    } else {
-      if (dr_reader->is_any_clear_active()) {
-        gsg->clear(dr_reader->get_object());
-      }
-      if (gsg->begin_scene()) {
-        delete dr_reader;
-        dr_reader = NULL;
-        cull_result->draw(current_thread);
-        gsg->end_scene();
-      }
+  } else if (!gsg->set_scene(scene_setup)) {
+    // The scene or lens is inappropriate somehow.
+    display_cat.error()
+      << gsg->get_type() << " cannot render scene with specified lens.\n";
+
+  } else {
+    if (gsg->begin_scene()) {
+      delete dr_reader;
+      dr_reader = NULL;
+      cull_result->draw(current_thread);
+      gsg->end_scene();
     }
     }
   }
   }
 
 

+ 30 - 7
panda/src/display/graphicsOutput.I

@@ -467,22 +467,45 @@ trigger_copy()  {
 //       Access: Published
 //       Access: Published
 //  Description: Creates a new DisplayRegion that covers the entire
 //  Description: Creates a new DisplayRegion that covers the entire
 //               window.
 //               window.
+//
+//               If is_stereo() is true for this window, and
+//               default-stereo-camera is configured true, this
+//               actually makes a StereoDisplayRegion.  Call
+//               make_mono_display_region() or
+//               make_stereo_display_region() if you want to insist on
+//               one or the other.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE DisplayRegion *GraphicsOutput::
 INLINE DisplayRegion *GraphicsOutput::
 make_display_region() {
 make_display_region() {
-  return add_display_region(new DisplayRegion(this));
+  return make_display_region(0.0f, 1.0f, 0.0f, 1.0f);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GraphicsOutput::make_display_region
+//     Function: GraphicsOutput::make_mono_display_region
 //       Access: Published
 //       Access: Published
-//  Description: Creates a new DisplayRegion that covers the indicated
-//               sub-rectangle within the window.  The range on all
-//               parameters is 0..1.
+//  Description: Creates a new DisplayRegion that covers the entire
+//               window.
+//
+//               This always returns a mono DisplayRegion, even if
+//               is_stereo() is true.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE DisplayRegion *GraphicsOutput::
 INLINE DisplayRegion *GraphicsOutput::
-make_display_region(float l, float r, float b, float t) {
-  return add_display_region(new DisplayRegion(this, l, r, b, t));
+make_mono_display_region() {
+  return make_mono_display_region(0.0f, 1.0f, 0.0f, 1.0f);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::make_stereo_display_region
+//       Access: Published
+//  Description: Creates a new DisplayRegion that covers the entire
+//               window.
+//
+//               This always returns a stereo DisplayRegion, even if
+//               is_stereo() is false.
+////////////////////////////////////////////////////////////////////
+INLINE StereoDisplayRegion *GraphicsOutput::
+make_stereo_display_region() {
+  return make_stereo_display_region(0.0f, 1.0f, 0.0f, 1.0f);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 99 - 17
panda/src/display/graphicsOutput.cxx

@@ -121,7 +121,7 @@ GraphicsOutput(GraphicsPipe *pipe,
   // We start out with one DisplayRegion that covers the whole window,
   // We start out with one DisplayRegion that covers the whole window,
   // which we may use internally for full-window operations like
   // which we may use internally for full-window operations like
   // clear() and get_screenshot().
   // clear() and get_screenshot().
-  _default_display_region = make_display_region(0.0f, 1.0f, 0.0f, 1.0f);
+  _default_display_region = make_mono_display_region(0.0f, 1.0f, 0.0f, 1.0f);
   _default_display_region->set_active(false);
   _default_display_region->set_active(false);
 
 
   _display_regions_stale = false;
   _display_regions_stale = false;
@@ -444,6 +444,68 @@ set_sort(int sort) {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::make_display_region
+//       Access: Published
+//  Description: Creates a new DisplayRegion that covers the indicated
+//               sub-rectangle within the window.  The range on all
+//               parameters is 0..1.
+//
+//               If is_stereo() is true for this window, and
+//               default-stereo-camera is configured true, this
+//               actually makes a StereoDisplayRegion.  Call
+//               make_mono_display_region() or
+//               make_stereo_display_region() if you want to insist on
+//               one or the other.
+////////////////////////////////////////////////////////////////////
+DisplayRegion *GraphicsOutput::
+make_display_region(float l, float r, float b, float t) {
+  if (is_stereo() && default_stereo_camera) {
+    return make_stereo_display_region(l, r, b, t);
+  } else {
+    return make_mono_display_region(l, r, b, t);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::make_mono_display_region
+//       Access: Published
+//  Description: Creates a new DisplayRegion that covers the indicated
+//               sub-rectangle within the window.  The range on all
+//               parameters is 0..1.
+//
+//               This always returns a mono DisplayRegion, even if
+//               is_stereo() is true.
+////////////////////////////////////////////////////////////////////
+DisplayRegion *GraphicsOutput::
+make_mono_display_region(float l, float r, float b, float t) {
+  return add_display_region(new DisplayRegion(this, l, r, b, t));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::make_stereo_display_region
+//       Access: Published
+//  Description: Creates a new DisplayRegion that covers the indicated
+//               sub-rectangle within the window.  The range on all
+//               parameters is 0..1.
+//
+//               This always returns a stereo DisplayRegion, even if
+//               is_stereo() is false.
+////////////////////////////////////////////////////////////////////
+StereoDisplayRegion *GraphicsOutput::
+make_stereo_display_region(float l, float r, float b, float t) {
+  PT(DisplayRegion) left = new DisplayRegion(this, l, r, b, t);
+  PT(DisplayRegion) right = new DisplayRegion(this, l, r, b, t);
+
+  PT(StereoDisplayRegion) stereo = new StereoDisplayRegion(this, l, r, b, t,
+                                                           left, right);
+  add_display_region(stereo);
+  add_display_region(left);
+  add_display_region(right);
+
+  return stereo;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsOutput::remove_display_region
 //     Function: GraphicsOutput::remove_display_region
 //       Access: Published
 //       Access: Published
@@ -459,22 +521,14 @@ remove_display_region(DisplayRegion *display_region) {
 
 
   nassertr(display_region != _default_display_region, false);
   nassertr(display_region != _default_display_region, false);
 
 
-  PT(DisplayRegion) drp = display_region;
-  TotalDisplayRegions::iterator dri =
-    find(_total_display_regions.begin(), _total_display_regions.end(), drp);
-  if (dri != _total_display_regions.end()) {
-    // Let's aggressively clean up the display region too.
-    display_region->cleanup();
-    display_region->_window = NULL;
-    _total_display_regions.erase(dri);
-    if (display_region->is_active()) {
-      _display_regions_stale = true;
-    }
-
-    return true;
+  if (display_region->is_stereo()) {
+    StereoDisplayRegion *sdr;
+    DCAST_INTO_R(sdr, display_region, false);
+    do_remove_display_region(sdr->get_left_eye());
+    do_remove_display_region(sdr->get_right_eye());
   }
   }
 
 
-  return false;
+  return do_remove_display_region(display_region);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -1031,9 +1085,9 @@ clear(Thread *current_thread) {
 bool GraphicsOutput::
 bool GraphicsOutput::
 copy_to_textures() {
 copy_to_textures() {
   bool okflag = true;
   bool okflag = true;
-  for (int i=0; i<count_textures(); i++) {
+  for (int i = 0; i < count_textures(); ++i) {
     RenderTextureMode rtm_mode = get_rtm_mode(i);
     RenderTextureMode rtm_mode = get_rtm_mode(i);
-    if ((rtm_mode == RTM_none)||(rtm_mode == RTM_bind_or_copy)) {
+    if ((rtm_mode == RTM_none) || (rtm_mode == RTM_bind_or_copy)) {
       continue;
       continue;
     }
     }
 
 
@@ -1219,6 +1273,34 @@ add_display_region(DisplayRegion *display_region) {
   return display_region;
   return display_region;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::do_remove_display_region
+//       Access: Private
+//  Description: Internal implementation of remove_display_region.
+//               Assumes the lock is already held.
+////////////////////////////////////////////////////////////////////
+bool GraphicsOutput::
+do_remove_display_region(DisplayRegion *display_region) {
+  nassertr(display_region != _default_display_region, false);
+
+  PT(DisplayRegion) drp = display_region;
+  TotalDisplayRegions::iterator dri =
+    find(_total_display_regions.begin(), _total_display_regions.end(), drp);
+  if (dri != _total_display_regions.end()) {
+    // Let's aggressively clean up the display region too.
+    display_region->cleanup();
+    display_region->_window = NULL;
+    _total_display_regions.erase(dri);
+    if (display_region->is_active()) {
+      _display_regions_stale = true;
+    }
+
+    return true;
+  }
+
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsOutput::do_determine_display_regions
 //     Function: GraphicsOutput::do_determine_display_regions
 //       Access: Private
 //       Access: Private

+ 7 - 2
panda/src/display/graphicsOutput.h

@@ -19,6 +19,7 @@
 
 
 #include "graphicsPipe.h"
 #include "graphicsPipe.h"
 #include "displayRegion.h"
 #include "displayRegion.h"
+#include "stereoDisplayRegion.h"
 #include "graphicsStateGuardian.h"
 #include "graphicsStateGuardian.h"
 #include "drawableRegion.h"
 #include "drawableRegion.h"
 #include "renderBuffer.h"
 #include "renderBuffer.h"
@@ -141,8 +142,11 @@ PUBLISHED:
   INLINE void trigger_copy();
   INLINE void trigger_copy();
   
   
   INLINE DisplayRegion *make_display_region();
   INLINE DisplayRegion *make_display_region();
-  INLINE DisplayRegion *make_display_region(float l, float r,
-                                            float b, float t);
+  DisplayRegion *make_display_region(float l, float r, float b, float t);
+  INLINE DisplayRegion *make_mono_display_region();
+  DisplayRegion *make_mono_display_region(float l, float r, float b, float t);
+  INLINE StereoDisplayRegion *make_stereo_display_region();
+  StereoDisplayRegion *make_stereo_display_region(float l, float r, float b, float t);
   bool remove_display_region(DisplayRegion *display_region);
   bool remove_display_region(DisplayRegion *display_region);
   void remove_all_display_regions();
   void remove_all_display_regions();
 
 
@@ -248,6 +252,7 @@ private:
   PT(GeomVertexData) create_texture_card_vdata(int x, int y);
   PT(GeomVertexData) create_texture_card_vdata(int x, int y);
   
   
   DisplayRegion *add_display_region(DisplayRegion *display_region);
   DisplayRegion *add_display_region(DisplayRegion *display_region);
+  bool do_remove_display_region(DisplayRegion *display_region);
 
 
   INLINE void win_display_regions_changed();
   INLINE void win_display_regions_changed();
 
 

+ 36 - 0
panda/src/display/stereoDisplayRegion.I

@@ -0,0 +1,36 @@
+// Filename: stereoDisplayRegion.I
+// Created by:  drose (19Feb09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: StereoDisplayRegion::get_left_eye
+//       Access: Published
+//  Description: Returns a pointer to the left DisplayRegion managed
+//               by this stereo object.
+////////////////////////////////////////////////////////////////////
+INLINE DisplayRegion *StereoDisplayRegion::
+get_left_eye() {
+  return _left_eye;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StereoDisplayRegion::get_right_eye
+//       Access: Published
+//  Description: Returns a pointer to the right DisplayRegion managed
+//               by this stereo object.
+////////////////////////////////////////////////////////////////////
+INLINE DisplayRegion *StereoDisplayRegion::
+get_right_eye() {
+  return _right_eye;
+}

+ 318 - 0
panda/src/display/stereoDisplayRegion.cxx

@@ -0,0 +1,318 @@
+// Filename: stereoDisplayRegion.cxx
+// Created by:  drose (19Feb09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "stereoDisplayRegion.h"
+#include "pandaNode.h"
+
+TypeHandle StereoDisplayRegion::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: StereoDisplayRegion::Constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+StereoDisplayRegion::
+StereoDisplayRegion(GraphicsOutput *window,
+                    float l, float r, float b, float t,
+                    DisplayRegion *left, DisplayRegion *right) :
+  DisplayRegion(window, l, r, b, t),
+  _left_eye(left),
+  _right_eye(right)
+{
+  nassertv(window == left->get_window() &&
+           window == right->get_window());
+  set_stereo_channel(Lens::SC_stereo);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StereoDisplayRegion::Destructor
+//       Access: Published, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+StereoDisplayRegion::
+~StereoDisplayRegion() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StereoDisplayRegion::set_clear_active
+//       Access: Published, Virtual
+//  Description: Sets the clear-active flag for any bitplane.
+////////////////////////////////////////////////////////////////////
+void StereoDisplayRegion::
+set_clear_active(int n, bool clear_active) {
+  // The clear_active flag gets set only on the parent, stereo display
+  // region.
+  DisplayRegion::set_clear_active(n, clear_active);
+
+  // Except for depth and stencil buffers.  These also get set on the
+  // right display region by default, on the assumption that we want
+  // to clear these buffers between drawing the eyes, and that the
+  // right eye is the second of the pair.
+  switch (n) {
+  case RTP_stencil:
+  case RTP_depth_stencil:
+  case RTP_depth:
+    _right_eye->set_clear_active(n, clear_active);
+    break;
+
+  default:
+    break;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StereoDisplayRegion::set_clear_value
+//       Access: Published, Virtual
+//  Description: Sets the clear value for any bitplane.
+////////////////////////////////////////////////////////////////////
+void StereoDisplayRegion::
+set_clear_value(int n, const Colorf &clear_value) {
+  DisplayRegion::set_clear_value(n, clear_value);
+  _left_eye->set_clear_value(n, clear_value);
+  _right_eye->set_clear_value(n, clear_value);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StereoDisplayRegion::disable_clears
+//       Access: Published, Virtual
+//  Description: Disables both the color and depth clear.  See
+//               set_clear_color_active and set_clear_depth_active.
+////////////////////////////////////////////////////////////////////
+void StereoDisplayRegion::
+disable_clears() {
+  DisplayRegion::disable_clears();
+  _left_eye->disable_clears();
+  _right_eye->disable_clears();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StereoDisplayRegion::set_pixel_zoom
+//       Access: Published, Virtual
+//  Description: Sets the pixel_zoom for left and right eyes.
+////////////////////////////////////////////////////////////////////
+void StereoDisplayRegion::
+set_pixel_zoom(float pixel_zoom) {
+  DisplayRegion::set_pixel_zoom(pixel_zoom);
+  _left_eye->set_pixel_zoom(pixel_zoom);
+  _right_eye->set_pixel_zoom(pixel_zoom);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StereoDisplayRegion::set_dimensions
+//       Access: Published, Virtual
+//  Description: Sets both the left and right DisplayRegions to the
+//               indicated dimensions.
+////////////////////////////////////////////////////////////////////
+void StereoDisplayRegion::
+set_dimensions(float l, float r, float b, float t) {
+  DisplayRegion::set_dimensions(l, r, b, t);
+  _left_eye->set_dimensions(l, r, b, t);
+  _right_eye->set_dimensions(l, r, b, t);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StereoDisplayRegion::is_stereo
+//       Access: Published, Virtual
+//  Description: Returns true if this is a StereoDisplayRegion, false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+bool StereoDisplayRegion::
+is_stereo() const {
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StereoDisplayRegion::set_camera
+//       Access: Published, Virtual
+//  Description: Sets both the left and right DisplayRegions to the
+//               indicated camera.
+////////////////////////////////////////////////////////////////////
+void StereoDisplayRegion::
+set_camera(const NodePath &camera) {
+  DisplayRegion::set_camera(camera);
+  _left_eye->set_camera(camera);
+  _right_eye->set_camera(camera);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StereoDisplayRegion::set_active
+//       Access: Published, Virtual
+//  Description: Sets the active flag on both the left and right
+//               DisplayRegions to the indicated value.
+////////////////////////////////////////////////////////////////////
+void StereoDisplayRegion::
+set_active(bool active) {
+  DisplayRegion::set_active(active);
+  _left_eye->set_active(active);
+  _right_eye->set_active(active);
+  if (active) {
+    // Reenable the appropriate eyes according to our stereo_channel
+    // setting.
+    set_stereo_channel(get_stereo_channel());
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StereoDisplayRegion::set_sort
+//       Access: Published, Virtual
+//  Description: Sets the indicated sort value on the overall
+//               DisplayRegion, the indicated sort value + 1 on the
+//               left eye, and the indicated sort value + 2 on the
+//               right eye.
+////////////////////////////////////////////////////////////////////
+void StereoDisplayRegion::
+set_sort(int sort) {
+  DisplayRegion::set_sort(sort);
+  _left_eye->set_sort(sort + 1);
+  _right_eye->set_sort(sort + 2);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StereoDisplayRegion::set_stereo_channel
+//       Access: Published, Virtual
+//  Description: Sets the stereo channels on the left and right eyes,
+//               and also sets the active flags independently on both
+//               eyes.  For a StereoDisplayRegion, a different action
+//               is performed for each different value:
+//
+//               SC_stereo - the left eye is set to SC_left, the right
+//               eye to SC_right, and both eyes are activated.
+//
+//               SC_left - the left eye is set to SC_left and
+//               activated; the right eye is deactivated.
+//
+//               SC_right - the right eye is set to SC_right and
+//               activated; the left eye is deactivated.
+//
+//               SC_mono - the left eye is set to SC_mono and
+//               activated; the right eye is deactivated.
+////////////////////////////////////////////////////////////////////
+void StereoDisplayRegion::
+set_stereo_channel(Lens::StereoChannel stereo_channel) {
+  DisplayRegion::set_stereo_channel(stereo_channel);
+  if (!is_active()) {
+    return;
+  }
+
+  switch (stereo_channel) {
+  case Lens::SC_stereo:
+    _left_eye->set_stereo_channel(Lens::SC_left);
+    _left_eye->set_active(true);
+    _right_eye->set_stereo_channel(Lens::SC_right);
+    _right_eye->set_active(true);
+    break;
+
+  case Lens::SC_left:
+    _left_eye->set_stereo_channel(Lens::SC_left);
+    _left_eye->set_active(true);
+    _right_eye->set_active(false);
+    break;
+
+  case Lens::SC_right:
+    _left_eye->set_active(false);
+    _right_eye->set_stereo_channel(Lens::SC_right);
+    _right_eye->set_active(true);
+    break;
+
+  case Lens::SC_mono:
+    _left_eye->set_stereo_channel(Lens::SC_mono);
+    _left_eye->set_active(true);
+    _right_eye->set_active(false);
+    break;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StereoDisplayRegion::set_incomplete_render
+//       Access: Published, Virtual
+//  Description: Sets the incomplete_render flag on both the left and
+//               right DisplayRegions to the indicated value.
+////////////////////////////////////////////////////////////////////
+void StereoDisplayRegion::
+set_incomplete_render(bool incomplete_render) {
+  DisplayRegion::set_incomplete_render(incomplete_render);
+  _left_eye->set_incomplete_render(incomplete_render);
+  _right_eye->set_incomplete_render(incomplete_render);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StereoDisplayRegion::set_texture_reload_priority
+//       Access: Published, Virtual
+//  Description: Sets the texture_reload_priority on both the left and
+//               right DisplayRegions to the indicated value.
+////////////////////////////////////////////////////////////////////
+void StereoDisplayRegion::
+set_texture_reload_priority(int texture_reload_priority) {
+  DisplayRegion::set_texture_reload_priority(texture_reload_priority);
+  _left_eye->set_texture_reload_priority(texture_reload_priority);
+  _right_eye->set_texture_reload_priority(texture_reload_priority);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StereoDisplayRegion::set_cull_traverser
+//       Access: Published, Virtual
+//  Description: Sets the CullTraverser for both the left and right
+//               DisplayRegions.
+////////////////////////////////////////////////////////////////////
+void StereoDisplayRegion::
+set_cull_traverser(CullTraverser *trav) {
+  DisplayRegion::set_cull_traverser(trav);
+  _left_eye->set_cull_traverser(trav);
+  _right_eye->set_cull_traverser(trav);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StereoDisplayRegion::set_cube_map_index
+//       Access: Published, Virtual
+//  Description: Sets the cube_map_index on both the left and
+//               right DisplayRegions to the indicated value.
+////////////////////////////////////////////////////////////////////
+void StereoDisplayRegion::
+set_cube_map_index(int cube_map_index) {
+  DisplayRegion::set_cube_map_index(cube_map_index);
+  _left_eye->set_cube_map_index(cube_map_index);
+  _right_eye->set_cube_map_index(cube_map_index);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StereoDisplayRegion::output
+//       Access: Published, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+void StereoDisplayRegion::
+output(ostream &out) const {
+  out << "StereoDisplayRegion(" << *_left_eye << ")";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: StereoDisplayRegion::make_cull_result_graph
+//       Access: Published, Virtual
+//  Description: Returns a special scene graph constructed to
+//               represent the results of the last frame's cull
+//               operation.
+////////////////////////////////////////////////////////////////////
+PT(PandaNode) StereoDisplayRegion::
+make_cull_result_graph() {
+  PT(PandaNode) root = new PandaNode("stereo");
+
+  PT(PandaNode) left = _left_eye->make_cull_result_graph();
+  left->set_name("left");
+  root->add_child(left, _left_eye->get_sort());
+
+  PT(PandaNode) right = _right_eye->make_cull_result_graph();
+  right->set_name("right");
+  root->add_child(right, _right_eye->get_sort());
+
+  return root;
+}

+ 98 - 0
panda/src/display/stereoDisplayRegion.h

@@ -0,0 +1,98 @@
+// Filename: stereoDisplayRegion.h
+// Created by:  drose (19Feb09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 STEREODISPLAYREGION_H
+#define STEREODISPLAYREGION_H
+
+#include "pandabase.h"
+
+#include "displayRegion.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : StereoDisplayRegion
+// Description : This is a special DisplayRegion wrapper that actually
+//               includes a pair of DisplayRegions internally: the
+//               left and right eyes.  The DisplayRegion represented
+//               here does not have a physical association with the
+//               window, but it pretends it does.  Instead, it
+//               maintains a pointer to the left and right
+//               DisplayRegions separately.
+//
+//               Operations on the StereoDisplayRegion object affect
+//               both left and right eyes together.  To access the
+//               left or right eyes independently, use get_left_eye()
+//               and get_right_eye().
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA_DISPLAY StereoDisplayRegion : public DisplayRegion {
+protected:
+  StereoDisplayRegion(GraphicsOutput *window,
+                      float l, float r, float b, float t,
+                      DisplayRegion *left, DisplayRegion *right);
+
+public:
+  virtual ~StereoDisplayRegion();
+
+PUBLISHED:
+  // Inherited from DrawableRegion
+  virtual void set_clear_active(int n, bool clear_aux_active);
+  virtual void set_clear_value(int n, const Colorf &clear_value);
+  virtual void disable_clears();
+  virtual void set_pixel_zoom(float pixel_zoom);
+
+  // Inherited from DisplayRegion
+  virtual void set_dimensions(float l, float r, float b, float t);
+  virtual bool is_stereo() const;
+  virtual void set_camera(const NodePath &camera);
+  virtual void set_active(bool active);
+  virtual void set_sort(int sort);
+  virtual void set_stereo_channel(Lens::StereoChannel stereo_channel);
+  virtual void set_incomplete_render(bool incomplete_render);
+  virtual void set_texture_reload_priority(int texture_reload_priority);
+  virtual void set_cull_traverser(CullTraverser *trav);
+  virtual void set_cube_map_index(int cube_map_index);
+
+  virtual void output(ostream &out) const;
+  virtual PT(PandaNode) make_cull_result_graph();
+
+  INLINE DisplayRegion *get_left_eye();
+  INLINE DisplayRegion *get_right_eye();
+
+private:
+  PT(DisplayRegion) _left_eye;
+  PT(DisplayRegion) _right_eye;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    DisplayRegion::init_type();
+    register_type(_type_handle, "StereoDisplayRegion",
+                  DisplayRegion::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;
+
+  friend class GraphicsOutput;
+  friend class DisplayRegionPipelineReader;
+};
+
+#include "stereoDisplayRegion.I"
+
+#endif

+ 0 - 2
panda/src/framework/config_framework.cxx

@@ -30,8 +30,6 @@ ConfigVariableDouble aspect_ratio
 ("aspect-ratio", 0.0);
 ("aspect-ratio", 0.0);
 ConfigVariableBool show_frame_rate_meter
 ConfigVariableBool show_frame_rate_meter
 ("show-frame-rate-meter", false);
 ("show-frame-rate-meter", false);
-ConfigVariableBool default_stereo_camera
-("default-stereo-camera", true);
 
 
 ConfigVariableString record_session
 ConfigVariableString record_session
 ("record-session", "");
 ("record-session", "");

+ 0 - 1
panda/src/framework/config_framework.h

@@ -27,7 +27,6 @@ NotifyCategoryDecl(framework, EXPCL_FRAMEWORK, EXPTP_FRAMEWORK);
 // Configure variables for framework package.
 // Configure variables for framework package.
 extern ConfigVariableDouble aspect_ratio;
 extern ConfigVariableDouble aspect_ratio;
 extern ConfigVariableBool show_frame_rate_meter;
 extern ConfigVariableBool show_frame_rate_meter;
-extern ConfigVariableBool default_stereo_camera;
 
 
 extern ConfigVariableString record_session;
 extern ConfigVariableString record_session;
 extern ConfigVariableString playback_session;
 extern ConfigVariableString playback_session;

+ 1 - 6
panda/src/framework/windowFramework.cxx

@@ -180,11 +180,6 @@ open_window(const WindowProperties &props, GraphicsEngine *engine,
     NodePath camera_np = make_camera();
     NodePath camera_np = make_camera();
     _display_region_3d->set_camera(camera_np);
     _display_region_3d->set_camera(camera_np);
 
 
-    if (_window->is_stereo() && default_stereo_camera) {
-      // Actually, let's make a stereo DisplayRegion.
-      _display_region_3d->set_stereo_channel(Lens::SC_stereo);
-    }
-
     set_background_type(_background_type);
     set_background_type(_background_type);
 
 
     if (show_frame_rate_meter) {
     if (show_frame_rate_meter) {
@@ -286,7 +281,7 @@ get_render_2d() {
     // display region.
     // display region.
     float l, r, b, t;
     float l, r, b, t;
     _display_region_3d->get_dimensions(l, r, b, t);
     _display_region_3d->get_dimensions(l, r, b, t);
-    _display_region_2d = _window->make_display_region(l, r, b, t);
+    _display_region_2d = _window->make_mono_display_region(l, r, b, t);
     _display_region_2d->set_sort(10);
     _display_region_2d->set_sort(10);
 
 
     // Finally, we need a camera to associate with the display region.
     // Finally, we need a camera to associate with the display region.

+ 1 - 1
panda/src/grutil/frameRateMeter.cxx

@@ -88,7 +88,7 @@ setup_window(GraphicsOutput *window) {
   _root.set_two_sided(1, 1);
   _root.set_two_sided(1, 1);
     
     
   // Create a display region that covers the entire window.
   // Create a display region that covers the entire window.
-  _display_region = _window->make_display_region();
+  _display_region = _window->make_mono_display_region();
   _display_region->set_sort(frame_rate_meter_layer_sort);
   _display_region->set_sort(frame_rate_meter_layer_sort);
     
     
   // Finally, we need a camera to associate with the display region.
   // Finally, we need a camera to associate with the display region.

+ 7 - 2
panda/src/gsgbase/Sources.pp

@@ -9,12 +9,17 @@
   #define COMBINED_SOURCES $[TARGET]_composite1.cxx     
   #define COMBINED_SOURCES $[TARGET]_composite1.cxx     
 
 
   #define SOURCES \
   #define SOURCES \
-    config_gsgbase.h graphicsStateGuardianBase.h
+    config_gsgbase.h \
+    displayRegionBase.I displayRegionBase.h \
+    graphicsStateGuardianBase.h    
 
 
   #define INCLUDED_SOURCES \
   #define INCLUDED_SOURCES \
-    config_gsgbase.cxx graphicsStateGuardianBase.cxx
+    config_gsgbase.cxx \
+    displayRegionBase.cxx \
+    graphicsStateGuardianBase.cxx
 
 
   #define INSTALL_HEADERS \
   #define INSTALL_HEADERS \
+    displayRegionBase.I displayRegionBase.h \
     graphicsStateGuardianBase.h
     graphicsStateGuardianBase.h
 
 
   #define IGATESCAN all
   #define IGATESCAN all

+ 2 - 0
panda/src/gsgbase/config_gsgbase.cxx

@@ -13,6 +13,7 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 #include "config_gsgbase.h"
 #include "config_gsgbase.h"
+#include "displayRegionBase.h"
 #include "graphicsStateGuardianBase.h"
 #include "graphicsStateGuardianBase.h"
 
 
 #include "dconfig.h"
 #include "dconfig.h"
@@ -20,5 +21,6 @@
 Configure(config_gsgbase);
 Configure(config_gsgbase);
 
 
 ConfigureFn(config_gsgbase) {
 ConfigureFn(config_gsgbase) {
+  DisplayRegionBase::init_type();
   GraphicsStateGuardianBase::init_type();
   GraphicsStateGuardianBase::init_type();
 }
 }

+ 29 - 0
panda/src/gsgbase/displayRegionBase.I

@@ -0,0 +1,29 @@
+// Filename: displayRegionBase.I
+// Created by:  drose (20Feb09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: DisplayRegionBase::Constructor
+//       Access: Protected
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE DisplayRegionBase::
+DisplayRegionBase() {
+}
+
+INLINE ostream &
+operator << (ostream &out, const DisplayRegionBase &dr) {
+  dr.output(out);
+  return out;
+}

+ 27 - 0
panda/src/gsgbase/displayRegionBase.cxx

@@ -0,0 +1,27 @@
+// Filename: displayRegionBase.cxx
+// Created by:  drose (20Feb09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "displayRegionBase.h"
+
+TypeHandle DisplayRegionBase::_type_handle;
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: DisplayRegionBase::Destructor
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+DisplayRegionBase::
+~DisplayRegionBase() {
+}

+ 59 - 0
panda/src/gsgbase/displayRegionBase.h

@@ -0,0 +1,59 @@
+// Filename: displayRegionBase.h
+// Created by:  drose (20Feb09)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 DISPLAYREGIONBASE_H
+#define DISPLAYREGIONBASE_H
+
+#include "pandabase.h"
+
+#include "typedReferenceCount.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : DisplayRegionBase
+// Description : An abstract base class for DisplayRegion, mainly so
+//               we can store DisplayRegion pointers in a Camera.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA_GSGBASE DisplayRegionBase : public TypedReferenceCount {
+protected:
+  INLINE DisplayRegionBase();
+
+public:
+  virtual ~DisplayRegionBase();
+
+PUBLISHED:
+  virtual void output(ostream &out) const=0;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TypedReferenceCount::init_type();
+    register_type(_type_handle, "DisplayRegionBase",
+                  TypedReferenceCount::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;
+};
+
+INLINE ostream &operator << (ostream &out, const DisplayRegionBase &dr);
+
+#include "displayRegionBase.I"
+
+#endif

+ 3 - 2
panda/src/gsgbase/gsgbase_composite1.cxx

@@ -1,4 +1,5 @@
 
 
-#include"config_gsgbase.cxx"
-#include"graphicsStateGuardianBase.cxx"
+#include "config_gsgbase.cxx"
+#include "displayRegionBase.cxx"
+#include "graphicsStateGuardianBase.cxx"
 
 

+ 2 - 2
panda/src/pgraph/camera.I

@@ -82,9 +82,9 @@ get_num_display_regions() const {
 //  Description: Returns the nth display region associated with the
 //  Description: Returns the nth display region associated with the
 //               camera.
 //               camera.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE DisplayRegion *Camera::
+INLINE DisplayRegionBase *Camera::
 get_display_region(int n) const {
 get_display_region(int n) const {
-  nassertr(n >= 0 && n < (int)_display_regions.size(), (DisplayRegion *)NULL);
+  nassertr(n >= 0 && n < (int)_display_regions.size(), (DisplayRegionBase *)NULL);
   return _display_regions[n];
   return _display_regions[n];
 }
 }
 
 

+ 2 - 2
panda/src/pgraph/camera.cxx

@@ -273,7 +273,7 @@ cleanup_aux_scene_data(Thread *current_thread) {
 //               intended to be called from the DisplayRegion.
 //               intended to be called from the DisplayRegion.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void Camera::
 void Camera::
-add_display_region(DisplayRegion *display_region) {
+add_display_region(DisplayRegionBase *display_region) {
   _display_regions.push_back(display_region);
   _display_regions.push_back(display_region);
 }
 }
 
 
@@ -285,7 +285,7 @@ add_display_region(DisplayRegion *display_region) {
 //               intended to be called from the DisplayRegion.
 //               intended to be called from the DisplayRegion.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void Camera::
 void Camera::
-remove_display_region(DisplayRegion *display_region) {
+remove_display_region(DisplayRegionBase *display_region) {
   DisplayRegions::iterator dri =
   DisplayRegions::iterator dri =
     find(_display_regions.begin(), _display_regions.end(), display_region);
     find(_display_regions.begin(), _display_regions.end(), display_region);
   if (dri != _display_regions.end()) {
   if (dri != _display_regions.end()) {

+ 5 - 6
panda/src/pgraph/camera.h

@@ -25,8 +25,7 @@
 #include "pointerTo.h"
 #include "pointerTo.h"
 #include "pmap.h"
 #include "pmap.h"
 #include "auxSceneData.h"
 #include "auxSceneData.h"
-
-class DisplayRegion;
+#include "displayRegionBase.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : Camera
 //       Class : Camera
@@ -54,7 +53,7 @@ PUBLISHED:
   INLINE const NodePath &get_scene() const;
   INLINE const NodePath &get_scene() const;
 
 
   INLINE int get_num_display_regions() const;
   INLINE int get_num_display_regions() const;
-  INLINE DisplayRegion *get_display_region(int n) const;
+  INLINE DisplayRegionBase *get_display_region(int n) const;
   MAKE_SEQ(get_display_regions, get_num_display_regions, get_display_region);
   MAKE_SEQ(get_display_regions, get_num_display_regions, get_display_region);
 
 
   INLINE void set_camera_mask(DrawMask mask);
   INLINE void set_camera_mask(DrawMask mask);
@@ -84,8 +83,8 @@ PUBLISHED:
   int cleanup_aux_scene_data(Thread *current_thread = Thread::get_current_thread());
   int cleanup_aux_scene_data(Thread *current_thread = Thread::get_current_thread());
 
 
 private:
 private:
-  void add_display_region(DisplayRegion *display_region);
-  void remove_display_region(DisplayRegion *display_region);
+  void add_display_region(DisplayRegionBase *display_region);
+  void remove_display_region(DisplayRegionBase *display_region);
 
 
   bool _active;
   bool _active;
   NodePath _scene;
   NodePath _scene;
@@ -94,7 +93,7 @@ private:
 
 
   DrawMask _camera_mask;
   DrawMask _camera_mask;
 
 
-  typedef pvector<DisplayRegion *> DisplayRegions;
+  typedef pvector<DisplayRegionBase *> DisplayRegions;
   DisplayRegions _display_regions;
   DisplayRegions _display_regions;
 
 
   CPT(RenderState) _initial_state;
   CPT(RenderState) _initial_state;