diff --git a/direct/src/showbase/showBase.h b/direct/src/showbase/showBase.h index dbbee18b8a..94a62ee629 100644 --- a/direct/src/showbase/showBase.h +++ b/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" diff --git a/panda/src/display/Sources.pp b/panda/src/display/Sources.pp index 2f3b347114..1e6ac39b04 100644 --- a/panda/src/display/Sources.pp +++ b/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 \ diff --git a/panda/src/display/displayRegion.cxx b/panda/src/display/displayRegion.cxx index 1ea6206af3..536482e5be 100644 --- a/panda/src/display/displayRegion.cxx +++ b/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()); } } diff --git a/panda/src/display/displayRegion.h b/panda/src/display/displayRegion.h index b87c5b1aed..54871ca55f 100644 --- a/panda/src/display/displayRegion.h +++ b/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); diff --git a/panda/src/display/display_composite1.cxx b/panda/src/display/display_composite1.cxx index e02e1bc597..1bcb07994e 100644 --- a/panda/src/display/display_composite1.cxx +++ b/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" diff --git a/panda/src/display/graphicsChannel.cxx b/panda/src/display/graphicsChannel.cxx index ce3f647cf3..ce7045ce0e 100644 --- a/panda/src/display/graphicsChannel.cxx +++ b/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(); } } diff --git a/panda/src/display/graphicsChannel.h b/panda/src/display/graphicsChannel.h index c49af5c7f6..7e58811506 100644 --- a/panda/src/display/graphicsChannel.h +++ b/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 ©); @@ -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 > GraphicsLayers; @@ -99,7 +99,7 @@ public: private: static TypeHandle _type_handle; - friend class GraphicsWindow; + friend class GraphicsOutput; friend class GraphicsLayer; }; diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index 0bbd5c9f07..a034e259b9 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/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. diff --git a/panda/src/display/graphicsEngine.h b/panda/src/display/graphicsEngine.h index c8cb042c1b..ec53a79fc7 100644 --- a/panda/src/display/graphicsEngine.h +++ b/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); diff --git a/panda/src/display/graphicsLayer.cxx b/panda/src/display/graphicsLayer.cxx index e5a8e9c3e6..f1f55a1f75 100644 --- a/panda/src/display/graphicsLayer.cxx +++ b/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; diff --git a/panda/src/display/graphicsLayer.h b/panda/src/display/graphicsLayer.h index d49aac7c11..90c25c6de0 100644 --- a/panda/src/display/graphicsLayer.h +++ b/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; }; diff --git a/panda/src/display/graphicsOutput.I b/panda/src/display/graphicsOutput.I new file mode 100644 index 0000000000..3fad9d71fd --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// 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(); + } +} diff --git a/panda/src/display/graphicsOutput.cxx b/panda/src/display/graphicsOutput.cxx new file mode 100644 index 0000000000..3434f01934 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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); + } + } + } + } + } + } +} diff --git a/panda/src/display/graphicsOutput.h b/panda/src/display/graphicsOutput.h new file mode 100644 index 0000000000..04c0e933e1 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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 ©); + void operator = (const GraphicsOutput ©); + +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 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 */ diff --git a/panda/src/display/graphicsPipe.cxx b/panda/src/display/graphicsPipe.cxx index 1b221132a4..05b1805692 100644 --- a/panda/src/display/graphicsPipe.cxx +++ b/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; } diff --git a/panda/src/display/graphicsPipe.h b/panda/src/display/graphicsPipe.h index 448d6a44b2..36f9a1cc26 100644 --- a/panda/src/display/graphicsPipe.h +++ b/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); diff --git a/panda/src/display/graphicsWindow.I b/panda/src/display/graphicsWindow.I index a3f05f9556..8b3bdd3e76 100644 --- a/panda/src/display/graphicsWindow.I +++ b/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(); - } -} diff --git a/panda/src/display/graphicsWindow.cxx b/panda/src/display/graphicsWindow.cxx index cdf9f7104a..d0699cd51d 100644 --- a/panda/src/display/graphicsWindow.cxx +++ b/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. +// Function: GraphicsWindow::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(). //////////////////////////////////////////////////////////////////// -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; +void GraphicsWindow:: +request_open() { + WindowProperties open_properties; + open_properties.set_open(true); + request_properties(open_properties); } //////////////////////////////////////////////////////////////////// -// Function: GraphicsWindow::begin_frame +// Function: GraphicsWindow::request_close // 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. +// 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:: -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); - } +request_close() { + WindowProperties close_properties; + close_properties.set_open(false); + request_properties(close_properties); } - + //////////////////////////////////////////////////////////////////// -// Function: GraphicsWindow::end_frame +// Function: GraphicsWindow::set_close_now // 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. +// 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_frame() { - nassertv(_gsg != (GraphicsStateGuardian *)NULL); - _gsg->end_frame(); -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindow::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 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. -//////////////////////////////////////////////////////////////////// -void GraphicsWindow:: -release_gsg() { - _gsg.clear(); -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindow::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 GraphicsWindow:: -begin_flip() { -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsWindow::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 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); - } - } - } - } - } - } -} diff --git a/panda/src/display/graphicsWindow.h b/panda/src/display/graphicsWindow.h index 833d4a60da..181ffd32f8 100644 --- a/panda/src/display/graphicsWindow.h +++ b/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 ©); - void operator = (const GraphicsWindow ©); - 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 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" diff --git a/panda/src/distort/nonlinearImager.cxx b/panda/src/distort/nonlinearImager.cxx index 47b63cad84..9611fa4da4 100644 --- a/panda/src/distort/nonlinearImager.cxx +++ b/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; diff --git a/panda/src/distort/nonlinearImager.h b/panda/src/distort/nonlinearImager.h index e605a5e3bb..c241133e11 100644 --- a/panda/src/distort/nonlinearImager.h +++ b/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; }; diff --git a/panda/src/framework/config_framework.cxx b/panda/src/framework/config_framework.cxx index 63d4dc8fa6..0c72c283f5 100644 --- a/panda/src/framework/config_framework.cxx +++ b/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. diff --git a/panda/src/framework/config_framework.h b/panda/src/framework/config_framework.h index f339d347dd..1abb1a6b3c 100644 --- a/panda/src/framework/config_framework.h +++ b/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; diff --git a/panda/src/framework/pandaFramework.cxx b/panda/src/framework/pandaFramework.cxx index 1f685b08a8..ac7e5e0e10 100644 --- a/panda/src/framework/pandaFramework.cxx +++ b/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; diff --git a/panda/src/framework/windowFramework.cxx b/panda/src/framework/windowFramework.cxx index 5f3521ae26..5c3f50563b 100644 --- a/panda/src/framework/windowFramework.cxx +++ b/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); diff --git a/panda/src/framework/windowFramework.h b/panda/src/framework/windowFramework.h index fcb473e4d0..2b81b790de 100644 --- a/panda/src/framework/windowFramework.h +++ b/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; diff --git a/panda/src/glgsg/glGraphicsStateGuardian.cxx b/panda/src/glgsg/glGraphicsStateGuardian.cxx index b10516efc9..2829e82800 100644 --- a/panda/src/glgsg/glGraphicsStateGuardian.cxx +++ b/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; } diff --git a/panda/src/glxdisplay/glxGraphicsPipe.h b/panda/src/glxdisplay/glxGraphicsPipe.h index aca330f271..37b7e485f2 100644 --- a/panda/src/glxdisplay/glxGraphicsPipe.h +++ b/panda/src/glxdisplay/glxGraphicsPipe.h @@ -20,6 +20,7 @@ #define GLXGRAPHICSPIPE_H #include "pandabase.h" +#include "graphicsWindow.h" #include "graphicsPipe.h" class glxGraphicsWindow;