define GraphicsOutput class

This commit is contained in:
David Rose 2004-02-06 23:41:00 +00:00
parent d684df5958
commit 26da9be3e7
28 changed files with 1269 additions and 873 deletions

View File

@ -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"

View File

@ -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 \

View File

@ -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());
}
}

View File

@ -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);

View File

@ -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"

View File

@ -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();
}
}

View File

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

View File

@ -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.

View File

@ -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);

View File

@ -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;

View File

@ -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;
};

View File

@ -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();
}
}

View File

@ -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);
}
}
}
}
}
}
}

View File

@ -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 &copy);
void operator = (const GraphicsOutput &copy);
PUBLISHED:
virtual ~GraphicsOutput();
INLINE GraphicsStateGuardian *get_gsg() const;
INLINE GraphicsPipe *get_pipe() const;
INLINE int get_x_size() const;
INLINE int get_y_size() const;
INLINE bool has_size() const;
INLINE bool is_valid() const;
virtual bool is_active() const;
GraphicsChannel *get_channel(int index);
void remove_channel(int index);
int get_max_channel_index() const;
bool is_channel_defined(int index) const;
int get_num_display_regions() const;
DisplayRegion *get_display_region(int n) const;
Filename take_screenshot(const string &prefix = "screenshot");
bool take_screenshot(const Filename &filename);
public:
// No need to publish these.
PT(DisplayRegion) make_scratch_display_region(int x_size, int y_size) const;
public:
// These are not intended to be called directly by the user.
INLINE void win_display_regions_changed();
virtual void request_open();
virtual void request_close();
virtual void set_close_now();
public:
// It is an error to call any of the following methods from any
// thread other than the draw thread. These methods are normally
// called by the GraphicsEngine.
virtual bool begin_frame();
void clear();
virtual void end_frame();
// This method is called in the draw thread prior to issuing any
// drawing commands for the window.
virtual void make_current();
virtual void release_gsg();
// These methods will be called within the app (main) thread.
virtual void begin_flip();
virtual void end_flip();
// It is an error to call any of the following methods from any
// thread other than the window thread. These methods are normally
// called by the GraphicsEngine.
virtual void process_events();
protected:
virtual void close_window();
virtual bool open_window();
virtual void reset_window(bool swapchain);
void declare_channel(int index, GraphicsChannel *chan);
protected:
PT(GraphicsStateGuardian) _gsg;
PT(GraphicsPipe) _pipe;
private:
INLINE void determine_display_regions() const;
void do_determine_display_regions();
protected:
Mutex _lock;
// protects _channels, _display_regions.
typedef pvector< PT(GraphicsChannel) > Channels;
Channels _channels;
typedef pvector<DisplayRegion *> DisplayRegions;
DisplayRegions _display_regions;
bool _display_regions_stale;
protected:
int _x_size;
int _y_size;
bool _has_size;
bool _is_valid;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
TypedWritableReferenceCount::init_type();
register_type(_type_handle, "GraphicsOutput",
TypedWritableReferenceCount::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
friend class GraphicsPipe;
friend class GraphicsEngine;
};
#include "graphicsOutput.I"
#endif /* GRAPHICSOUTPUT_H */

View File

@ -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;
}

View File

@ -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);

View File

@ -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();
}
}

View File

@ -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);
}
}
}
}
}
}
}

View File

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

View File

@ -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;

View File

@ -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;
};

View File

@ -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.

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

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

View File

@ -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;
}

View File

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