Browse Source

*** empty log message ***

Josh Yelon 19 years ago
parent
commit
6d0692fec6
37 changed files with 639 additions and 719 deletions
  1. 14 4
      direct/src/showbase/BufferViewer.py
  2. 4 0
      doc/makepanda/confauto.in
  3. 1 0
      panda/src/display/frameBufferProperties.h
  4. 0 76
      panda/src/display/graphicsEngine.cxx
  5. 0 1
      panda/src/display/graphicsEngine.h
  6. 17 2
      panda/src/display/graphicsOutput.I
  7. 68 68
      panda/src/display/graphicsOutput.cxx
  8. 26 3
      panda/src/display/graphicsOutput.h
  9. 2 2
      panda/src/display/graphicsStateGuardian.h
  10. 9 6
      panda/src/display/renderBuffer.h
  11. 4 14
      panda/src/dxgsg8/wdxGraphicsBuffer8.cxx
  12. 0 1
      panda/src/dxgsg8/wdxGraphicsBuffer8.h
  13. 6 1
      panda/src/dxgsg8/wdxGraphicsWindow8.cxx
  14. 4 14
      panda/src/dxgsg9/wdxGraphicsBuffer9.cxx
  15. 0 2
      panda/src/dxgsg9/wdxGraphicsBuffer9.h
  16. 5 0
      panda/src/dxgsg9/wdxGraphicsWindow9.cxx
  17. 182 133
      panda/src/glstuff/glGraphicsBuffer_src.cxx
  18. 14 26
      panda/src/glstuff/glGraphicsBuffer_src.h
  19. 133 153
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  20. 0 3
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  21. 8 15
      panda/src/glxdisplay/glxGraphicsBuffer.cxx
  22. 0 1
      panda/src/glxdisplay/glxGraphicsBuffer.h
  23. 9 16
      panda/src/glxdisplay/glxGraphicsWindow.cxx
  24. 0 2
      panda/src/glxdisplay/glxGraphicsWindow.h
  25. 1 0
      panda/src/gobj/texture.cxx
  26. 0 97
      panda/src/grutil/cardMaker.I
  27. 97 0
      panda/src/grutil/cardMaker.cxx
  28. 6 5
      panda/src/grutil/cardMaker.h
  29. 1 0
      panda/src/mesadisplay/osMesaGraphicsBuffer.cxx
  30. 6 15
      panda/src/osxdisplay/osxGraphicsBuffer.cxx
  31. 0 2
      panda/src/osxdisplay/osxGraphicsBuffer.h
  32. 8 23
      panda/src/osxdisplay/osxGraphicsWindow.cxx
  33. 0 1
      panda/src/osxdisplay/osxGraphicsWindow.h
  34. 7 15
      panda/src/wgldisplay/wglGraphicsBuffer.cxx
  35. 0 1
      panda/src/wgldisplay/wglGraphicsBuffer.h
  36. 7 16
      panda/src/wgldisplay/wglGraphicsWindow.cxx
  37. 0 1
      panda/src/wgldisplay/wglGraphicsWindow.h

+ 14 - 4
direct/src/showbase/BufferViewer.py

@@ -20,6 +20,8 @@ class BufferViewer(DirectObject):
         self.cullsort = 10000
         self.cards = []
         self.cardindex = 0
+        self.cardmaker = CardMaker("cubemaker")
+        self.cardmaker.setFrame(-1,1,-1,1)
         self.task = 0
         self.window = 0
         self.dirty = 1
@@ -39,7 +41,7 @@ class BufferViewer(DirectObject):
         # started.
         self.enable(self.enabled)
 
-    def isValidTextureSet(self, list):
+    def isValidTextureSet(self, x):
         """Access: private. Returns true if the parameter is a
         list of GraphicsOutput and Texture, or the keyword 'all'."""
         if (isinstance(x, list)):
@@ -270,10 +272,18 @@ class BufferViewer(DirectObject):
             for itex in range(win.countTextures()):
                 tex = win.getTexture(itex)
                 if (include.has_key(tex)) and (exclude.has_key(tex)==0):
-                    card = win.getTextureCard()
-                    card.setTexture(tex)
-                    cards.append(card)
+                    if (tex.getTextureType() == Texture.TTCubeMap):
+                        for face in range(6):
+                            self.cardmaker.setUvRangeCube(face)
+                            card = NodePath(self.cardmaker.generate())
+                            card.setTexture(tex)
+                            cards.append(card)
+                    else:
+                        card = win.getTextureCard()
+                        card.setTexture(tex)
+                        cards.append(card)
                     wins.append(win)
+                    exclude[tex] = 1
         self.cards = cards
         if (len(cards)==0):
             self.task = 0

+ 4 - 0
doc/makepanda/confauto.in

@@ -88,3 +88,7 @@ egg-object-type-direct-widget   <Scalar> collide-mask { 0x80000000 } <Collide> {
 # Define a new cull bin that will render on top of everything else.
 
 cull-bin gui-popup 60 unsorted
+
+# Paranoid clock. This fixes flaky hardware clocks.
+
+paranoid-clock 1

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

@@ -64,6 +64,7 @@ PUBLISHED:
   INLINE bool has_mode(int bit) const;
   INLINE bool is_single_buffered() const;
   INLINE bool is_stereo() const;
+
   bool subsumes(const FrameBufferProperties &prop) const;
   
   INLINE void set_frame_buffer_mode(int frameBuffer_mode);

+ 0 - 76
panda/src/display/graphicsEngine.cxx

@@ -450,7 +450,6 @@ remove_all_windows() {
   
   _windows.clear();
 
-  _app.do_release(this);
   _app.do_close(this);
   terminate_threads();
 }
@@ -922,7 +921,6 @@ cull_and_draw_together(const GraphicsEngine::Windows &wlist) {
   for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
     GraphicsOutput *win = (*wi);
     if (win->is_active() && win->get_gsg()->is_active()) {
-      win->get_gsg()->set_current_properties(&win->get_fb_properties());
       if (win->begin_frame(GraphicsOutput::FM_render)) {
         win->clear();
       
@@ -1088,7 +1086,6 @@ draw_bins(const GraphicsEngine::Windows &wlist) {
   for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
     GraphicsOutput *win = (*wi);
     if (win->is_active() && win->get_gsg()->is_active()) {
-      win->get_gsg()->set_current_properties(&win->get_fb_properties());
       if (win->begin_frame(GraphicsOutput::FM_render)) {
         win->clear();
       
@@ -1149,7 +1146,6 @@ make_contexts(const GraphicsEngine::Windows &wlist) {
   Windows::const_iterator wi;
   for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
     GraphicsOutput *win = (*wi);
-    win->get_gsg()->set_current_properties(&win->get_fb_properties());
     if (win->begin_frame(GraphicsOutput::FM_refresh)) {
       win->end_frame(GraphicsOutput::FM_refresh);
     }
@@ -1599,27 +1595,6 @@ terminate_threads() {
     thread->_cv_mutex.lock();
   }
   
-  // Now tell them to release their windows' graphics contexts.
-  for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
-    RenderThread *thread = (*ti).second;
-    
-    while (thread->_thread_state != TS_wait) {
-      thread->_cv_done.wait();
-    }
-    thread->_thread_state = TS_do_release;
-    thread->_cv_start.signal();
-    thread->_cv_mutex.release();
-  }
-  
-  // Grab the mutex again to wait for the above to complete.
-  for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
-    RenderThread *thread = (*ti).second;
-    thread->_cv_mutex.lock();
-    while (thread->_thread_state != TS_wait) {
-      thread->_cv_done.wait();
-    }
-  }
-
   // Now tell them to close their windows and terminate.
   for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
     RenderThread *thread = (*ti).second;
@@ -1776,30 +1751,6 @@ remove_window(GraphicsOutput *window) {
 
   Windows::iterator wi;
 
-  wi = _cdraw.find(ptwin);
-  if (wi != _cdraw.end()) {
-    // The window is on our _cdraw list, meaning its GSG operations are
-    // serviced by this thread (cull and draw in the same operation).
-    
-    // Move it to the pending release thread so we can release the GSG
-    // when the thread next runs.  We can't do this immediately,
-    // because we might not have been called from the subthread.
-    _pending_release.push_back(ptwin);
-    _cdraw.erase(wi);
-  }
-
-  wi = _draw.find(ptwin);
-  if (wi != _draw.end()) {
-    // The window is on our _draw list, meaning its GSG operations are
-    // serviced by this thread (draw performed on this thread).
-    
-    // Move it to the pending release thread so we can release the GSG
-    // when the thread next runs.  We can't do this immediately,
-    // because we might not have been called from the subthread.
-    _pending_release.push_back(ptwin);
-    _draw.erase(wi);
-  }
-
   wi = _window.find(ptwin);
   if (wi != _window.end()) {
     // The window is on our _window list, meaning its open/close
@@ -1924,22 +1875,6 @@ do_flip(GraphicsEngine *engine) {
   engine->flip_windows(_draw);
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsEngine::WindowRenderer::do_release
-//       Access: Public
-//  Description: Releases the rendering contexts for all windows on
-//               the _draw list.
-////////////////////////////////////////////////////////////////////
-void GraphicsEngine::WindowRenderer::
-do_release(GraphicsEngine *) {
-  MutexHolder holder(_wl_lock);
-  Windows::iterator wi;
-  for (wi = _draw.begin(); wi != _draw.end(); ++wi) {
-    GraphicsOutput *win = (*wi);
-    win->release_gsg();
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsEngine::WindowRenderer::do_close
 //       Access: Public
@@ -1982,16 +1917,6 @@ void GraphicsEngine::WindowRenderer::
 do_pending(GraphicsEngine *engine) {
   MutexHolder holder(_wl_lock);
 
-  if (!_pending_release.empty()) {
-    // Release any GSG's that were waiting.
-    Windows::iterator wi;
-    for (wi = _pending_release.begin(); wi != _pending_release.end(); ++wi) {
-      GraphicsOutput *win = (*wi);
-      win->release_gsg();
-    }
-    _pending_release.clear();
-  }
-
   if (!_pending_close.empty()) {
     // Close any windows that were pending closure, but only if their
     // associated GSG has already been released.
@@ -2128,7 +2053,6 @@ thread_main() {
 
     case TS_do_release:
       do_pending(_engine);
-      do_release(_engine);
       break;
 
     case TS_do_windows:

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

@@ -294,7 +294,6 @@ private:
     Windows _window;  // window stage, i.e. process windowing events 
 
     // These are not kept sorted.
-    Windows _pending_release;  // moved from _draw, pending release_gsg.
     Windows _pending_close;    // moved from _window, pending close.
 
     GSGs _gsgs;       // draw stage

+ 17 - 2
panda/src/display/graphicsOutput.I

@@ -106,12 +106,27 @@ get_texture(int i) const {
   return _textures[i]._texture;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::get_texture_plane
+//       Access: Published
+//  Description: Returns the RenderTexturePlane associated with the
+//               nth render-texture.  Returns 0 if there is no such
+//               texture.
+////////////////////////////////////////////////////////////////////
+INLINE GraphicsOutput::RenderTexturePlane GraphicsOutput::
+get_texture_plane(int i) const {
+  if ((i < 0) || (i >= ((int)_textures.size()))) {
+    return (RenderTexturePlane)0;
+  }
+  return _textures[i]._plane;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsOutput::get_rtm_mode
 //       Access: Published
 //  Description: Returns the RenderTextureMode associated with the
-//               nth texture.  Returns RTM_none if there is no such
-//               texture.
+//               nth render-texture.  Returns RTM_none if there is
+//               no such texture.
 ////////////////////////////////////////////////////////////////////
 INLINE GraphicsOutput::RenderTextureMode GraphicsOutput::
 get_rtm_mode(int i) const {

+ 68 - 68
panda/src/display/graphicsOutput.cxx

@@ -218,23 +218,49 @@ clear_render_textures() {
 //
 //               If tex is not NULL, it is the texture that will be
 //               set up for rendering into; otherwise, a new Texture
-//               object will be created (in which case you may call
-//               get_texture() to retrieve the new texture pointer
-//               later).
+//               object will be created, in which case you may call
+//               get_texture() to retrieve the new texture pointer.
 //
+//               You can specify a bitplane to attach the texture to.
+//               the legal choices are:
+//
+//               * RTP_depth
+//               * RTP_stencil
+//               * RTP_color
+//               * RTP_aux_rgba_0
+//               * RTP_aux_rgba_1
+//               * RTP_aux_rgba_2
+//               * RTP_aux_rgba_3
+//
+//               If you do not specify a bitplane to attach the 
+//               texture to, this routine will use a default based
+//               on the texture's format:
+//
+//               * F_depth_component attaches to RTP_depth
+//               * F_stencil_index attaches to RTP_stencil
+//               * all other formats attach to RTP_color.
+//
+//               The texture's format will be changed to match
+//               the format of the bitplane to which it is attached.
+//               For example, if you pass in an F_rgba texture and
+//               order that it be attached to RTP_depth, it will turn
+//               into an F_depth_component texture.
+//               
 //               Also see make_texture_buffer(), which is a
 //               higher-level interface for preparing
 //               render-to-a-texture mode.
 ////////////////////////////////////////////////////////////////////
 void GraphicsOutput::
-add_render_texture(Texture *tex, RenderTextureMode mode) {
+add_render_texture(Texture *tex, RenderTextureMode mode,
+                   RenderTexturePlane plane) {
   if (mode == RTM_none) {
     return;
   }
   MutexHolder holder(_lock);
 
   throw_event("render-texture-targets-changed");
-
+  
+  // Create texture if necessary.
   if (tex == (Texture *)NULL) {
     tex = new Texture(get_name());
     tex->set_wrap_u(Texture::WM_clamp);
@@ -242,13 +268,45 @@ add_render_texture(Texture *tex, RenderTextureMode mode) {
   } else {
     tex->clear_ram_image();
   }
-  tex->set_match_framebuffer_format(true);
+
+  // Choose a default bitplane.
+  if (plane == RTP_COUNT) {
+    if (tex->get_format()==Texture::F_depth_component) {
+      plane = RTP_depth;
+    } else if (tex->get_format()==Texture::F_stencil_index) {
+      plane = RTP_stencil;
+    } else {
+      plane = RTP_color;
+    }
+  }
+  
+  // Set the texture's format to match the bitplane.
+  // (And validate the bitplane, while we're at it).
+
+  if (plane == RTP_depth) {
+    tex->set_format(Texture::F_depth_component);
+    tex->set_match_framebuffer_format(true);
+  } else if (plane == RTP_stencil) {
+    tex->set_format(Texture::F_stencil_index);
+    tex->set_match_framebuffer_format(true);
+  } else if ((plane == RTP_color)||
+             (plane == RTP_aux_rgba_0)||
+             (plane == RTP_aux_rgba_1)||
+             (plane == RTP_aux_rgba_2)||
+             (plane == RTP_aux_rgba_3)) {
+    tex->set_format(Texture::F_rgba);
+    tex->set_match_framebuffer_format(true);
+  } else {
+    display_cat.error() <<
+      "add_render_texture: invalid bitplane specified.\n";
+    return;
+  }
 
   // Go ahead and tell the texture our anticipated size, even if it
   // might be inaccurate (particularly if this is a GraphicsWindow,
   // which has system-imposed restrictions on size).
-  tex->set_x_size(get_x_size());
-  tex->set_y_size(get_y_size());
+  tex->set_x_size(Texture::up_to_power_2(get_x_size()));
+  tex->set_y_size(Texture::up_to_power_2(get_y_size()));
 
   if ((mode == RTM_bind_or_copy)&&(support_render_texture==0)) {
     mode = RTM_copy_texture;
@@ -259,36 +317,15 @@ add_render_texture(Texture *tex, RenderTextureMode mode) {
     }
   }
 
+
   RenderTexture result;
   result._texture = tex;
+  result._plane = plane;
   result._rtm_mode = mode;
   _textures.push_back(result);
 
   nassertv(_gsg != (GraphicsStateGuardian *)NULL);
   set_inverted(_gsg->get_copy_texture_inverted());
-
-  // Sanity check that we don't have two textures of the same type.
-  int count_stencil_textures = 0;
-  int count_depth_textures = 0;
-  int count_color_textures = 0;
-  for (int i=0; i<count_textures(); i++) {
-    Texture::Format fmt = get_texture(i)->get_format();
-    if (fmt == Texture::F_depth_component) {
-      count_depth_textures += 1;
-    } else if (fmt == Texture::F_stencil_index) {
-      count_stencil_textures += 1;
-    } else {
-      count_color_textures += 1;
-    }
-  }
-  if ((count_color_textures > 1)||
-      (count_depth_textures > 1)||
-      (count_stencil_textures > 1)) {
-    display_cat.error() <<
-      "Currently, each GraphicsOutput can only render to one color texture, "
-      "one depth texture, and one stencil texture at a time.  RTM aborted.\n";
-    clear_render_textures();
-  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -778,21 +815,6 @@ make_cube_map(const string &name, int size, NodePath &camera_rig,
   tex->set_wrap_v(Texture::WM_clamp);
   GraphicsOutput *buffer;
 
-  // I'll remove this permanently in a few days.
-  //  if (show_buffers) {
-  //    // If show_buffers is true, we'd like to create a window with the
-  //    // six buffers spread out and all visible at once, for the user's
-  //    // convenience.
-  //    buffer = make_texture_buffer(name, size * 3, size * 2, tex, to_ram);
-  //    tex->set_x_size(size);
-  //    tex->set_y_size(size);
-  //
-  //  } else {
-  //    // In the normal case, the six buffers are stacked on top of each
-  //    // other like pancakes.
-  //    buffer = make_texture_buffer(name, size, size, tex, to_ram);
-  //  }
-
   buffer = make_texture_buffer(name, size, size, tex, to_ram);
 
   // We don't need to clear the overall buffer; instead, we'll clear
@@ -811,13 +833,6 @@ make_cube_map(const string &name, int size, NodePath &camera_rig,
     camera_np.look_at(cube_faces[i]._look_at, cube_faces[i]._up);
 
     DisplayRegion *dr;
-    // I'll remove this permanently in a few days. - Josh
-    //    if (show_buffers) {
-    //      const ShowBuffersCubeMapRegions &r = cube_map_regions[i];
-    //      dr = buffer->make_display_region(r.l, r.r, r.b, r.t);
-    //    } else {
-    //      dr = buffer->make_display_region();
-    //    }
     dr = buffer->make_display_region();
 
     dr->set_cube_map_index(i);
@@ -1093,21 +1108,6 @@ void GraphicsOutput::
 select_cube_map(int) {
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsOutput::release_gsg
-//       Access: Public
-//  Description: Releases the current GSG pointer, if it is currently
-//               held, and resets the GSG to NULL.  The window will be
-//               permanently unable to render; this is normally called
-//               only just before destroying the window.  This should
-//               only be called from within the draw thread.
-////////////////////////////////////////////////////////////////////
-void GraphicsOutput::
-release_gsg() {
-  _gsg.clear();
-  _active = false;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsOutput::begin_flip
 //       Access: Public, Virtual

+ 26 - 3
panda/src/display/graphicsOutput.h

@@ -82,6 +82,28 @@ PUBLISHED:
     RTM_triggered_copy_ram,
   };
 
+  // It seems awkward to have this type, and also
+  // RenderBuffer::Type.  However, the fact that RenderBuffer::Type
+  // is a bitmask makes it awfully awkward to work with.
+  enum RenderTexturePlane {
+    RTP_color,
+    RTP_depth,
+    RTP_stencil,
+    RTP_aux_rgba_0,
+    RTP_aux_rgba_1,
+    RTP_aux_rgba_2,
+    RTP_aux_rgba_3,
+    RTP_aux_hrgba_0,
+    RTP_aux_hrgba_1,
+    RTP_aux_hrgba_2,
+    RTP_aux_hrgba_3,
+    RTP_aux_float_0,
+    RTP_aux_float_1,
+    RTP_aux_float_2,
+    RTP_aux_float_3,
+    RTP_COUNT
+  };
+
   // There are many reasons to call begin_frame/end_frame.
   enum FrameMode {
     FM_render,   // We are rendering a frame.
@@ -98,9 +120,11 @@ PUBLISHED:
   INLINE int count_textures() const;
   INLINE bool has_texture() const;
   INLINE Texture *get_texture(int i=0) const;
+  INLINE RenderTexturePlane get_texture_plane(int i=0) const;
   INLINE RenderTextureMode get_rtm_mode(int i=0) const;
   void clear_render_textures();
-  void add_render_texture(Texture *tex, RenderTextureMode mode);
+  void add_render_texture(Texture *tex, RenderTextureMode mode, 
+                          RenderTexturePlane bitplane=RTP_COUNT);
   void setup_render_texture(Texture *tex, bool allow_bind, bool to_ram);
 
   INLINE int get_x_size() const;
@@ -200,8 +224,6 @@ public:
   void change_scenes(DisplayRegion *new_dr);
   virtual void select_cube_map(int cube_map_index);
 
-  virtual void release_gsg();
-  
   // These methods will be called within the app (main) thread.
   virtual void begin_flip();
   virtual void end_flip();
@@ -226,6 +248,7 @@ protected:
   class RenderTexture {
   public:
     PT(Texture) _texture;
+    RenderTexturePlane _plane;
     RenderTextureMode _rtm_mode;
   };
   PT(GraphicsStateGuardian) _gsg;

+ 2 - 2
panda/src/display/graphicsStateGuardian.h

@@ -185,6 +185,8 @@ public:
   virtual void end_scene();
   virtual void end_frame();
 
+  void set_current_properties(FrameBufferProperties *properties);
+  
   virtual bool depth_offset_decals();
   virtual CPT(RenderState) begin_decal_base_first();
   virtual CPT(RenderState) begin_decal_nested();
@@ -244,8 +246,6 @@ protected:
   virtual void bind_clip_plane(const NodePath &plane, int plane_id);
   virtual void end_bind_clip_planes();
 
-  void set_current_properties(FrameBufferProperties *properties);
-  
   virtual void free_pointers();
   virtual void close_gsg();
   void panic_deactivate();

+ 9 - 6
panda/src/display/renderBuffer.h

@@ -38,16 +38,19 @@ public:
     T_aux_rgba_1       = 0x00000002,
     T_aux_rgba_2       = 0x00000004,
     T_aux_rgba_3       = 0x00000008,
+    T_aux_rgba_ALL     = 0x0000000F,
 
-    T_aux_hrgba_0      = 0x00000010,
-    T_aux_hrgba_1      = 0x00000020,
-    T_aux_hrgba_2      = 0x00000040,
+    T_aux_hrgba_0      = 0x00000010, // These can't really be implemented until 
+    T_aux_hrgba_1      = 0x00000020, // we have support for hrgba textures.
+    T_aux_hrgba_2      = 0x00000040, // I've just added the bits for the future.
     T_aux_hrgba_3      = 0x00000080,
+    T_aux_hrgba_ALL    = 0x000000F0,
 
-    T_aux_float_0      = 0x00000100,
-    T_aux_float_1      = 0x00000200,
-    T_aux_float_2      = 0x00000400,
+    T_aux_float_0      = 0x00000100, // These can't really be implemented until 
+    T_aux_float_1      = 0x00000200, // we have support for float textures.
+    T_aux_float_2      = 0x00000400, // I've just added the bits for the future.
     T_aux_float_3      = 0x00000800,
+    T_aux_float_ALL    = 0x00000F00,
 
     T_aux_undef_0      = 0x00001000,
     T_aux_undef_1      = 0x00002000,

+ 4 - 14
panda/src/dxgsg8/wdxGraphicsBuffer8.cxx

@@ -95,6 +95,7 @@ begin_frame(FrameMode mode) {
     clear_cube_map_selection();
   }
   
+  _gsg->set_current_properties(&get_fb_properties());
   return _gsg->begin_frame();
 }
 
@@ -328,20 +329,6 @@ select_cube_map(int cube_map_index) {
   }
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: wdxGraphicsBuffer8::release_gsg
-//       Access: Public, Virtual
-//  Description: Releases the current GSG pointer, if it is currently
-//               held, and resets the GSG to NULL.  The window will be
-//               permanently unable to render; this is normally called
-//               only just before destroying the window.  This should
-//               only be called from within the draw thread.
-////////////////////////////////////////////////////////////////////
-void wdxGraphicsBuffer8::
-release_gsg() {
-  GraphicsBuffer::release_gsg();
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: wdxGraphicsBuffer8::process_events
 //       Access: Public, Virtual
@@ -398,6 +385,9 @@ close_buffer() {
       this -> _new_z_stencil_surface -> Release ( );
       this -> _new_z_stencil_surface = NULL;
     }
+    
+    _gsg.clear();
+    _active = false;
   }
 
   _cube_map_index = -1;

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

@@ -48,7 +48,6 @@ public:
   virtual void end_frame(FrameMode mode);
   
   virtual void select_cube_map(int cube_map_index);
-  virtual void release_gsg();
 
   virtual void process_events();
 

+ 6 - 1
panda/src/dxgsg8/wdxGraphicsWindow8.cxx

@@ -98,7 +98,8 @@ begin_frame(FrameMode mode) {
   if (mode == FM_render) {
     clear_cube_map_selection();
   }
-  
+
+  _gsg->set_current_properties(&get_fb_properties());
   bool return_val = _gsg->begin_frame();
   _dxgsg->set_render_target();
   return return_val;
@@ -251,6 +252,10 @@ verify_window_sizes(int numsizes, int *dimen) {
 void wdxGraphicsWindow8::
 close_window() {
   wdxdisplay8_cat.debug() << "wdx closed window\n";
+  if (_gsg != (GraphicsStateGuardian*)NULL) {
+    _gsg.clear();
+    _active = false;
+  }
   _dxgsg->release_swap_chain(&_wcontext);
   WinGraphicsWindow::close_window();
 }

+ 4 - 14
panda/src/dxgsg9/wdxGraphicsBuffer9.cxx

@@ -93,6 +93,7 @@ begin_frame(FrameMode mode) {
     clear_cube_map_selection();
   }
   
+  _gsg->set_current_properties(&get_fb_properties());
   return _gsg->begin_frame();
 }
 
@@ -364,20 +365,6 @@ select_cube_map(int cube_map_index) {
   }
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: wdxGraphicsBuffer9::release_gsg
-//       Access: Public, Virtual
-//  Description: Releases the current GSG pointer, if it is currently
-//               held, and resets the GSG to NULL.  The window will be
-//               permanently unable to render; this is normally called
-//               only just before destroying the window.  This should
-//               only be called from within the draw thread.
-////////////////////////////////////////////////////////////////////
-void wdxGraphicsBuffer9::
-release_gsg() {
-  GraphicsBuffer::release_gsg();
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: wdxGraphicsBuffer9::process_events
 //       Access: Public, Virtual
@@ -434,6 +421,9 @@ close_buffer() {
       this -> _new_z_stencil_surface -> Release ( );
       this -> _new_z_stencil_surface = NULL;
     }
+    
+    _gsg.clear();
+    _active = false;
   }
 
   _cube_map_index = -1;

+ 0 - 2
panda/src/dxgsg9/wdxGraphicsBuffer9.h

@@ -48,8 +48,6 @@ public:
   virtual void end_frame(FrameMode mode);
 
   virtual void select_cube_map(int cube_map_index);
-  virtual void release_gsg();
-
   virtual void process_events();
 
 protected:

+ 5 - 0
panda/src/dxgsg9/wdxGraphicsWindow9.cxx

@@ -119,6 +119,7 @@ begin_frame(FrameMode mode) {
     clear_cube_map_selection();
   }
   
+  _gsg->set_current_properties(&get_fb_properties());
   bool return_val = _gsg->begin_frame();
   _dxgsg->set_render_target();
   return return_val;
@@ -252,6 +253,10 @@ verify_window_sizes(int numsizes, int *dimen) {
 void wdxGraphicsWindow9::
 close_window() {
   wdxdisplay9_cat.debug() << "wdx closed window\n";
+  if (_gsg != (GraphicsStateGuardian *)NULL) {
+    _gsg.clear();
+    _active = false;
+  }
   _dxgsg->release_swap_chain(&_wcontext);
   WinGraphicsWindow::close_window();
 }

+ 182 - 133
panda/src/glstuff/glGraphicsBuffer_src.cxx

@@ -40,17 +40,10 @@ CLP(GraphicsBuffer)(GraphicsPipe *pipe,
   _fbo = 0;
   _rb_size_x = 0;
   _rb_size_y = 0;
-  for (int i=0; i<SLOT_COUNT; i++) {
+  for (int i=0; i<RTP_COUNT; i++) {
     _rb[i] = 0;
     _tex[i] = 0;
   }
-  _attach_point[SLOT_depth]   = GL_DEPTH_ATTACHMENT_EXT;
-  _attach_point[SLOT_stencil] = GL_STENCIL_ATTACHMENT_EXT;
-  _attach_point[SLOT_color]   = GL_COLOR_ATTACHMENT0_EXT;
-
-  _slot_format[SLOT_depth]   = GL_DEPTH_COMPONENT;
-  _slot_format[SLOT_stencil] = GL_STENCIL_INDEX;
-  _slot_format[SLOT_color]   = GL_RGBA;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -77,9 +70,6 @@ begin_frame(FrameMode mode) {
     return false;
   }
 
-  CLP(GraphicsStateGuardian) *glgsg;
-  DCAST_INTO_R(glgsg, _gsg, false);
-
   if (!_host->begin_frame(FM_parasite)) {
     return false;
   }
@@ -88,33 +78,52 @@ begin_frame(FrameMode mode) {
   if (mode == FM_render) {
     rebuild_bitplanes();
     clear_cube_map_selection();
-
-    // Verify that the frame buffer is ready for rendering.
-    GLenum status = glgsg->_glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
-    if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
-      GLCAT.error() << "EXT_framebuffer_object reports non-framebuffer-completeness.\n";
-      switch(status) {
-      case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
-        GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT\n"; break;
-      case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
-        GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT\n"; break;
-      case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
-        GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT\n"; break;
-      case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
-        GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_FORMATS_EXT\n"; break;
-      case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
-        GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT\n"; break;
-      case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
-        GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT\n"; break;
-      case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
-        GLCAT.error() << "FRAMEBUFFER_UNSUPPORTED_EXT\n"; break;
-      default:
-        GLCAT.error() << "OTHER PROBLEM\n"; break;
-      }
-      glgsg->bind_fbo(0);
+    if (!check_fbo()) {
       return false;
     }
   }
+
+  _gsg->set_current_properties(&get_fb_properties());
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: glGraphicsBuffer::check_fbo
+//       Access: Private
+//  Description: Calls 'glCheckFramebufferStatus'.  On error, 
+//               prints out an appropriate error message and unbinds
+//               the fbo.  Returns true for OK or false for error.
+////////////////////////////////////////////////////////////////////
+bool CLP(GraphicsBuffer)::
+check_fbo() {
+  CLP(GraphicsStateGuardian) *glgsg;
+  DCAST_INTO_R(glgsg, _gsg, false);
+
+  GLenum status = glgsg->_glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
+  if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+    GLCAT.error() << "EXT_framebuffer_object reports non-framebuffer-completeness.\n";
+    switch(status) {
+    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
+      GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT\n"; break;
+    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
+      GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT\n"; break;
+    case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
+      GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT\n"; break;
+    case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
+      GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_FORMATS_EXT\n"; break;
+    case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
+      GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT\n"; break;
+    case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
+      GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT\n"; break;
+    case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
+      GLCAT.error() << "FRAMEBUFFER_UNSUPPORTED_EXT\n"; break;
+    default:
+      GLCAT.error() << "OTHER PROBLEM\n"; break;
+    }
+    
+    glgsg->bind_fbo(0);
+    return false;
+  }
   return true;
 }
 
@@ -151,26 +160,45 @@ rebuild_bitplanes() {
                           _host->get_y_size());
     }
   }
-  int desired_x = _x_size;
-  int desired_y = _y_size;
+  int bitplane_x = _x_size;
+  int bitplane_y = _y_size;
   if (!glgsg->get_supports_tex_non_pow2()) {
-    desired_x = Texture::up_to_power_2(desired_x);
-    desired_y = Texture::up_to_power_2(desired_y);
+    bitplane_x = Texture::up_to_power_2(bitplane_x);
+    bitplane_y = Texture::up_to_power_2(bitplane_y);
+  }
+  bool rb_resize = false;
+  if ((bitplane_x != _rb_size_x)||
+      (bitplane_y != _rb_size_y)) {
+    _rb_size_x = bitplane_x;
+    _rb_size_y = bitplane_y;
+    rb_resize = true;
   }
 
-  // Scan the textures list and determine what should be attached.
+  // These variables indicate what should be bound to each bitplane.
   
-  Texture *attach[SLOT_COUNT];
-  for (int i=0; i<SLOT_COUNT; i++) {
-    attach[i] = 0;
+  Texture *attach[RTP_COUNT];
+  attach[RTP_color] = 0;
+  attach[RTP_depth] = 0;
+  attach[RTP_stencil] = 0;
+  for (int i=0; i<_fb_properties.get_aux_rgba(); i++) {
+    attach[RTP_aux_rgba_0+i] = 0;
+  }
+  for (int i=0; i<_fb_properties.get_aux_hrgba(); i++) {
+    attach[RTP_aux_hrgba_0+i] = 0;
   }
+  for (int i=0; i<_fb_properties.get_aux_float(); i++) {
+    attach[RTP_aux_float_0+i] = 0;
+  }
+  
+  // Sort the textures list into appropriate slots.
+  
   for (int i=0; i<count_textures(); i++) {
     if (get_rtm_mode(i) != RTM_bind_or_copy) {
       continue;
     }
     Texture *tex = get_texture(i);
-    Texture::Format fmt = tex->get_format();
-
+    RenderTexturePlane plane = get_texture_plane(i);
+    
     // If it's a not a 2D texture or a cube map, punt it.
     if ((tex->get_texture_type() != Texture::TT_2d_texture)&&
         (tex->get_texture_type() != Texture::TT_cube_map)) {
@@ -178,106 +206,123 @@ rebuild_bitplanes() {
       continue;
     }
     
-    // Identify right attachment point.
-    
-    int slot = SLOT_COUNT;
-    if (fmt == Texture::F_depth_component) {
-      slot = SLOT_depth;
-    } else if (fmt == Texture::F_stencil_index) {
-      slot = SLOT_stencil;
-    } else if ((fmt == Texture::F_rgba)||(fmt == Texture::F_rgb)) {
-      slot = SLOT_color;
-    } else {
-      _textures[i]._rtm_mode = RTM_copy_texture;
-      continue;
-    }
-    
-    // If there's already a texture bound to this slot,
-    // then punt this texture.  
-    if (attach[slot]) {
+    // If I can't find an appropriate slot, or if there's
+    // already a texture bound to this slot, then punt
+    // this texture.  
+
+    if (attach[plane]) {
       _textures[i]._rtm_mode = RTM_copy_texture;
       continue;
     }
     
     // Assign the texture to this slot.
-    attach[slot] = tex;
+    attach[plane] = tex;
   }
 
 
   // For all slots, update the slot.
-    
-  for (int slot=0; slot<SLOT_COUNT; slot++) {
-    if (slot == SLOT_stencil) continue;
-    Texture *tex = attach[slot];
-    if (tex) {
-      // If the texture is already bound to the slot, and it's
-      // the right size, then no update of this slot is needed.
-      if ((_tex[slot] == tex)&&
-          (tex->get_x_size() == desired_x)&&
-          (tex->get_y_size() == desired_y)) {
-        continue;
-      }
-      
-      // Bind the texture to the slot.
-      tex->set_x_size(desired_x);
-      tex->set_y_size(desired_y);
-      TextureContext *tc = tex->prepare_now(glgsg->get_prepared_objects(), glgsg);
-      nassertv(tc != (TextureContext *)NULL);
-      CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
-      
-      if (tex->get_texture_type() == Texture::TT_2d_texture) {
-        glgsg->upload_blank_image(tex, gtc);
-        glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, _attach_point[slot],
-                                       GL_TEXTURE_2D, gtc->_index, 0);
-      } else {
-        glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, _attach_point[slot],
-                                       GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, gtc->_index, 0);
-      }
-      _tex[slot] = tex;
-      
-      // If there was a renderbuffer bound to this slot, delete it.
-      if (_rb[slot] != 0) {
-        glgsg->_glDeleteRenderbuffers(1, &(_rb[slot]));
-        _rb[slot] = 0;
-      }
-      
-    } else {
-      
-      // If a renderbuffer is already attached to the slot, and it's
-      // the right size, then no update of this slot is needed.
-      if ((_rb[slot] != 0)&&
-          (_rb_size_x == desired_x)&&
-          (_rb_size_y == desired_y)) {
-        continue;
-      }
-      
-      // If there's no renderbuffer for this slot, create one.
-      if (_rb[slot] == 0) {
-        glgsg->_glGenRenderbuffers(1, &(_rb[slot]));
-      }
-      
-      // Resize the renderbuffer appropriately.
-      glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, _rb[slot]);
-      glgsg->_glRenderbufferStorage(GL_RENDERBUFFER_EXT, _slot_format[slot],
-                                    desired_x, desired_y);
-      glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
-      
-      // Bind the renderbuffer to the slot.
-      glgsg->_glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, _attach_point[slot],
-                                        GL_RENDERBUFFER_EXT, _rb[slot]);
-      
-      // Toss any texture that was connected to the slot.
-      _tex[slot] = 0;
-    }
-  }
   
-  // These record the size of all nonzero renderbuffers.
-  _rb_size_x = desired_x;
-  _rb_size_y = desired_y;
+  bind_slot(rb_resize, attach, RTP_depth,   
+            GL_DEPTH_ATTACHMENT_EXT,    GL_DEPTH_COMPONENT,  Texture::F_depth_component);
+  //bind_slot(rb_resize, attach, RTP_stencil,
+  //          GL_STENCIL_ATTACHMENT_EXT,  GL_STENCIL_INDEX,    Texture::F_stencil_index);
+  bind_slot(rb_resize, attach, RTP_color, 
+            GL_COLOR_ATTACHMENT0_EXT,   GL_RGBA,             Texture::F_rgba);
+  int next = GL_COLOR_ATTACHMENT1_EXT;
+  for (int i=0; i<_fb_properties.get_aux_rgba(); i++) {
+    bind_slot(rb_resize, attach, (RenderTexturePlane)(RTP_aux_rgba_0+i),
+              next, GL_RGBA, Texture::F_rgba);
+    next += 1;
+  }
+  for (int i=0; i<_fb_properties.get_aux_hrgba(); i++) {
+    bind_slot(rb_resize, attach, (RenderTexturePlane)(RTP_aux_hrgba_0+i),
+              next, GL_RGBA, Texture::F_rgba);
+    next += 1;
+  }
+  for (int i=0; i<_fb_properties.get_aux_float(); i++) {
+    bind_slot(rb_resize, attach, (RenderTexturePlane)(RTP_aux_float_0+i),
+              next, GL_RGBA, Texture::F_rgba);
+    next += 1;
+  }
   
   glgsg->report_my_gl_errors();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: glGraphicsBuffer::bind_slot
+//       Access: Private
+//  Description: Attaches either a texture or a renderbuffer to the
+//               specified bitplane.
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsBuffer)::
+bind_slot(bool rb_resize, Texture **attach, RenderTexturePlane slot,
+          GLenum attachpoint, GLenum texformat, Texture::Format fmt) {
+  
+  CLP(GraphicsStateGuardian) *glgsg;
+  DCAST_INTO_V(glgsg, _gsg);
+
+  Texture *tex = attach[slot];
+  if (tex) {
+    // If the texture is already bound to the slot, and it's
+    // the right size, then no update of this slot is needed.
+    if ((_tex[slot] == tex)&&
+        (tex->get_x_size() == _rb_size_x)&&
+        (tex->get_y_size() == _rb_size_y)) {
+      return;
+    }
+    
+    // Bind the texture to the slot.
+    tex->set_x_size(_rb_size_x);
+    tex->set_y_size(_rb_size_y);
+    tex->set_format(fmt);
+    TextureContext *tc = tex->prepare_now(glgsg->get_prepared_objects(), glgsg);
+    nassertv(tc != (TextureContext *)NULL);
+    CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
+    glgsg->apply_texture(tc);
+    
+    if (tex->get_texture_type() == Texture::TT_2d_texture) {
+      glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, attachpoint,
+                                     GL_TEXTURE_2D, gtc->_index, 0);
+    } else {
+      glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, attachpoint,
+                                     GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, gtc->_index, 0);
+    }
+    _tex[slot] = tex;
+    
+    // If there was a renderbuffer bound to this slot, delete it.
+    if (_rb[slot] != 0) {
+      glgsg->_glDeleteRenderbuffers(1, &(_rb[slot]));
+      _rb[slot] = 0;
+    }
+    
+  } else {
+    
+    // If a renderbuffer is already attached to the slot, and it's
+    // the right size, then no update of this slot is needed.
+    if ((_rb[slot] != 0)&&(!rb_resize)) {
+      return;
+    }
+    
+    // If there's no renderbuffer for this slot, create one.
+    if (_rb[slot] == 0) {
+      glgsg->_glGenRenderbuffers(1, &(_rb[slot]));
+    }
+    
+    // Resize the renderbuffer appropriately.
+    glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, _rb[slot]);
+    glgsg->_glRenderbufferStorage(GL_RENDERBUFFER_EXT, texformat,
+                                  _rb_size_x, _rb_size_y);
+    glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
+    
+    // Bind the renderbuffer to the slot.
+    glgsg->_glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, attachpoint,
+                                      GL_RENDERBUFFER_EXT, _rb[slot]);
+    
+    // Toss any texture that was connected to the slot.
+    _tex[slot] = 0;
+  }
+}
+  
 ////////////////////////////////////////////////////////////////////
 //     Function: glGraphicsBuffer::generate_mipmaps
 //       Access: Private
@@ -292,7 +337,7 @@ generate_mipmaps() {
   CLP(GraphicsStateGuardian) *glgsg;
   DCAST_INTO_V(glgsg, _gsg);
 
-  for (int slot=0; slot<SLOT_COUNT; slot++) {
+  for (int slot=0; slot<RTP_COUNT; slot++) {
     Texture *tex = _tex[slot];
     if ((tex != 0) && (tex->uses_mipmaps())) {
       glgsg->_state._texture = 0;
@@ -395,7 +440,7 @@ close_buffer() {
   DCAST_INTO_V(glgsg, _gsg);
   
   // Delete the renderbuffers.
-  for (int i=0; i<SLOT_COUNT; i++) {
+  for (int i=0; i<RTP_COUNT; i++) {
     if (_rb[i] != 0) {
       glgsg->_glDeleteRenderbuffers(1, &(_rb[i]));
       _rb[i] = 0;
@@ -408,5 +453,9 @@ close_buffer() {
   // Delete the FBO itself.
   nassertv(_fbo != 0);
   glgsg->_glDeleteFramebuffers(1, &_fbo);
+  
+  // Release the Gsg
+  _gsg.clear();
+  _active = false;
 }
 

+ 14 - 26
panda/src/glstuff/glGraphicsBuffer_src.h

@@ -25,21 +25,15 @@
 //
 //               The glGraphicsBuffer is based on the OpenGL
 //               EXT_framebuffer_object and ARB_draw_buffers extensions.
-//               This design has three significant advantages over the
-//               wglGraphicsBuffer and glxGraphicsBuffer.
+//               This design has significant advantages over the
+//               older wglGraphicsBuffer and glxGraphicsBuffer.
 //
-//               As you might expect, this type of buffer can export
-//               its color buffer as a texture.  But it can also export
-//               its depth buffer, its stencil buffer, and any number
-//               of auxiliary buffers.  This is the biggest advantage:
-//               it can render to many textures at the same time.
-//
-//               There is also a speed advantage.  When using a
-//               glGraphicsBuffer, it is not necessary to call the
-//               extremely expensive wglMakeCurrent on buffer switches.
-//
-//               The glGraphicsBuffer can also track the size of a host
-//               window, and automatically resize itself to match.
+//               * Can export depth and stencil.
+//               * Supports auxiliary bitplanes.
+//               * Supports non-power-of-two padding.
+//               * Supports tracking of host window size.
+//               * Faster than pbuffers.
+//               * Can render onto a texture without clearing it first.
 //
 //               If either of the necessary OpenGL extensions is not
 //               available, then the glGraphicsBuffer will not be
@@ -69,24 +63,18 @@ protected:
 
 private:
   
+  void bind_slot(bool rb_resize, Texture **attach, RenderTexturePlane plane,
+                 GLenum attachpoint, GLenum texformat, Texture::Format fmt);
+  bool check_fbo();
   void generate_mipmaps();
   void rebuild_bitplanes();
   
-  enum {
-    SLOT_color,
-    SLOT_depth,
-    SLOT_stencil,
-    SLOT_COUNT
-  };
-
   GLuint      _fbo;
   int         _rb_size_x;
   int         _rb_size_y;
-  GLuint      _rb[SLOT_COUNT];
-  PT(Texture) _tex[SLOT_COUNT];
-  GLenum      _attach_point[SLOT_COUNT];
-  GLenum      _slot_format[SLOT_COUNT];
-
+  PT(Texture) _tex[RTP_COUNT];
+  GLuint      _rb[RTP_COUNT];
+  
 public:
   static TypeHandle get_class_type() {
     return _type_handle;

+ 133 - 153
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -3024,24 +3024,15 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
   TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
   nassertv(tc != (TextureContext *)NULL);
   CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
+  apply_texture(tc);
 
   if (z >= 0) {
     // Copy to a cube map face.  This doesn't seem to work too well
     // with CopyTexSubImage2D, so we always use CopyTexImage2D.
-    GLP(BindTexture)(GL_TEXTURE_CUBE_MAP_ARB, gtc->_index);
     GLP(CopyTexImage2D)(GL_TEXTURE_CUBE_MAP_POSITIVE_X + z, 0,
                         get_internal_image_format(tex),
                         xo, yo, w, h, 0);
-
   } else {
-    // If the texture has never been uploaded before, create it.  We
-    // cannot use glCopyTexImage2D to create a texture that may be
-    // larger than the screen, so use glTexImage2D with arbitrary
-    // data.
-    GLP(BindTexture)(GL_TEXTURE_2D, gtc->_index);
-    upload_blank_image(tex, gtc);
-
-    // Copy the pixel data from the frame buffer.
     GLP(CopyTexSubImage2D)(GL_TEXTURE_2D, 0, 0, 0, xo, yo, w, h);
   }
 
@@ -6375,11 +6366,14 @@ bool CLP(GraphicsStateGuardian)::
 upload_texture(CLP(TextureContext) *gtc) {
   Texture *tex = gtc->get_texture();
   CPTA_uchar image = tex->get_ram_image();
+
+  Texture::CompressionMode image_compression;
   if (image.is_null()) {
-    return false;
+    image_compression = Texture::CM_off;
+  } else {
+    image_compression = tex->get_ram_image_compression();
   }
-  Texture::CompressionMode image_compression = tex->get_ram_image_compression();
-
+  
   int width = tex->get_x_size();
   int height = tex->get_y_size();
   int depth = tex->get_z_size();
@@ -6409,71 +6403,75 @@ upload_texture(CLP(TextureContext) *gtc) {
     return false;
   }
 
-  int texel_size = tex->get_num_components() * tex->get_component_width();
-
-  // If it doesn't fit, we have to reduce it on-the-fly.  This is kind
-  // of expensive and it doesn't look great; it would have been better
-  // if the user had specified max-texture-dimension to reduce the
-  // texture at load time instead.  Of course, the user doesn't always
-  // know ahead of time what the hardware limits are.
-  if (max_dimension > 0 && image_compression == Texture::CM_off) {
-    if (width > max_dimension) {
-      int byte_chunk = texel_size;
-      int stride = 1;
-      int new_width = width;
-      while (new_width > max_dimension) {
-        stride <<= 1;
-        new_width >>= 1;
+  if (!image.is_null()) {
+
+    // If it doesn't fit, we have to reduce it on-the-fly.  This is kind
+    // of expensive and it doesn't look great; it would have been better
+    // if the user had specified max-texture-dimension to reduce the
+    // texture at load time instead.  Of course, the user doesn't always
+    // know ahead of time what the hardware limits are.
+    if (max_dimension > 0 && image_compression == Texture::CM_off) {
+      if (width > max_dimension) {
+        int texel_size = tex->get_num_components() * tex->get_component_width();
+        int byte_chunk = texel_size;
+        int stride = 1;
+        int new_width = width;
+        while (new_width > max_dimension) {
+          stride <<= 1;
+          new_width >>= 1;
+        }
+        GLCAT.info()
+          << "Reducing width of " << tex->get_name()
+          << " from " << width << " to " << new_width << "\n";
+        image = reduce_image(image, byte_chunk, stride);
+        width = new_width;
       }
-      GLCAT.info()
-        << "Reducing width of " << tex->get_name()
-        << " from " << width << " to " << new_width << "\n";
-      image = reduce_image(image, byte_chunk, stride);
-      width = new_width;
-    }
-    if (height > max_dimension) {
-      int byte_chunk = width * texel_size;
-      int stride = 1;
-      int new_height = height;
-      while (new_height > max_dimension) {
-        stride <<= 1;
-        new_height >>= 1;
+      if (height > max_dimension) {
+        int texel_size = tex->get_num_components() * tex->get_component_width();
+        int byte_chunk = width * texel_size;
+        int stride = 1;
+        int new_height = height;
+        while (new_height > max_dimension) {
+          stride <<= 1;
+          new_height >>= 1;
+        }
+        GLCAT.info()
+          << "Reducing height of " << tex->get_name()
+          << " from " << height << " to " << new_height << "\n";
+        image = reduce_image(image, byte_chunk, stride);
+        height = new_height;
       }
-      GLCAT.info()
-        << "Reducing height of " << tex->get_name()
-        << " from " << height << " to " << new_height << "\n";
-      image = reduce_image(image, byte_chunk, stride);
-      height = new_height;
-    }
-    if (depth > max_dimension) {
-      int byte_chunk = height * width * texel_size;
-      int stride = 1;
-      int new_depth = depth;
-      while (new_depth > max_dimension) {
-        stride <<= 1;
-        new_depth >>= 1;
+      if (depth > max_dimension) {
+        int texel_size = tex->get_num_components() * tex->get_component_width();
+        int byte_chunk = height * width * texel_size;
+        int stride = 1;
+        int new_depth = depth;
+        while (new_depth > max_dimension) {
+          stride <<= 1;
+          new_depth >>= 1;
+        }
+        GLCAT.info()
+          << "Reducing depth of " << tex->get_name()
+          << " from " << depth << " to " << new_depth << "\n";
+        image = reduce_image(image, byte_chunk, stride);
+        depth = new_depth;
       }
-      GLCAT.info()
-        << "Reducing depth of " << tex->get_name()
-        << " from " << depth << " to " << new_depth << "\n";
-      image = reduce_image(image, byte_chunk, stride);
-      depth = new_depth;
     }
-  }
-
-  if (!_supports_bgr) {
-    // If the GL doesn't claim to support BGR, we may have to reverse
-    // the component ordering of the image.
-    image = fix_component_ordering(image, external_format, tex);
-  }
+    
+    if (!_supports_bgr) {
+      // If the GL doesn't claim to support BGR, we may have to reverse
+      // the component ordering of the image.
+      image = fix_component_ordering(image, external_format, tex);
+    }
 
 #ifndef NDEBUG
-  if (image_compression == Texture::CM_off) {
-    int wanted_size =
-      compute_gl_image_size(width, height, depth, external_format, component_type);
-    nassertr(wanted_size == (int)image.size(), false);
-  }
+    if (image_compression == Texture::CM_off) {
+      int wanted_size =
+        compute_gl_image_size(width, height, depth, external_format, component_type);
+      nassertr(wanted_size == (int)image.size(), false);
+    }
 #endif  // NDEBUG
+  }
 
   GLP(PixelStorei)(GL_UNPACK_ALIGNMENT, 1);
 
@@ -6541,7 +6539,9 @@ upload_texture(CLP(TextureContext) *gtc) {
     gtc->_depth = depth;
 
 #ifdef DO_PSTATS
-    gtc->update_data_size_bytes(get_texture_memory_size(tex));
+    if (!image.is_null()) {
+      gtc->update_data_size_bytes(get_texture_memory_size(tex));
+    }
 #endif
 
     report_my_gl_errors();
@@ -6552,59 +6552,6 @@ upload_texture(CLP(TextureContext) *gtc) {
   return false;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::upload_blank_image
-//       Access: Private
-//  Description: Uploads a blank, non-mipmapped image to the specified
-//               texture object.  This is usually used to prepare the
-//               texture for render-to-texture operations.
-////////////////////////////////////////////////////////////////////
-bool CLP(GraphicsStateGuardian)::
-upload_blank_image(Texture *tex, CLP(TextureContext) *gtc)
-
-{
-  GLint internal_format = get_internal_image_format(tex);
-  
-  if ((gtc->_already_applied == false)||
-      (gtc->_internal_format != internal_format)||
-      (gtc->_width  != tex->get_x_size())||
-      (gtc->_height != tex->get_y_size())||
-      (gtc->_depth  != 1)) {
-    
-    GLP(BindTexture)(GL_TEXTURE_2D, gtc->_index);
-    
-    char *image = new char[tex->get_x_size() * tex->get_y_size()];
-    memset(image, 128, tex->get_x_size() * tex->get_y_size());
-
-    switch (tex->get_format()) {
-    case Texture::F_depth_component:
-      GLP(TexImage2D)(GL_TEXTURE_2D, 0, internal_format,
-                      tex->get_x_size(), tex->get_y_size(), 0,
-                      GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, image);
-      break;
-    case Texture::F_stencil_index:
-      GLP(TexImage2D)(GL_TEXTURE_2D, 0, internal_format,
-                      tex->get_x_size(), tex->get_y_size(), 0,
-                      GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, image);
-      break;
-    default:
-      GLP(TexImage2D)(GL_TEXTURE_2D, 0, internal_format,
-                      tex->get_x_size(), tex->get_y_size(), 0,
-                      GL_LUMINANCE, GL_UNSIGNED_BYTE, image);
-      break;
-    }
-
-    delete image;
-    
-    gtc->_already_applied = true;
-    gtc->_internal_format = internal_format;
-    gtc->_width  = tex->get_x_size();
-    gtc->_height = tex->get_y_size();
-    gtc->_depth  = 1;
-  }
-  
-  return true;
-}
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::upload_texture_image
@@ -6622,7 +6569,7 @@ upload_texture_image(CLP(TextureContext) *gtc,
 		     Texture::CompressionMode image_compression) {
   // Make sure the error stack is cleared out before we begin.
   report_my_gl_errors();
-
+  
   if (target == GL_NONE) {
     // Unsupported target (e.g. 3-d texturing on GL 1.1).
     return false;
@@ -6633,6 +6580,7 @@ upload_texture_image(CLP(TextureContext) *gtc,
 
   PStatTimer timer(_load_texture_pcollector);
   Texture *tex = gtc->get_texture();
+  CPTA_uchar image = tex->get_ram_image();
 
   if (GLCAT.is_debug()) {
     if (image_compression != Texture::CM_off) {
@@ -6644,33 +6592,11 @@ upload_texture_image(CLP(TextureContext) *gtc,
     }
   }
 
-  int num_ram_mipmap_levels = 1;
+  int num_ram_mipmap_levels = 0;
   bool load_ram_mipmaps = false;
 
-  if (uses_mipmaps) {
-    num_ram_mipmap_levels = tex->get_num_ram_mipmap_images();
-
-    if (num_ram_mipmap_levels == 1) {
-      // No RAM mipmap levels available.  Should we generate some?
-      if (!_supports_generate_mipmap || 
-          (!auto_generate_mipmaps && image_compression == Texture::CM_off)) {
-        // Yes, the GL won't generate them, so we need to.
-        tex->generate_ram_mipmap_images();
-        num_ram_mipmap_levels = tex->get_num_ram_mipmap_images();
-      }
-    }
-
-    if (num_ram_mipmap_levels != 1) {
-      // We will load the mipmap levels from RAM.  Don't ask the GL to
-      // generate them.
-      if (_supports_generate_mipmap) {
-        GLP(TexParameteri)(target, GL_GENERATE_MIPMAP, false);
-      }
-      load_ram_mipmaps = true;
-
-    } else {
-      // We don't have mipmap levels in RAM.  Ask the GL to generate
-      // them if it can.
+  if (image.is_null()) {
+    if (uses_mipmaps) {
       if (_supports_generate_mipmap) {
         GLP(TexParameteri)(target, GL_GENERATE_MIPMAP, true);
       } else {
@@ -6679,10 +6605,46 @@ upload_texture_image(CLP(TextureContext) *gtc,
         uses_mipmaps = false;
       }
     }
+  } else {
+    num_ram_mipmap_levels = 1;
+    if (uses_mipmaps) {
+      num_ram_mipmap_levels = tex->get_num_ram_mipmap_images();
+    
+      if (num_ram_mipmap_levels == 1) {
+        // No RAM mipmap levels available.  Should we generate some?
+        if (!_supports_generate_mipmap || 
+            (!auto_generate_mipmaps && image_compression == Texture::CM_off)) {
+          // Yes, the GL won't generate them, so we need to.
+          tex->generate_ram_mipmap_images();
+          num_ram_mipmap_levels = tex->get_num_ram_mipmap_images();
+        }
+      }
+      
+      if (num_ram_mipmap_levels != 1) {
+        // We will load the mipmap levels from RAM.  Don't ask the GL to
+        // generate them.
+        if (_supports_generate_mipmap) {
+          GLP(TexParameteri)(target, GL_GENERATE_MIPMAP, false);
+        }
+        load_ram_mipmaps = true;
+        
+      } else {
+        // We don't have mipmap levels in RAM.  Ask the GL to generate
+        // them if it can.
+        if (_supports_generate_mipmap) {
+          GLP(TexParameteri)(target, GL_GENERATE_MIPMAP, true);
+        } else {
+          // If it can't, do without mipmaps.
+          GLP(TexParameteri)(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+          uses_mipmaps = false;
+        }
+      }
+    }
   }
-
+  
   int highest_level = 0;
-
+  
+  
   if (!gtc->_already_applied ||
       gtc->_internal_format != internal_format ||
       gtc->_width != width ||
@@ -6690,6 +6652,24 @@ upload_texture_image(CLP(TextureContext) *gtc,
       gtc->_depth != depth) {
     // We need to reload a new image.
 
+    if (num_ram_mipmap_levels == 0) {
+      int *blank_image = new int[width * height];
+      int color = 0xFF808080;
+      switch (z) {
+      case 0: color = 0xFF0000FF; break;
+      case 1: color = 0xFF00FF00; break;
+      case 2: color = 0xFFFF0000; break;
+      case 3: color = 0xFF00FFFF; break;
+      case 4: color = 0xFFFFFF00; break;
+      case 5: color = 0xFFFF00FF; break;
+      }
+      for (int i=0; i<width * height; i++) blank_image[i]=color;
+      GLP(TexImage2D)(target, 0, internal_format,
+                      width, height, 0,
+                      external_format, GL_UNSIGNED_BYTE, blank_image);
+      delete blank_image;
+    }
+    
     for (int n = 0; n < num_ram_mipmap_levels; ++n) {
       const unsigned char *image = tex->get_ram_mipmap_image(n);
       if (image == (const unsigned char *)NULL) {

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

@@ -274,7 +274,6 @@ protected:
   void specify_texture(Texture *tex);
   void apply_texture(TextureContext *tc);
   bool upload_texture(CLP(TextureContext) *gtc);
-  bool upload_blank_image(Texture *tex, CLP(TextureContext) *gtc);
   bool upload_texture_image(CLP(TextureContext) *gtc, bool uses_mipmaps, 
                             GLenum target, GLint internal_format, 
                             int width, int height, int depth,
@@ -372,8 +371,6 @@ public:
   bool _supports_draw_range_elements;
   PFNGLDRAWRANGEELEMENTSPROC _glDrawRangeElements;
 
-  bool _supports_depth_texture;
-
   PFNGLTEXIMAGE3DPROC _glTexImage3D;
   PFNGLTEXSUBIMAGE3DPROC _glTexSubImage3D;
 

+ 8 - 15
panda/src/glxdisplay/glxGraphicsBuffer.cxx

@@ -97,6 +97,8 @@ begin_frame(FrameMode mode) {
     // begin_render_texture();
     clear_cube_map_selection();
   }
+  
+  _gsg()->set_current_properties(&get_fb_properties());
   return _gsg->begin_frame();
 }
 
@@ -128,21 +130,6 @@ end_frame(FrameMode mode) {
   }
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: glxGraphicsBuffer::release_gsg
-//       Access: Public
-//  Description: Releases the current GSG pointer, if it is currently
-//               held, and resets the GSG to NULL.  The window will be
-//               permanently unable to render; this is normally called
-//               only just before destroying the window.  This should
-//               only be called from within the draw thread.
-////////////////////////////////////////////////////////////////////
-void glxGraphicsBuffer::
-release_gsg() {
-  glXMakeCurrent(_display, None, NULL);
-  GraphicsBuffer::release_gsg();
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: glxGraphicsBuffer::close_buffer
 //       Access: Protected, Virtual
@@ -151,6 +138,12 @@ release_gsg() {
 ////////////////////////////////////////////////////////////////////
 void glxGraphicsBuffer::
 close_buffer() {
+  if (_gsg != (GraphicsStateGuardian *)NULL) {
+    glXMakeCurrent(_display, None, NULL);
+    _gsg.clear();
+    _active = false;
+  }
+
   if (_pbuffer != None) {
     glXDestroyPbuffer(_display, _pbuffer);
     _pbuffer = None;

+ 0 - 1
panda/src/glxdisplay/glxGraphicsBuffer.h

@@ -45,7 +45,6 @@ public:
 
   virtual bool begin_frame(FrameMode mode);
   virtual void end_frame(FrameMode mode);
-  virtual void release_gsg();
 
 protected:
   virtual void close_buffer();

+ 9 - 16
panda/src/glxdisplay/glxGraphicsWindow.cxx

@@ -105,20 +105,6 @@ move_pointer(int device, int x, int y) {
   return true;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: glxGraphicsWindow::release_gsg
-//       Access: Public
-//  Description: Releases the current GSG pointer, if it is currently
-//               held, and resets the GSG to NULL.  The window will be
-//               permanently unable to render; this is normally called
-//               only just before destroying the window.  This should
-//               only be called from within the draw thread.
-////////////////////////////////////////////////////////////////////
-void glxGraphicsWindow::
-release_gsg() {
-  glXMakeCurrent(_display, None, NULL);
-  GraphicsWindow::release_gsg();
-}
 
 ////////////////////////////////////////////////////////////////////
 //     Function: glxGraphicsWindow::begin_frame
@@ -157,6 +143,8 @@ begin_frame(FrameMode mode) {
     // begin_render_texture();
     clear_cube_map_selection();
   }
+  
+  _gsg()->set_current_properties(&get_fb_properties());
   return _gsg->begin_frame();
 }
 
@@ -375,8 +363,7 @@ process_events() {
           // In this case, the default case, the app does not intend
           // to service the request, so we do by closing the window.
 
-          // TODO: don't call release_gsg() in the window thread.
-          release_gsg();
+          // TODO: don't release the gsg in the window thread.
           close_window();
           properties.set_open(false);
           system_changed_properties(properties);
@@ -493,6 +480,12 @@ set_properties_now(WindowProperties &properties) {
 ////////////////////////////////////////////////////////////////////
 void glxGraphicsWindow::
 close_window() {
+  if (_gsg != (GraphicsStateGuardian *)NULL) {
+    glXMakeCurrent(_display, None, NULL);
+    _gsg.clear();
+    _active = false;
+  }
+  
   if (_ic != (XIC)NULL) {
     XDestroyIC(_ic);
     _ic = (XIC)NULL;

+ 0 - 2
panda/src/glxdisplay/glxGraphicsWindow.h

@@ -41,8 +41,6 @@ public:
   virtual ~glxGraphicsWindow();
 
   virtual bool move_pointer(int device, int x, int y);
-  virtual void release_gsg();
-
   virtual bool begin_frame(FrameMode mode);
   virtual void end_frame(FrameMode mode);
   virtual void begin_flip();

+ 1 - 0
panda/src/gobj/texture.cxx

@@ -931,6 +931,7 @@ set_ram_image(PTA_uchar image, Texture::CompressionMode compression,
 ////////////////////////////////////////////////////////////////////
 void Texture::
 clear_ram_image() {
+  ++_modified;
   _ram_image_compression = CM_off;
   _ram_images.clear();
 }

+ 0 - 97
panda/src/grutil/cardMaker.I

@@ -60,103 +60,6 @@ set_has_3d_uvs(bool flag) {
   _has_3d_uvs = flag;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: CardMaker::set_uv_range
-//       Access: Public
-//  Description: Sets the range of UV's that will be applied to the
-//               vertices.  If set_has_uvs() is true (as it is by
-//               default), the vertices will be generated with the
-//               indicated range of UV's, which will be useful if a
-//               texture is applied.
-////////////////////////////////////////////////////////////////////
-INLINE void CardMaker::
-set_uv_range(const TexCoord3f &ll, const TexCoord3f &lr, const TexCoord3f &ur, const TexCoord3f &ul) {
-  _ll_tex = ll;
-  _lr_tex = lr;
-  _ur_tex = ur;
-  _ul_tex = ul;
-  _has_uvs = true;
-  _has_3d_uvs = true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: CardMaker::set_uv_range
-//       Access: Public
-//  Description: Sets the range of UV's that will be applied to the
-//               vertices.  If set_has_uvs() is true (as it is by
-//               default), the vertices will be generated with the
-//               indicated range of UV's, which will be useful if a
-//               texture is applied.
-////////////////////////////////////////////////////////////////////
-INLINE void CardMaker::
-set_uv_range(const TexCoordf &ll, const TexCoordf &lr, const TexCoordf &ur, const TexCoordf &ul) {
-  _ll_tex.set(ll[0], ll[1], 0.0f);
-  _lr_tex.set(lr[0], lr[1], 0.0f);
-  _ur_tex.set(ur[0], ur[1], 0.0f);
-  _ul_tex.set(ul[0], ul[1], 0.0f);
-  _has_uvs = true;
-  _has_3d_uvs = false;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: CardMaker::set_uv_range
-//       Access: Public
-//  Description: Sets the range of UV's that will be applied to the
-//               vertices.  If set_has_uvs() is true (as it is by
-//               default), the vertices will be generated with the
-//               indicated range of UV's, which will be useful if a
-//               texture is applied.
-////////////////////////////////////////////////////////////////////
-INLINE void CardMaker::
-set_uv_range(const TexCoordf &ll, const TexCoordf &ur) {
-  _ll_tex.set(ll[0], ll[1], 0.0f);
-  _lr_tex.set(ur[0], ll[1], 0.0f);
-  _ur_tex.set(ur[0], ur[1], 0.0f);
-  _ul_tex.set(ll[0], ur[1], 0.0f);
-  _has_uvs = true;
-  _has_3d_uvs = false;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: CardMaker::set_uv_range
-//       Access: Public
-//  Description: Sets the range of UV's that will be applied to the
-//               vertices.  If set_has_uvs() is true (as it is by
-//               default), the vertices will be generated with the
-//               indicated range of UV's, which will be useful if a
-//               texture is applied.
-////////////////////////////////////////////////////////////////////
-INLINE void CardMaker::
-set_uv_range(const LVector4f &x, const LVector4f &y, const LVector4f &z) {
-  _ll_tex.set(x[0], y[0], z[0]);
-  _lr_tex.set(x[1], y[1], z[1]);
-  _ur_tex.set(x[2], y[2], z[2]);
-  _ul_tex.set(x[3], y[3], z[3]);
-  _has_uvs = true;
-  _has_3d_uvs = true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: CardMaker::set_uv_range_cube
-//       Access: Public
-//  Description: Sets the range of UV's that will be applied to the
-//               vertices appropriately for a cube-map face.
-////////////////////////////////////////////////////////////////////
-INLINE void CardMaker::
-set_uv_range_cube(int face) {
-  LVector4f varya(-1,  1,  1, -1);
-  LVector4f varyb(-1, -1,  1,  1);
-  LVector4f fixed( 1,  1,  1,  1);
-  switch(face) {
-  case 0: set_uv_range( fixed, -varyb,  varya); break; // positive_x
-  case 1: set_uv_range(-fixed, -varyb, -varya); break; // negative_x
-  case 2: set_uv_range(-varya,  fixed,  varyb); break; // positive_y
-  case 3: set_uv_range(-varya, -fixed, -varyb); break; // negative_y
-  case 4: set_uv_range(-varya, -varyb,  fixed); break; // positive_z
-  case 5: set_uv_range( varya, -varyb, -fixed); break; // negative_z
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: CardMaker::set_frame
 //       Access: Public

+ 97 - 0
panda/src/grutil/cardMaker.cxx

@@ -159,6 +159,103 @@ generate() {
   return gnode.p();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CardMaker::set_uv_range
+//       Access: Public
+//  Description: Sets the range of UV's that will be applied to the
+//               vertices.  If set_has_uvs() is true (as it is by
+//               default), the vertices will be generated with the
+//               indicated range of UV's, which will be useful if a
+//               texture is applied.
+////////////////////////////////////////////////////////////////////
+INLINE void CardMaker::
+set_uv_range(const TexCoord3f &ll, const TexCoord3f &lr, const TexCoord3f &ur, const TexCoord3f &ul) {
+  _ll_tex = ll;
+  _lr_tex = lr;
+  _ur_tex = ur;
+  _ul_tex = ul;
+  _has_uvs = true;
+  _has_3d_uvs = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CardMaker::set_uv_range
+//       Access: Public
+//  Description: Sets the range of UV's that will be applied to the
+//               vertices.  If set_has_uvs() is true (as it is by
+//               default), the vertices will be generated with the
+//               indicated range of UV's, which will be useful if a
+//               texture is applied.
+////////////////////////////////////////////////////////////////////
+INLINE void CardMaker::
+set_uv_range(const TexCoordf &ll, const TexCoordf &lr, const TexCoordf &ur, const TexCoordf &ul) {
+  _ll_tex.set(ll[0], ll[1], 0.0f);
+  _lr_tex.set(lr[0], lr[1], 0.0f);
+  _ur_tex.set(ur[0], ur[1], 0.0f);
+  _ul_tex.set(ul[0], ul[1], 0.0f);
+  _has_uvs = true;
+  _has_3d_uvs = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CardMaker::set_uv_range
+//       Access: Public
+//  Description: Sets the range of UV's that will be applied to the
+//               vertices.  If set_has_uvs() is true (as it is by
+//               default), the vertices will be generated with the
+//               indicated range of UV's, which will be useful if a
+//               texture is applied.
+////////////////////////////////////////////////////////////////////
+INLINE void CardMaker::
+set_uv_range(const TexCoordf &ll, const TexCoordf &ur) {
+  _ll_tex.set(ll[0], ll[1], 0.0f);
+  _lr_tex.set(ur[0], ll[1], 0.0f);
+  _ur_tex.set(ur[0], ur[1], 0.0f);
+  _ul_tex.set(ll[0], ur[1], 0.0f);
+  _has_uvs = true;
+  _has_3d_uvs = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CardMaker::set_uv_range
+//       Access: Public
+//  Description: Sets the range of UV's that will be applied to the
+//               vertices.  If set_has_uvs() is true (as it is by
+//               default), the vertices will be generated with the
+//               indicated range of UV's, which will be useful if a
+//               texture is applied.
+////////////////////////////////////////////////////////////////////
+INLINE void CardMaker::
+set_uv_range(const LVector4f &x, const LVector4f &y, const LVector4f &z) {
+  _ll_tex.set(x[0], y[0], z[0]);
+  _lr_tex.set(x[1], y[1], z[1]);
+  _ur_tex.set(x[2], y[2], z[2]);
+  _ul_tex.set(x[3], y[3], z[3]);
+  _has_uvs = true;
+  _has_3d_uvs = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CardMaker::set_uv_range_cube
+//       Access: Public
+//  Description: Sets the range of UV's that will be applied to the
+//               vertices appropriately for a cube-map face.
+////////////////////////////////////////////////////////////////////
+INLINE void CardMaker::
+set_uv_range_cube(int face) {
+  LVector4f varya(-1,  1,  1, -1);
+  LVector4f varyb(-1, -1,  1,  1);
+  LVector4f fixed( 1,  1,  1,  1);
+  switch(face) {
+  case 0: set_uv_range( fixed, -varyb, -varya); break; // positive_x
+  case 1: set_uv_range(-fixed, -varyb,  varya); break; // negative_x
+  case 2: set_uv_range( varya,  fixed,  varyb); break; // positive_y
+  case 3: set_uv_range( varya, -fixed, -varyb); break; // negative_y
+  case 4: set_uv_range( varya, -varyb,  fixed); break; // positive_z
+  case 5: set_uv_range(-varya, -varyb, -fixed); break; // negative_z
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CardMaker::rescale_source_geometry
 //       Access: Private

+ 6 - 5
panda/src/grutil/cardMaker.h

@@ -38,13 +38,14 @@ PUBLISHED:
   INLINE ~CardMaker();
 
   void reset();
-  INLINE void set_uv_range(const TexCoordf &ll, const TexCoordf &ur);
-  INLINE void set_uv_range(const TexCoordf &ll, const TexCoordf &lr, const TexCoordf &ur, const TexCoordf &ul);
-  INLINE void set_uv_range(const TexCoord3f &ll, const TexCoord3f &lr, const TexCoord3f &ur, const TexCoord3f &ul);
-  INLINE void set_uv_range(const LVector4f &x, const LVector4f &y, const LVector4f &z);
+  void set_uv_range(const TexCoordf &ll, const TexCoordf &ur);
+  void set_uv_range(const TexCoordf &ll, const TexCoordf &lr, const TexCoordf &ur, const TexCoordf &ul);
+  void set_uv_range(const TexCoord3f &ll, const TexCoord3f &lr, const TexCoord3f &ur, const TexCoord3f &ul);
+  void set_uv_range(const LVector4f &x, const LVector4f &y, const LVector4f &z);
+  void set_uv_range_cube(int face);
+
   INLINE void set_has_uvs(bool flag);
   INLINE void set_has_3d_uvs(bool flag);
-  INLINE void set_uv_range_cube(int face);
 
   INLINE void set_frame(float left, float right, float bottom, float top);
   INLINE void set_frame(const LVecBase4f &frame);

+ 1 - 0
panda/src/mesadisplay/osMesaGraphicsBuffer.cxx

@@ -76,6 +76,7 @@ begin_frame(FrameMode mode) {
     // begin_render_texture();
     clear_cube_map_selection();
   }
+  _gsg->set_current_properties(&get_fb_properties());
   return _gsg->begin_frame();
 }
 

+ 6 - 15
panda/src/osxdisplay/osxGraphicsBuffer.cxx

@@ -82,6 +82,7 @@ begin_frame(FrameMode mode) {
     // begin_render_texture();
     clear_cube_map_selection();
   }
+  _gsg->set_current_properties(&get_fb_properties());
   return _gsg->begin_frame();
 }
 
@@ -113,20 +114,6 @@ end_frame(FrameMode mode) {
     clear_cube_map_selection();
   }
 }
-////////////////////////////////////////////////////////////////////
-//     Function: osxGraphicsBuffer::release_gsg
-//       Access: Public
-//  Description: Releases the current GSG pointer, if it is currently
-//               held, and resets the GSG to NULL.  The window will be
-//               permanently unable to render; this is normally called
-//               only just before destroying the window.  This should
-//               only be called from within the draw thread.
-////////////////////////////////////////////////////////////////////
-void osxGraphicsBuffer::
-release_gsg() {
-  //osxMakeCurrent(_display, None, NULL);
-  GraphicsBuffer::release_gsg();
-}
 
 ////////////////////////////////////////////////////////////////////
 //     Function: osxGraphicsBuffer::close_buffer
@@ -136,7 +123,11 @@ release_gsg() {
 ////////////////////////////////////////////////////////////////////
 void osxGraphicsBuffer::
 close_buffer() {
- 
+  if (_gsg != (GraphicsStateGuardian *)NULL) {
+    //osxMakeCurrent(_display, None, NULL);
+    _gsg.clear();
+    _active = false;
+  }
   _is_valid = false;
 }
 

+ 0 - 2
panda/src/osxdisplay/osxGraphicsBuffer.h

@@ -45,8 +45,6 @@ public:
 
   virtual bool begin_frame(FrameMode mode);
   virtual void end_frame(FrameMode mode);
-  virtual void release_gsg();
-
 
 protected:
   virtual void close_buffer();

+ 8 - 23
panda/src/osxdisplay/osxGraphicsWindow.cxx

@@ -568,8 +568,8 @@ bool osxGraphicsWindow::begin_frame(FrameMode mode)
  
  
 	
-		_gsg->reset_if_new();
-
+  _gsg->reset_if_new();
+  _gsg->set_current_properties(&get_fb_properties());
   return _gsg->begin_frame();
 }
 
@@ -590,22 +590,6 @@ void osxGraphicsWindow::end_frame(FrameMode mode)
   trigger_flip();
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: osxGraphicsWindow::release_gsg
-//       Access: Public, Virtual
-//  Description: Releases the current GSG pointer, if it is currently
-//               held, and resets the GSG to NULL.  The window will be
-//               permanently unable to render; this is normally called
-//               only just before destroying the window.  This should
-//               only be called from within the draw thread.
-////////////////////////////////////////////////////////////////////
-void osxGraphicsWindow::release_gsg() 
-{
-	ReleaseSystemResources();
-		
-  GraphicsWindow::release_gsg();
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: osxGraphicsWindow::begin_flip
 //       Access: Public, Virtual
@@ -632,11 +616,12 @@ void osxGraphicsWindow::begin_flip()
 //  Description: Closes the window right now.  Called from the window
 //               thread.
 ////////////////////////////////////////////////////////////////////
-void osxGraphicsWindow::close_window() {
-
-	ReleaseSystemResources();
-	GraphicsWindow::close_window();
-
+void osxGraphicsWindow::close_window()
+{
+  ReleaseSystemResources();
+  _gsg.clear();
+  _active = false;
+  GraphicsWindow::close_window();
 }
 
 //////////////////////////////////////////////////////////

+ 0 - 1
panda/src/osxdisplay/osxGraphicsWindow.h

@@ -50,7 +50,6 @@ public:
   virtual bool move_pointer(int device, int x, int y);
 
 //  virtual void make_current();
-  virtual void release_gsg();
   virtual bool begin_frame(FrameMode mode);
   virtual void end_frame(FrameMode mode);
   virtual void begin_flip();

+ 7 - 15
panda/src/wgldisplay/wglGraphicsBuffer.cxx

@@ -91,13 +91,15 @@ begin_frame(FrameMode mode) {
       }
     }
   }
-
+  
   wglMakeCurrent(_pbuffer_dc, wglgsg->get_context(_pbuffer_dc));
   
   if (mode == FM_render) {
     begin_render_texture();
     clear_cube_map_selection();
   }
+
+  _gsg->set_current_properties(&get_fb_properties());
   return _gsg->begin_frame();
 }
 
@@ -228,20 +230,6 @@ select_cube_map(int cube_map_index) {
   wglgsg->_wglSetPbufferAttribARB(_pbuffer, iattrib_list);
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: wglGraphicsBuffer::release_gsg
-//       Access: Public, Virtual
-//  Description: Releases the current GSG pointer, if it is currently
-//               held, and resets the GSG to NULL.  The window will be
-//               permanently unable to render; this is normally called
-//               only just before destroying the window.  This should
-//               only be called from within the draw thread.
-////////////////////////////////////////////////////////////////////
-void wglGraphicsBuffer::
-release_gsg() {
-  GraphicsBuffer::release_gsg();
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: wglGraphicsBuffer::process_events
 //       Access: Public, Virtual
@@ -284,7 +272,11 @@ close_buffer() {
     if (_pbuffer) {
       wglgsg->_wglDestroyPbufferARB(_pbuffer);
     }
+    
+    _gsg.clear();
+    _active = false;
   }
+
   _pbuffer_dc = 0;
   _pbuffer = 0;
 

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

@@ -53,7 +53,6 @@ public:
   virtual void end_frame(FrameMode mode);
 
   virtual void select_cube_map(int cube_map_index);
-  virtual void release_gsg();
 
   virtual void process_events();
 

+ 7 - 16
panda/src/wgldisplay/wglGraphicsWindow.cxx

@@ -168,7 +168,7 @@ begin_frame(FrameMode mode) {
   if (_gsg == (GraphicsStateGuardian *)NULL) {
     return false;
   }
-
+  
   wglGraphicsStateGuardian *wglgsg;
   DCAST_INTO_R(wglgsg, _gsg, false);
   
@@ -181,6 +181,7 @@ begin_frame(FrameMode mode) {
     clear_cube_map_selection();
   }
   
+  _gsg->set_current_properties(&get_fb_properties());
   return _gsg->begin_frame();
 }
 
@@ -213,21 +214,6 @@ end_frame(FrameMode mode) {
   }
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: wglGraphicsWindow::release_gsg
-//       Access: Public, Virtual
-//  Description: Releases the current GSG pointer, if it is currently
-//               held, and resets the GSG to NULL.  The window will be
-//               permanently unable to render; this is normally called
-//               only just before destroying the window.  This should
-//               only be called from within the draw thread.
-////////////////////////////////////////////////////////////////////
-void wglGraphicsWindow::
-release_gsg() {
-  wglMakeCurrent(_hdc, NULL);
-  GraphicsWindow::release_gsg();
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: wglGraphicsWindow::begin_flip
 //       Access: Public, Virtual
@@ -268,6 +254,11 @@ begin_flip() {
 ////////////////////////////////////////////////////////////////////
 void wglGraphicsWindow::
 close_window() {
+  if (_gsg != (GraphicsStateGuardian *)NULL) {
+    wglMakeCurrent(_hdc, NULL);
+    _gsg.clear();
+    _active = false;
+  }
   ReleaseDC(_hWnd, _hdc);
   _hdc = (HDC)0;
   WinGraphicsWindow::close_window();

+ 0 - 1
panda/src/wgldisplay/wglGraphicsWindow.h

@@ -40,7 +40,6 @@ public:
   virtual bool begin_frame(FrameMode mode);
   virtual void end_frame(FrameMode mode);
 
-  virtual void release_gsg();
   virtual void begin_flip();
 
 protected: