Sfoglia il codice sorgente

fix some stereo-fbo and cube map issues, introducing DisplayRegion::set_target_tex_page()

David Rose 12 anni fa
parent
commit
f615e0beeb

+ 50 - 13
panda/src/display/displayRegion.I

@@ -239,17 +239,41 @@ get_texture_reload_priority() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: DisplayRegion::get_cube_map_index
+//     Function: DisplayRegion::set_cube_map_index
 //       Access: Published
-//  Description: Returns the cube map face index associated with this
+//  Description: Deprecated; replaced by set_target_tex_page().
+////////////////////////////////////////////////////////////////////
+INLINE void DisplayRegion::
+set_cube_map_index(int cube_map_index) {
+  set_target_tex_page(cube_map_index, 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DisplayRegion::get_target_tex_page
+//       Access: Published
+//  Description: Returns the target page number associated with this
 //               particular DisplayRegion, or -1 if it is not
-//               associated with a cube map.  See
-//               set_cube_map_index().
+//               associated with a page.  See
+//               set_target_tex_page().
 ////////////////////////////////////////////////////////////////////
 INLINE int DisplayRegion::
-get_cube_map_index() const {
+get_target_tex_page() const {
   CDReader cdata(_cycler);
-  return cdata->_cube_map_index;
+  return cdata->_target_tex_page;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DisplayRegion::get_target_tex_view
+//       Access: Published
+//  Description: Returns the target view number associated with this
+//               particular DisplayRegion, or -1 if it is not
+//               associated with a view.  See
+//               set_target_tex_page().
+////////////////////////////////////////////////////////////////////
+INLINE int DisplayRegion::
+get_target_tex_view() const {
+  CDReader cdata(_cycler);
+  return cdata->_target_tex_view;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -776,16 +800,29 @@ get_tex_view_offset() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: DisplayRegionPipelineReader::get_cube_map_index
-//       Access: Public
-//  Description: Returns the cube map face index associated with this
+//     Function: DisplayRegionPipelineReader::get_target_tex_page
+//       Access: Published
+//  Description: Returns the target page number associated with this
+//               particular DisplayRegion, or -1 if it is not
+//               associated with a page.  See
+//               set_target_tex_page().
+////////////////////////////////////////////////////////////////////
+INLINE int DisplayRegionPipelineReader::
+get_target_tex_page() const {
+  return _cdata->_target_tex_page;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DisplayRegionPipelineReader::get_target_tex_view
+//       Access: Published
+//  Description: Returns the target view number associated with this
 //               particular DisplayRegion, or -1 if it is not
-//               associated with a cube map.  See
-//               set_cube_map_index().
+//               associated with a view.  See
+//               set_target_tex_page().
 ////////////////////////////////////////////////////////////////////
 INLINE int DisplayRegionPipelineReader::
-get_cube_map_index() const {
-  return _cdata->_cube_map_index;
+get_target_tex_view() const {
+  return _cdata->_target_tex_view;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 20 - 11
panda/src/display/displayRegion.cxx

@@ -387,22 +387,29 @@ get_cull_traverser() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: DisplayRegion::set_cube_map_index
+//     Function: DisplayRegion::set_target_tex_page
 //       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.
+//               rendering the faces of a cube map or multipage and/or
+//               multiview texture.  
+//
+//               This sets up the DisplayRegion to render to the ith
+//               page and jth view of its associated texture(s); the
+//               value must be consistent with the range of values
+//               availble to the texture.  A normal DisplayRegion that
+//               is not associated with any particular page should be
+//               set to page -1 and view 0.
+//
+//               This is particularly useful when rendering cube maps
+//               and/or stereo textures.
 ////////////////////////////////////////////////////////////////////
 void DisplayRegion::
-set_cube_map_index(int cube_map_index) {
+set_target_tex_page(int page, int view) {
   int pipeline_stage = Thread::get_current_pipeline_stage();
   nassertv(pipeline_stage == 0);
   CDWriter cdata(_cycler);
-  cdata->_cube_map_index = cube_map_index;
+  cdata->_target_tex_page = page;
+  cdata->_target_tex_view = view;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -816,7 +823,8 @@ CData() :
   _sort(0),
   _stereo_channel(Lens::SC_mono),
   _tex_view_offset(0),
-  _cube_map_index(-1)
+  _target_tex_page(-1),
+  _target_tex_view(-1)
 {
 }
 
@@ -841,7 +849,8 @@ CData(const DisplayRegion::CData &copy) :
   _sort(copy._sort),
   _stereo_channel(copy._stereo_channel),
   _tex_view_offset(copy._tex_view_offset),
-  _cube_map_index(copy._cube_map_index)
+  _target_tex_page(copy._target_tex_page),
+  _target_tex_view(copy._target_tex_view)
 {
 }
 

+ 8 - 4
panda/src/display/displayRegion.h

@@ -111,8 +111,10 @@ PUBLISHED:
   virtual void set_cull_traverser(CullTraverser *trav);
   CullTraverser *get_cull_traverser();
 
-  virtual void set_cube_map_index(int cube_map_index);
-  INLINE int get_cube_map_index() const;
+  INLINE void set_cube_map_index(int cube_map_index);
+  virtual void set_target_tex_page(int page, int view);
+  INLINE int get_target_tex_page() const;
+  INLINE int get_target_tex_view() const;
 
   INLINE void set_cull_callback(CallbackObject *object);
   INLINE void clear_cull_callback();
@@ -210,7 +212,8 @@ private:
     int _sort;
     Lens::StereoChannel _stereo_channel;
     int _tex_view_offset;
-    int _cube_map_index;
+    int _target_tex_page;
+    int _target_tex_view;
 
     PT(CallbackObject) _cull_callback;
     PT(CallbackObject) _draw_callback;
@@ -308,7 +311,8 @@ public:
   INLINE Lens::StereoChannel get_stereo_channel() const;
   INLINE int get_tex_view_offset();
   INLINE bool get_clear_depth_between_eyes() const;
-  INLINE int get_cube_map_index() const;
+  INLINE int get_target_tex_page() const;
+  INLINE int get_target_tex_view() const;
   INLINE CallbackObject *get_draw_callback() const;
 
   INLINE void get_pixels(int &pl, int &pr, int &pb, int &pt) const;

+ 5 - 3
panda/src/display/graphicsOutput.I

@@ -862,12 +862,14 @@ end_frame_spam(FrameMode mode) {
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsOutput::clear_cube_map_selection
 //       Access: Public
-//  Description: Clear the variables that select a cube-map face.
+//  Description: Clear the variables that select a cube-map face (or
+//               other multipage or multiview texture face).
 ////////////////////////////////////////////////////////////////////
 INLINE void GraphicsOutput::
 clear_cube_map_selection() {
-  _cube_map_index = -1;
-  _cube_map_dr = NULL;
+  _target_tex_page = -1;
+  _target_tex_view = -1;
+  _prev_page_dr = NULL;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 47 - 72
panda/src/display/graphicsOutput.cxx

@@ -106,9 +106,9 @@ GraphicsOutput(GraphicsEngine *engine, GraphicsPipe *pipe,
 
   _is_valid = false;
   _flip_ready = false;
-  _cube_map_index = -1;
-  _cube_map_dr = NULL;
-  _tex_view_offset = -1;
+  _target_tex_page = -1;
+  _target_tex_view = -1;
+  _prev_page_dr = NULL;
   _sort = 0;
   _child_sort = 0;
   _got_child_sort = false;
@@ -1069,7 +1069,7 @@ make_cube_map(const string &name, int size, NodePath &camera_rig,
     DisplayRegion *dr;
     dr = buffer->make_display_region();
 
-    dr->set_cube_map_index(i);
+    dr->set_target_tex_page(i, 0);
     dr->copy_clear_settings(*this);
     dr->set_camera(camera_np);
   }
@@ -1341,13 +1341,16 @@ end_frame(FrameMode mode, Thread *current_thread) {
 ////////////////////////////////////////////////////////////////////
 void GraphicsOutput::
 change_scenes(DisplayRegionPipelineReader *new_dr) {
-  int new_cube_map_index = new_dr->get_cube_map_index();
-  if (new_cube_map_index != -1 &&
-      new_cube_map_index != _cube_map_index) {
-    int old_cube_map_index = _cube_map_index;
-    DisplayRegion *old_cube_map_dr = _cube_map_dr;
-    _cube_map_index = new_cube_map_index;
-    _cube_map_dr = new_dr->get_object();
+  int new_target_tex_page = new_dr->get_target_tex_page();
+  int new_target_tex_view = new_dr->get_target_tex_view();
+  if ((new_target_tex_page != -1 && new_target_tex_page != _target_tex_page) ||
+      new_target_tex_view != _target_tex_view) {
+    int old_target_tex_page = _target_tex_page;
+    int old_target_tex_view = _target_tex_view;
+    DisplayRegion *old_page_dr = _prev_page_dr;
+    _target_tex_page = new_target_tex_page;
+    _target_tex_view = new_target_tex_view;
+    _prev_page_dr = new_dr->get_object();
 
     CDReader cdata(_cycler);
     RenderTextures::const_iterator ri;
@@ -1356,83 +1359,55 @@ change_scenes(DisplayRegionPipelineReader *new_dr) {
       Texture *texture = (*ri)._texture;
       if (rtm_mode != RTM_none) {
         if (rtm_mode == RTM_bind_or_copy || rtm_mode == RTM_bind_layered) {
-          // In render-to-texture mode, switch the rendering backend to
-          // the new cube map face, so that the subsequent frame will be
-          // rendered to the new face.
+          // In render-to-texture mode, switch the rendering backend
+          // to the new page, so that the subsequent frame will be
+          // rendered to the correct page.
+          select_target_tex_page(_target_tex_page, _target_tex_view);
 
-          select_cube_map(new_cube_map_index);
-
-        } else if (old_cube_map_index != -1) {
+        } else if (old_target_tex_page != -1) {
           // In copy-to-texture mode, copy the just-rendered framebuffer
-          // to the old cube map face.
-          nassertv(old_cube_map_dr != (DisplayRegion *)NULL);
+          // to the old texture page.
+
+          // TODO: we should probably pass the view parameter into
+          // framebuffer_copy_to_xxx(), as we do the page parameter.
+          // Instead these methods draw the view parameter from
+          // dr->get_target_tex_view(), which is not altogether wrong
+          // but is a strange approach.
+
+          nassertv(old_page_dr != (DisplayRegion *)NULL);
           if (display_cat.is_debug()) {
             display_cat.debug()
               << "Copying texture for " << get_name() << " at scene change.\n";
             display_cat.debug()
-              << "cube_map_index = " << old_cube_map_index << "\n";
+              << "target_tex_page = " << old_target_tex_page << "\n";
           }
           RenderBuffer buffer = _gsg->get_render_buffer(get_draw_buffer_type(),
                                                         get_fb_properties());
           if (rtm_mode == RTM_copy_ram) {
-            _gsg->framebuffer_copy_to_ram(texture, old_cube_map_index,
-                                          old_cube_map_dr, buffer);
+            _gsg->framebuffer_copy_to_ram(texture, old_target_tex_page,
+                                          old_page_dr, buffer);
           } else {
-            _gsg->framebuffer_copy_to_texture(texture, old_cube_map_index,
-                                              old_cube_map_dr, buffer);
+            _gsg->framebuffer_copy_to_texture(texture, old_target_tex_page,
+                                              old_page_dr, buffer);
           }
         }
       }
     }
   }
-
-  int new_tex_view_offset = new_dr->get_tex_view_offset();
-  if (new_tex_view_offset != _tex_view_offset) {
-    int old_tex_view_offset = _tex_view_offset;
-    //DisplayRegion *old_cube_map_dr = _cube_map_dr;
-    _tex_view_offset = new_tex_view_offset;
-    //_cube_map_dr = new_dr->get_object();
-
-    CDReader cdata(_cycler);
-    RenderTextures::const_iterator ri;
-    for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) {
-      RenderTextureMode rtm_mode = (*ri)._rtm_mode;
-      Texture *texture = (*ri)._texture;
-      if (rtm_mode == RTM_bind_or_copy || rtm_mode == RTM_bind_layered) {
-        // In render-to-texture mode, switch the rendering backend to
-        // the new view, so that the subsequent frame will be
-        // rendered to the new view.
-
-        select_tex_view(new_tex_view_offset);
-        break;
-      }
-    }
-  }
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GraphicsOutput::select_cube_map
+//     Function: GraphicsOutput::select_target_tex_page
 //       Access: Public, Virtual
 //  Description: Called internally when the window is in
 //               render-to-a-texture mode and we are in the process of
-//               rendering the six faces of a cube map.  This should
-//               do whatever needs to be done to switch the buffer to
-//               the indicated face.
-////////////////////////////////////////////////////////////////////
-void GraphicsOutput::
-select_cube_map(int) {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsOutput::select_tex_view
-//       Access: Public, Virtual
-//  Description: Called internally when the window is in
-//               render-to-a-texture mode and the DisplayRegion
-//               requests that we switch rendering to a different
-//               texture view.
+//               rendering the six faces of a cube map, or any other
+//               multi-page and/or multi-view texture.  This should do
+//               whatever needs to be done to switch the buffer to the
+//               indicated page and view.
 ////////////////////////////////////////////////////////////////////
 void GraphicsOutput::
-select_tex_view(int) {
+select_target_tex_page(int, int) {
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1603,7 +1578,7 @@ copy_to_textures() {
         display_cat.debug()
           << "Copying texture for " << get_name() << " at frame end.\n";
         display_cat.debug()
-          << "cube_map_index = " << _cube_map_index << "\n";
+          << "target_tex_page = " << _target_tex_page << "\n";
       }
       RenderTexturePlane plane = (*ri)._plane;
       RenderBuffer buffer(_gsg, DrawableRegion::get_renderbuffer_type(plane));
@@ -1613,24 +1588,24 @@ copy_to_textures() {
       }
 
       bool copied = false;
-      if (_cube_map_dr != (DisplayRegion *)NULL) {
+      if (_prev_page_dr != (DisplayRegion *)NULL) {
         if ((rtm_mode == RTM_copy_ram)||(rtm_mode == RTM_triggered_copy_ram)) {
           copied =
-            _gsg->framebuffer_copy_to_ram(texture, _cube_map_index,
-                                          _cube_map_dr, buffer);
+            _gsg->framebuffer_copy_to_ram(texture, _target_tex_page,
+                                          _prev_page_dr, buffer);
         } else {
           copied =
-            _gsg->framebuffer_copy_to_texture(texture, _cube_map_index,
-                                              _cube_map_dr, buffer);
+            _gsg->framebuffer_copy_to_texture(texture, _target_tex_page,
+                                              _prev_page_dr, buffer);
         }
       } else {
         if ((rtm_mode == RTM_copy_ram)||(rtm_mode == RTM_triggered_copy_ram)) {
           copied =
-            _gsg->framebuffer_copy_to_ram(texture, _cube_map_index,
+            _gsg->framebuffer_copy_to_ram(texture, _target_tex_page,
                                           _overlay_display_region, buffer);
         } else {
           copied =
-            _gsg->framebuffer_copy_to_texture(texture, _cube_map_index,
+            _gsg->framebuffer_copy_to_texture(texture, _target_tex_page,
                                               _overlay_display_region, buffer);
         }
       }

+ 4 - 5
panda/src/display/graphicsOutput.h

@@ -260,8 +260,7 @@ public:
   virtual void end_frame(FrameMode mode, Thread *current_thread);
 
   void change_scenes(DisplayRegionPipelineReader *new_dr);
-  virtual void select_cube_map(int cube_map_index);
-  virtual void select_tex_view(int tex_view_offset);
+  virtual void select_target_tex_page(int page, int view);
 
   // These methods will be called within the app (main) thread.
   virtual void begin_flip();
@@ -311,9 +310,9 @@ protected:
   bool _stereo;
   string _name;
   bool _flip_ready;
-  int _cube_map_index;
-  DisplayRegion *_cube_map_dr;
-  int _tex_view_offset;
+  int _target_tex_page;
+  int _target_tex_view;
+  DisplayRegion *_prev_page_dr;
   PT(Geom) _texture_card;
   bool _trigger_copy;
 

+ 1 - 1
panda/src/display/graphicsStateGuardian.cxx

@@ -2754,7 +2754,7 @@ make_shadow_buffer(const NodePath &light_np, GraphicsOutputBase *host) {
     for (int i = 0; i < 6; ++i) {
       PT(DisplayRegion) dr = sbuffer->make_mono_display_region(0, 1, 0, 1);
       dr->set_lens_index(i);
-      dr->set_cube_map_index(i);
+      dr->set_target_tex_page(i, 0);
       dr->set_camera(light_np);
       dr->set_clear_depth_active(true);
     }

+ 6 - 6
panda/src/display/stereoDisplayRegion.cxx

@@ -284,16 +284,16 @@ set_cull_traverser(CullTraverser *trav) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: StereoDisplayRegion::set_cube_map_index
+//     Function: StereoDisplayRegion::set_target_tex_page
 //       Access: Published, Virtual
-//  Description: Sets the cube_map_index on both the left and
+//  Description: Sets the page and view 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);
+set_target_tex_page(int page, int view) {
+  DisplayRegion::set_target_tex_page(page, view);
+  _left_eye->set_target_tex_page(page, view);
+  _right_eye->set_target_tex_page(page, view);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
panda/src/display/stereoDisplayRegion.h

@@ -61,7 +61,7 @@ PUBLISHED:
   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 set_target_tex_page(int page, int view);
 
   virtual void output(ostream &out) const;
   virtual PT(PandaNode) make_cull_result_graph();

+ 3 - 3
panda/src/dxgsg8/wdxGraphicsBuffer8.cxx

@@ -394,7 +394,7 @@ rebuild_bitplanes() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: wdxGraphicsBuffer8::select_cube_map
+//     Function: wdxGraphicsBuffer8::select_target_tex_page
 //       Access: Public, Virtual
 //  Description: Called internally when the window is in
 //               render-to-a-texture mode and we are in the process of
@@ -403,8 +403,8 @@ rebuild_bitplanes() {
 //               the indicated face.
 ////////////////////////////////////////////////////////////////////
 void wdxGraphicsBuffer8::
-select_cube_map(int cube_map_index) {
-  _cube_map_index = cube_map_index;
+select_target_tex_page(int page, int view) {
+  _cube_map_index = page;
 
   HRESULT hr;
   Texture *color_tex = 0;

+ 1 - 1
panda/src/dxgsg8/wdxGraphicsBuffer8.h

@@ -46,7 +46,7 @@ public:
   virtual bool begin_frame(FrameMode mode, Thread *current_thread);
   virtual void end_frame(FrameMode mode, Thread *current_thread);
   
-  virtual void select_cube_map(int cube_map_index);
+  virtual void select_target_tex_page(int page, int view);
 
   virtual void process_events();
 

+ 1 - 1
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -1902,7 +1902,7 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
   // must use a render target type texture for StretchRect
   tex->set_render_to_texture(true);
 
-  int view = dr->get_tex_view_offset();
+  int view = dr->get_target_tex_view();
   TextureContext *tc = tex->prepare_now(view, get_prepared_objects(), this);
   if (tc == (TextureContext *)NULL) {
     return false;

+ 3 - 3
panda/src/dxgsg9/wdxGraphicsBuffer9.cxx

@@ -582,7 +582,7 @@ rebuild_bitplanes() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: wdxGraphicsBuffer9::select_cube_map
+//     Function: wdxGraphicsBuffer9::select_target_tex_page
 //       Access: Public, Virtual
 //  Description: Called internally when the window is in
 //               render-to-a-texture mode and we are in the process of
@@ -591,13 +591,13 @@ rebuild_bitplanes() {
 //               the indicated face.
 ////////////////////////////////////////////////////////////////////
 void wdxGraphicsBuffer9::
-select_cube_map(int cube_map_index) {
+select_target_tex_page(int page, int view) {
 
   DWORD render_target_index;
   
   render_target_index = 0;
 
-  _cube_map_index = cube_map_index;
+  _cube_map_index = page;
 
   HRESULT hr;
   Texture *color_tex = 0;

+ 1 - 1
panda/src/dxgsg9/wdxGraphicsBuffer9.h

@@ -46,7 +46,7 @@ public:
   virtual bool begin_frame(FrameMode mode, Thread *current_thread);
   virtual void end_frame(FrameMode mode, Thread *current_thread);
 
-  virtual void select_cube_map(int cube_map_index);
+  virtual void select_target_tex_page(int page, int view);
   
   virtual void process_events();
 

+ 70 - 83
panda/src/glstuff/glGraphicsBuffer_src.cxx

@@ -80,7 +80,7 @@ CLP(GraphicsBuffer)(GraphicsEngine *engine, GraphicsPipe *pipe,
   }
 
   _shared_depth_buffer = 0;
-  _active_cube_map_index = -1;
+  _bound_tex_page = -1;
   _bound_tex_view = 0;
 }
 
@@ -125,7 +125,7 @@ begin_frame(FrameMode mode, Thread *current_thread) {
   begin_frame_spam(mode);
 
   check_host_valid();
-  _active_cube_map_index = -1;
+  _bound_tex_page = -1;
 
   if (!_is_valid) {
     if (GLCAT.is_debug()) {
@@ -1056,7 +1056,7 @@ end_frame(FrameMode mode, Thread *current_thread) {
   CLP(GraphicsStateGuardian) *glgsg;
   DCAST_INTO_V(glgsg, _gsg);
   glgsg->bind_fbo(0);
-  _active_cube_map_index = -1;
+  _bound_tex_page = -1;
 
   if (mode == FM_render) {
     generate_mipmaps();
@@ -1086,108 +1086,95 @@ set_size(int x, int y) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: glGraphicsBuffer::select_cube_map
+//     Function: glGraphicsBuffer::select_target_tex_page
 //       Access: Public, Virtual
 //  Description: Called internally when the window is in
 //               render-to-a-texture mode and we are in the process of
-//               rendering the six layers of a cube map.  This should
-//               do whatever needs to be done to switch the buffer to
-//               the indicated face.
+//               rendering the six faces of a cube map, or any other
+//               multi-page and/or multi-view texture.  This should do
+//               whatever needs to be done to switch the buffer to the
+//               indicated page and view.
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsBuffer)::
-select_cube_map(int cube_map_index) {
-  nassertv(cube_map_index >= 0 && cube_map_index < _fbo.size());
-
-  if (_active_cube_map_index != -1) {
-    // Resolve the multisample rendering for the previous face.
-    if (_requested_multisamples && _fbo_multisample) {
-      resolve_multisamples();
-    }
-  }
+select_target_tex_page(int page, int view) {
+  nassertv(page >= 0 && page < _fbo.size());
 
   CLP(GraphicsStateGuardian) *glgsg;
   DCAST_INTO_V(glgsg, _gsg);
 
-  glgsg->bind_fbo(_fbo[cube_map_index]);
-  _active_cube_map_index = cube_map_index;
+  bool switched_page = (_bound_tex_page != page);
+  bool switched_view = (_bound_tex_view != view);
 
-  report_my_gl_errors();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: glGraphicsBuffer::select_tex_view
-//       Access: Public, Virtual
-//  Description: Called internally when the window is in
-//               render-to-a-texture mode and the DisplayRegion
-//               requests that we switch rendering to a different
-//               texture view.
-//
-//               In the FBO case, we do this by re-binding the
-//               texture that is attached to the color plane.
-////////////////////////////////////////////////////////////////////
-void CLP(GraphicsBuffer)::
-select_tex_view(int view) {
-  CLP(GraphicsStateGuardian) *glgsg;
-  DCAST_INTO_V(glgsg, _gsg);
-
-  if (view == _bound_tex_view) {
-    return;
+  if (switched_page) {
+    if (_bound_tex_page != -1) {
+      // Resolve the multisample rendering for the previous face.
+      if (_requested_multisamples && _fbo_multisample) {
+        resolve_multisamples();
+      }
+    }
+    
+    glgsg->bind_fbo(_fbo[page]);
+    _bound_tex_page = page;
   }
 
-  // We assume that we've already configured the texture earlier
-  // in bind_bitplanes.  Therefore, since we can safely assume that
-  // all texture views have the same format, we can just bind the
-  // new view here.
+  if (switched_view || switched_page) {
+    // We assume that we've already configured the texture earlier
+    // in bind_bitplanes.  Therefore, since we can safely assume that
+    // all texture views have the same format, we can just bind the
+    // new view here.
 
-  Texture *tex = _tex[RTP_color];
-  if (tex != NULL) {
-    if (view >= tex->get_num_views()) {
-      tex->set_num_views(view + 1);
-    }
+    Texture *tex = _tex[RTP_color];
+    if (tex != NULL) {
+      if (view >= tex->get_num_views()) {
+        tex->set_num_views(view + 1);
+      }
 
-    GLenum target = glgsg->get_texture_target(tex->get_texture_type());
-    if (target == GL_TEXTURE_CUBE_MAP) {
-      target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + _active_cube_map_index;
-    }
+      GLenum target = glgsg->get_texture_target(tex->get_texture_type());
+      if (target == GL_TEXTURE_CUBE_MAP) {
+        target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + _bound_tex_page;
+      }
 
-    // Create the OpenGL texture object.
-    TextureContext *tc = tex->prepare_now(view, glgsg->get_prepared_objects(), glgsg);
-    nassertv(tc != (TextureContext *)NULL);
-    CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
-    glgsg->update_texture(tc, true);
+      // Create the OpenGL texture object.
+      TextureContext *tc = tex->prepare_now(view, glgsg->get_prepared_objects(), glgsg);
+      nassertv(tc != (TextureContext *)NULL);
+      CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
+      glgsg->update_texture(tc, true);
 
-    if (GLCAT.is_spam()) {
-      GLCAT.spam()
-        << "Binding texture " << *tex
-        << " view " << view << " to color attachment.\n";
-    }
+      if (GLCAT.is_spam()) {
+        GLCAT.spam()
+          << "Binding texture " << *tex
+          << " view " << view << " to color attachment.\n";
+      }
 
-  #ifndef OPENGLES
-    GLclampf priority = 1.0f;
-    glPrioritizeTextures(1, &gtc->_index, &priority);
-  #endif
-    glgsg->update_texture(tc, true);
+#ifndef OPENGLES
+      GLclampf priority = 1.0f;
+      glPrioritizeTextures(1, &gtc->_index, &priority);
+#endif
+      glgsg->update_texture(tc, true);
 
-    if (_rb_size_z == 1) {
-      if (target == GL_TEXTURE_3D) {
-        glgsg->_glFramebufferTexture3D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
-                                       target, gtc->_index, 0, _active_cube_map_index);
-      } else if (target == GL_TEXTURE_2D_ARRAY_EXT) {
-        glgsg->_glFramebufferTextureLayer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
-                                          gtc->_index, 0, _active_cube_map_index);
+      if (_rb_size_z == 1) {
+        if (target == GL_TEXTURE_3D) {
+          glgsg->_glFramebufferTexture3D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+                                         target, gtc->_index, 0, _bound_tex_page);
+        } else if (target == GL_TEXTURE_2D_ARRAY_EXT) {
+          glgsg->_glFramebufferTextureLayer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+                                            gtc->_index, 0, _bound_tex_page);
+        } else {
+          glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+                                         target, gtc->_index, 0);
+        }
       } else {
-        glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
-                                       target, gtc->_index, 0);
+        glgsg->_glFramebufferTexture(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+                                     gtc->_index, 0);
       }
-    } else {
-      glgsg->_glFramebufferTexture(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
-                                   gtc->_index, 0);
+
+      report_my_gl_errors();
     }
 
-    report_my_gl_errors();
+    _bound_tex_view = view;
   }
 
-  _bound_tex_view = view;
+  report_my_gl_errors();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1531,8 +1518,8 @@ resolve_multisamples() {
 
   glgsg->report_my_gl_errors();
   GLuint fbo = _fbo[0];
-  if (_active_cube_map_index != -1) {
-    fbo = _fbo[_active_cube_map_index];
+  if (_bound_tex_page != -1) {
+    fbo = _fbo[_bound_tex_page];
   }
   glgsg->_glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, fbo);
   glgsg->_glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, _fbo_multisample);

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

@@ -74,8 +74,7 @@ public:
 
   virtual void set_size(int x, int y);
 
-  virtual void select_cube_map(int cube_map_index);
-  virtual void select_tex_view(int tex_view_offset);
+  virtual void select_target_tex_page(int page, int view);
 
   virtual bool share_depth_buffer(GraphicsOutput *graphics_output);
   virtual void unshare_depth_buffer();
@@ -129,7 +128,7 @@ private:
 
   // The cube map face we are currently drawing to or have just
   // finished drawing to, or -1 if we are not drawing to a cube map.
-  int _active_cube_map_index;
+  int _bound_tex_page;
   int _bound_tex_view;
 
   bool _initial_clear;

+ 15 - 4
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -4282,7 +4282,7 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
     }
   }
 
-  int view = dr->get_tex_view_offset();
+  int view = dr->get_target_tex_view();
   TextureContext *tc = tex->prepare_now(view, get_prepared_objects(), this);
   nassertr(tc != (TextureContext *)NULL, false);
   CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
@@ -4463,6 +4463,13 @@ framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr,
                        component_type, format);
   }
 
+  nassertr(z < tex->get_z_size(), false);
+
+  int view = dr->get_target_tex_view();
+  if (view >= tex->get_num_views()) {
+    tex->set_num_views(view + 1);
+  }
+
   GLenum external_format = get_external_image_format(tex);
 
   if (GLCAT.is_spam()) {
@@ -4513,10 +4520,14 @@ framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr,
 
   unsigned char *image_ptr = tex->modify_ram_image();
   size_t image_size = tex->get_ram_image_size();
-  if (z >= 0) {
-    nassertr(z < tex->get_z_size(), false);
+  if (z >= 0 || view > 0) {
     image_size = tex->get_expected_ram_page_size();
-    image_ptr += z * image_size;
+    if (z >= 0) {
+      image_ptr += z * image_size;
+    }
+    if (view > 0) {
+      image_ptr += (view * tex->get_z_size()) * image_size;
+    }
   }
 
   GLP(ReadPixels)(xo, yo, w, h,

+ 15 - 4
panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx

@@ -1359,7 +1359,7 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
 
   tex->setup_2d_texture(w, h, Texture::T_unsigned_byte, Texture::F_rgba);
 
-  int view = dr->get_tex_view_offset();
+  int view = dr->get_target_tex_view();
   TextureContext *tc = tex->prepare_now(view, get_prepared_objects(), this);
   nassertr(tc != (TextureContext *)NULL, false);
   TinyTextureContext *gtc = DCAST(TinyTextureContext, tc);
@@ -1431,12 +1431,23 @@ framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr,
                        component_type, format);
   }
 
+  nassertr(z < tex->get_z_size(), false);
+
+  int view = dr->get_target_tex_view();
+  if (view >= tex->get_num_views()) {
+    tex->set_num_views(view + 1);
+  }
+
   unsigned char *image_ptr = tex->modify_ram_image();
   size_t image_size = tex->get_ram_image_size();
-  if (z >= 0) {
-    nassertr(z < tex->get_z_size(), false);
+  if (z >= 0 || view > 0) {
     image_size = tex->get_expected_ram_page_size();
-    image_ptr += z * image_size;
+    if (z >= 0) {
+      image_ptr += z * image_size;
+    }
+    if (view > 0) {
+      image_ptr += (view * tex->get_z_size()) * image_size;
+    }
   }
 
   PIXEL *ip = (PIXEL *)(image_ptr + image_size);

+ 3 - 3
panda/src/wgldisplay/wglGraphicsBuffer.cxx

@@ -205,7 +205,7 @@ bind_texture_to_pbuffer() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: wglGraphicsBuffer::select_cube_map
+//     Function: wglGraphicsBuffer::select_target_tex_page
 //       Access: Public, Virtual
 //  Description: Called internally when the window is in
 //               render-to-a-texture mode and we are in the process of
@@ -214,7 +214,7 @@ bind_texture_to_pbuffer() {
 //               the indicated face.
 ////////////////////////////////////////////////////////////////////
 void wglGraphicsBuffer::
-select_cube_map(int cube_map_index) {
+select_target_tex_page(int page, int view) {
   wglGraphicsStateGuardian *wglgsg;
   DCAST_INTO_V(wglgsg, _gsg);
 
@@ -225,7 +225,7 @@ select_cube_map(int cube_map_index) {
   int ni = 0;
 
   iattrib_list[ni++] = WGL_CUBE_MAP_FACE_ARB;
-  iattrib_list[ni++] = WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + cube_map_index;
+  iattrib_list[ni++] = WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + page;
 
   // Terminate the list.
   nassertv(ni <= max_attrib_list);

+ 1 - 1
panda/src/wgldisplay/wglGraphicsBuffer.h

@@ -49,7 +49,7 @@ public:
   virtual bool begin_frame(FrameMode mode, Thread *current_thread);
   virtual void end_frame(FrameMode mode, Thread *current_thread);
 
-  virtual void select_cube_map(int cube_map_index);
+  virtual void select_target_tex_page(int page, int view);
 
   virtual void process_events();