Browse Source

define GraphicsBuffer

David Rose 22 years ago
parent
commit
37be15fdfd

+ 82 - 36
direct/src/showbase/ShowBase.py

@@ -111,6 +111,8 @@ class ShowBase(DirectObject.DirectObject):
             self.config.GetFloat('win-background-b', 0.41),
             self.config.GetFloat('win-background-b', 0.41),
             1.0)
             1.0)
 
 
+        self.windowType = self.config.GetString('window-type', 'onscreen')
+
         # base.win is the main, or only window; base.winList is a list of
         # base.win is the main, or only window; base.winList is a list of
         # *all* windows.  Similarly with base.camList.
         # *all* windows.  Similarly with base.camList.
         self.win = None
         self.win = None
@@ -184,29 +186,8 @@ class ShowBase(DirectObject.DirectObject):
         sys.exitfunc = self.exitfunc
         sys.exitfunc = self.exitfunc
 
 
         # Open the default rendering window.
         # Open the default rendering window.
-        if self.config.GetBool('open-default-window', 1):
-            self.openMainWindow()
-
-            # Give the window a chance to truly open.
-            self.graphicsEngine.renderFrame()
-            self.graphicsEngine.renderFrame()
-            if self.win != None and self.win.isClosed():
-                self.notify.info("Window did not open, removing.")
-                self.closeWindow(self.win)
-
-            if self.win == None:
-                # Try a little harder if the window wouldn't open.
-                self.makeAllPipes()
-                while self.win == None and len(self.pipeList) > 1:
-                    self.pipeList.remove(self.pipe)
-                    self.pipe = self.pipeList[0]
-                    self.openMainWindow()
-
-                    self.graphicsEngine.renderFrame()
-                    self.graphicsEngine.renderFrame()
-                    if self.win != None and self.win.isClosed():
-                        self.notify.info("Window did not open, removing.")
-                        self.closeWindow(self.win)
+        if self.windowType != 'none':
+            self.openDefaultWindow()
 
 
         self.loader = Loader.Loader(self)
         self.loader = Loader.Loader(self)
         self.eventMgr = eventMgr
         self.eventMgr = eventMgr
@@ -353,7 +334,8 @@ class ShowBase(DirectObject.DirectObject):
                 else:
                 else:
                     self.notify.info("Could not make graphics pipe %s." % (pipeType.getName()))
                     self.notify.info("Could not make graphics pipe %s." % (pipeType.getName()))
 
 
-    def openWindow(self, props = None, pipe = None, gsg = None):
+    def openWindow(self, props = None, pipe = None, gsg = None,
+                   type = None):
         """
         """
         Creates a window and adds it to the list of windows that are
         Creates a window and adds it to the list of windows that are
         to be updated every frame.
         to be updated every frame.
@@ -378,15 +360,24 @@ class ShowBase(DirectObject.DirectObject):
                 # Couldn't make a gsg.
                 # Couldn't make a gsg.
                 return None
                 return None
 
 
-        win = self.graphicsEngine.makeWindow(pipe, gsg)
-        if win == None:
-            # Couldn't create a window!
-            return None
+        if type == None:
+            type = self.windowType
 
 
         if props == None:
         if props == None:
             props = self.defaultWindowProps
             props = self.defaultWindowProps
 
 
-        win.requestProperties(props)
+        if type == 'onscreen':
+            win = self.graphicsEngine.makeWindow(pipe, gsg)
+        elif type == 'offscreen':
+            win = self.graphicsEngine.makeBuffer(
+                pipe, gsg, props.getXSize(), props.getYSize())
+            
+        if win == None:
+            # Couldn't create a window!
+            return None
+
+        if hasattr(win, "requestProperties"):
+            win.requestProperties(props)
 
 
         # By default, the window is cleared to the background color.
         # By default, the window is cleared to the background color.
         win.setClearColorActive(1)
         win.setClearColorActive(1)
@@ -438,6 +429,59 @@ class ShowBase(DirectObject.DirectObject):
             self.win = None
             self.win = None
             self.frameRateMeter = None
             self.frameRateMeter = None
 
 
+    def openDefaultWindow(self):
+        # Creates the main window for the first time, without being
+        # too particular about the kind of graphics API that is
+        # chosen.  The suggested window type from the load-display
+        # config variable is tried first; if that fails, the first
+        # window type that can be successfully opened at all is
+        # accepted.  Returns true on success, false otherwise.
+        #
+        # This is intended to be called only once, at application
+        # startup.  It is normally called automatically unless
+        # window-type is configured to 'none'.
+        
+        self.openMainWindow()
+
+        # Give the window a chance to truly open.
+        self.graphicsEngine.renderFrame()
+        self.graphicsEngine.renderFrame()
+        if self.win != None and not self.isMainWindowOpen():
+            self.notify.info("Window did not open, removing.")
+            self.closeWindow(self.win)
+
+        if self.win == None:
+            # Try a little harder if the window wouldn't open.
+            self.makeAllPipes()
+            while self.win == None and len(self.pipeList) > 1:
+                self.pipeList.remove(self.pipe)
+                self.pipe = self.pipeList[0]
+                self.openMainWindow()
+
+                self.graphicsEngine.renderFrame()
+                self.graphicsEngine.renderFrame()
+                if self.win != None and not self.isMainWindowOpen():
+                    self.notify.info("Window did not open, removing.")
+                    self.closeWindow(self.win)
+
+        if self.win == None:
+            # This doesn't really need to be an error condition, but I
+            # figure any app that includes ShowBase really wants to
+            # have a window open.
+            self.notify.error("Unable to open %s window." % (self.windowType))
+
+        return (self.win != None)
+
+    def isMainWindowOpen(self):
+        if self.win != None:
+            # Temporary try .. except for old Pandas.
+            try:
+                valid = self.win.isValid()
+            except:
+                valid = self.win.isOpen()
+            return valid
+        return 0
+        
     def openMainWindow(self):
     def openMainWindow(self):
         """
         """
         Creates the initial, main window for the application, and sets
         Creates the initial, main window for the application, and sets
@@ -562,13 +606,15 @@ class ShowBase(DirectObject.DirectObject):
         if win == None:
         if win == None:
             win = self.win
             win = self.win
 
 
-        props = self.defaultWindowProps
-        if win:
-            props = win.getProperties()
-        if not props.hasSize():
-            props = win.getRequestedProperties()
-        if props.hasSize():
-            aspectRatio = float(props.getXSize()) / float(props.getYSize())
+        if win.hasSize():
+            aspectRatio = float(win.getXSize()) / float(win.getYSize())
+
+        else:
+            props = self.defaultWindowProps
+            if not props.hasSize():
+                props = win.getRequestedProperties()
+            if props.hasSize():
+                aspectRatio = float(props.getXSize()) / float(props.getYSize())
 
 
         return aspectRatio
         return aspectRatio
 
 

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

@@ -24,6 +24,7 @@
     graphicsLayer.I  \
     graphicsLayer.I  \
     graphicsLayer.h \
     graphicsLayer.h \
     graphicsOutput.I graphicsOutput.h \
     graphicsOutput.I graphicsOutput.h \
+    graphicsBuffer.I graphicsBuffer.h \
     graphicsPipe.I graphicsPipe.h  \
     graphicsPipe.I graphicsPipe.h  \
     graphicsPipeSelection.I graphicsPipeSelection.h \
     graphicsPipeSelection.I graphicsPipeSelection.h \
     graphicsStateGuardian.I \
     graphicsStateGuardian.I \
@@ -48,6 +49,7 @@
     graphicsEngine.cxx \
     graphicsEngine.cxx \
     graphicsLayer.cxx \
     graphicsLayer.cxx \
     graphicsOutput.cxx \
     graphicsOutput.cxx \
+    graphicsBuffer.cxx \
     graphicsPipe.cxx \
     graphicsPipe.cxx \
     graphicsPipeSelection.cxx \
     graphicsPipeSelection.cxx \
     graphicsStateGuardian.cxx  \
     graphicsStateGuardian.cxx  \
@@ -70,6 +72,7 @@
     graphicsEngine.I graphicsEngine.h \
     graphicsEngine.I graphicsEngine.h \
     graphicsLayer.I graphicsLayer.h \
     graphicsLayer.I graphicsLayer.h \
     graphicsOutput.I graphicsOutput.h \
     graphicsOutput.I graphicsOutput.h \
+    graphicsBuffer.I graphicsBuffer.h \
     graphicsPipe.I graphicsPipe.h \
     graphicsPipe.I graphicsPipe.h \
     graphicsPipeSelection.I graphicsPipeSelection.h \
     graphicsPipeSelection.I graphicsPipeSelection.h \
     graphicsStateGuardian.I \
     graphicsStateGuardian.I \

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

@@ -21,6 +21,8 @@
 #include "graphicsStateGuardian.h"
 #include "graphicsStateGuardian.h"
 #include "savedFrameBuffer.h"
 #include "savedFrameBuffer.h"
 #include "graphicsPipe.h"
 #include "graphicsPipe.h"
+#include "graphicsOutput.h"
+#include "graphicsBuffer.h"
 #include "graphicsWindow.h"
 #include "graphicsWindow.h"
 #include "graphicsChannel.h"
 #include "graphicsChannel.h"
 #include "graphicsLayer.h"
 #include "graphicsLayer.h"
@@ -103,7 +105,9 @@ init_libdisplay() {
   GraphicsStateGuardian::init_type();
   GraphicsStateGuardian::init_type();
   SavedFrameBuffer::init_type();
   SavedFrameBuffer::init_type();
   GraphicsPipe::init_type();
   GraphicsPipe::init_type();
+  GraphicsOutput::init_type();
   GraphicsWindow::init_type();
   GraphicsWindow::init_type();
+  GraphicsBuffer::init_type();
   GraphicsChannel::init_type();
   GraphicsChannel::init_type();
   GraphicsLayer::init_type();
   GraphicsLayer::init_type();
   HardwareChannel::init_type();
   HardwareChannel::init_type();

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

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

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

@@ -6,3 +6,6 @@
 #include "hardwareChannel.cxx"
 #include "hardwareChannel.cxx"
 #include "savedFrameBuffer.cxx"
 #include "savedFrameBuffer.cxx"
 #include "windowProperties.cxx"
 #include "windowProperties.cxx"
+#include "graphicsWindow.cxx"
+#include "graphicsBuffer.cxx"
+#include "graphicsOutput.cxx"

+ 18 - 0
panda/src/display/graphicsBuffer.I

@@ -0,0 +1,18 @@
+// Filename: graphicsBuffer.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] .
+//
+////////////////////////////////////////////////////////////////////
+

+ 56 - 0
panda/src/display/graphicsBuffer.cxx

@@ -0,0 +1,56 @@
+// Filename: graphicsBuffer.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 "graphicsBuffer.h"
+
+TypeHandle GraphicsBuffer::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsBuffer::Constructor
+//       Access: Protected
+//  Description: Normally, the GraphicsBuffer constructor is not
+//               called directly; these are created instead via the
+//               GraphicsEngine::make_buffer() function.
+////////////////////////////////////////////////////////////////////
+GraphicsBuffer::
+GraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
+               int x_size, int y_size) :
+  GraphicsOutput(pipe, gsg)
+{
+#ifdef DO_MEMORY_USAGE
+  MemoryUsage::update_type(this, this);
+#endif
+
+  if (display_cat.is_debug()) {
+    display_cat.debug()
+      << "Creating new offscreen buffer using GSG " << (void *)gsg << "\n";
+  }
+
+  _x_size = x_size;
+  _y_size = y_size;
+  _has_size = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsBuffer::Destructor
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+GraphicsBuffer::
+~GraphicsBuffer() {
+}

+ 60 - 0
panda/src/display/graphicsBuffer.h

@@ -0,0 +1,60 @@
+// Filename: graphicsBuffer.h
+// Created by:  mike (09Jan97)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 GRAPHICSBUFFER_H
+#define GRAPHICSBUFFER_H
+
+#include "pandabase.h"
+
+#include "graphicsOutput.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : GraphicsBuffer
+// Description : An offscreen buffer for rendering into.  Pretty much
+//               all you can do with this is render into it and then
+//               get the framebuffer out as an image.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA GraphicsBuffer : public GraphicsOutput {
+protected:
+  GraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
+                 int x_size, int y_size);
+
+PUBLISHED:
+  virtual ~GraphicsBuffer();
+  
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    GraphicsOutput::init_type();
+    register_type(_type_handle, "GraphicsBuffer",
+                  GraphicsOutput::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "graphicsBuffer.I"
+
+#endif /* GRAPHICSBUFFER_H */

+ 15 - 0
panda/src/display/graphicsEngine.I

@@ -94,6 +94,21 @@ make_window(GraphicsPipe *pipe, GraphicsStateGuardian *gsg) {
   return make_window(pipe, gsg, get_threading_model());
   return make_window(pipe, gsg, get_threading_model());
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::make_buffer
+//       Access: Published
+//  Description: Creates a new offscreen buffer using the indicated
+//               GraphicsStateGuardian and returns it.  The
+//               GraphicsEngine becomes the owner of the buffer; it
+//               will persist at least until remove_buffer() is called
+//               later.
+////////////////////////////////////////////////////////////////////
+INLINE GraphicsBuffer *GraphicsEngine::
+make_buffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
+            int x_size, int y_size) {
+  return make_buffer(pipe, gsg, x_size, y_size, get_threading_model());
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsEngine::close_gsg
 //     Function: GraphicsEngine::close_gsg
 //       Access: Published
 //       Access: Published

+ 73 - 33
panda/src/display/graphicsEngine.cxx

@@ -209,46 +209,47 @@ make_window(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
 
 
   // TODO: ask the window thread to make the window.
   // TODO: ask the window thread to make the window.
   PT(GraphicsWindow) window = pipe->make_window(gsg);
   PT(GraphicsWindow) window = pipe->make_window(gsg);
-  if (window != (GraphicsWindow *)NULL) {
-    MutexHolder holder(_lock);
-    _windows.insert(window.p());
-
-    WindowRenderer *cull = get_window_renderer(threading_model.get_cull_name());
-    WindowRenderer *draw = get_window_renderer(threading_model.get_draw_name());
-    draw->add_gsg(gsg);
-
-    if (threading_model.get_cull_sorting()) {
-      cull->add_window(cull->_cull, window);
-      draw->add_window(draw->_draw, window);
-    } else {
-      cull->add_window(cull->_cdraw, window);
-    }
-
-    // We should ask the pipe which thread it prefers to run its
-    // windowing commands in (the "window thread").  This is the
-    // thread that handles the commands to open, resize, etc. the
-    // window.  X requires this to be done in the app thread, but some
-    // pipes might prefer this to be done in draw, for instance.  For
-    // now, we assume this is the app thread.
-    _app.add_window(_app._window, window);
+  do_add_window(window, gsg, threading_model);
+  return window;
+}
 
 
-    display_cat.info()
-      << "Created " << window->get_type() << "\n";
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::make_buffer
+//       Access: Published
+//  Description: Creates a new offscreen buffer using the indicated
+//               GraphicsStateGuardian and returns it.  The
+//               GraphicsEngine becomes the owner of the buffer; it
+//               will persist at least until remove_window() is called
+//               later.
+////////////////////////////////////////////////////////////////////
+GraphicsBuffer *GraphicsEngine::
+make_buffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
+            int x_size, int y_size,
+            const GraphicsThreadingModel &threading_model) {
+  if (gsg != (GraphicsStateGuardian *)NULL) {
+    nassertr(pipe == gsg->get_pipe(), NULL);
+    nassertr(this == gsg->get_engine(), NULL);
+    nassertr(threading_model.get_draw_name() ==
+             gsg->get_threading_model().get_draw_name(), NULL);
   }
   }
-  return window;
+
+  // TODO: ask the window thread to make the buffer.
+  PT(GraphicsBuffer) buffer = pipe->make_buffer(gsg, x_size, y_size);
+  do_add_window(buffer, gsg, threading_model);
+  return buffer;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsEngine::remove_window
 //     Function: GraphicsEngine::remove_window
 //       Access: Published
 //       Access: Published
-//  Description: Removes the indicated window from the set of windows
-//               that will be processed when render_frame() is called.
-//               This also closes the window if it is open, and
-//               removes the window from its GraphicsPipe, allowing
-//               the window to be destructed if there are no other
-//               references to it.  (However, the window may not be
-//               actually closed until next frame, if it is controlled
-//               by a sub-thread.)
+//  Description: Removes the indicated window or offscreen buffer from
+//               the set of windows that will be processed when
+//               render_frame() is called.  This also closes the
+//               window if it is open, and removes the window from its
+//               GraphicsPipe, allowing the window to be destructed if
+//               there are no other references to it.  (However, the
+//               window may not be actually closed until next frame,
+//               if it is controlled by a sub-thread.)
 //
 //
 //               The return value is true if the window was removed,
 //               The return value is true if the window was removed,
 //               false if it was not found.
 //               false if it was not found.
@@ -844,6 +845,45 @@ setup_gsg(GraphicsStateGuardian *gsg, SceneSetup *scene_setup) {
   return true;
   return true;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::do_add_window
+//       Access: Private
+//  Description: An internal function called by make_window() and
+//               make_buffer() and similar functions to add the
+//               newly-created GraphicsOutput object to the engine's
+//               tables.
+////////////////////////////////////////////////////////////////////
+void GraphicsEngine::
+do_add_window(GraphicsOutput *window, GraphicsStateGuardian *gsg,
+              const GraphicsThreadingModel &threading_model) {
+  if (window != (GraphicsOutput *)NULL) {
+    MutexHolder holder(_lock);
+    _windows.insert(window);
+
+    WindowRenderer *cull = get_window_renderer(threading_model.get_cull_name());
+    WindowRenderer *draw = get_window_renderer(threading_model.get_draw_name());
+    draw->add_gsg(gsg);
+
+    if (threading_model.get_cull_sorting()) {
+      cull->add_window(cull->_cull, window);
+      draw->add_window(draw->_draw, window);
+    } else {
+      cull->add_window(cull->_cdraw, window);
+    }
+
+    // We should ask the pipe which thread it prefers to run its
+    // windowing commands in (the "window thread").  This is the
+    // thread that handles the commands to open, resize, etc. the
+    // window.  X requires this to be done in the app thread, but some
+    // pipes might prefer this to be done in draw, for instance.  For
+    // now, we assume this is the app thread.
+    _app.add_window(_app._window, window);
+
+    display_cat.info()
+      << "Created " << window->get_type() << "\n";
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsEngine::do_remove_window
 //     Function: GraphicsEngine::do_remove_window
 //       Access: Private
 //       Access: Private

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

@@ -21,6 +21,7 @@
 
 
 #include "pandabase.h"
 #include "pandabase.h"
 #include "graphicsWindow.h"
 #include "graphicsWindow.h"
+#include "graphicsBuffer.h"
 #include "frameBufferProperties.h"
 #include "frameBufferProperties.h"
 #include "graphicsThreadingModel.h"
 #include "graphicsThreadingModel.h"
 #include "sceneSetup.h"
 #include "sceneSetup.h"
@@ -75,6 +76,14 @@ PUBLISHED:
   GraphicsWindow *make_window(GraphicsPipe *pipe,
   GraphicsWindow *make_window(GraphicsPipe *pipe,
                               GraphicsStateGuardian *gsg,
                               GraphicsStateGuardian *gsg,
                               const GraphicsThreadingModel &threading_model);
                               const GraphicsThreadingModel &threading_model);
+  INLINE GraphicsBuffer *make_buffer(GraphicsPipe *pipe,
+                                     GraphicsStateGuardian *gsg,
+                                     int x_size, int y_size);
+  GraphicsBuffer *make_buffer(GraphicsPipe *pipe,
+                              GraphicsStateGuardian *gsg,
+                              int x_size, int y_size,
+                              const GraphicsThreadingModel &threading_model);
+
   bool remove_window(GraphicsOutput *window);
   bool remove_window(GraphicsOutput *window);
   void remove_all_windows();
   void remove_all_windows();
   void reset_all_windows(bool swapchain);
   void reset_all_windows(bool swapchain);
@@ -121,6 +130,8 @@ private:
 
 
   bool setup_gsg(GraphicsStateGuardian *gsg, SceneSetup *scene_setup);
   bool setup_gsg(GraphicsStateGuardian *gsg, SceneSetup *scene_setup);
 
 
+  void do_add_window(GraphicsOutput *window, GraphicsStateGuardian *gsg,
+                     const GraphicsThreadingModel &threading_model);
   void do_remove_window(GraphicsOutput *window);
   void do_remove_window(GraphicsOutput *window);
   void terminate_threads();
   void terminate_threads();
 
 

+ 26 - 6
panda/src/display/graphicsOutput.cxx

@@ -267,7 +267,7 @@ get_display_region(int n) const {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GraphicsOutput::take_screenshot
+//     Function: GraphicsOutput::save_screenshot
 //       Access: Published
 //       Access: Published
 //  Description: Saves a screenshot of the window to a default
 //  Description: Saves a screenshot of the window to a default
 //               filename, and returns the filename, or empty string
 //               filename, and returns the filename, or empty string
@@ -282,7 +282,7 @@ get_display_region(int n) const {
 //                 All other % strings in strftime().
 //                 All other % strings in strftime().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 Filename GraphicsOutput::
 Filename GraphicsOutput::
-take_screenshot(const string &prefix) {
+save_screenshot(const string &prefix) {
   time_t now = time(NULL);
   time_t now = time(NULL);
   struct tm *ttm = localtime(&now);
   struct tm *ttm = localtime(&now);
   int frame_count = ClockObject::get_global_clock()->get_frame_count();
   int frame_count = ClockObject::get_global_clock()->get_frame_count();
@@ -340,20 +340,40 @@ take_screenshot(const string &prefix) {
   }
   }
 
 
   Filename filename = filename_strm.str();
   Filename filename = filename_strm.str();
-  if (take_screenshot(filename)) {
+  if (save_screenshot(filename)) {
     return filename;
     return filename;
   }
   }
   return Filename();
   return Filename();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GraphicsOutput::take_screenshot
+//     Function: GraphicsOutput::save_screenshot
 //       Access: Published
 //       Access: Published
 //  Description: Saves a screenshot of the window to the indicated
 //  Description: Saves a screenshot of the window to the indicated
 //               filename.  Returns true on success, false on failure.
 //               filename.  Returns true on success, false on failure.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool GraphicsOutput::
 bool GraphicsOutput::
-take_screenshot(const Filename &filename) {
+save_screenshot(const Filename &filename) {
+  PNMImage image;
+  if (!get_screenshot(image)) {
+    return false;
+  }
+
+  if (!image.write(filename)) {
+    return false;
+  }
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::get_screenshot
+//       Access: Published
+//  Description: Captures the most-recently rendered image from the
+//               framebuffer into the indicated PNMImage.  Returns
+//               true on success, false on failure.
+////////////////////////////////////////////////////////////////////
+bool GraphicsOutput::
+get_screenshot(PNMImage &image) {
   if (_gsg == (GraphicsStateGuardian *)NULL) {
   if (_gsg == (GraphicsStateGuardian *)NULL) {
     return false;
     return false;
   }
   }
@@ -371,7 +391,7 @@ take_screenshot(const Filename &filename) {
     return false;
     return false;
   }
   }
 
 
-  if (!p.write(filename)) {
+  if (!p.store(image)) {
     return false;
     return false;
   }
   }
 
 

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

@@ -33,6 +33,8 @@
 #include "filename.h"
 #include "filename.h"
 #include "pvector.h"
 #include "pvector.h"
 
 
+class PNMImage;
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : GraphicsOutput
 //       Class : GraphicsOutput
 // Description : This is a base class for the various different
 // Description : This is a base class for the various different
@@ -85,8 +87,9 @@ PUBLISHED:
   int get_num_display_regions() const;
   int get_num_display_regions() const;
   DisplayRegion *get_display_region(int n) const;
   DisplayRegion *get_display_region(int n) const;
 
 
-  Filename take_screenshot(const string &prefix = "screenshot");
-  bool take_screenshot(const Filename &filename);
+  Filename save_screenshot(const string &prefix = "screenshot");
+  bool save_screenshot(const Filename &filename);
+  bool get_screenshot(PNMImage &image);
 
 
 public:
 public:
   // No need to publish these.
   // No need to publish these.

+ 29 - 11
panda/src/display/graphicsPipe.I

@@ -36,21 +36,39 @@ is_valid() const {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GraphicsPipe::supports_fullscreen
+//     Function: GraphicsPipe::get_supported_types
 //       Access: Published
 //       Access: Published
-//  Description: Returns false if this pipe is known to not support
-//               any creation of fullscreen windows.  If this returns
-//               false, any attempt to create a window with the
-//               fullscreen property set will certainly fail.
+//  Description: Returns the mask of bits that represents the kinds of
+//               GraphicsOutput objects this pipe might be able to
+//               successfully create.  The return value is the union
+//               of bits in GraphicsPipe::OutputTypes that represents
+//               the set of GraphicsOutput types.
 //
 //
-//               Returns true when the pipe will probably support
-//               fullscreen windows.  This is not, however, a
-//               guarantee that an attempt to create a fullscreen
-//               window will not fail.
+//               A 1 bit in a particular position is not a guarantee
+//               of success, but a 0 bit is a guarantee of failure.
+////////////////////////////////////////////////////////////////////
+INLINE int GraphicsPipe::
+get_supported_types() const {
+  return _supported_types;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsPipe::supports_type
+//       Access: Published
+//  Description: A convenience function to ask if a particular type or
+//               types of GraphicsObjects are supported.  The
+//               parameter is a union of one or more bits defined in
+//               GrpahicsPipe::OutputTypes.
+//
+//               Returns true if all of the requested types are listed
+//               in the supported_types mask, false if any one of them
+//               is not.  This is not a guarantee that the indicated
+//               output type will successfully be created when it is
+//               attempted.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool GraphicsPipe::
 INLINE bool GraphicsPipe::
-supports_fullscreen() const {
-  return _supports_fullscreen;
+supports_type(int flags) const {
+  return (_supported_types & flags) == flags;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 25 - 4
panda/src/display/graphicsPipe.cxx

@@ -17,6 +17,8 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 #include "graphicsPipe.h"
 #include "graphicsPipe.h"
+#include "graphicsWindow.h"
+#include "graphicsBuffer.h"
 #include "config_display.h"
 #include "config_display.h"
 #include "mutexHolder.h"
 #include "mutexHolder.h"
 
 
@@ -33,13 +35,12 @@ GraphicsPipe() {
   // should set this to false if it determines otherwise.
   // should set this to false if it determines otherwise.
   _is_valid = true;
   _is_valid = true;
 
 
-  // Similarly, we initially assume the pipe will support fullscreen
-  // windows.  A derived class can choose to inform us otherwise.
-  _supports_fullscreen = true;
+  // A derived class must indicate the kinds of GraphicsOutput objects
+  // it can create.
+  _supported_types = 0;
 
 
   _display_width = 0;
   _display_width = 0;
   _display_height = 0;
   _display_height = 0;
-
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -146,3 +147,23 @@ close_gsg(GraphicsStateGuardian *gsg) {
     gsg->close_gsg();
     gsg->close_gsg();
   }
   }
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsPipe::make_window
+//       Access: Protected, Virtual
+//  Description: Creates a new window on the pipe, if possible.
+////////////////////////////////////////////////////////////////////
+PT(GraphicsWindow) GraphicsPipe::
+make_window(GraphicsStateGuardian *) {
+  return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsPipe::make_buffer
+//       Access: Protected, Virtual
+//  Description: Creates a new offscreen buffer on the pipe, if possible.
+////////////////////////////////////////////////////////////////////
+PT(GraphicsBuffer) GraphicsPipe::
+make_buffer(GraphicsStateGuardian *, int, int) {
+  return NULL;
+}

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

@@ -29,6 +29,7 @@
 class HardwareChannel;
 class HardwareChannel;
 class GraphicsOutput;
 class GraphicsOutput;
 class GraphicsWindow;
 class GraphicsWindow;
+class GraphicsBuffer;
 class GraphicsStateGuardian;
 class GraphicsStateGuardian;
 class FrameBufferProperties;
 class FrameBufferProperties;
 
 
@@ -64,8 +65,15 @@ private:
 PUBLISHED:
 PUBLISHED:
   virtual ~GraphicsPipe();
   virtual ~GraphicsPipe();
 
 
+  enum OutputTypes {
+    OT_window            = 0x0001,
+    OT_fullscreen_window = 0x0002,
+    OT_buffer            = 0x0004,
+  };
+
   INLINE bool is_valid() const;
   INLINE bool is_valid() const;
-  INLINE bool supports_fullscreen() const;
+  INLINE int get_supported_types() const;
+  INLINE bool supports_type(int flags) const;
 
 
   INLINE int get_display_width() const;
   INLINE int get_display_width() const;
   INLINE int get_display_height() const;
   INLINE int get_display_height() const;
@@ -85,12 +93,13 @@ protected:
   // the interface on GraphicsEngine to make a new window or gsg.
   // the interface on GraphicsEngine to make a new window or gsg.
   virtual PT(GraphicsStateGuardian) make_gsg(const FrameBufferProperties &properties);
   virtual PT(GraphicsStateGuardian) make_gsg(const FrameBufferProperties &properties);
   virtual void close_gsg(GraphicsStateGuardian *gsg);
   virtual void close_gsg(GraphicsStateGuardian *gsg);
-  virtual PT(GraphicsWindow) make_window(GraphicsStateGuardian *gsg)=0;
+  virtual PT(GraphicsWindow) make_window(GraphicsStateGuardian *gsg);
+  virtual PT(GraphicsBuffer) make_buffer(GraphicsStateGuardian *gsg, int x_size, int y_size);
 
 
   Mutex _lock;
   Mutex _lock;
 
 
   bool _is_valid;
   bool _is_valid;
-  bool _supports_fullscreen;
+  int _supported_types;
   int _display_width;
   int _display_width;
   int _display_height;
   int _display_height;
   PT(GraphicsDevice) _device;
   PT(GraphicsDevice) _device;

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

@@ -29,7 +29,6 @@
 #include "buttonEvent.h"
 #include "buttonEvent.h"
 #include "notify.h"
 #include "notify.h"
 #include "pmutex.h"
 #include "pmutex.h"
-#include "filename.h"
 #include "pvector.h"
 #include "pvector.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

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

@@ -1091,7 +1091,7 @@ event_f9(CPT_Event event, void *data) {
       self->_engine.render_frame();
       self->_engine.render_frame();
     }
     }
 
 
-    Filename filename = wf->get_graphics_window()->take_screenshot();
+    Filename filename = wf->get_graphics_window()->save_screenshot();
     string text;
     string text;
     if (filename.empty()) {
     if (filename.empty()) {
       text = "Screenshot failed";
       text = "Screenshot failed";

+ 1 - 1
panda/src/glxdisplay/glxGraphicsPipe.cxx

@@ -49,7 +49,7 @@ glxGraphicsPipe(const string &display) {
   setlocale(LC_ALL, "");
   setlocale(LC_ALL, "");
 
 
   _is_valid = false;
   _is_valid = false;
-  _supports_fullscreen = false;
+  _supported_types = OT_window;
   _display = NULL;
   _display = NULL;
   _screen = 0;
   _screen = 0;
   _root = (Window)NULL;
   _root = (Window)NULL;

+ 2 - 0
panda/src/windisplay/winGraphicsPipe.cxx

@@ -28,6 +28,8 @@ TypeHandle WinGraphicsPipe::_type_handle;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 WinGraphicsPipe::
 WinGraphicsPipe::
 WinGraphicsPipe() {
 WinGraphicsPipe() {
+  _supported_types = OT_window | OT_fullscreen_window;
+
   // these fns arent defined on win95, so get dynamic ptrs to them
   // these fns arent defined on win95, so get dynamic ptrs to them
   // to avoid ugly DLL loader failures on w95
   // to avoid ugly DLL loader failures on w95
   _pfnTrackMouseEvent = NULL;
   _pfnTrackMouseEvent = NULL;