diff --git a/direct/src/showbase/ShowBase.py b/direct/src/showbase/ShowBase.py index aa22c9f5f9..f5ecd84812 100644 --- a/direct/src/showbase/ShowBase.py +++ b/direct/src/showbase/ShowBase.py @@ -111,6 +111,8 @@ class ShowBase(DirectObject.DirectObject): self.config.GetFloat('win-background-b', 0.41), 1.0) + self.windowType = self.config.GetString('window-type', 'onscreen') + # base.win is the main, or only window; base.winList is a list of # *all* windows. Similarly with base.camList. self.win = None @@ -184,29 +186,8 @@ class ShowBase(DirectObject.DirectObject): sys.exitfunc = self.exitfunc # 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.eventMgr = eventMgr @@ -353,7 +334,8 @@ class ShowBase(DirectObject.DirectObject): else: 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 to be updated every frame. @@ -378,15 +360,24 @@ class ShowBase(DirectObject.DirectObject): # Couldn't make a gsg. 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: 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. win.setClearColorActive(1) @@ -438,6 +429,59 @@ class ShowBase(DirectObject.DirectObject): self.win = 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): """ Creates the initial, main window for the application, and sets @@ -562,13 +606,15 @@ class ShowBase(DirectObject.DirectObject): if win == None: 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 diff --git a/panda/src/display/Sources.pp b/panda/src/display/Sources.pp index 1e6ac39b04..429f975963 100644 --- a/panda/src/display/Sources.pp +++ b/panda/src/display/Sources.pp @@ -24,6 +24,7 @@ graphicsLayer.I \ graphicsLayer.h \ graphicsOutput.I graphicsOutput.h \ + graphicsBuffer.I graphicsBuffer.h \ graphicsPipe.I graphicsPipe.h \ graphicsPipeSelection.I graphicsPipeSelection.h \ graphicsStateGuardian.I \ @@ -48,6 +49,7 @@ graphicsEngine.cxx \ graphicsLayer.cxx \ graphicsOutput.cxx \ + graphicsBuffer.cxx \ graphicsPipe.cxx \ graphicsPipeSelection.cxx \ graphicsStateGuardian.cxx \ @@ -70,6 +72,7 @@ graphicsEngine.I graphicsEngine.h \ graphicsLayer.I graphicsLayer.h \ graphicsOutput.I graphicsOutput.h \ + graphicsBuffer.I graphicsBuffer.h \ graphicsPipe.I graphicsPipe.h \ graphicsPipeSelection.I graphicsPipeSelection.h \ graphicsStateGuardian.I \ diff --git a/panda/src/display/config_display.cxx b/panda/src/display/config_display.cxx index 11cda8e6a0..1ec027b7ee 100644 --- a/panda/src/display/config_display.cxx +++ b/panda/src/display/config_display.cxx @@ -21,6 +21,8 @@ #include "graphicsStateGuardian.h" #include "savedFrameBuffer.h" #include "graphicsPipe.h" +#include "graphicsOutput.h" +#include "graphicsBuffer.h" #include "graphicsWindow.h" #include "graphicsChannel.h" #include "graphicsLayer.h" @@ -103,7 +105,9 @@ init_libdisplay() { GraphicsStateGuardian::init_type(); SavedFrameBuffer::init_type(); GraphicsPipe::init_type(); + GraphicsOutput::init_type(); GraphicsWindow::init_type(); + GraphicsBuffer::init_type(); GraphicsChannel::init_type(); GraphicsLayer::init_type(); HardwareChannel::init_type(); diff --git a/panda/src/display/display_composite1.cxx b/panda/src/display/display_composite1.cxx index 1bcb07994e..7d6d0c60c2 100644 --- a/panda/src/display/display_composite1.cxx +++ b/panda/src/display/display_composite1.cxx @@ -5,9 +5,7 @@ #include "graphicsChannel.cxx" #include "graphicsEngine.cxx" #include "graphicsLayer.cxx" -#include "graphicsOutput.cxx" #include "graphicsPipe.cxx" #include "graphicsStateGuardian.cxx" -#include "graphicsWindow.cxx" #include "graphicsWindowInputDevice.cxx" diff --git a/panda/src/display/display_composite2.cxx b/panda/src/display/display_composite2.cxx index 3fe09dd71b..a0f3fc5204 100644 --- a/panda/src/display/display_composite2.cxx +++ b/panda/src/display/display_composite2.cxx @@ -6,3 +6,6 @@ #include "hardwareChannel.cxx" #include "savedFrameBuffer.cxx" #include "windowProperties.cxx" +#include "graphicsWindow.cxx" +#include "graphicsBuffer.cxx" +#include "graphicsOutput.cxx" diff --git a/panda/src/display/graphicsBuffer.I b/panda/src/display/graphicsBuffer.I new file mode 100644 index 0000000000..034da2c316 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + diff --git a/panda/src/display/graphicsBuffer.cxx b/panda/src/display/graphicsBuffer.cxx new file mode 100644 index 0000000000..eab78020ea --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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() { +} diff --git a/panda/src/display/graphicsBuffer.h b/panda/src/display/graphicsBuffer.h new file mode 100644 index 0000000000..942e02cab1 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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 */ diff --git a/panda/src/display/graphicsEngine.I b/panda/src/display/graphicsEngine.I index 3c358eeac3..07c36871e2 100644 --- a/panda/src/display/graphicsEngine.I +++ b/panda/src/display/graphicsEngine.I @@ -94,6 +94,21 @@ make_window(GraphicsPipe *pipe, GraphicsStateGuardian *gsg) { 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 // Access: Published diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index a034e259b9..63f1652cf4 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -209,46 +209,47 @@ make_window(GraphicsPipe *pipe, GraphicsStateGuardian *gsg, // TODO: ask the window thread to make the window. 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); - - display_cat.info() - << "Created " << window->get_type() << "\n"; - } + do_add_window(window, gsg, threading_model); return window; } +//////////////////////////////////////////////////////////////////// +// 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); + } + + // 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 // 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, // false if it was not found. @@ -844,6 +845,45 @@ setup_gsg(GraphicsStateGuardian *gsg, SceneSetup *scene_setup) { 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 // Access: Private diff --git a/panda/src/display/graphicsEngine.h b/panda/src/display/graphicsEngine.h index ec53a79fc7..32f41ae843 100644 --- a/panda/src/display/graphicsEngine.h +++ b/panda/src/display/graphicsEngine.h @@ -21,6 +21,7 @@ #include "pandabase.h" #include "graphicsWindow.h" +#include "graphicsBuffer.h" #include "frameBufferProperties.h" #include "graphicsThreadingModel.h" #include "sceneSetup.h" @@ -75,6 +76,14 @@ PUBLISHED: GraphicsWindow *make_window(GraphicsPipe *pipe, GraphicsStateGuardian *gsg, 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); void remove_all_windows(); void reset_all_windows(bool swapchain); @@ -121,6 +130,8 @@ private: 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 terminate_threads(); diff --git a/panda/src/display/graphicsOutput.cxx b/panda/src/display/graphicsOutput.cxx index 3434f01934..e5f29c2ec7 100644 --- a/panda/src/display/graphicsOutput.cxx +++ b/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 // Description: Saves a screenshot of the window to a default // filename, and returns the filename, or empty string @@ -282,7 +282,7 @@ get_display_region(int n) const { // All other % strings in strftime(). //////////////////////////////////////////////////////////////////// Filename GraphicsOutput:: -take_screenshot(const string &prefix) { +save_screenshot(const string &prefix) { time_t now = time(NULL); struct tm *ttm = localtime(&now); int frame_count = ClockObject::get_global_clock()->get_frame_count(); @@ -340,20 +340,40 @@ take_screenshot(const string &prefix) { } Filename filename = filename_strm.str(); - if (take_screenshot(filename)) { + if (save_screenshot(filename)) { return filename; } return Filename(); } //////////////////////////////////////////////////////////////////// -// Function: GraphicsOutput::take_screenshot +// Function: GraphicsOutput::save_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) { +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) { return false; } @@ -371,7 +391,7 @@ take_screenshot(const Filename &filename) { return false; } - if (!p.write(filename)) { + if (!p.store(image)) { return false; } diff --git a/panda/src/display/graphicsOutput.h b/panda/src/display/graphicsOutput.h index 04c0e933e1..5c1ae9cbd8 100644 --- a/panda/src/display/graphicsOutput.h +++ b/panda/src/display/graphicsOutput.h @@ -33,6 +33,8 @@ #include "filename.h" #include "pvector.h" +class PNMImage; + //////////////////////////////////////////////////////////////////// // Class : GraphicsOutput // Description : This is a base class for the various different @@ -85,8 +87,9 @@ PUBLISHED: 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); + Filename save_screenshot(const string &prefix = "screenshot"); + bool save_screenshot(const Filename &filename); + bool get_screenshot(PNMImage &image); public: // No need to publish these. diff --git a/panda/src/display/graphicsPipe.I b/panda/src/display/graphicsPipe.I index 72d67f1925..23e47be2ac 100644 --- a/panda/src/display/graphicsPipe.I +++ b/panda/src/display/graphicsPipe.I @@ -36,21 +36,39 @@ is_valid() const { } //////////////////////////////////////////////////////////////////// -// Function: GraphicsPipe::supports_fullscreen +// Function: GraphicsPipe::get_supported_types // 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:: -supports_fullscreen() const { - return _supports_fullscreen; +supports_type(int flags) const { + return (_supported_types & flags) == flags; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/display/graphicsPipe.cxx b/panda/src/display/graphicsPipe.cxx index 05b1805692..155d9e540f 100644 --- a/panda/src/display/graphicsPipe.cxx +++ b/panda/src/display/graphicsPipe.cxx @@ -17,6 +17,8 @@ //////////////////////////////////////////////////////////////////// #include "graphicsPipe.h" +#include "graphicsWindow.h" +#include "graphicsBuffer.h" #include "config_display.h" #include "mutexHolder.h" @@ -33,13 +35,12 @@ GraphicsPipe() { // should set this to false if it determines otherwise. _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_height = 0; - } //////////////////////////////////////////////////////////////////// @@ -146,3 +147,23 @@ close_gsg(GraphicsStateGuardian *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; +} diff --git a/panda/src/display/graphicsPipe.h b/panda/src/display/graphicsPipe.h index df21ffc7fe..62232af158 100644 --- a/panda/src/display/graphicsPipe.h +++ b/panda/src/display/graphicsPipe.h @@ -29,6 +29,7 @@ class HardwareChannel; class GraphicsOutput; class GraphicsWindow; +class GraphicsBuffer; class GraphicsStateGuardian; class FrameBufferProperties; @@ -64,8 +65,15 @@ private: PUBLISHED: virtual ~GraphicsPipe(); + enum OutputTypes { + OT_window = 0x0001, + OT_fullscreen_window = 0x0002, + OT_buffer = 0x0004, + }; + 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_height() const; @@ -85,12 +93,13 @@ protected: // the interface on GraphicsEngine to make a new window or gsg. virtual PT(GraphicsStateGuardian) make_gsg(const FrameBufferProperties &properties); 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; bool _is_valid; - bool _supports_fullscreen; + int _supported_types; int _display_width; int _display_height; PT(GraphicsDevice) _device; diff --git a/panda/src/display/graphicsWindow.h b/panda/src/display/graphicsWindow.h index 181ffd32f8..d3c571e8b1 100644 --- a/panda/src/display/graphicsWindow.h +++ b/panda/src/display/graphicsWindow.h @@ -29,7 +29,6 @@ #include "buttonEvent.h" #include "notify.h" #include "pmutex.h" -#include "filename.h" #include "pvector.h" //////////////////////////////////////////////////////////////////// diff --git a/panda/src/framework/pandaFramework.cxx b/panda/src/framework/pandaFramework.cxx index ac7e5e0e10..a077432246 100644 --- a/panda/src/framework/pandaFramework.cxx +++ b/panda/src/framework/pandaFramework.cxx @@ -1091,7 +1091,7 @@ event_f9(CPT_Event event, void *data) { self->_engine.render_frame(); } - Filename filename = wf->get_graphics_window()->take_screenshot(); + Filename filename = wf->get_graphics_window()->save_screenshot(); string text; if (filename.empty()) { text = "Screenshot failed"; diff --git a/panda/src/glxdisplay/glxGraphicsPipe.cxx b/panda/src/glxdisplay/glxGraphicsPipe.cxx index 76bae7b988..0500934b1b 100644 --- a/panda/src/glxdisplay/glxGraphicsPipe.cxx +++ b/panda/src/glxdisplay/glxGraphicsPipe.cxx @@ -49,7 +49,7 @@ glxGraphicsPipe(const string &display) { setlocale(LC_ALL, ""); _is_valid = false; - _supports_fullscreen = false; + _supported_types = OT_window; _display = NULL; _screen = 0; _root = (Window)NULL; diff --git a/panda/src/windisplay/winGraphicsPipe.cxx b/panda/src/windisplay/winGraphicsPipe.cxx index 4ca2d8bbc4..82b8748ab2 100644 --- a/panda/src/windisplay/winGraphicsPipe.cxx +++ b/panda/src/windisplay/winGraphicsPipe.cxx @@ -28,6 +28,8 @@ TypeHandle WinGraphicsPipe::_type_handle; //////////////////////////////////////////////////////////////////// WinGraphicsPipe:: WinGraphicsPipe() { + _supported_types = OT_window | OT_fullscreen_window; + // these fns arent defined on win95, so get dynamic ptrs to them // to avoid ugly DLL loader failures on w95 _pfnTrackMouseEvent = NULL;