Pārlūkot izejas kodu

define GraphicsOutput class

David Rose 22 gadi atpakaļ
vecāks
revīzija
26da9be3e7

+ 1 - 1
direct/src/showbase/showBase.h

@@ -22,8 +22,8 @@
 #include "directbase.h"
 
 #include "eventHandler.h"
-#include "graphicsPipe.h"
 #include "graphicsWindow.h"
+#include "graphicsPipe.h"
 #include "animControl.h"
 #include "pointerTo.h"
 #include "dconfig.h"

+ 12 - 5
panda/src/display/Sources.pp

@@ -22,12 +22,15 @@
     graphicsChannel.I graphicsChannel.h \
     graphicsEngine.I graphicsEngine.h \
     graphicsLayer.I  \
-    graphicsLayer.h graphicsPipe.I graphicsPipe.h  \
+    graphicsLayer.h \
+    graphicsOutput.I graphicsOutput.h \
+    graphicsPipe.I graphicsPipe.h  \
     graphicsPipeSelection.I graphicsPipeSelection.h \
     graphicsStateGuardian.I \
-    graphicsStateGuardian.h graphicsWindow.I \
+    graphicsStateGuardian.h \
     graphicsThreadingModel.I graphicsThreadingModel.h \
-    graphicsWindow.h graphicsWindowInputDevice.I  \
+    graphicsWindow.I graphicsWindow.h \
+    graphicsWindowInputDevice.I  \
     graphicsWindowInputDevice.h \
     graphicsDevice.h graphicsDevice.I \
     windowProperties.I windowProperties.h \
@@ -43,7 +46,9 @@
     frameBufferProperties.cxx \
     geomContext.cxx geomNodeContext.cxx graphicsChannel.cxx  \
     graphicsEngine.cxx \
-    graphicsLayer.cxx graphicsPipe.cxx \
+    graphicsLayer.cxx \
+    graphicsOutput.cxx \
+    graphicsPipe.cxx \
     graphicsPipeSelection.cxx \
     graphicsStateGuardian.cxx  \
     graphicsThreadingModel.cxx \
@@ -64,10 +69,12 @@
     graphicsChannel.I graphicsChannel.h \
     graphicsEngine.I graphicsEngine.h \
     graphicsLayer.I graphicsLayer.h \
+    graphicsOutput.I graphicsOutput.h \
     graphicsPipe.I graphicsPipe.h \
     graphicsPipeSelection.I graphicsPipeSelection.h \
     graphicsStateGuardian.I \
-    graphicsStateGuardian.h graphicsWindow.I graphicsWindow.h \
+    graphicsStateGuardian.h \
+    graphicsWindow.I graphicsWindow.h \
     graphicsThreadingModel.I graphicsThreadingModel.h \
     graphicsWindowInputDevice.I graphicsWindowInputDevice.h \
     graphicsDevice.I graphicsDevice.h \

+ 9 - 22
panda/src/display/displayRegion.cxx

@@ -19,7 +19,7 @@
 
 #include "graphicsLayer.h"
 #include "graphicsChannel.h"
-#include "graphicsWindow.h"
+#include "graphicsOutput.h"
 #include "config_display.h"
 #include "displayRegion.h"
 #include "camera.h"
@@ -190,12 +190,9 @@ set_dimensions(float l, float r, float b, float t) {
   _b = b;
   _t = t;
 
-  const GraphicsWindow *win = get_window();
-  if (win != (GraphicsWindow *)NULL) {
-    WindowProperties properties = win->get_properties();
-    if (properties.has_size()) {
-      do_compute_pixels(properties.get_x_size(), properties.get_y_size());
-    }
+  const GraphicsOutput *win = get_window();
+  if (win != (GraphicsOutput *)NULL && win->has_size()) {
+    do_compute_pixels(win->get_x_size(), win->get_y_size());
   }
 }
 
@@ -228,11 +225,11 @@ get_channel() const {
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegion::get_window
 //       Access: Published
-//  Description: Returns the GraphicsWindow that this DisplayRegion is
+//  Description: Returns the GraphicsOutput that this DisplayRegion is
 //               ultimately associated with, or NULL if no window is
 //               associated.
 ////////////////////////////////////////////////////////////////////
-GraphicsWindow *DisplayRegion::
+GraphicsOutput *DisplayRegion::
 get_window() const {
   MutexHolder holder(_lock);
   return (_layer != (GraphicsLayer *)NULL) ? _layer->get_window() : NULL;
@@ -324,21 +321,11 @@ set_active(bool active) {
 ////////////////////////////////////////////////////////////////////
 void DisplayRegion::
 compute_pixels() {
-  const GraphicsWindow *win = get_window();
-  if (win != (GraphicsWindow *)NULL) {
+  const GraphicsOutput *win = get_window();
+  if (win != (GraphicsOutput *)NULL) {
     MutexHolder holder(_lock);
-    WindowProperties properties = win->get_properties();
-    if (!properties.has_size()) {
-      // If the window doesn't know its size yet, maybe it will
-      // eventually be given the size it's requesting.
-      properties = win->get_requested_properties();
-    }
 
-    if (properties.has_size()) {
-      do_compute_pixels(properties.get_x_size(), properties.get_y_size());
-    } else {
-      do_compute_pixels(0, 0);
-    }
+    do_compute_pixels(win->get_x_size(), win->get_y_size());
   }
 }
 

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

@@ -31,7 +31,7 @@
 
 class GraphicsLayer;
 class GraphicsChannel;
-class GraphicsWindow;
+class GraphicsOutput;
 class GraphicsPipe;
 class CullHandler;
 class Camera;
@@ -64,7 +64,7 @@ PUBLISHED:
 
   GraphicsLayer *get_layer() const;
   GraphicsChannel *get_channel() const;
-  GraphicsWindow *get_window() const;
+  GraphicsOutput *get_window() const;
   GraphicsPipe *get_pipe() const;
 
   void set_camera(const NodePath &camera);

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

@@ -5,6 +5,7 @@
 #include "graphicsChannel.cxx"
 #include "graphicsEngine.cxx"
 #include "graphicsLayer.cxx"
+#include "graphicsOutput.cxx"
 #include "graphicsPipe.cxx"
 #include "graphicsStateGuardian.cxx"
 #include "graphicsWindow.cxx"

+ 8 - 8
panda/src/display/graphicsChannel.cxx

@@ -17,7 +17,7 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "graphicsChannel.h"
-#include "graphicsWindow.h"
+#include "graphicsOutput.h"
 #include "graphicsLayer.h"
 #include "config_display.h"
 #include "mutexHolder.h"
@@ -42,10 +42,10 @@ GraphicsChannel() {
 //       Access: Public
 //  Description: This is public just so derived window types can
 //               easily call it.  Don't call it directly; instead, use
-//               GraphicsWindow::get_channel() to get a channel.
+//               GraphicsOutput::get_channel() to get a channel.
 ////////////////////////////////////////////////////////////////////
 GraphicsChannel::
-GraphicsChannel(GraphicsWindow *window)
+GraphicsChannel(GraphicsOutput *window)
   : _window(window)
 {
   _is_active = true;
@@ -201,14 +201,14 @@ get_layer(int index) const {
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsChannel::get_window
 //       Access: Published
-//  Description: Returns the GraphicsWindow that this channel is
+//  Description: Returns the GraphicsOutput that this channel is
 //               associated with.  It is possible that the
-//               GraphicsWindow might have been deleted while an
+//               GraphicsOutput might have been deleted while an
 //               outstanding PT(GraphicsChannel) prevented all of its
 //               children channels from also being deleted; in this
 //               unlikely case, get_window() may return NULL.
 ////////////////////////////////////////////////////////////////////
-GraphicsWindow *GraphicsChannel::
+GraphicsOutput *GraphicsChannel::
 get_window() const {
   MutexHolder holder(_lock);
   return _window;
@@ -224,7 +224,7 @@ get_window() const {
 GraphicsPipe *GraphicsChannel::
 get_pipe() const {
   MutexHolder holder(_lock);
-  return (_window != (GraphicsWindow *)NULL) ? _window->get_pipe() : NULL;
+  return (_window != (GraphicsOutput *)NULL) ? _window->get_pipe() : NULL;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -274,7 +274,7 @@ window_resized(int x_size, int y_size) {
 ////////////////////////////////////////////////////////////////////
 void GraphicsChannel::
 win_display_regions_changed() {
-  if (_window != (GraphicsWindow *)NULL) {
+  if (_window != (GraphicsOutput *)NULL) {
     _window->win_display_regions_changed();
   }
 }

+ 7 - 7
panda/src/display/graphicsChannel.h

@@ -28,14 +28,14 @@
 
 class GraphicsChannel;
 class GraphicsPipe;
-class GraphicsWindow;
+class GraphicsOutput;
 class CullHandler;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : GraphicsChannel
 // Description : This represents a single hardware output.  Typically
-//               there is exactly one channel per window, but some
-//               implementations (e.g. SGI) support potentially
+//               there is exactly one channel per GraphicsOutput, but
+//               some implementations (e.g. SGI) support potentially
 //               several different video channel ports connected to
 //               different parts within a window.
 ////////////////////////////////////////////////////////////////////
@@ -44,7 +44,7 @@ protected:
   GraphicsChannel();
 
 public:
-  GraphicsChannel(GraphicsWindow *window);
+  GraphicsChannel(GraphicsOutput *window);
 
 private:
   GraphicsChannel(const GraphicsChannel &copy);
@@ -59,7 +59,7 @@ PUBLISHED:
   int get_num_layers() const;
   GraphicsLayer *get_layer(int index) const;
 
-  GraphicsWindow *get_window() const;
+  GraphicsOutput *get_window() const;
   GraphicsPipe *get_pipe() const;
 
   void set_active(bool active);
@@ -73,7 +73,7 @@ private:
 
 protected:
   Mutex _lock;
-  GraphicsWindow *_window;
+  GraphicsOutput *_window;
   bool _is_active;
 
   typedef ov_multiset< PT(GraphicsLayer), IndirectLess<GraphicsLayer> > GraphicsLayers;
@@ -99,7 +99,7 @@ public:
 private:
   static TypeHandle _type_handle;
 
-  friend class GraphicsWindow;
+  friend class GraphicsOutput;
   friend class GraphicsLayer;
 };
 

+ 22 - 30
panda/src/display/graphicsEngine.cxx

@@ -211,7 +211,7 @@ make_window(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
   PT(GraphicsWindow) window = pipe->make_window(gsg);
   if (window != (GraphicsWindow *)NULL) {
     MutexHolder holder(_lock);
-    _windows.insert(window);
+    _windows.insert(window.p());
 
     WindowRenderer *cull = get_window_renderer(threading_model.get_cull_name());
     WindowRenderer *draw = get_window_renderer(threading_model.get_draw_name());
@@ -263,9 +263,9 @@ make_window(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
 //               at a time.
 ////////////////////////////////////////////////////////////////////
 bool GraphicsEngine::
-remove_window(GraphicsWindow *window) {
+remove_window(GraphicsOutput *window) {
   // First, make sure we know what this window is.
-  PT(GraphicsWindow) ptwin = window;
+  PT(GraphicsOutput) ptwin = window;
   size_t count;
   {
     MutexHolder holder(_lock);
@@ -291,7 +291,7 @@ void GraphicsEngine::
 remove_all_windows() {
   Windows::iterator wi;
   for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
-    GraphicsWindow *win = (*wi);
+    GraphicsOutput *win = (*wi);
     do_remove_window(win);
   }
 
@@ -314,7 +314,7 @@ void GraphicsEngine::
 reset_all_windows(bool swapchain) {
   Windows::iterator wi;
   for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
-    GraphicsWindow *win = (*wi);
+    GraphicsOutput *win = (*wi);
     //    if (win->is_active())
     win->reset_window(swapchain);
   }
@@ -477,7 +477,7 @@ void GraphicsEngine::
 cull_and_draw_together(const GraphicsEngine::Windows &wlist) {
   Windows::const_iterator wi;
   for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
-    GraphicsWindow *win = (*wi);
+    GraphicsOutput *win = (*wi);
     if (win->is_active()) {
       if (win->begin_frame()) {
         win->clear();
@@ -533,7 +533,7 @@ void GraphicsEngine::
 cull_bin_draw(const GraphicsEngine::Windows &wlist) {
   Windows::const_iterator wi;
   for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
-    GraphicsWindow *win = (*wi);
+    GraphicsOutput *win = (*wi);
     if (win->is_active()) {
       // This should be done in the draw thread, not here.
       if (win->begin_frame()) {
@@ -596,7 +596,7 @@ void GraphicsEngine::
 process_events(const GraphicsEngine::Windows &wlist) {
   Windows::const_iterator wi;
   for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
-    GraphicsWindow *win = (*wi);
+    GraphicsOutput *win = (*wi);
     win->process_events();
   }
 }
@@ -612,11 +612,11 @@ void GraphicsEngine::
 flip_windows(const GraphicsEngine::Windows &wlist) {
   Windows::const_iterator wi;
   for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
-    GraphicsWindow *win = (*wi);
+    GraphicsOutput *win = (*wi);
     win->begin_flip();
   }
   for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
-    GraphicsWindow *win = (*wi);
+    GraphicsOutput *win = (*wi);
     win->end_flip();
   }
 }
@@ -853,7 +853,7 @@ setup_gsg(GraphicsStateGuardian *gsg, SceneSetup *scene_setup) {
 //               _windows list itself.
 ////////////////////////////////////////////////////////////////////
 void GraphicsEngine::
-do_remove_window(GraphicsWindow *window) {
+do_remove_window(GraphicsOutput *window) {
   PT(GraphicsPipe) pipe = window->get_pipe();
   window->_pipe = (GraphicsPipe *)NULL;
 
@@ -967,7 +967,7 @@ add_gsg(GraphicsStateGuardian *gsg) {
 //               be a member of the WindowRenderer.
 ////////////////////////////////////////////////////////////////////
 void GraphicsEngine::WindowRenderer::
-add_window(Windows &wlist, GraphicsWindow *window) {
+add_window(Windows &wlist, GraphicsOutput *window) {
   MutexHolder holder(_wl_lock);
   wlist.insert(window);
 }
@@ -981,9 +981,9 @@ add_window(Windows &wlist, GraphicsWindow *window) {
 //               list for later closure.
 ////////////////////////////////////////////////////////////////////
 void GraphicsEngine::WindowRenderer::
-remove_window(GraphicsWindow *window) {
+remove_window(GraphicsOutput *window) {
   MutexHolder holder(_wl_lock);
-  PT(GraphicsWindow) ptwin = window;
+  PT(GraphicsOutput) ptwin = window;
 
   _cull.erase(ptwin);
 
@@ -1020,14 +1020,12 @@ remove_window(GraphicsWindow *window) {
     // thread.
 
     // Make sure the window isn't about to request itself open.
-    WindowProperties close_properties;
-    close_properties.set_open(false);
-    ptwin->request_properties(close_properties);
+    ptwin->request_close();
 
     // If the window is already open, move it to the _pending_close list so
     // it can be closed later.  We can't close it immediately, because
     // we might not have been called from the subthread.
-    if (!ptwin->is_closed()) {
+    if (ptwin->is_valid()) {
       _pending_close.insert(ptwin);
     }
 
@@ -1095,7 +1093,7 @@ do_release(GraphicsEngine *) {
   MutexHolder holder(_wl_lock);
   Windows::iterator wi;
   for (wi = _draw.begin(); wi != _draw.end(); ++wi) {
-    GraphicsWindow *win = (*wi);
+    GraphicsOutput *win = (*wi);
     win->release_gsg();
   }
 }
@@ -1107,14 +1105,11 @@ do_release(GraphicsEngine *) {
 ////////////////////////////////////////////////////////////////////
 void GraphicsEngine::WindowRenderer::
 do_close(GraphicsEngine *engine) {
-  WindowProperties close_properties;
-  close_properties.set_open(false);
-
   MutexHolder holder(_wl_lock);
   Windows::iterator wi;
   for (wi = _window.begin(); wi != _window.end(); ++wi) {
-    GraphicsWindow *win = (*wi);
-    win->set_properties_now(close_properties);
+    GraphicsOutput *win = (*wi);
+    win->set_close_now();
   }
 
   // Also close all of the GSG's.
@@ -1149,24 +1144,21 @@ do_pending(GraphicsEngine *engine) {
     // Release any GSG's that were waiting.
     Windows::iterator wi;
     for (wi = _pending_release.begin(); wi != _pending_release.end(); ++wi) {
-      GraphicsWindow *win = (*wi);
+      GraphicsOutput *win = (*wi);
       win->release_gsg();
     }
     _pending_release.clear();
   }
 
   if (!_pending_close.empty()) {
-    WindowProperties close_properties;
-    close_properties.set_open(false);
-
     // Close any windows that were pending closure, but only if their
     // associated GSG has already been released.
     Windows new_pending_close;
     Windows::iterator wi;
     for (wi = _pending_close.begin(); wi != _pending_close.end(); ++wi) {
-      GraphicsWindow *win = (*wi);
+      GraphicsOutput *win = (*wi);
       if (win->get_gsg() == (GraphicsStateGuardian *)NULL) {
-        win->set_properties_now(close_properties);
+        win->set_close_now();
       } else {
         // If the GSG hasn't been released yet, we have to save the
         // close operation for next frame.

+ 5 - 5
panda/src/display/graphicsEngine.h

@@ -75,7 +75,7 @@ PUBLISHED:
   GraphicsWindow *make_window(GraphicsPipe *pipe,
                               GraphicsStateGuardian *gsg,
                               const GraphicsThreadingModel &threading_model);
-  bool remove_window(GraphicsWindow *window);
+  bool remove_window(GraphicsOutput *window);
   void remove_all_windows();
   void reset_all_windows(bool swapchain);
   bool is_empty() const;
@@ -97,7 +97,7 @@ public:
   };
 
 private:
-  typedef pset< PT(GraphicsWindow) > Windows;
+  typedef pset< PT(GraphicsOutput) > Windows;
   typedef pset< PT(GraphicsStateGuardian) > GSGs;
 
   void cull_and_draw_together(const Windows &wlist);
@@ -121,7 +121,7 @@ private:
 
   bool setup_gsg(GraphicsStateGuardian *gsg, SceneSetup *scene_setup);
 
-  void do_remove_window(GraphicsWindow *window);
+  void do_remove_window(GraphicsOutput *window);
   void terminate_threads();
 
   // The WindowRenderer class records the stages of the pipeline that
@@ -130,8 +130,8 @@ private:
   class WindowRenderer {
   public:
     void add_gsg(GraphicsStateGuardian *gsg);
-    void add_window(Windows &wlist, GraphicsWindow *window);
-    void remove_window(GraphicsWindow *window);
+    void add_window(Windows &wlist, GraphicsOutput *window);
+    void remove_window(GraphicsOutput *window);
     void do_frame(GraphicsEngine *engine);
     void do_flip(GraphicsEngine *engine);
     void do_release(GraphicsEngine *engine);

+ 3 - 3
panda/src/display/graphicsLayer.cxx

@@ -18,7 +18,7 @@
 
 #include "graphicsLayer.h"
 #include "graphicsChannel.h"
-#include "graphicsWindow.h"
+#include "graphicsOutput.h"
 #include "config_display.h"
 #include "notify.h"
 #include "mutexHolder.h"
@@ -222,11 +222,11 @@ get_channel() const {
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsLayer::get_window
 //       Access: Published
-//  Description: Returns the GraphicsWindow that this layer is
+//  Description: Returns the GraphicsOutput that this layer is
 //               ultimately associated with, or NULL if no window is
 //               associated.
 ////////////////////////////////////////////////////////////////////
-GraphicsWindow *GraphicsLayer::
+GraphicsOutput *GraphicsLayer::
 get_window() const {
   MutexHolder holder(_lock);
   return (_channel != (GraphicsChannel *)NULL) ? _channel->get_window() : NULL;

+ 3 - 3
panda/src/display/graphicsLayer.h

@@ -28,7 +28,7 @@
 #include "pvector.h"
 
 class GraphicsChannel;
-class GraphicsWindow;
+class GraphicsOutput;
 class GraphicsPipe;
 class CullHandler;
 
@@ -67,7 +67,7 @@ PUBLISHED:
   bool remove_dr(DisplayRegion *display_region);
 
   GraphicsChannel *get_channel() const;
-  GraphicsWindow *get_window() const;
+  GraphicsOutput *get_window() const;
   GraphicsPipe *get_pipe() const;
 
   void set_active(bool active);
@@ -109,7 +109,7 @@ private:
   static TypeHandle _type_handle;
 
   friend class GraphicsChannel;
-  friend class GraphicsWindow;
+  friend class GraphicsOutput;
   friend class DisplayRegion;
 };
 

+ 142 - 0
panda/src/display/graphicsOutput.I

@@ -0,0 +1,142 @@
+// Filename: graphicsOutput.I
+// Created by:  drose (06Feb04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::get_gsg
+//       Access: Published
+//  Description: Returns the GSG that is associated with this window.
+//               There is a one-to-one association between windows and
+//               GSG's.
+//
+//               This may return NULL if the graphics context has not
+//               yet been created for the window, e.g. before the
+//               first frame has rendered; or after the window has
+//               been closed.
+////////////////////////////////////////////////////////////////////
+INLINE GraphicsStateGuardian *GraphicsOutput::
+get_gsg() const {
+  return _gsg;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::get_pipe
+//       Access: Published
+//  Description: Returns the GraphicsPipe that this window is
+//               associated with.  It is possible that the
+//               GraphicsPipe might have been deleted while an
+//               outstanding PT(GraphicsOutput) prevented all of its
+//               children windows from also being deleted; in this
+//               unlikely case, get_pipe() may return NULL.
+////////////////////////////////////////////////////////////////////
+INLINE GraphicsPipe *GraphicsOutput::
+get_pipe() const {
+  return _pipe;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::get_x_size
+//       Access: Published
+//  Description: Returns the width of the graphics frame buffer, if it
+//               is known.  In certain cases (e.g. fullscreen
+//               windows), the size may not be known until after the
+//               object has been fully created.  Check has_size()
+//               first.
+//
+//               Certain objects (like windows) may change size
+//               spontaneously; this method is not thread-safe.  To
+//               get the size of a window in a thread-safe manner,
+//               query get_properties().
+////////////////////////////////////////////////////////////////////
+INLINE int GraphicsOutput::
+get_x_size() const {
+  return _x_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::get_y_size
+//       Access: Published
+//  Description: Returns the height of the graphics frame buffer, if it
+//               is known.  In certain cases (e.g. fullscreen
+//               windows), the size may not be known until after the
+//               object has been fully created.  Check has_size()
+//               first.
+//
+//               Certain objects (like windows) may change size
+//               spontaneously; this method is not thread-safe.  To
+//               get the size of a window in a thread-safe manner,
+//               query get_properties().
+////////////////////////////////////////////////////////////////////
+INLINE int GraphicsOutput::
+get_y_size() const {
+  return _y_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::has_size
+//       Access: Published
+//  Description: Returns true if the size of the window/frame buffer
+//               is known, false otherwise.  In certain cases the size
+//               may not be known until after the object has been
+//               fully created.  Also, certain objects (like windows)
+//               may change size spontaneously.
+////////////////////////////////////////////////////////////////////
+INLINE bool GraphicsOutput::
+has_size() const {
+  return _has_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::is_valid
+//       Access: Published
+//  Description: Returns true if the output is fully created and ready
+//               for rendering, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool GraphicsOutput::
+is_valid() const {
+  return _is_valid;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::win_display_regions_changed
+//       Access: Public
+//  Description: Intended to be called when the active state on a
+//               nested channel or layer or display region changes,
+//               forcing the window to recompute its list of active
+//               display regions.
+////////////////////////////////////////////////////////////////////
+INLINE void GraphicsOutput::
+win_display_regions_changed() {
+  _display_regions_stale = true;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::determine_display_regions
+//       Access: Private
+//  Description: Recomputes the list of active DisplayRegions within
+//               the window, if they have changed recently.
+////////////////////////////////////////////////////////////////////
+INLINE void GraphicsOutput::
+determine_display_regions() const {
+  // This function isn't strictly speaking const, but we pretend it is
+  // because it only updates a transparent cache value.
+  if (_display_regions_stale) {
+    ((GraphicsOutput *)this)->do_determine_display_regions();
+  }
+}

+ 663 - 0
panda/src/display/graphicsOutput.cxx

@@ -0,0 +1,663 @@
+// Filename: graphicsOutput.cxx
+// Created by:  drose (06Feb04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "graphicsOutput.h"
+#include "graphicsPipe.h"
+#include "config_display.h"
+#include "mutexHolder.h"
+#include "hardwareChannel.h"
+
+TypeHandle GraphicsOutput::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::Constructor
+//       Access: Protected
+//  Description: Normally, the GraphicsOutput constructor is not
+//               called directly; these are created instead via the
+//               GraphicsEngine::make_window() function.
+////////////////////////////////////////////////////////////////////
+GraphicsOutput::
+GraphicsOutput(GraphicsPipe *pipe, GraphicsStateGuardian *gsg) {
+#ifdef DO_MEMORY_USAGE
+  MemoryUsage::update_type(this, this);
+#endif
+  _pipe = pipe;
+  _gsg = gsg;
+  _x_size = 0;
+  _y_size = 0;
+  _has_size = false;
+  _is_valid = false;
+
+  _display_regions_stale = false;
+
+  // By default, each new GraphicsOutput is set up to clear color and
+  // depth.
+  set_clear_color_active(true);
+  set_clear_depth_active(true);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::Copy Constructor
+//       Access: Private
+//  Description:
+////////////////////////////////////////////////////////////////////
+GraphicsOutput::
+GraphicsOutput(const GraphicsOutput &) {
+  nassertv(false);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::Copy Assignment Operator
+//       Access: Private
+//  Description:
+////////////////////////////////////////////////////////////////////
+void GraphicsOutput::
+operator = (const GraphicsOutput &) {
+  nassertv(false);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::Destructor
+//       Access: Published, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+GraphicsOutput::
+~GraphicsOutput() {
+  // The window should be closed by the time we destruct.
+  nassertv(!is_valid());
+
+  // We shouldn't have a GraphicsPipe pointer anymore.
+  nassertv(_pipe == (GraphicsPipe *)NULL);
+
+  // We don't have to destruct our child channels explicitly, since
+  // they are all reference-counted and will go away when their
+  // pointers do.  However, we do need to zero out their pointers to
+  // us.
+  Channels::iterator ci;
+  for (ci = _channels.begin(); ci != _channels.end(); ++ci) {
+    (*ci)->_window = NULL;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::is_active
+//       Access: Published, Virtual
+//  Description: Returns true if the window is ready to be rendered
+//               into, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool GraphicsOutput::
+is_active() const {
+  return is_valid();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::get_channel
+//       Access: Public
+//  Description: Returns a GraphicsChannel pointer that can be used to
+//               access the indicated channel number.  All windows
+//               have at least one channel, channel 0, which
+//               corresponds to the entire window.  If the hardware
+//               supports it, some kinds of windows may also have a
+//               number of hardware channels available at indices
+//               1..n, which will correspond to a subregion of the
+//               window.
+//
+//               This function returns a GraphicsChannel pointer if a
+//               channel is available, or NULL if it is not.  If
+//               called twice with the same index number, it will
+//               return the same pointer.
+////////////////////////////////////////////////////////////////////
+GraphicsChannel *GraphicsOutput::
+get_channel(int index) {
+  MutexHolder holder(_lock);
+  nassertr(index >= 0, NULL);
+
+  if (index < (int)_channels.size()) {
+    if (_channels[index] != (GraphicsChannel *)NULL) {
+      return _channels[index];
+    }
+  }
+
+  // This channel has never been requested before; define it.
+
+  PT(GraphicsChannel) chan;
+  if (index == 0) {
+    // Channel 0 is the default channel: the entire screen.
+    chan = new GraphicsChannel(this);
+  } else {
+    // Any other channel is some hardware-specific channel.
+    GraphicsPipe *pipe = _pipe;
+    if (pipe != (GraphicsPipe *)NULL) {
+      chan = _pipe->get_hw_channel(this, index);
+      if (chan == (GraphicsChannel *)NULL) {
+        display_cat.error()
+          << "GraphicsOutput::get_channel() - got a NULL channel" << endl;
+      } else {
+        if (chan->get_window() != this) {
+          chan = NULL;
+        }
+      }
+    }
+  }
+
+  if (chan != (GraphicsChannel *)NULL) {
+    declare_channel(index, chan);
+  }
+
+  return chan;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::remove_channel
+//       Access: Public
+//  Description: Deletes a GraphicsChannel that was previously created
+//               via a call to get_channel().  Note that the channel
+//               is not actually deleted until all pointers to it are
+//               cleared.
+////////////////////////////////////////////////////////////////////
+void GraphicsOutput::
+remove_channel(int index) {
+  MutexHolder holder(_lock);
+  if (index >= 0 && index < (int)_channels.size()) {
+    _channels[index].clear();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::get_max_channel_index
+//       Access: Public
+//  Description: Returns the largest channel index number yet created,
+//               plus 1.  All channels associated with this window
+//               will have an index number in the range [0,
+//               get_max_channel_index()).  This function, in
+//               conjunction with is_channel_defined(), below, may be
+//               used to determine the complete set of channels
+//               associated with the window.
+////////////////////////////////////////////////////////////////////
+int GraphicsOutput::
+get_max_channel_index() const {
+  int result;
+  {
+    MutexHolder holder(_lock);
+    result = _channels.size();
+  }
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::is_channel_defined
+//       Access: Public
+//  Description: Returns true if the channel with the given index
+//               number has already been defined, false if it hasn't.
+//               If this returns true, calling get_channel() on the
+//               given index number will return the channel pointer.
+//               If it returns false, calling get_channel() will
+//               create and return a new channel pointer.
+////////////////////////////////////////////////////////////////////
+bool GraphicsOutput::
+is_channel_defined(int index) const {
+  bool result;
+  {
+    MutexHolder holder(_lock);
+    if (index < 0 || index >= (int)_channels.size()) {
+      result = false;
+    } else {
+      result = (_channels[index] != (GraphicsChannel *)NULL);
+    }
+  }
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::get_num_display_regions
+//       Access: Published
+//  Description: Returns the number of active DisplayRegions that have
+//               been created within the various layers and channels
+//               of the window.
+////////////////////////////////////////////////////////////////////
+int GraphicsOutput::
+get_num_display_regions() const {
+  determine_display_regions();
+  int result;
+  {
+    MutexHolder holder(_lock);
+    result = _display_regions.size();
+  }
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::get_display_region
+//       Access: Published
+//  Description: Returns the nth active DisplayRegion of those that
+//               have been created within the various layers and
+//               channels of the window.  This may return NULL if n is
+//               out of bounds; particularly likely if the number of
+//               display regions has changed since the last call to
+//               get_num_display_regions().
+////////////////////////////////////////////////////////////////////
+DisplayRegion *GraphicsOutput::
+get_display_region(int n) const {
+  determine_display_regions();
+  DisplayRegion *result;
+  {
+    MutexHolder holder(_lock);
+    if (n >= 0 && n < (int)_display_regions.size()) {
+      result = _display_regions[n];
+    } else {
+      result = NULL;
+    }
+  }
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::take_screenshot
+//       Access: Published
+//  Description: Saves a screenshot of the window to a default
+//               filename, and returns the filename, or empty string
+//               if the screenshot failed.  The default filename is
+//               generated from the supplied prefix and from the
+//               Configrc variable screenshot-filename, which contains
+//               the following strings:
+//
+//                 %~p - the supplied prefix
+//                 %~f - the frame count
+//                 %~e - the value of screenshot-extension
+//                 All other % strings in strftime().
+////////////////////////////////////////////////////////////////////
+Filename GraphicsOutput::
+take_screenshot(const string &prefix) {
+  time_t now = time(NULL);
+  struct tm *ttm = localtime(&now);
+  int frame_count = ClockObject::get_global_clock()->get_frame_count();
+
+  static const int buffer_size = 1024;
+  char buffer[buffer_size];
+
+  ostringstream filename_strm;
+
+  size_t i = 0;
+  while (i < screenshot_filename.length()) {
+    char ch1 = screenshot_filename[i++];
+    if (ch1 == '%' && i < screenshot_filename.length()) {
+      char ch2 = screenshot_filename[i++];
+      if (ch2 == '~' && i < screenshot_filename.length()) {
+        char ch3 = screenshot_filename[i++];
+        switch (ch3) {
+        case 'p':
+          filename_strm << prefix;
+          break;
+
+        case 'f':
+          filename_strm << frame_count;
+          break;
+
+        case 'e':
+          filename_strm << screenshot_extension;
+          break;
+        }
+
+      } else {
+        // Use strftime() to decode the percent code.
+        char format[3] = {'%', ch2, '\0'};
+        if (strftime(buffer, buffer_size, format, ttm)) {
+          for (char *b = buffer; *b != '\0'; b++) {
+            switch (*b) {
+            case ' ':
+            case ':':
+            case '/':
+              filename_strm << '-';
+              break;
+
+            case '\n':
+              break;
+
+            default:
+              filename_strm << *b;
+            }
+          }
+        }
+      }
+    } else {
+      filename_strm << ch1;
+    }
+  }
+
+  Filename filename = filename_strm.str();
+  if (take_screenshot(filename)) {
+    return filename;
+  }
+  return Filename();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::take_screenshot
+//       Access: Published
+//  Description: Saves a screenshot of the window to the indicated
+//               filename.  Returns true on success, false on failure.
+////////////////////////////////////////////////////////////////////
+bool GraphicsOutput::
+take_screenshot(const Filename &filename) {
+  if (_gsg == (GraphicsStateGuardian *)NULL) {
+    return false;
+  }
+
+  if (!is_valid()) {
+    return false;
+  }
+
+  PixelBuffer p(_x_size, _y_size, 3, 1, PixelBuffer::T_unsigned_byte,
+                PixelBuffer::F_rgb);
+
+  DisplayRegion dr(_x_size, _y_size);
+  RenderBuffer rb = _gsg->get_render_buffer(RenderBuffer::T_front);
+  if (!p.copy(_gsg, &dr, rb)) {
+    return false;
+  }
+
+  if (!p.write(filename)) {
+    return false;
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::make_scratch_display_region
+//       Access: Public
+//  Description: Allocates and returns a temporary DisplayRegion that
+//               may be used to render offscreen into.  This
+//               DisplayRegion is not associated with any layer.
+//
+//               To allocate a normal DisplayRegion for rendering, use
+//               the interface provided in GraphicsLayer.
+////////////////////////////////////////////////////////////////////
+PT(DisplayRegion) GraphicsOutput::
+make_scratch_display_region(int x_size, int y_size) const {
+#ifndef NDEBUG
+  if (x_size > _x_size || y_size > _y_size) {
+    display_cat.error()
+      << "make_scratch_display_region(): requested region of size " 
+      << x_size << ", " << y_size << " is larger than window of size "
+      << _x_size << ", " << _y_size << ".\n";
+    x_size = min(x_size, _x_size);
+    y_size = min(y_size, _y_size);
+  }
+#endif
+
+  PT(DisplayRegion) region = new DisplayRegion(x_size, y_size);
+  region->copy_clear_settings(*this);
+  return region;
+}
+ 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::request_open
+//       Access: Public, Virtual
+//  Description: This is called by the GraphicsEngine to request that
+//               the window (or whatever) open itself or, in general,
+//               make itself valid, at the next call to
+//               process_events().
+////////////////////////////////////////////////////////////////////
+void GraphicsOutput::
+request_open() {
+}
+ 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::request_close
+//       Access: Public, Virtual
+//  Description: This is called by the GraphicsEngine to request that
+//               the window (or whatever) close itself or, in general,
+//               make itself invalid, at the next call to
+//               process_events().  By that time we promise the gsg
+//               pointer will be cleared.
+////////////////////////////////////////////////////////////////////
+void GraphicsOutput::
+request_close() {
+}
+ 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::set_close_now
+//       Access: Public, Virtual
+//  Description: This is called by the GraphicsEngine to insist that
+//               the output be closed immediately.  This is only
+//               called from the window thread.
+////////////////////////////////////////////////////////////////////
+void GraphicsOutput::
+set_close_now() {
+}
+ 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::begin_frame
+//       Access: Public, Virtual
+//  Description: This function will be called within the draw thread
+//               before beginning rendering for a given frame.  It
+//               should do whatever setup is required, and return true
+//               if the frame should be rendered, or false if it
+//               should be skipped.
+////////////////////////////////////////////////////////////////////
+bool GraphicsOutput::
+begin_frame() {
+  if (_gsg == (GraphicsStateGuardian *)NULL) {
+    return false;
+  }
+
+  // Okay, we already have a GSG, so activate it.
+  make_current();
+  return _gsg->begin_frame();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::clear
+//       Access: Public
+//  Description: Clears the entire framebuffer before rendering,
+//               according to the settings of get_color_clear_active()
+//               and get_depth_clear_active() (inherited from
+//               ClearableRegion).
+//
+//               This function is called only within the draw thread.
+////////////////////////////////////////////////////////////////////
+void GraphicsOutput::
+clear() {
+  if (is_any_clear_active()) {
+    nassertv(_gsg != (GraphicsStateGuardian *)NULL);
+
+    PT(DisplayRegion) win_dr =
+      make_scratch_display_region(_x_size, _y_size);
+    DisplayRegionStack old_dr = _gsg->push_display_region(win_dr);
+    _gsg->clear(this);
+    _gsg->pop_display_region(old_dr);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::end_frame
+//       Access: Public, Virtual
+//  Description: This function will be called within the draw thread
+//               after rendering is completed for a given frame.  It
+//               should do whatever finalization is required.
+////////////////////////////////////////////////////////////////////
+void GraphicsOutput::
+end_frame() {
+  nassertv(_gsg != (GraphicsStateGuardian *)NULL);
+  _gsg->end_frame();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::make_current
+//       Access: Public, Virtual
+//  Description: This function will be called within the draw thread
+//               during begin_frame() to ensure the graphics context
+//               is ready for drawing.
+////////////////////////////////////////////////////////////////////
+void GraphicsOutput::
+make_current() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     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();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::begin_flip
+//       Access: Public, Virtual
+//  Description: This function will be called within the draw thread
+//               after end_frame() has been called on all windows, to
+//               initiate the exchange of the front and back buffers.
+//
+//               This should instruct the window to prepare for the
+//               flip at the next video sync, but it should not wait.
+//
+//               We have the two separate functions, begin_flip() and
+//               end_flip(), to make it easier to flip all of the
+//               windows at the same time.
+////////////////////////////////////////////////////////////////////
+void GraphicsOutput::
+begin_flip() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::end_flip
+//       Access: Public, Virtual
+//  Description: This function will be called within the draw thread
+//               after begin_flip() has been called on all windows, to
+//               finish the exchange of the front and back buffers.
+//
+//               This should cause the window to wait for the flip, if
+//               necessary.
+////////////////////////////////////////////////////////////////////
+void GraphicsOutput::
+end_flip() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::process_events
+//       Access: Public, Virtual
+//  Description: Do whatever processing in the window thread is
+//               appropriate for this output object each frame.
+//
+//               This function is called only within the window
+//               thread.
+////////////////////////////////////////////////////////////////////
+void GraphicsOutput::
+process_events() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::close_window
+//       Access: Protected, Virtual
+//  Description: Closes the window right now.  Called from the window
+//               thread.
+////////////////////////////////////////////////////////////////////
+void GraphicsOutput::
+close_window() {
+  display_cat.info()
+    << "Closing " << get_type() << "\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::reset_window
+//       Access: Protected, Virtual
+//  Description: resets the window framebuffer from its derived
+//               children. Does nothing here.
+////////////////////////////////////////////////////////////////////
+void GraphicsOutput::
+reset_window(bool swapchain) {
+  display_cat.info()
+    << "Resetting " << get_type() << "\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::open_window
+//       Access: Protected, Virtual
+//  Description: Opens the window right now.  Called from the window
+//               thread.  Returns true if the window is successfully
+//               opened, or false if there was a problem.
+////////////////////////////////////////////////////////////////////
+bool GraphicsOutput::
+open_window() {
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::declare_channel
+//       Access: Protected
+//  Description: An internal function to add the indicated
+//               newly-created channel to the list at the indicated
+//               channel number.
+//
+//               The caller must grab and hold _lock before making
+//               this call.
+////////////////////////////////////////////////////////////////////
+void GraphicsOutput::
+declare_channel(int index, GraphicsChannel *chan) {
+  nassertv(index >= 0);
+  if (index >= (int)_channels.size()) {
+    _channels.reserve(index);
+    while (index >= (int)_channels.size()) {
+      _channels.push_back(NULL);
+    }
+  }
+
+  nassertv(index < (int)_channels.size());
+  _channels[index] = chan;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::do_determine_display_regions
+//       Access: Private
+//  Description: Recomputes the list of active DisplayRegions within
+//               the window.
+////////////////////////////////////////////////////////////////////
+void GraphicsOutput::
+do_determine_display_regions() {
+  MutexHolder holder(_lock);
+  _display_regions_stale = false;
+  _display_regions.clear();
+  Channels::const_iterator ci;
+  for (ci = _channels.begin(); ci != _channels.end(); ++ci) {
+    GraphicsChannel *chan = (*ci);
+    if (chan->is_active()) {
+      GraphicsChannel::GraphicsLayers::const_iterator li;
+      for (li = chan->_layers.begin(); li != chan->_layers.end(); ++li) {
+        GraphicsLayer *layer = (*li);
+        if (layer->is_active()) {
+          GraphicsLayer::DisplayRegions::const_iterator dri;
+          for (dri = layer->_display_regions.begin(); 
+               dri != layer->_display_regions.end(); 
+               ++dri) {
+            DisplayRegion *dr = (*dri);
+            if (dr->is_active()) {
+              _display_regions.push_back(dr);
+            }
+          }
+        }
+      }
+    }
+  }
+}

+ 180 - 0
panda/src/display/graphicsOutput.h

@@ -0,0 +1,180 @@
+// Filename: graphicsOutput.h
+// Created by:  drose (06Feb04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef GRAPHICSOUTPUT_H
+#define GRAPHICSOUTPUT_H
+
+#include "pandabase.h"
+
+#include "graphicsChannel.h"
+#include "graphicsPipe.h"
+#include "displayRegion.h"
+#include "graphicsStateGuardian.h"
+#include "clearableRegion.h"
+
+#include "typedWritableReferenceCount.h"
+#include "notify.h"
+#include "pmutex.h"
+#include "filename.h"
+#include "pvector.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : GraphicsOutput
+// Description : This is a base class for the various different
+//               classes that represent the result of a frame of
+//               rendering.  The most common kind of GraphicsOutput is
+//               a GraphicsWindow, which is a real-time window on the
+//               desktop, but other examples are GraphicsBuffer, which
+//               is an offscreen buffer, and GraphicsTexture, which is
+//               an offscreen texture that may be rendered into and
+//               then applied to geometry.
+//
+//               The actual rendering, and anything associated with
+//               the graphics context itself, is managed by the
+//               associated GraphicsStateGuardian (which might output
+//               to multiple GraphicsOutput objects).
+//
+//               GraphicsOutputs are not actually writable to bam
+//               files, of course, but they may be passed as event
+//               parameters, so they inherit from
+//               TypedWritableReferenceCount instead of
+//               TypedReferenceCount for that convenience.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA GraphicsOutput : public TypedWritableReferenceCount, public ClearableRegion {
+protected:
+  GraphicsOutput(GraphicsPipe *pipe, GraphicsStateGuardian *gsg);
+
+private:
+  GraphicsOutput(const GraphicsOutput &copy);
+  void operator = (const GraphicsOutput &copy);
+
+PUBLISHED:
+  virtual ~GraphicsOutput();
+
+  INLINE GraphicsStateGuardian *get_gsg() const;
+  INLINE GraphicsPipe *get_pipe() const;
+
+  INLINE int get_x_size() const;
+  INLINE int get_y_size() const;
+  INLINE bool has_size() const;
+  INLINE bool is_valid() const;
+
+  virtual bool is_active() const;
+
+  GraphicsChannel *get_channel(int index);
+  void remove_channel(int index);
+
+  int get_max_channel_index() const;
+  bool is_channel_defined(int index) const;
+
+  int get_num_display_regions() const;
+  DisplayRegion *get_display_region(int n) const;
+
+  Filename take_screenshot(const string &prefix = "screenshot");
+  bool take_screenshot(const Filename &filename);
+
+public:
+  // No need to publish these.
+  PT(DisplayRegion) make_scratch_display_region(int x_size, int y_size) const;
+
+public:
+  // These are not intended to be called directly by the user.
+  INLINE void win_display_regions_changed();
+
+  virtual void request_open();
+  virtual void request_close();
+  virtual void set_close_now();
+
+public:
+  // It is an error to call any of the following methods from any
+  // thread other than the draw thread.  These methods are normally
+  // called by the GraphicsEngine.
+  virtual bool begin_frame();
+  void clear();
+  virtual void end_frame();
+
+  // This method is called in the draw thread prior to issuing any
+  // drawing commands for the window.
+  virtual void make_current();
+  virtual void release_gsg();
+
+  // These methods will be called within the app (main) thread.
+  virtual void begin_flip();
+  virtual void end_flip();
+
+  // It is an error to call any of the following methods from any
+  // thread other than the window thread.  These methods are normally
+  // called by the GraphicsEngine.
+  virtual void process_events();
+
+protected:
+  virtual void close_window();
+  virtual bool open_window();
+  virtual void reset_window(bool swapchain);
+
+  void declare_channel(int index, GraphicsChannel *chan);
+  
+protected:
+  PT(GraphicsStateGuardian) _gsg;
+  PT(GraphicsPipe) _pipe;
+
+private:
+  INLINE void determine_display_regions() const;
+  void do_determine_display_regions();
+
+protected:
+  Mutex _lock; 
+  // protects _channels, _display_regions.
+
+  typedef pvector< PT(GraphicsChannel) > Channels;
+  Channels _channels;
+
+  typedef pvector<DisplayRegion *> DisplayRegions;
+  DisplayRegions _display_regions;
+  bool _display_regions_stale;
+
+protected:
+  int _x_size;
+  int _y_size;
+  bool _has_size;
+  bool _is_valid;
+  
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TypedWritableReferenceCount::init_type();
+    register_type(_type_handle, "GraphicsOutput",
+                  TypedWritableReferenceCount::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+
+  friend class GraphicsPipe;
+  friend class GraphicsEngine;
+};
+
+#include "graphicsOutput.I"
+
+#endif /* GRAPHICSOUTPUT_H */

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

@@ -98,7 +98,7 @@ get_num_hw_channels() {
 //               always return NULL.
 ////////////////////////////////////////////////////////////////////
 HardwareChannel *GraphicsPipe::
-get_hw_channel(GraphicsWindow *, int) {
+get_hw_channel(GraphicsOutput *, int) {
   return (HardwareChannel*)0L;
 }
 

+ 3 - 4
panda/src/display/graphicsPipe.h

@@ -25,16 +25,15 @@
 #include "typedReferenceCount.h"
 #include "pointerTo.h"
 #include "pmutex.h"
-#include "pvector.h"
 
 class HardwareChannel;
-class GraphicsWindow;
+class GraphicsOutput;
 class GraphicsStateGuardian;
 class FrameBufferProperties;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : GraphicsPipe
-// Description : An object to create GraphicsWindows that share a
+// Description : An object to create GraphicsOutputs that share a
 //               particular 3-D API.  Normally, there will only be one
 //               GraphicsPipe in an application, although it is
 //               possible to have multiple of these at once if there
@@ -74,7 +73,7 @@ PUBLISHED:
 
 public:
   virtual int get_num_hw_channels();
-  virtual HardwareChannel *get_hw_channel(GraphicsWindow *window, int index);
+  virtual HardwareChannel *get_hw_channel(GraphicsOutput *window, int index);
 
   INLINE GraphicsDevice *get_device() const;
   virtual PT(GraphicsDevice) make_device(void *scrn = NULL);

+ 0 - 73
panda/src/display/graphicsWindow.I

@@ -33,18 +33,6 @@ is_closed() const {
   return !_properties.get_open();
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::is_active
-//       Access: Published
-//  Description: Returns true if the window is ready to be rendered
-//               into, false otherwise.
-////////////////////////////////////////////////////////////////////
-INLINE bool GraphicsWindow::
-is_active() const {
-  // Make this smarter?
-  return _properties.get_open() && !_properties.get_minimized();
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindow::is_fullscreen
 //       Access: Published
@@ -55,64 +43,3 @@ INLINE bool GraphicsWindow::
 is_fullscreen() const {
   return _properties.get_fullscreen();
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::get_gsg
-//       Access: Published
-//  Description: Returns the GSG that is associated with this window.
-//               There is a one-to-one association between windows and
-//               GSG's.
-//
-//               This may return NULL if the graphics context has not
-//               yet been created for the window, e.g. before the
-//               first frame has rendered; or after the window has
-//               been closed.
-////////////////////////////////////////////////////////////////////
-INLINE GraphicsStateGuardian *GraphicsWindow::
-get_gsg() const {
-  return _gsg;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::get_pipe
-//       Access: Published
-//  Description: Returns the GraphicsPipe that this window is
-//               associated with.  It is possible that the
-//               GraphicsPipe might have been deleted while an
-//               outstanding PT(GraphicsWindow) prevented all of its
-//               children windows from also being deleted; in this
-//               unlikely case, get_pipe() may return NULL.
-////////////////////////////////////////////////////////////////////
-INLINE GraphicsPipe *GraphicsWindow::
-get_pipe() const {
-  return _pipe;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::win_display_regions_changed
-//       Access: Public
-//  Description: Intended to be called when the active state on a
-//               nested channel or layer or display region changes,
-//               forcing the window to recompute its list of active
-//               display regions.
-////////////////////////////////////////////////////////////////////
-INLINE void GraphicsWindow::
-win_display_regions_changed() {
-  _display_regions_stale = true;
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::determine_display_regions
-//       Access: Private
-//  Description: Recomputes the list of active DisplayRegions within
-//               the window, if they have changed recently.
-////////////////////////////////////////////////////////////////////
-INLINE void GraphicsWindow::
-determine_display_regions() const {
-  // This function isn't strictly speaking const, but we pretend it is
-  // because it only updates a transparent cache value.
-  if (_display_regions_stale) {
-    ((GraphicsWindow *)this)->do_determine_display_regions();
-  }
-}

+ 65 - 564
panda/src/display/graphicsWindow.cxx

@@ -25,8 +25,6 @@
 #include "hardwareChannel.h"
 #include "throw_event.h"
 
-#include "pmap.h"
-
 TypeHandle GraphicsWindow::_type_handle;
 
 ////////////////////////////////////////////////////////////////////
@@ -37,12 +35,12 @@ TypeHandle GraphicsWindow::_type_handle;
 //               GraphicsEngine::make_window() function.
 ////////////////////////////////////////////////////////////////////
 GraphicsWindow::
-GraphicsWindow(GraphicsPipe *pipe, GraphicsStateGuardian *gsg) {
+GraphicsWindow(GraphicsPipe *pipe, GraphicsStateGuardian *gsg) :
+  GraphicsOutput(pipe, gsg)
+{
 #ifdef DO_MEMORY_USAGE
   MemoryUsage::update_type(this, this);
 #endif
-  _pipe = pipe;
-  _gsg = gsg;
 
   if (display_cat.is_debug()) {
     display_cat.debug()
@@ -58,32 +56,7 @@ GraphicsWindow(GraphicsPipe *pipe, GraphicsStateGuardian *gsg) {
   _properties.set_minimized(false);
   _properties.set_cursor_hidden(false);
 
-  _display_regions_stale = false;
   _window_event = "window-event";
-
-  // By default, windows are set up to clear color and depth.
-  set_clear_color_active(true);
-  set_clear_depth_active(true);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::Copy Constructor
-//       Access: Private
-//  Description:
-////////////////////////////////////////////////////////////////////
-GraphicsWindow::
-GraphicsWindow(const GraphicsWindow &) {
-  nassertv(false);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::Copy Assignment Operator
-//       Access: Private
-//  Description:
-////////////////////////////////////////////////////////////////////
-void GraphicsWindow::
-operator = (const GraphicsWindow &) {
-  nassertv(false);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -93,20 +66,6 @@ operator = (const GraphicsWindow &) {
 ////////////////////////////////////////////////////////////////////
 GraphicsWindow::
 ~GraphicsWindow() {
-  // The window should be closed by the time we destruct.
-  nassertv(!_properties.get_open());
-
-  // And we shouldn't have a GraphicsPipe pointer anymore.
-  nassertv(_pipe == (GraphicsPipe *)NULL);
-
-  // We don't have to destruct our child channels explicitly, since
-  // they are all reference-counted and will go away when their
-  // pointers do.  However, we do need to zero out their pointers to
-  // us.
-  Channels::iterator ci;
-  for (ci = _channels.begin(); ci != _channels.end(); ++ci) {
-    (*ci)->_window = NULL;
-  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -118,7 +77,7 @@ WindowProperties GraphicsWindow::
 get_properties() const {
   WindowProperties result;
   {
-    MutexHolder holder(_lock);
+    MutexHolder holder(_properties_lock);
     result = _properties;
   }
   return result;
@@ -136,7 +95,7 @@ WindowProperties GraphicsWindow::
 get_requested_properties() const {
   WindowProperties result;
   {
-    MutexHolder holder(_lock);
+    MutexHolder holder(_properties_lock);
     result = _requested_properties;
   }
   return result;
@@ -150,7 +109,7 @@ get_requested_properties() const {
 ////////////////////////////////////////////////////////////////////
 void GraphicsWindow::
 clear_rejected_properties() {
-  MutexHolder holder(_lock);
+  MutexHolder holder(_properties_lock);
   _rejected_properties.clear();
 }
 
@@ -167,7 +126,7 @@ WindowProperties GraphicsWindow::
 get_rejected_properties() const {
   WindowProperties result;
   {
-    MutexHolder holder(_lock);
+    MutexHolder holder(_properties_lock);
     result = _rejected_properties;
   }
   return result;
@@ -186,10 +145,22 @@ get_rejected_properties() const {
 ////////////////////////////////////////////////////////////////////
 void GraphicsWindow::
 request_properties(const WindowProperties &requested_properties) {
-  MutexHolder holder(_lock);
+  MutexHolder holder(_properties_lock);
   _requested_properties.add_properties(requested_properties);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsWindow::is_active
+//       Access: Published, Virtual
+//  Description: Returns true if the window is ready to be rendered
+//               into, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool GraphicsWindow::
+is_active() const {
+  // Make this smarter?
+  return _properties.get_open() && !_properties.get_minimized();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindow::set_window_event
 //       Access: Published
@@ -204,7 +175,7 @@ request_properties(const WindowProperties &requested_properties) {
 ////////////////////////////////////////////////////////////////////
 void GraphicsWindow::
 set_window_event(const string &window_event) {
-  MutexHolder holder(_lock);
+  MutexHolder holder(_properties_lock);
   _window_event = window_event;
 }
 
@@ -218,289 +189,11 @@ set_window_event(const string &window_event) {
 string GraphicsWindow::
 get_window_event() const {
   string result;
-  MutexHolder holder(_lock);
+  MutexHolder holder(_properties_lock);
   result = _window_event;
   return result;
 }
 
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::get_channel
-//       Access: Public
-//  Description: Returns a GraphicsChannel pointer that can be used to
-//               access the indicated channel number.  All windows
-//               have at least one channel, channel 0, which
-//               corresponds to the entire window.  If the hardware
-//               supports it, some kinds of windows may also have a
-//               number of hardware channels available at indices
-//               1..n, which will correspond to a subregion of the
-//               window.
-//
-//               This function returns a GraphicsChannel pointer if a
-//               channel is available, or NULL if it is not.  If
-//               called twice with the same index number, it will
-//               return the same pointer.
-////////////////////////////////////////////////////////////////////
-GraphicsChannel *GraphicsWindow::
-get_channel(int index) {
-  MutexHolder holder(_lock);
-  nassertr(index >= 0, NULL);
-
-  if (index < (int)_channels.size()) {
-    if (_channels[index] != (GraphicsChannel *)NULL) {
-      return _channels[index];
-    }
-  }
-
-  // This channel has never been requested before; define it.
-
-  PT(GraphicsChannel) chan;
-  if (index == 0) {
-    // Channel 0 is the default channel: the entire screen.
-    chan = new GraphicsChannel(this);
-  } else {
-    // Any other channel is some hardware-specific channel.
-    GraphicsPipe *pipe = _pipe;
-    if (pipe != (GraphicsPipe *)NULL) {
-      chan = _pipe->get_hw_channel(this, index);
-      if (chan == (GraphicsChannel *)NULL) {
-        display_cat.error()
-          << "GraphicsWindow::get_channel() - got a NULL channel" << endl;
-      } else {
-        if (chan->get_window() != this) {
-          chan = NULL;
-        }
-      }
-    }
-  }
-
-  if (chan != (GraphicsChannel *)NULL) {
-    declare_channel(index, chan);
-  }
-
-  return chan;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::remove_channel
-//       Access: Public
-//  Description: Deletes a GraphicsChannel that was previously created
-//               via a call to get_channel().  Note that the channel
-//               is not actually deleted until all pointers to it are
-//               cleared.
-////////////////////////////////////////////////////////////////////
-void GraphicsWindow::
-remove_channel(int index) {
-  MutexHolder holder(_lock);
-  if (index >= 0 && index < (int)_channels.size()) {
-    _channels[index].clear();
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::get_max_channel_index
-//       Access: Public
-//  Description: Returns the largest channel index number yet created,
-//               plus 1.  All channels associated with this window
-//               will have an index number in the range [0,
-//               get_max_channel_index()).  This function, in
-//               conjunction with is_channel_defined(), below, may be
-//               used to determine the complete set of channels
-//               associated with the window.
-////////////////////////////////////////////////////////////////////
-int GraphicsWindow::
-get_max_channel_index() const {
-  int result;
-  {
-    MutexHolder holder(_lock);
-    result = _channels.size();
-  }
-  return result;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::is_channel_defined
-//       Access: Public
-//  Description: Returns true if the channel with the given index
-//               number has already been defined, false if it hasn't.
-//               If this returns true, calling get_channel() on the
-//               given index number will return the channel pointer.
-//               If it returns false, calling get_channel() will
-//               create and return a new channel pointer.
-////////////////////////////////////////////////////////////////////
-bool GraphicsWindow::
-is_channel_defined(int index) const {
-  bool result;
-  {
-    MutexHolder holder(_lock);
-    if (index < 0 || index >= (int)_channels.size()) {
-      result = false;
-    } else {
-      result = (_channels[index] != (GraphicsChannel *)NULL);
-    }
-  }
-  return result;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::get_num_display_regions
-//       Access: Published
-//  Description: Returns the number of active DisplayRegions that have
-//               been created within the various layers and channels
-//               of the window.
-////////////////////////////////////////////////////////////////////
-int GraphicsWindow::
-get_num_display_regions() const {
-  determine_display_regions();
-  int result;
-  {
-    MutexHolder holder(_lock);
-    result = _display_regions.size();
-  }
-  return result;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::get_display_region
-//       Access: Published
-//  Description: Returns the nth active DisplayRegion of those that
-//               have been created within the various layers and
-//               channels of the window.  This may return NULL if n is
-//               out of bounds; particularly likely if the number of
-//               display regions has changed since the last call to
-//               get_num_display_regions().
-////////////////////////////////////////////////////////////////////
-DisplayRegion *GraphicsWindow::
-get_display_region(int n) const {
-  determine_display_regions();
-  DisplayRegion *result;
-  {
-    MutexHolder holder(_lock);
-    if (n >= 0 && n < (int)_display_regions.size()) {
-      result = _display_regions[n];
-    } else {
-      result = NULL;
-    }
-  }
-  return result;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::take_screenshot
-//       Access: Published
-//  Description: Saves a screenshot of the window to a default
-//               filename, and returns the filename, or empty string
-//               if the screenshot failed.  The default filename is
-//               generated from the supplied prefix and from the
-//               Configrc variable screenshot-filename, which contains
-//               the following strings:
-//
-//                 %~p - the supplied prefix
-//                 %~f - the frame count
-//                 %~e - the value of screenshot-extension
-//                 All other % strings in strftime().
-////////////////////////////////////////////////////////////////////
-Filename GraphicsWindow::
-take_screenshot(const string &prefix) {
-  time_t now = time(NULL);
-  struct tm *ttm = localtime(&now);
-  int frame_count = ClockObject::get_global_clock()->get_frame_count();
-
-  static const int buffer_size = 1024;
-  char buffer[buffer_size];
-
-  ostringstream filename_strm;
-
-  size_t i = 0;
-  while (i < screenshot_filename.length()) {
-    char ch1 = screenshot_filename[i++];
-    if (ch1 == '%' && i < screenshot_filename.length()) {
-      char ch2 = screenshot_filename[i++];
-      if (ch2 == '~' && i < screenshot_filename.length()) {
-        char ch3 = screenshot_filename[i++];
-        switch (ch3) {
-        case 'p':
-          filename_strm << prefix;
-          break;
-
-        case 'f':
-          filename_strm << frame_count;
-          break;
-
-        case 'e':
-          filename_strm << screenshot_extension;
-          break;
-        }
-
-      } else {
-        // Use strftime() to decode the percent code.
-        char format[3] = {'%', ch2, '\0'};
-        if (strftime(buffer, buffer_size, format, ttm)) {
-          for (char *b = buffer; *b != '\0'; b++) {
-            switch (*b) {
-            case ' ':
-            case ':':
-            case '/':
-              filename_strm << '-';
-              break;
-
-            case '\n':
-              break;
-
-            default:
-              filename_strm << *b;
-            }
-          }
-        }
-      }
-    } else {
-      filename_strm << ch1;
-    }
-  }
-
-  Filename filename = filename_strm.str();
-  if (take_screenshot(filename)) {
-    return filename;
-  }
-  return Filename();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::take_screenshot
-//       Access: Published
-//  Description: Saves a screenshot of the window to the indicated
-//               filename.  Returns true on success, false on failure.
-////////////////////////////////////////////////////////////////////
-bool GraphicsWindow::
-take_screenshot(const Filename &filename) {
-  if (_gsg == (GraphicsStateGuardian *)NULL) {
-    return false;
-  }
-
-  WindowProperties props = get_properties();
-  if (!props.has_size()) {
-    return false;
-  }
-
-  int x_size = props.get_x_size();
-  int y_size = props.get_y_size();
-
-  PixelBuffer p(x_size, y_size, 3, 1, PixelBuffer::T_unsigned_byte,
-                PixelBuffer::F_rgb);
-
-  DisplayRegion dr(x_size, y_size);
-  RenderBuffer rb = _gsg->get_render_buffer(RenderBuffer::T_front);
-  if (!p.copy(_gsg, &dr, rb)) {
-    return false;
-  }
-
-  if (!p.write(filename)) {
-    return false;
-  }
-
-  return true;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindow::get_num_input_devices
 //       Access: Published
@@ -653,157 +346,50 @@ int GraphicsWindow::
 verify_window_sizes(int numsizes, int *dimen) {
   return numsizes;
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::make_scratch_display_region
-//       Access: Public
-//  Description: Allocates and returns a temporary DisplayRegion that
-//               may be used to render offscreen into.  This
-//               DisplayRegion is not associated with any layer.
-//
-//               To allocate a normal DisplayRegion for rendering, use
-//               the interface provided in GraphicsLayer.
-////////////////////////////////////////////////////////////////////
-PT(DisplayRegion) GraphicsWindow::
-make_scratch_display_region(int x_size, int y_size) const {
-#ifndef NDEBUG
-  {
-    MutexHolder holder(_lock);
-    if (x_size > _properties.get_x_size() || 
-        y_size > _properties.get_y_size()) {
-      display_cat.error()
-        << "make_scratch_display_region(): requested region of size " 
-        << x_size << ", " << y_size << " is larger than window of size "
-        << _properties.get_x_size() << ", " << _properties.get_y_size()
-        << ".\n";
-      x_size = min(x_size, _properties.get_x_size());
-      y_size = min(y_size, _properties.get_y_size());
-    }
-  }
-#endif
-
-  PT(DisplayRegion) region = new DisplayRegion(x_size, y_size);
-  region->copy_clear_settings(*this);
-  return region;
-}
  
 ////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::begin_frame
-//       Access: Public, Virtual
-//  Description: This function will be called within the draw thread
-//               before beginning rendering for a given frame.  It
-//               should do whatever setup is required, and return true
-//               if the frame should be rendered, or false if it
-//               should be skipped.
-////////////////////////////////////////////////////////////////////
-bool GraphicsWindow::
-begin_frame() {
-  if (_gsg == (GraphicsStateGuardian *)NULL) {
-    return false;
-  }
-
-  // Okay, we already have a GSG, so activate it.
-  make_current();
-  return _gsg->begin_frame();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::clear
-//       Access: Public
-//  Description: Clears the entire framebuffer before rendering,
-//               according to the settings of get_color_clear_active()
-//               and get_depth_clear_active() (inherited from
-//               ClearableRegion).
-//
-//               This function is called only within the draw thread.
-////////////////////////////////////////////////////////////////////
-void GraphicsWindow::
-clear() {
-  if (is_any_clear_active()) {
-    nassertv(_gsg != (GraphicsStateGuardian *)NULL);
-
-    int x_size, y_size;
-    {
-      MutexHolder holder(_lock);
-      x_size = _properties.get_x_size();
-      y_size = _properties.get_y_size();
-    }
-    PT(DisplayRegion) win_dr =
-      make_scratch_display_region(x_size, y_size);
-    DisplayRegionStack old_dr = _gsg->push_display_region(win_dr);
-    _gsg->clear(this);
-    _gsg->pop_display_region(old_dr);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::end_frame
-//       Access: Public, Virtual
-//  Description: This function will be called within the draw thread
-//               after rendering is completed for a given frame.  It
-//               should do whatever finalization is required.
-////////////////////////////////////////////////////////////////////
-void GraphicsWindow::
-end_frame() {
-  nassertv(_gsg != (GraphicsStateGuardian *)NULL);
-  _gsg->end_frame();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::make_current
+//     Function: GraphicsWindow::request_open
 //       Access: Public, Virtual
-//  Description: This function will be called within the draw thread
-//               during begin_frame() to ensure the graphics context
-//               is ready for drawing.
-////////////////////////////////////////////////////////////////////
-void GraphicsWindow::
-make_current() {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::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.
+//  Description: This is called by the GraphicsEngine to request that
+//               the window (or whatever) open itself or, in general,
+//               make itself valid, at the next call to
+//               process_events().
 ////////////////////////////////////////////////////////////////////
 void GraphicsWindow::
-release_gsg() {
-  _gsg.clear();
+request_open() {
+  WindowProperties open_properties;
+  open_properties.set_open(true);
+  request_properties(open_properties);
 }
-
+ 
 ////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::begin_flip
+//     Function: GraphicsWindow::request_close
 //       Access: Public, Virtual
-//  Description: This function will be called within the draw thread
-//               after end_frame() has been called on all windows, to
-//               initiate the exchange of the front and back buffers.
-//
-//               This should instruct the window to prepare for the
-//               flip at the next video sync, but it should not wait.
-//
-//               We have the two separate functions, begin_flip() and
-//               end_flip(), to make it easier to flip all of the
-//               windows at the same time.
+//  Description: This is called by the GraphicsEngine to request that
+//               the window (or whatever) close itself or, in general,
+//               make itself invalid, at the next call to
+//               process_events().  By that time we promise the gsg
+//               pointer will be cleared.
 ////////////////////////////////////////////////////////////////////
 void GraphicsWindow::
-begin_flip() {
+request_close() {
+  WindowProperties close_properties;
+  close_properties.set_open(false);
+  request_properties(close_properties);
 }
-
+ 
 ////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::end_flip
+//     Function: GraphicsWindow::set_close_now
 //       Access: Public, Virtual
-//  Description: This function will be called within the draw thread
-//               after begin_flip() has been called on all windows, to
-//               finish the exchange of the front and back buffers.
-//
-//               This should cause the window to wait for the flip, if
-//               necessary.
+//  Description: This is called by the GraphicsEngine to insist that
+//               the window be closed immediately.  This is only
+//               called from the window thread.
 ////////////////////////////////////////////////////////////////////
 void GraphicsWindow::
-end_flip() {
+set_close_now() {
+  WindowProperties close_properties;
+  close_properties.set_open(false);
+  set_properties_now(close_properties);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -825,7 +411,7 @@ process_events() {
     // bitmask after all.
     WindowProperties properties;
     {
-      MutexHolder holder(_lock);
+      MutexHolder holder(_properties_lock);
       properties = _requested_properties;
       _requested_properties.clear();
 
@@ -871,11 +457,15 @@ set_properties_now(WindowProperties &properties) {
       if (open_window()) {
         // When the window is first opened, force its size to be
         // broadcast to its display regions.
+        _x_size = _properties.get_x_size();
+        _y_size = _properties.get_y_size();
+        _has_size = true;
+        _is_valid = true;
+
         Channels::iterator ci;
         for (ci = _channels.begin(); ci != _channels.end(); ++ci) {
           GraphicsChannel *chan = (*ci);
-          chan->window_resized(_properties.get_x_size(), 
-                               _properties.get_y_size());
+          chan->window_resized(_x_size, _y_size);
         }
 
       } else {
@@ -893,6 +483,7 @@ set_properties_now(WindowProperties &properties) {
       // yet.
       nassertv(_gsg == (GraphicsStateGuardian *)NULL);
       close_window();
+      _is_valid = false;
     }
     return;
   }
@@ -947,43 +538,7 @@ set_properties_now(WindowProperties &properties) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::close_window
-//       Access: Protected, Virtual
-//  Description: Closes the window right now.  Called from the window
-//               thread.
-////////////////////////////////////////////////////////////////////
-void GraphicsWindow::
-close_window() {
-  display_cat.info()
-    << "Closing " << get_type() << "\n";
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::reset_window
-//       Access: Protected, Virtual
-//  Description: resets the window framebuffer from its derived
-//               children. Does nothing here.
-////////////////////////////////////////////////////////////////////
-void GraphicsWindow::
-reset_window(bool swapchain) {
-  display_cat.info()
-    << "Resetting " << get_type() << "\n";
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::open_window
-//       Access: Protected, Virtual
-//  Description: Opens the window right now.  Called from the window
-//               thread.  Returns true if the window is successfully
-//               opened, or false if there was a problem.
-////////////////////////////////////////////////////////////////////
-bool GraphicsWindow::
-open_window() {
-  return false;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::open_window
+//     Function: GraphicsWindow::do_reshape_request
 //       Access: Protected, Virtual
 //  Description: Called from the window thread in response to a request
 //               from within the code (via request_properties()) to
@@ -1006,7 +561,7 @@ do_reshape_request(int x_origin, int y_origin, int x_size, int y_size) {
 ////////////////////////////////////////////////////////////////////
 void GraphicsWindow::
 system_changed_properties(const WindowProperties &properties) {
-  MutexHolder holder(_lock);
+  MutexHolder holder(_properties_lock);
 
   if (properties.has_size()) {
     system_changed_size(properties.get_x_size(), properties.get_y_size());
@@ -1031,6 +586,10 @@ void GraphicsWindow::
 system_changed_size(int x_size, int y_size) {
   if (x_size != _properties.get_x_size() || 
       y_size != _properties.get_y_size()) {
+    _x_size = x_size;
+    _y_size = y_size;
+    _has_size = true;
+    
     Channels::iterator ci;
     for (ci = _channels.begin(); ci != _channels.end(); ++ci) {
       GraphicsChannel *chan = (*ci);
@@ -1038,61 +597,3 @@ system_changed_size(int x_size, int y_size) {
     }
   }
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::declare_channel
-//       Access: Protected
-//  Description: An internal function to add the indicated
-//               newly-created channel to the list at the indicated
-//               channel number.
-//
-//               The caller must grab and hold _lock before making
-//               this call.
-////////////////////////////////////////////////////////////////////
-void GraphicsWindow::
-declare_channel(int index, GraphicsChannel *chan) {
-  nassertv(index >= 0);
-  if (index >= (int)_channels.size()) {
-    _channels.reserve(index);
-    while (index >= (int)_channels.size()) {
-      _channels.push_back(NULL);
-    }
-  }
-
-  nassertv(index < (int)_channels.size());
-  _channels[index] = chan;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsWindow::do_determine_display_regions
-//       Access: Private
-//  Description: Recomputes the list of active DisplayRegions within
-//               the window.
-////////////////////////////////////////////////////////////////////
-void GraphicsWindow::
-do_determine_display_regions() {
-  MutexHolder holder(_lock);
-  _display_regions_stale = false;
-  _display_regions.clear();
-  Channels::const_iterator ci;
-  for (ci = _channels.begin(); ci != _channels.end(); ++ci) {
-    GraphicsChannel *chan = (*ci);
-    if (chan->is_active()) {
-      GraphicsChannel::GraphicsLayers::const_iterator li;
-      for (li = chan->_layers.begin(); li != chan->_layers.end(); ++li) {
-        GraphicsLayer *layer = (*li);
-        if (layer->is_active()) {
-          GraphicsLayer::DisplayRegions::const_iterator dri;
-          for (dri = layer->_display_regions.begin(); 
-               dri != layer->_display_regions.end(); 
-               ++dri) {
-            DisplayRegion *dr = (*dri);
-            if (dr->is_active()) {
-              _display_regions.push_back(dr);
-            }
-          }
-        }
-      }
-    }
-  }
-}

+ 14 - 97
panda/src/display/graphicsWindow.h

@@ -21,56 +21,27 @@
 
 #include "pandabase.h"
 
+#include "graphicsOutput.h"
 #include "graphicsWindowInputDevice.h"
 #include "windowProperties.h"
-#include "graphicsChannel.h"
-#include "graphicsPipe.h"
-#include "displayRegion.h"
-#include "graphicsStateGuardian.h"
-#include "clearableRegion.h"
-
-#include "typedWritableReferenceCount.h"
 #include "mouseData.h"
 #include "modifierButtons.h"
 #include "buttonEvent.h"
-#include "iterator_types.h"
 #include "notify.h"
 #include "pmutex.h"
 #include "filename.h"
-
 #include "pvector.h"
-#include "pdeque.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : GraphicsWindow
-// Description : An output medium for receiving the results of
-//               rendering.  Typically this is a window on the
-//               computer desktop, but it may also be the entire
-//               desktop or console screen (i.e. a fullscreen window),
-//               or a window on another machine, or even a disk file.
-//
-//               The GraphicsWindow class handles all of the details
-//               about creating a window and its framebuffer, and
-//               managing the properties associated with the windowing
-//               system, such as position and size and keyboard/mouse
-//               input.  The actual rendering, and anything associated
-//               with the graphics context itself, is managed by the
-//               window's GraphicsStateGuardian.
-//
-//               GraphicsWindows are not actually writable to bam
-//               files, of course, but they may be passed as event
-//               parameters, so they inherit from
-//               TypedWritableReferenceCount instead of
-//               TypedReferenceCount for that convenience.
+// Description : A window, fullscreen or on a desktop, into which a
+//               graphics device sends its output for interactive
+//               display.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA GraphicsWindow : public TypedWritableReferenceCount, public ClearableRegion {
+class EXPCL_PANDA GraphicsWindow : public GraphicsOutput {
 protected:
   GraphicsWindow(GraphicsPipe *pipe, GraphicsStateGuardian *gsg);
 
-private:
-  GraphicsWindow(const GraphicsWindow &copy);
-  void operator = (const GraphicsWindow &copy);
-
 PUBLISHED:
   virtual ~GraphicsWindow();
 
@@ -80,27 +51,12 @@ PUBLISHED:
   WindowProperties get_rejected_properties() const;
   void request_properties(const WindowProperties &requested_properties);
   INLINE bool is_closed() const;
-  INLINE bool is_active() const;
+  virtual bool is_active() const;
   INLINE bool is_fullscreen() const;
 
   void set_window_event(const string &window_event);
   string get_window_event() const;
 
-  INLINE GraphicsStateGuardian *get_gsg() const;
-  INLINE GraphicsPipe *get_pipe() const;
-
-  GraphicsChannel *get_channel(int index);
-  void remove_channel(int index);
-
-  int get_max_channel_index() const;
-  bool is_channel_defined(int index) const;
-
-  int get_num_display_regions() const;
-  DisplayRegion *get_display_region(int n) const;
-
-  Filename take_screenshot(const string &prefix = "screenshot");
-  bool take_screenshot(const Filename &filename);
-
   // Mouse and keyboard routines
   int get_num_input_devices() const;
   string get_input_device_name(int device) const;
@@ -115,28 +71,10 @@ public:
 
   virtual int verify_window_sizes(int numsizes, int *dimen);
 
-  PT(DisplayRegion) make_scratch_display_region(int x_size, int y_size) const;
-
 public:
-  // These are not intended to be called directly by the user.
-  INLINE void win_display_regions_changed();
-
-public:
-  // It is an error to call any of the following methods from any
-  // thread other than the draw thread.  These methods are normally
-  // called by the GraphicsEngine.
-  virtual bool begin_frame();
-  void clear();
-  virtual void end_frame();
-
-  // This method is called in the draw thread prior to issuing any
-  // drawing commands for the window.
-  virtual void make_current();
-  virtual void release_gsg();
-
-  // These methods will be called within the app (main) thread.
-  virtual void begin_flip();
-  virtual void end_flip();
+  virtual void request_open();
+  virtual void request_close();
+  virtual void set_close_now();
 
   // It is an error to call any of the following methods from any
   // thread other than the window thread.  These methods are normally
@@ -145,14 +83,9 @@ public:
   virtual void set_properties_now(WindowProperties &properties);
 
 protected:
-  virtual void close_window();
-  virtual bool open_window();
-  virtual void reset_window(bool swapchain);
   virtual bool do_reshape_request(int x_origin, int y_origin,
                                   int x_size, int y_size);
 
-  void declare_channel(int index, GraphicsChannel *chan);
-
   // It is an error to call any of the following methods from any
   // thread other than the window thread.
   void system_changed_properties(const WindowProperties &properties);
@@ -163,26 +96,13 @@ protected:
   InputDevices _input_devices;
   Mutex _input_lock;
 
-  PT(GraphicsStateGuardian) _gsg;
-  PT(GraphicsPipe) _pipe;
-
-private:
-  INLINE void determine_display_regions() const;
-  void do_determine_display_regions();
-
 protected:
   WindowProperties _properties;
 
 private:
-  Mutex _lock; 
-  // protects _channels, _display_regions, and _requested_properties.
-
-  typedef pvector< PT(GraphicsChannel) > Channels;
-  Channels _channels;
-
-  typedef pvector<DisplayRegion *> DisplayRegions;
-  DisplayRegions _display_regions;
-  bool _display_regions_stale;
+  Mutex _properties_lock; 
+  // protects _requested_properties, _rejected_properties, and
+  // _window_event.
 
   WindowProperties _requested_properties;
   WindowProperties _rejected_properties;
@@ -193,9 +113,9 @@ public:
     return _type_handle;
   }
   static void init_type() {
-    TypedWritableReferenceCount::init_type();
+    GraphicsOutput::init_type();
     register_type(_type_handle, "GraphicsWindow",
-                  TypedWritableReferenceCount::get_class_type());
+                  GraphicsOutput::get_class_type());
   }
   virtual TypeHandle get_type() const {
     return get_class_type();
@@ -204,9 +124,6 @@ public:
 
 private:
   static TypeHandle _type_handle;
-
-  friend class GraphicsPipe;
-  friend class GraphicsEngine;
 };
 
 #include "graphicsWindow.I"

+ 2 - 2
panda/src/distort/nonlinearImager.cxx

@@ -21,7 +21,7 @@
 
 #include "graphicsStateGuardian.h"
 #include "matrixLens.h"
-#include "graphicsWindow.h"
+#include "graphicsOutput.h"
 #include "graphicsEngine.h"
 #include "dcast.h"
 
@@ -257,7 +257,7 @@ get_screen_active(int index) const {
 ////////////////////////////////////////////////////////////////////
 int NonlinearImager::
 add_viewer(DisplayRegion *dr) {
-  GraphicsWindow *win = dr->get_window();
+  GraphicsOutput *win = dr->get_window();
   GraphicsStateGuardian *gsg = win->get_gsg();
   nassertr(_viewers.empty() || (gsg == _gsg && win == _win), -1);
   _gsg = gsg;

+ 2 - 2
panda/src/distort/nonlinearImager.h

@@ -32,7 +32,7 @@
 
 class GraphicsEngine;
 class GraphicsStateGuardian;
-class GraphicsWindow;
+class GraphicsOutput;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : NonlinearImager
@@ -163,7 +163,7 @@ private:
   Viewers _viewers;
   Screens _screens;
   GraphicsStateGuardian *_gsg;
-  GraphicsWindow *_win;
+  GraphicsOutput *_win;
 
   bool _stale;
 };

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

@@ -33,8 +33,9 @@ const int win_height = config_framework.GetInt("win-height", 480);
 const bool fullscreen = config_framework.GetBool("fullscreen", false);
 const bool undecorated = config_framework.GetBool("undecorated", false);
 const bool cursor_hidden = config_framework.GetBool("cursor-hidden", false);
-const float aspect_ratio = config_framework.GetFloat("aspect-ratio", 0.0f);
+const string window_title = config_framework.GetString("window-title", "Panda");
 
+const float aspect_ratio = config_framework.GetFloat("aspect-ratio", 0.0f);
 const bool show_frame_rate_meter = config_framework.GetBool("show-frame-rate-meter", false);
 
 // The default window background color.

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

@@ -30,8 +30,9 @@ extern const int win_height;
 extern const bool fullscreen;
 extern const bool undecorated;
 extern const bool cursor_hidden;
-extern const float aspect_ratio;
+extern const string window_title;
 
+extern const float aspect_ratio;
 extern const bool show_frame_rate_meter;
 
 extern const float win_background_r;

+ 1 - 1
panda/src/framework/pandaFramework.cxx

@@ -39,7 +39,7 @@ PandaFramework() :
   _is_open = false;
   _made_default_pipe = false;
   _data_root = NodePath("data");
-  _window_title = "Panda";
+  _window_title = window_title;
   _start_time = 0.0;
   _frame_count = 0;
   _wireframe_enabled = false;

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

@@ -808,13 +808,23 @@ make_camera() {
   _cameras.push_back(camera);
 
   PT(Lens) lens = new PerspectiveLens;
-  WindowProperties properties = _window->get_properties();
-  if (!properties.has_size()) {
-    properties = _window->get_requested_properties();
-  }
-  if (properties.has_size()) {
-    lens->set_film_size(properties.get_x_size(), properties.get_y_size());
+
+  if (aspect_ratio != 0.0f) {
+    // If we're given an explict aspect ratio, use it
+    lens->set_aspect_ratio(aspect_ratio);
+
+  } else {
+    // Otherwise, infer the aspect ratio from the window size.  This
+    // does assume we have square pixels on our output device.
+    WindowProperties properties = _window->get_properties();
+    if (!properties.has_size()) {
+      properties = _window->get_requested_properties();
+    }
+    if (properties.has_size()) {
+      lens->set_film_size(properties.get_x_size(), properties.get_y_size());
+    }
   }
+
   camera->set_lens(lens);
   camera->set_scene(get_render());
   dr->set_camera(camera_np);

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

@@ -30,6 +30,7 @@
 #include "pointerTo.h"
 #include "pvector.h"
 #include "typedWritableReferenceCount.h"
+#include "graphicsWindow.h"
 
 class PandaFramework;
 class AmbientLight;

+ 99 - 33
panda/src/glgsg/glGraphicsStateGuardian.cxx

@@ -123,7 +123,7 @@ issue_transformed_color_gl(const Geom *geom, Geom::ColorIterator &citerator,
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::uchar_bgr_to_rgb
+//     Function: uchar_bgr_to_rgb
 //  Description: Recopies the given array of pixels, converting from
 //               BGR to RGB arrangement.
 ////////////////////////////////////////////////////////////////////
@@ -140,7 +140,7 @@ uchar_bgr_to_rgb(unsigned char *dest, const unsigned char *source,
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::uchar_bgra_to_rgba
+//     Function: uchar_bgra_to_rgba
 //  Description: Recopies the given array of pixels, converting from
 //               BGRA to RGBA arrangement.
 ////////////////////////////////////////////////////////////////////
@@ -157,6 +157,98 @@ uchar_bgra_to_rgba(unsigned char *dest, const unsigned char *source,
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ushort_bgr_to_rgb
+//  Description: Recopies the given array of pixels, converting from
+//               BGR to RGB arrangement.
+////////////////////////////////////////////////////////////////////
+static void
+ushort_bgr_to_rgb(unsigned short *dest, const unsigned short *source, 
+                  int num_pixels) {
+  for (int i = 0; i < num_pixels; i++) {
+    dest[0] = source[2];
+    dest[1] = source[1];
+    dest[2] = source[0];
+    dest += 3;
+    source += 3;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ushort_bgra_to_rgba
+//  Description: Recopies the given array of pixels, converting from
+//               BGRA to RGBA arrangement.
+////////////////////////////////////////////////////////////////////
+static void
+ushort_bgra_to_rgba(unsigned short *dest, const unsigned short *source, 
+                    int num_pixels) {
+  for (int i = 0; i < num_pixels; i++) {
+    dest[0] = source[2];
+    dest[1] = source[1];
+    dest[2] = source[0];
+    dest[3] = source[3];
+    dest += 4;
+    source += 4;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: fix_component_ordering
+//  Description: Reverses the order of the components within the
+//               image, to convert (for instance) GL_BGR to GL_RGB.
+//               Returns the PTA_uchar representing the converted
+//               image, or the original image if it is unchanged.
+////////////////////////////////////////////////////////////////////
+static PTA_uchar
+fix_component_ordering(GLenum external_format, PixelBuffer *pb) {
+  PTA_uchar new_image = pb->_image;
+
+  switch (external_format) {
+  case GL_RGB:
+    switch (pb->get_image_type()) {
+    case PixelBuffer::T_unsigned_byte:
+      new_image = PTA_uchar::empty_array(pb->_image.size());
+      uchar_bgr_to_rgb(new_image, pb->_image, pb->_image.size() / 3);
+      break;
+
+    case PixelBuffer::T_unsigned_short:
+      new_image = PTA_uchar::empty_array(pb->_image.size());
+      ushort_bgr_to_rgb((unsigned short *)new_image.p(), 
+                        (unsigned short *)pb->_image.p(), 
+                        pb->_image.size() / 6);
+      break;
+
+    default:
+      break;
+    }
+    break;
+
+  case GL_RGBA:
+    switch (pb->get_image_type()) {
+    case PixelBuffer::T_unsigned_byte:
+      new_image = PTA_uchar::empty_array(pb->_image.size());
+      uchar_bgra_to_rgba(new_image, pb->_image, pb->_image.size() / 4);
+      break;
+
+    case PixelBuffer::T_unsigned_short:
+      new_image = PTA_uchar::empty_array(pb->_image.size());
+      ushort_bgra_to_rgba((unsigned short *)new_image.p(), 
+                          (unsigned short *)pb->_image.p(), 
+                          pb->_image.size() / 8);
+      break;
+
+    default:
+      break;
+    }
+    break;
+
+  default:
+    break;
+  }
+
+  return new_image;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::Constructor
 //       Access: Public
@@ -2023,16 +2115,7 @@ copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) {
 
   // We may have to reverse the byte ordering of the image if GL
   // didn't do it for us.
-  if (external_format == GL_RGB && pb->get_image_type() == PixelBuffer::T_unsigned_byte) {
-    PTA_uchar new_image = PTA_uchar::empty_array(pb->_image.size());
-    uchar_bgr_to_rgb(new_image, pb->_image, pb->_image.size() / 3);
-    pb->_image = new_image;
-
-  } else if (external_format == GL_RGBA && pb->get_image_type() == PixelBuffer::T_unsigned_byte) {
-    PTA_uchar new_image = PTA_uchar::empty_array(pb->_image.size());
-    uchar_bgra_to_rgba(new_image, pb->_image, pb->_image.size() / 4);
-    pb->_image = new_image;
-  }
+  pb->_image = fix_component_ordering(external_format, pb);
 
   report_gl_errors();
   return true;
@@ -2829,32 +2912,21 @@ apply_texture_immediate(Texture *tex) {
 
   int xsize = pb->get_xsize();
   int ysize = pb->get_ysize();
-  int num_pixels = xsize * ysize;
 
   GLenum internal_format = get_internal_image_format(pb->get_format());
   GLenum external_format = get_external_image_format(pb->get_format());
   GLenum type = get_image_type(pb->get_image_type());
 
-  uchar *image = pb->_image;
-  uchar *locally_allocated_image = (uchar *)NULL;
+  PTA_uchar image = pb->_image;
   if (!gl_supports_bgr) {
     // If the GL doesn't claim to support BGR, we may have to reverse
-    // the byte ordering of the image.
-    if (external_format == GL_RGB && pb->get_image_type() == PixelBuffer::T_unsigned_byte) {
-      locally_allocated_image = new uchar[num_pixels * 3];
-      image = locally_allocated_image;
-      uchar_bgr_to_rgb(image, pb->_image, num_pixels);
-    } else if (external_format == GL_RGBA && pb->get_image_type() == PixelBuffer::T_unsigned_byte) {
-      locally_allocated_image = new uchar[num_pixels * 4];
-      image = locally_allocated_image;
-      uchar_bgra_to_rgba(image, pb->_image, num_pixels);
-    }
+    // the component ordering of the image.
+    image = fix_component_ordering(external_format, pb);
   }
 
 #ifndef NDEBUG
   int wanted_size = 
-    compute_gl_image_size(xsize, ysize,
-                          external_format, type);
+    compute_gl_image_size(xsize, ysize, external_format, type);
   nassertr(wanted_size == (int)pb->_image.size(), false);
 #endif  // NDEBUG
 
@@ -2888,9 +2960,6 @@ apply_texture_immediate(Texture *tex) {
         }
       report_gl_errors();
 
-      if (locally_allocated_image != (uchar *)NULL) {
-        delete[] locally_allocated_image;
-      }
       return true;
     }
   }
@@ -2909,9 +2978,6 @@ apply_texture_immediate(Texture *tex) {
                         ((error_string != (const GLubyte *)NULL) ? " : " : "") << endl;
   }
 
-  if (locally_allocated_image != (uchar *)NULL) {
-    delete[] locally_allocated_image;
-  }
   return true;
 }
 

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

@@ -20,6 +20,7 @@
 #define GLXGRAPHICSPIPE_H
 
 #include "pandabase.h"
+#include "graphicsWindow.h"
 #include "graphicsPipe.h"
 
 class glxGraphicsWindow;