759 lines
23 KiB
Text
759 lines
23 KiB
Text
|
/**
|
||
|
* PANDA 3D SOFTWARE
|
||
|
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||
|
*
|
||
|
* All use of this software is subject to the terms of the revised BSD
|
||
|
* license. You should have received a copy of this license along
|
||
|
* with this source code in a file named "LICENSE."
|
||
|
*
|
||
|
* @file graphicsOutput.I
|
||
|
* @author drose
|
||
|
* @date 2004-02-06
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* 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;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the graphics engine that created this output. Since there is
|
||
|
* normally only one GraphicsEngine object in an application, this is usually
|
||
|
* the same as the global GraphicsEngine.
|
||
|
*/
|
||
|
INLINE GraphicsEngine *GraphicsOutput::
|
||
|
get_engine() const {
|
||
|
return _engine;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the name that was passed to the GraphicsOutput constructor.
|
||
|
*/
|
||
|
INLINE const std::string &GraphicsOutput::
|
||
|
get_name() const {
|
||
|
return _name;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* If the GraphicsOutput is set to render into a texture, returns the number
|
||
|
* of textures that are being rendered into. Normally, the textures would be
|
||
|
* associated with different buffers - a color texture, a depth texture, and a
|
||
|
* stencil texture.
|
||
|
*/
|
||
|
INLINE int GraphicsOutput::
|
||
|
count_textures() const {
|
||
|
CDReader cdata(_cycler);
|
||
|
return cdata->_textures.size();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if the GraphicsOutput is rendering into any textures at all.
|
||
|
*/
|
||
|
INLINE bool GraphicsOutput::
|
||
|
has_texture() const {
|
||
|
CDReader cdata(_cycler);
|
||
|
return (cdata->_textures.size() > 0);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the nth texture into which the GraphicsOutput renders. Returns
|
||
|
* NULL if there is no such texture.
|
||
|
*
|
||
|
* If the texture is non-NULL, it may be applied to geometry to be rendered
|
||
|
* for any other windows or outputs that share the same GSG as this
|
||
|
* GraphicsOutput. The effect is undefined for windows that share a different
|
||
|
* GSG; usually in these cases the texture will be invalid.
|
||
|
*/
|
||
|
INLINE Texture *GraphicsOutput::
|
||
|
get_texture(int i) const {
|
||
|
CDReader cdata(_cycler);
|
||
|
if ((i < 0) || (i >= ((int)cdata->_textures.size()))) {
|
||
|
return nullptr;
|
||
|
}
|
||
|
return cdata->_textures[i]._texture;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the RenderTexturePlane associated with the nth render-texture.
|
||
|
* Returns 0 if there is no such texture.
|
||
|
*/
|
||
|
INLINE GraphicsOutput::RenderTexturePlane GraphicsOutput::
|
||
|
get_texture_plane(int i) const {
|
||
|
CDReader cdata(_cycler);
|
||
|
if ((i < 0) || (i >= ((int)cdata->_textures.size()))) {
|
||
|
return (RenderTexturePlane)0;
|
||
|
}
|
||
|
return cdata->_textures[i]._plane;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the RenderTextureMode associated with the nth render-texture.
|
||
|
* Returns RTM_none if there is no such texture.
|
||
|
*/
|
||
|
INLINE GraphicsOutput::RenderTextureMode GraphicsOutput::
|
||
|
get_rtm_mode(int i) const {
|
||
|
CDReader cdata(_cycler);
|
||
|
if ((i < 0) || (i >= ((int)cdata->_textures.size()))) {
|
||
|
return RTM_none;
|
||
|
}
|
||
|
return cdata->_textures[i]._rtm_mode;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the visible size of the window or 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 const LVecBase2i &GraphicsOutput::
|
||
|
get_size() const {
|
||
|
return _size;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the visible width of the window or 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 _size.get_x();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the visible height of the window or 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 _size.get_y();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the internal size of the window or buffer. This is almost always
|
||
|
* the same as get_size(), except when a pixel_zoom is in effect--see
|
||
|
* set_pixel_zoom().
|
||
|
*/
|
||
|
INLINE LVecBase2i GraphicsOutput::
|
||
|
get_fb_size() const {
|
||
|
return LVecBase2i(std::max(int(_size.get_x() * get_pixel_factor()), 1),
|
||
|
std::max(int(_size.get_y() * get_pixel_factor()), 1));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the internal width of the window or buffer. This is almost always
|
||
|
* the same as get_x_size(), except when a pixel_zoom is in effect--see
|
||
|
* set_pixel_zoom().
|
||
|
*/
|
||
|
INLINE int GraphicsOutput::
|
||
|
get_fb_x_size() const {
|
||
|
return std::max(int(_size.get_x() * get_pixel_factor()), 1);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the internal height of the window or buffer. This is almost always
|
||
|
* the same as get_y_size(), except when a pixel_zoom is in effect--see
|
||
|
* set_pixel_zoom().
|
||
|
*/
|
||
|
INLINE int GraphicsOutput::
|
||
|
get_fb_y_size() const {
|
||
|
return std::max(int(_size.get_y() * get_pixel_factor()), 1);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* If side-by-side stereo is enabled, this returns the pixel size of the left
|
||
|
* eye, based on scaling get_size() by get_sbs_left_dimensions(). If side-by-
|
||
|
* side stereo is not enabled, this returns the same as get_size().
|
||
|
*/
|
||
|
INLINE LVecBase2i GraphicsOutput::
|
||
|
get_sbs_left_size() const {
|
||
|
PN_stdfloat left_w = _sbs_left_dimensions[1] - _sbs_left_dimensions[0];
|
||
|
PN_stdfloat left_h = _sbs_left_dimensions[3] - _sbs_left_dimensions[2];
|
||
|
return LVecBase2i(std::max(int(_size.get_x() * left_w), 1),
|
||
|
std::max(int(_size.get_y() * left_h), 1));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* If side-by-side stereo is enabled, this returns the pixel width of the left
|
||
|
* eye, based on scaling get_x_size() by get_sbs_left_dimensions(). If side-
|
||
|
* by-side stereo is not enabled, this returns the same as get_x_size().
|
||
|
*/
|
||
|
INLINE int GraphicsOutput::
|
||
|
get_sbs_left_x_size() const {
|
||
|
PN_stdfloat left_w = _sbs_left_dimensions[1] - _sbs_left_dimensions[0];
|
||
|
return std::max(int(_size.get_x() * left_w), 1);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* If side-by-side stereo is enabled, this returns the pixel height of the
|
||
|
* left eye, based on scaling get_y_size() by get_sbs_left_dimensions(). If
|
||
|
* side-by-side stereo is not enabled, this returns the same as get_y_size().
|
||
|
*/
|
||
|
INLINE int GraphicsOutput::
|
||
|
get_sbs_left_y_size() const {
|
||
|
PN_stdfloat left_h = _sbs_left_dimensions[3] - _sbs_left_dimensions[2];
|
||
|
return std::max(int(_size.get_y() * left_h), 1);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* If side-by-side stereo is enabled, this returns the pixel size of the right
|
||
|
* eye, based on scaling get_size() by get_sbs_right_dimensions(). If side-
|
||
|
* by-side stereo is not enabled, this returns the same as get_size().
|
||
|
*/
|
||
|
INLINE LVecBase2i GraphicsOutput::
|
||
|
get_sbs_right_size() const {
|
||
|
PN_stdfloat right_w = _sbs_right_dimensions[1] - _sbs_right_dimensions[0];
|
||
|
PN_stdfloat right_h = _sbs_right_dimensions[3] - _sbs_right_dimensions[2];
|
||
|
return LVecBase2i(std::max(int(_size.get_x() * right_w), 1),
|
||
|
std::max(int(_size.get_y() * right_h), 1));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* If side-by-side stereo is enabled, this returns the pixel width of the
|
||
|
* right eye, based on scaling get_x_size() by get_sbs_right_dimensions(). If
|
||
|
* side-by-side stereo is not enabled, this returns the same as get_x_size().
|
||
|
*/
|
||
|
INLINE int GraphicsOutput::
|
||
|
get_sbs_right_x_size() const {
|
||
|
PN_stdfloat right_w = _sbs_right_dimensions[1] - _sbs_right_dimensions[0];
|
||
|
return std::max(int(_size.get_x() * right_w), 1);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* If side-by-side stereo is enabled, this returns the pixel height of the
|
||
|
* right eye, based on scaling get_y_size() by get_sbs_right_dimensions(). If
|
||
|
* side-by-side stereo is not enabled, this returns the same as get_y_size().
|
||
|
*/
|
||
|
INLINE int GraphicsOutput::
|
||
|
get_sbs_right_y_size() const {
|
||
|
PN_stdfloat right_h = _sbs_right_dimensions[3] - _sbs_right_dimensions[2];
|
||
|
return std::max(int(_size.get_y() * right_h), 1);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if the output is fully created and ready for rendering, false
|
||
|
* otherwise.
|
||
|
*/
|
||
|
INLINE bool GraphicsOutput::
|
||
|
is_valid() const {
|
||
|
return _is_valid && _is_nonzero_size;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if the output has a nonzero size in both X and Y, or false if
|
||
|
* it is zero (and therefore invalid).
|
||
|
*/
|
||
|
INLINE bool GraphicsOutput::
|
||
|
is_nonzero_size() const {
|
||
|
return _is_nonzero_size;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the current setting of the inverted flag. When this is true, the
|
||
|
* scene is rendered into the window upside-down, flipped like a mirror along
|
||
|
* the X axis. See set_inverted().
|
||
|
*/
|
||
|
INLINE bool GraphicsOutput::
|
||
|
get_inverted() const {
|
||
|
return _inverted;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Changes the "swap eyes" flag. This flag is normally false. When it is
|
||
|
* true, the left and right channels of a stereo DisplayRegion are sent to the
|
||
|
* opposite channels in the rendering backend. This is meant to work around
|
||
|
* hardware that inadvertently swaps the output channels, or hardware for
|
||
|
* which it cannot be determined which channel is which until runtime.
|
||
|
*/
|
||
|
INLINE void GraphicsOutput::
|
||
|
set_swap_eyes(bool swap_eyes) {
|
||
|
_swap_eyes = swap_eyes;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the current setting of the "swap eyes" flag. See set_swap_eyes().
|
||
|
*/
|
||
|
INLINE bool GraphicsOutput::
|
||
|
get_swap_eyes() const {
|
||
|
return _swap_eyes;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Enables red-blue stereo mode on this particular window. When red-blue
|
||
|
* stereo mode is in effect, DisplayRegions that have the "left" channel set
|
||
|
* will render in the red (or specified) channel only, while DisplayRegions
|
||
|
* that have the "right" channel set will render in the blue (or specified)
|
||
|
* channel only.
|
||
|
*
|
||
|
* The remaining two parameters specify the particular color channel(s) to
|
||
|
* associate with each eye. Use the bits defined in
|
||
|
* ColorWriteAttrib::Channels.
|
||
|
*
|
||
|
* This can be used to achieve a cheesy stereo mode in the absence of
|
||
|
* hardware-supported stereo.
|
||
|
*/
|
||
|
INLINE void GraphicsOutput::
|
||
|
set_red_blue_stereo(bool red_blue_stereo,
|
||
|
unsigned int left_eye_color_mask,
|
||
|
unsigned int right_eye_color_mask) {
|
||
|
_red_blue_stereo = red_blue_stereo;
|
||
|
if (_red_blue_stereo) {
|
||
|
_left_eye_color_mask = left_eye_color_mask;
|
||
|
_right_eye_color_mask = right_eye_color_mask;
|
||
|
} else {
|
||
|
_left_eye_color_mask = 0x0f;
|
||
|
_right_eye_color_mask = 0x0f;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns whether red-blue stereo mode is in effect for this particular
|
||
|
* window. See set_red_blue_stereo().
|
||
|
*/
|
||
|
INLINE bool GraphicsOutput::
|
||
|
get_red_blue_stereo() const {
|
||
|
return _red_blue_stereo;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the color mask in effect when rendering a left-eye view in red_blue
|
||
|
* stereo mode. This is one or more bits defined in
|
||
|
* ColorWriteAttrib::Channels. See set_red_blue_stereo().
|
||
|
*/
|
||
|
INLINE unsigned int GraphicsOutput::
|
||
|
get_left_eye_color_mask() const {
|
||
|
return _left_eye_color_mask;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the color mask in effect when rendering a right-eye view in
|
||
|
* red_blue stereo mode. This is one or more bits defined in
|
||
|
* ColorWriteAttrib::Channels. See set_red_blue_stereo().
|
||
|
*/
|
||
|
INLINE unsigned int GraphicsOutput::
|
||
|
get_right_eye_color_mask() const {
|
||
|
return _right_eye_color_mask;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns whether side-by-side stereo mode is in effect for this particular
|
||
|
* window. See set_side_by_side_stereo().
|
||
|
*/
|
||
|
INLINE bool GraphicsOutput::
|
||
|
get_side_by_side_stereo() const {
|
||
|
return _side_by_side_stereo;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the effective sub-region of the window for displaying the left
|
||
|
* channel, if side-by-side stereo mode is in effect for the window. See
|
||
|
* set_side_by_side_stereo().
|
||
|
*/
|
||
|
INLINE const LVecBase4 &GraphicsOutput::
|
||
|
get_sbs_left_dimensions() const {
|
||
|
return _sbs_left_dimensions;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the effective sub-region of the window for displaying the right
|
||
|
* channel, if side-by-side stereo mode is in effect for the window. See
|
||
|
* set_side_by_side_stereo().
|
||
|
*/
|
||
|
INLINE const LVecBase4 &GraphicsOutput::
|
||
|
get_sbs_right_dimensions() const {
|
||
|
return _sbs_right_dimensions;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the framebuffer properties of the window.
|
||
|
*/
|
||
|
INLINE const FrameBufferProperties &GraphicsOutput::
|
||
|
get_fb_properties() const {
|
||
|
return _fb_properties;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns Returns true if this window can render stereo DisplayRegions,
|
||
|
* either through red-blue stereo (see set_red_blue_stereo()) or through true
|
||
|
* hardware stereo rendering.
|
||
|
*/
|
||
|
INLINE bool GraphicsOutput::
|
||
|
is_stereo() const {
|
||
|
return _red_blue_stereo || _side_by_side_stereo || _fb_properties.is_stereo();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Resets the delete flag, so the GraphicsOutput will not be automatically
|
||
|
* deleted before the beginning of the next frame.
|
||
|
*/
|
||
|
INLINE void GraphicsOutput::
|
||
|
clear_delete_flag() {
|
||
|
_delete_flag = false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the sorting order of this particular GraphicsOutput. The various
|
||
|
* GraphicsOutputs within a particular thread will be rendered in the
|
||
|
* indicated order.
|
||
|
*/
|
||
|
INLINE int GraphicsOutput::
|
||
|
get_sort() const {
|
||
|
return _sort;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Specifies the sort value of future offscreen buffers created by
|
||
|
* make_texture_sort().
|
||
|
*
|
||
|
* The purpose of this method is to allow the user to limit the sort value
|
||
|
* chosen for a buffer created via make_texture_buffer(). Normally, this
|
||
|
* buffer will be assigned a value of get_sort() - 1, so that it will be
|
||
|
* rendered before this window is rendered; but sometimes this isn't
|
||
|
* sufficiently early, especially if other buffers also have a view into the
|
||
|
* same scene.
|
||
|
*
|
||
|
* If you specify a value here, then new buffers created via
|
||
|
* make_texture_buffer() will be given that sort value instead of get_sort() -
|
||
|
* 1.
|
||
|
*/
|
||
|
INLINE void GraphicsOutput::
|
||
|
set_child_sort(int child_sort) {
|
||
|
_child_sort = child_sort;
|
||
|
_got_child_sort = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Resets the sort value of future offscreen buffers created by
|
||
|
* make_texture_sort() to the default value. See set_child_sort().
|
||
|
*/
|
||
|
INLINE void GraphicsOutput::
|
||
|
clear_child_sort() {
|
||
|
_got_child_sort = false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the sort value of future offscreen buffers created by
|
||
|
* make_texture_sort(). See set_child_sort().
|
||
|
*/
|
||
|
INLINE int GraphicsOutput::
|
||
|
get_child_sort() const {
|
||
|
if (_got_child_sort) {
|
||
|
return _child_sort;
|
||
|
} else {
|
||
|
return get_sort() - 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* When the GraphicsOutput is in triggered copy mode, this function triggers
|
||
|
* the copy (at the end of the next frame).
|
||
|
* @returns a future that can be awaited.
|
||
|
*/
|
||
|
INLINE AsyncFuture *GraphicsOutput::
|
||
|
trigger_copy() {
|
||
|
AsyncFuture *future = _trigger_copy;
|
||
|
if (future == nullptr) {
|
||
|
future = new AsyncFuture;
|
||
|
_trigger_copy = future;
|
||
|
}
|
||
|
return future;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates a new DisplayRegion that covers the entire window.
|
||
|
*
|
||
|
* If is_stereo() is true for this window, and default-stereo-camera is
|
||
|
* configured true, this actually makes a StereoDisplayRegion. Call
|
||
|
* make_mono_display_region() or make_stereo_display_region() if you want to
|
||
|
* insist on one or the other.
|
||
|
*/
|
||
|
INLINE DisplayRegion *GraphicsOutput::
|
||
|
make_display_region() {
|
||
|
return make_display_region(0.0f, 1.0f, 0.0f, 1.0f);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates a new DisplayRegion that covers the indicated sub-rectangle within
|
||
|
* the window. The range on all parameters is 0..1.
|
||
|
*
|
||
|
* If is_stereo() is true for this window, and default-stereo-camera is
|
||
|
* configured true, this actually makes a StereoDisplayRegion. Call
|
||
|
* make_mono_display_region() or make_stereo_display_region() if you want to
|
||
|
* insist on one or the other.
|
||
|
*/
|
||
|
DisplayRegion *GraphicsOutput::
|
||
|
make_display_region(PN_stdfloat l, PN_stdfloat r, PN_stdfloat b, PN_stdfloat t) {
|
||
|
return make_display_region(LVecBase4(l, r, b, t));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates a new DisplayRegion that covers the entire window.
|
||
|
*
|
||
|
* This generally returns a mono DisplayRegion, even if is_stereo() is true.
|
||
|
* However, if side-by-side stereo is enabled, this will return a
|
||
|
* StereoDisplayRegion whose two eyes are both set to SC_mono. (This is
|
||
|
* necessary because in side-by-side stereo mode, it is necessary to draw even
|
||
|
* mono DisplayRegions twice).
|
||
|
*/
|
||
|
INLINE DisplayRegion *GraphicsOutput::
|
||
|
make_mono_display_region() {
|
||
|
return make_mono_display_region(0.0f, 1.0f, 0.0f, 1.0f);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates a new DisplayRegion that covers the entire window.
|
||
|
*
|
||
|
* This generally returns a mono DisplayRegion, even if is_stereo() is true.
|
||
|
* However, if side-by-side stereo is enabled, this will return a
|
||
|
* StereoDisplayRegion whose two eyes are both set to SC_mono. (This is
|
||
|
* necessary because in side-by-side stereo mode, it is necessary to draw even
|
||
|
* mono DisplayRegions twice).
|
||
|
*/
|
||
|
INLINE DisplayRegion *GraphicsOutput::
|
||
|
make_mono_display_region(PN_stdfloat l, PN_stdfloat r, PN_stdfloat b, PN_stdfloat t) {
|
||
|
return make_mono_display_region(LVecBase4(l, r, b, t));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates a new DisplayRegion that covers the entire window.
|
||
|
*
|
||
|
* This always returns a stereo DisplayRegion, even if is_stereo() is false.
|
||
|
*/
|
||
|
INLINE StereoDisplayRegion *GraphicsOutput::
|
||
|
make_stereo_display_region() {
|
||
|
return make_stereo_display_region(0.0f, 1.0f, 0.0f, 1.0f);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates a new DisplayRegion that covers the entire window.
|
||
|
*
|
||
|
* This always returns a stereo DisplayRegion, even if is_stereo() is false.
|
||
|
*/
|
||
|
INLINE StereoDisplayRegion *GraphicsOutput::
|
||
|
make_stereo_display_region(PN_stdfloat l, PN_stdfloat r, PN_stdfloat b, PN_stdfloat t) {
|
||
|
return make_stereo_display_region(LVecBase4(l, r, b, t));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the special "overlay" DisplayRegion that is created for each window
|
||
|
* or buffer. This DisplayRegion covers the entire window, but cannot be used
|
||
|
* for rendering. It is a placeholder only, to indicate the dimensions of the
|
||
|
* window, and is usually used internally for purposes such as clearing the
|
||
|
* window, or grabbing a screenshot of the window.
|
||
|
*
|
||
|
* There are very few applications that require access to this DisplayRegion.
|
||
|
* Normally, you should create your own DisplayRegion that covers the window,
|
||
|
* if you want to render to the window.
|
||
|
*/
|
||
|
INLINE DisplayRegion *GraphicsOutput::
|
||
|
get_overlay_display_region() const {
|
||
|
return _overlay_display_region;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Saves a screenshot of the region 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 Config 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().
|
||
|
*/
|
||
|
INLINE Filename GraphicsOutput::
|
||
|
make_screenshot_filename(const std::string &prefix) {
|
||
|
return DisplayRegion::make_screenshot_filename(prefix);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Saves a screenshot of the region to a default filename, and returns the
|
||
|
* filename, or empty string if the screenshot failed. The filename is
|
||
|
* generated by make_screenshot_filename().
|
||
|
*/
|
||
|
INLINE Filename GraphicsOutput::
|
||
|
save_screenshot_default(const std::string &prefix) {
|
||
|
return _overlay_display_region->save_screenshot_default(prefix);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Saves a screenshot of the region to the indicated filename. The image
|
||
|
* comment is an optional user readable string that will be saved with the
|
||
|
* header of the image (if the file format supports embedded data; for example
|
||
|
* jpg allows comments). Returns true on success, false on failure.
|
||
|
*/
|
||
|
INLINE bool GraphicsOutput::
|
||
|
save_screenshot(const Filename &filename, const std::string &image_comment) {
|
||
|
return _overlay_display_region->save_screenshot(filename, image_comment);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Captures the most-recently rendered image from the framebuffer into the
|
||
|
* indicated PNMImage. Returns true on success, false on failure.
|
||
|
*/
|
||
|
INLINE bool GraphicsOutput::
|
||
|
get_screenshot(PNMImage &image) {
|
||
|
return _overlay_display_region->get_screenshot(image);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Captures the most-recently rendered image from the framebuffer and returns
|
||
|
* it as Texture, or NULL on failure.
|
||
|
*/
|
||
|
INLINE PT(Texture) GraphicsOutput::
|
||
|
get_screenshot() {
|
||
|
return _overlay_display_region->get_screenshot();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* The sorting operator is used to order the GraphicsOutput object in order by
|
||
|
* their sort number, so that they will render in the correct order in the
|
||
|
* GraphicsEngine.
|
||
|
*/
|
||
|
INLINE bool GraphicsOutput::
|
||
|
operator < (const GraphicsOutput &other) const {
|
||
|
if (_sort != other._sort) {
|
||
|
return _sort < other._sort;
|
||
|
}
|
||
|
return _internal_sort_index < other._internal_sort_index;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* 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.
|
||
|
CDLockedReader cdata(_cycler);
|
||
|
if (cdata->_active_display_regions_stale) {
|
||
|
CDWriter cdataw(((GraphicsOutput *)this)->_cycler, cdata, false);
|
||
|
((GraphicsOutput *)this)->do_determine_display_regions(cdataw);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Intended to be called when the active state on a nested display region
|
||
|
* changes, forcing the window to recompute its list of active display
|
||
|
* regions.
|
||
|
*/
|
||
|
INLINE void GraphicsOutput::
|
||
|
win_display_regions_changed() {
|
||
|
CDWriter cdata(_cycler, true);
|
||
|
cdata->_active_display_regions_stale = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a PStatCollector for timing the cull operation for just this
|
||
|
* GraphicsOutput.
|
||
|
*/
|
||
|
INLINE PStatCollector &GraphicsOutput::
|
||
|
get_cull_window_pcollector() {
|
||
|
return _cull_window_pcollector;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a PStatCollector for timing the draw operation for just this
|
||
|
* GraphicsOutput.
|
||
|
*/
|
||
|
INLINE PStatCollector &GraphicsOutput::
|
||
|
get_draw_window_pcollector() {
|
||
|
return _draw_window_pcollector;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a PStatCollector for timing the clear operation for just this
|
||
|
* GraphicsOutput.
|
||
|
*/
|
||
|
INLINE PStatCollector &GraphicsOutput::
|
||
|
get_clear_window_pcollector() {
|
||
|
return _clear_window_pcollector;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Display the spam message associated with begin_frame
|
||
|
*/
|
||
|
INLINE void GraphicsOutput::
|
||
|
begin_frame_spam(FrameMode mode) {
|
||
|
if (display_cat.is_spam()) {
|
||
|
display_cat.spam()
|
||
|
<< "begin_frame(" << mode << "): " << get_type() << " "
|
||
|
<< get_name() << " " << (void *)this << "\n";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Display the spam message associated with end_frame
|
||
|
*/
|
||
|
INLINE void GraphicsOutput::
|
||
|
end_frame_spam(FrameMode mode) {
|
||
|
if (display_cat.is_spam()) {
|
||
|
display_cat.spam()
|
||
|
<< "end_frame(" << mode << "): " << get_type() << " "
|
||
|
<< get_name() << " " << (void *)this << "\n";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Clear the variables that select a cube-map face (or other multipage texture
|
||
|
* face).
|
||
|
*/
|
||
|
INLINE void GraphicsOutput::
|
||
|
clear_cube_map_selection() {
|
||
|
_target_tex_page = -1;
|
||
|
_prev_page_dr = nullptr;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* To be called at the end of the frame, after the window has successfully
|
||
|
* been drawn and is ready to be flipped (if appropriate).
|
||
|
*/
|
||
|
INLINE void GraphicsOutput::
|
||
|
trigger_flip() {
|
||
|
if (!_fb_properties.is_single_buffered()) {
|
||
|
_flip_ready = true;
|
||
|
}
|
||
|
}
|