mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 02:42:49 -04:00
885 lines
33 KiB
C++
885 lines
33 KiB
C++
// Filename: displayRegion.cxx
|
|
// Created by: cary (10Feb99)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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."
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "displayRegion.h"
|
|
#include "stereoDisplayRegion.h"
|
|
#include "graphicsEngine.h"
|
|
#include "graphicsOutput.h"
|
|
#include "config_display.h"
|
|
#include "texture.h"
|
|
#include "camera.h"
|
|
#include "dcast.h"
|
|
#include "pnmImage.h"
|
|
|
|
#include <time.h>
|
|
|
|
TypeHandle DisplayRegion::_type_handle;
|
|
TypeHandle DisplayRegionPipelineReader::_type_handle;
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::Constructor
|
|
// Access: Protected
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
DisplayRegion::
|
|
DisplayRegion(GraphicsOutput *window, const LVecBase4 &dimensions) :
|
|
_window(window),
|
|
_incomplete_render(true),
|
|
_texture_reload_priority(0),
|
|
_cull_region_pcollector("Cull:Invalid"),
|
|
_draw_region_pcollector("Draw:Invalid")
|
|
{
|
|
_screenshot_buffer_type = window->get_draw_buffer_type();
|
|
_draw_buffer_type = window->get_draw_buffer_type();
|
|
set_dimensions(dimensions);
|
|
compute_pixels_all_stages();
|
|
|
|
_window->add_display_region(this);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::Copy Constructor
|
|
// Access: Private
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
DisplayRegion::
|
|
DisplayRegion(const DisplayRegion ©) :
|
|
_window(NULL),
|
|
_cull_region_pcollector("Cull:Invalid"),
|
|
_draw_region_pcollector("Draw:Invalid")
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::Copy Assignment Operator
|
|
// Access: Private
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void DisplayRegion::
|
|
operator = (const DisplayRegion&) {
|
|
nassertv(false);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::Destructor
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
DisplayRegion::
|
|
~DisplayRegion() {
|
|
cleanup();
|
|
|
|
// The window pointer should already have been cleared by the time
|
|
// the DisplayRegion destructs (since the GraphicsOutput class keeps
|
|
// a reference count on the DisplayRegion).
|
|
nassertv(_window == (GraphicsOutput *)NULL);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::cleanup
|
|
// Access: Public
|
|
// Description: Cleans up some pointers associated with the
|
|
// DisplayRegion to help reduce the chance of memory
|
|
// leaks due to circular reference counts.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DisplayRegion::
|
|
cleanup() {
|
|
set_camera(NodePath());
|
|
|
|
CDCullWriter cdata(_cycler_cull, true);
|
|
cdata->_cull_result = NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::set_lens_index
|
|
// Access: Published
|
|
// Description: Sets the lens index, allows for multiple lenses to
|
|
// be attached to a camera. This is useful for a
|
|
// variety of setups, such as fish eye rendering.
|
|
// The default is 0.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DisplayRegion::
|
|
set_lens_index(int index) {
|
|
int pipeline_stage = Thread::get_current_pipeline_stage();
|
|
nassertv(pipeline_stage == 0);
|
|
CDWriter cdata(_cycler);
|
|
cdata->_lens_index = index;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::set_dimensions
|
|
// Access: Published, Virtual
|
|
// Description: Changes the portion of the framebuffer this
|
|
// DisplayRegion corresponds to. The parameters range
|
|
// from 0 to 1, where 0,0 is the lower left corner and
|
|
// 1,1 is the upper right; (0, 1, 0, 1) represents the
|
|
// whole screen.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DisplayRegion::
|
|
set_dimensions(const LVecBase4 &dimensions) {
|
|
int pipeline_stage = Thread::get_current_pipeline_stage();
|
|
nassertv(pipeline_stage == 0);
|
|
CDWriter cdata(_cycler);
|
|
|
|
cdata->_dimensions = dimensions;
|
|
|
|
if (_window != (GraphicsOutput *)NULL && _window->has_size()) {
|
|
do_compute_pixels(_window->get_fb_x_size(), _window->get_fb_y_size(), cdata);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::get_pipe
|
|
// Access: Published
|
|
// Description: Returns the GraphicsPipe that this DisplayRegion is
|
|
// ultimately associated with, or NULL if no pipe is
|
|
// associated.
|
|
////////////////////////////////////////////////////////////////////
|
|
GraphicsPipe *DisplayRegion::
|
|
get_pipe() const {
|
|
return (_window != (GraphicsOutput *)NULL) ? _window->get_pipe() : NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::is_stereo
|
|
// Access: Published, Virtual
|
|
// Description: Returns true if this is a StereoDisplayRegion, false
|
|
// otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DisplayRegion::
|
|
is_stereo() const {
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::set_camera
|
|
// Access: Published, Virtual
|
|
// Description: Sets the camera that is associated with this
|
|
// DisplayRegion. There is a one-to-many association
|
|
// between cameras and DisplayRegions; one camera may be
|
|
// shared by multiple DisplayRegions.
|
|
//
|
|
// The camera is actually set via a NodePath, which
|
|
// clarifies which instance of the camera (if there
|
|
// happen to be multiple instances) we should use.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DisplayRegion::
|
|
set_camera(const NodePath &camera) {
|
|
int pipeline_stage = Thread::get_current_pipeline_stage();
|
|
|
|
// We allow set_camera(NodePath()) to happen in cleanup(), which can
|
|
// be called from any pipeline stage.
|
|
nassertv(pipeline_stage == 0 || camera.is_empty());
|
|
CDStageWriter cdata(_cycler, 0);
|
|
|
|
Camera *camera_node = (Camera *)NULL;
|
|
if (!camera.is_empty()) {
|
|
DCAST_INTO_V(camera_node, camera.node());
|
|
}
|
|
|
|
if (camera_node != cdata->_camera_node) {
|
|
// Note that these operations on the DisplayRegion are not
|
|
// pipelined: they operate across all pipeline stages. Since we
|
|
// have already asserted we are running in pipeline stage 0, no
|
|
// problem.
|
|
if (cdata->_camera_node != (Camera *)NULL) {
|
|
// We need to tell the old camera we're not using him anymore.
|
|
cdata->_camera_node->remove_display_region(this);
|
|
}
|
|
cdata->_camera_node = camera_node;
|
|
if (cdata->_camera_node != (Camera *)NULL) {
|
|
// Now tell the new camera we are using him.
|
|
cdata->_camera_node->add_display_region(this);
|
|
}
|
|
}
|
|
|
|
cdata->_camera = camera;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::set_active
|
|
// Access: Published, Virtual
|
|
// Description: Sets the active flag associated with the
|
|
// DisplayRegion. If the DisplayRegion is marked
|
|
// inactive, nothing is rendered.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DisplayRegion::
|
|
set_active(bool active) {
|
|
int pipeline_stage = Thread::get_current_pipeline_stage();
|
|
nassertv(pipeline_stage == 0);
|
|
CDLockedReader cdata(_cycler);
|
|
|
|
if (active != cdata->_active) {
|
|
CDWriter cdataw(_cycler, cdata);
|
|
cdataw->_active = active;
|
|
win_display_regions_changed();
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::set_sort
|
|
// Access: Published, Virtual
|
|
// Description: Sets the sort value associated with the
|
|
// DisplayRegion. Within a window, DisplayRegions will
|
|
// be rendered in order from the lowest sort value to
|
|
// the highest.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DisplayRegion::
|
|
set_sort(int sort) {
|
|
nassertv(Thread::get_current_pipeline_stage() == 0);
|
|
CDLockedReader cdata(_cycler);
|
|
|
|
if (sort != cdata->_sort) {
|
|
CDWriter cdataw(_cycler, cdata);
|
|
cdataw->_sort = sort;
|
|
win_display_regions_changed();
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::set_stereo_channel
|
|
// Access: Published, Virtual
|
|
// Description: Specifies whether the DisplayRegion represents the
|
|
// left or right channel of a stereo pair, or whether it
|
|
// is a normal, monocular image. This automatically
|
|
// adjusts the lens that is used to render to this
|
|
// DisplayRegion to its left or right eye, according to
|
|
// the lens's stereo properties.
|
|
//
|
|
// When the DisplayRegion is attached to a stereo window
|
|
// (one for which is_stereo() returns true), this also
|
|
// specifies which physical channel the DisplayRegion
|
|
// renders to.
|
|
//
|
|
// Normally you would create at least two DisplayRegions
|
|
// for a stereo window, one for each of the left and
|
|
// right channels. The two DisplayRegions may share the
|
|
// same camera (and thus the same lens); this parameter
|
|
// is used to control the exact properties of the lens
|
|
// when it is used to render into this DisplayRegion.
|
|
//
|
|
// Also see the StereoDisplayRegion, which automates
|
|
// managing a pair of left/right DisplayRegions.
|
|
//
|
|
// An ordinary DisplayRegion may be set to SC_mono,
|
|
// SC_left, or SC_right. You may set SC_stereo only on
|
|
// a StereoDisplayRegion.
|
|
//
|
|
// This call also resets tex_view_offset to its default
|
|
// value, which is 0 for the left eye or 1 for the right
|
|
// eye of a stereo display region, or 0 for a mono
|
|
// display region.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DisplayRegion::
|
|
set_stereo_channel(Lens::StereoChannel stereo_channel) {
|
|
nassertv(is_stereo() || stereo_channel != Lens::SC_stereo);
|
|
|
|
nassertv(Thread::get_current_pipeline_stage() == 0);
|
|
|
|
CDWriter cdata(_cycler);
|
|
cdata->_stereo_channel = stereo_channel;
|
|
cdata->_tex_view_offset = (stereo_channel == Lens::SC_right) ? 1 : 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::set_tex_view_offset
|
|
// Access: Published, Virtual
|
|
// Description: Sets the current texture view offset for this
|
|
// DisplayRegion. This is normally set to zero. If
|
|
// nonzero, it is used to select a particular view of
|
|
// any multiview textures that are rendered within this
|
|
// DisplayRegion.
|
|
//
|
|
// For a StereoDisplayRegion, this is normally 0 for the
|
|
// left eye, and 1 for the right eye, to support stereo
|
|
// textures. This is set automatically when you call
|
|
// set_stereo_channel().
|
|
////////////////////////////////////////////////////////////////////
|
|
void DisplayRegion::
|
|
set_tex_view_offset(int tex_view_offset) {
|
|
nassertv(Thread::get_current_pipeline_stage() == 0);
|
|
|
|
CDWriter cdata(_cycler);
|
|
cdata->_tex_view_offset = tex_view_offset;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::set_incomplete_render
|
|
// Access: Published, Virtual
|
|
// Description: Sets the incomplete_render flag. When this is
|
|
// true, the frame will be rendered even if some of the
|
|
// geometry or textures in the scene are not available
|
|
// (e.g. they have been temporarily paged out). When
|
|
// this is false, the frame will be held up while this
|
|
// data is reloaded.
|
|
//
|
|
// This flag may also be set on the
|
|
// GraphicsStateGuardian. It will be considered true
|
|
// for a given DisplayRegion only if it is true on both
|
|
// the GSG and on the DisplayRegion.
|
|
//
|
|
// See GraphicsStateGuardian::set_incomplete_render()
|
|
// for more detail.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DisplayRegion::
|
|
set_incomplete_render(bool incomplete_render) {
|
|
_incomplete_render = incomplete_render;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::set_texture_reload_priority
|
|
// Access: Published, Virtual
|
|
// Description: Specifies an integer priority which is assigned to
|
|
// any asynchronous texture reload requests spawned
|
|
// while processing this DisplayRegion. This controls
|
|
// which textures are loaded first when multiple
|
|
// textures need to be reloaded at once; it also
|
|
// controls the relative priority between asynchronous
|
|
// texture loads and asynchronous model or animation
|
|
// loads.
|
|
//
|
|
// Specifying a larger number here makes the textures
|
|
// rendered by this DisplayRegion load up first. This
|
|
// may be particularly useful to do, for instance, for
|
|
// the DisplayRegion that renders the gui.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DisplayRegion::
|
|
set_texture_reload_priority(int texture_reload_priority) {
|
|
_texture_reload_priority = texture_reload_priority;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::set_cull_traverser
|
|
// Access: Published, Virtual
|
|
// Description: Specifies the CullTraverser that will be used to draw
|
|
// the contents of this DisplayRegion. Normally the
|
|
// default CullTraverser is sufficient, but this may be
|
|
// changed to change the default cull behavior.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DisplayRegion::
|
|
set_cull_traverser(CullTraverser *trav) {
|
|
_trav = trav;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::get_cull_traverser
|
|
// Access: Published
|
|
// Description: Returns the CullTraverser that will be used to draw
|
|
// the contents of this DisplayRegion.
|
|
////////////////////////////////////////////////////////////////////
|
|
CullTraverser *DisplayRegion::
|
|
get_cull_traverser() {
|
|
if (_trav == (CullTraverser *)NULL) {
|
|
_trav = new CullTraverser;
|
|
}
|
|
return _trav;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::set_cube_map_index
|
|
// Access: Published, Virtual
|
|
// Description: This is a special parameter that is only used when
|
|
// rendering the faces of a cube map. Normally you
|
|
// should not need to set it directly. This sets up the
|
|
// DisplayRegion to render to the nth cube map face; the
|
|
// value must be between 0 and 5, inclusive. A normal
|
|
// DisplayRegion that is not associated with any
|
|
// particular cube map should be set to -1.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DisplayRegion::
|
|
set_cube_map_index(int cube_map_index) {
|
|
int pipeline_stage = Thread::get_current_pipeline_stage();
|
|
nassertv(pipeline_stage == 0);
|
|
CDWriter cdata(_cycler);
|
|
cdata->_cube_map_index = cube_map_index;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::output
|
|
// Access: Published, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void DisplayRegion::
|
|
output(ostream &out) const {
|
|
CDReader cdata(_cycler);
|
|
out << "DisplayRegion(" << cdata->_dimensions << ")=pixels(" << cdata->_pl
|
|
<< " " << cdata->_pr << " " << cdata->_pb << " " << cdata->_pt
|
|
<< ")";
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::make_screenshot_filename
|
|
// Access: Published, Static
|
|
// Description: Synthesizes a suitable default filename for passing
|
|
// to save_screenshot().
|
|
//
|
|
// 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().
|
|
////////////////////////////////////////////////////////////////////
|
|
Filename DisplayRegion::
|
|
make_screenshot_filename(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;
|
|
}
|
|
}
|
|
|
|
return Filename(filename_strm.str());
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::save_screenshot_default
|
|
// Access: Published
|
|
// Description: 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().
|
|
////////////////////////////////////////////////////////////////////
|
|
Filename DisplayRegion::
|
|
save_screenshot_default(const string &prefix) {
|
|
Filename filename = make_screenshot_filename(prefix);
|
|
if (save_screenshot(filename)) {
|
|
return filename;
|
|
}
|
|
return Filename();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::save_screenshot
|
|
// Access: Published
|
|
// Description: Saves a screenshot of the region to the indicated
|
|
// filename. Returns true on success, false on failure.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DisplayRegion::
|
|
save_screenshot(const Filename &filename, const string &image_comment) {
|
|
PNMImage image;
|
|
if (!get_screenshot(image)) {
|
|
return false;
|
|
}
|
|
|
|
image.set_comment(image_comment);
|
|
if (!image.write(filename)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::get_screenshot
|
|
// Access: Published
|
|
// Description: Captures the most-recently rendered image from the
|
|
// framebuffer into the indicated PNMImage. Returns
|
|
// true on success, false on failure.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DisplayRegion::
|
|
get_screenshot(PNMImage &image) {
|
|
PT(Texture) tex = get_screenshot();
|
|
|
|
if (tex == NULL) {
|
|
return false;
|
|
}
|
|
|
|
if (!tex->store(image)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::get_screenshot
|
|
// Access: Published
|
|
// Description: Captures the most-recently rendered image from the
|
|
// framebuffer and returns it as a Texture, or NULL
|
|
// on failure.
|
|
////////////////////////////////////////////////////////////////////
|
|
PT(Texture) DisplayRegion::
|
|
get_screenshot() {
|
|
Thread *current_thread = Thread::get_current_thread();
|
|
|
|
GraphicsOutput *window = get_window();
|
|
nassertr(window != (GraphicsOutput *)NULL, NULL);
|
|
|
|
GraphicsStateGuardian *gsg = window->get_gsg();
|
|
nassertr(gsg != (GraphicsStateGuardian *)NULL, NULL);
|
|
|
|
if (!window->begin_frame(GraphicsOutput::FM_refresh, current_thread)) {
|
|
return NULL;
|
|
}
|
|
|
|
PT(Texture) tex = new Texture;
|
|
|
|
RenderBuffer buffer = gsg->get_render_buffer(get_screenshot_buffer_type(),
|
|
_window->get_fb_properties());
|
|
if (!gsg->framebuffer_copy_to_ram(tex, -1, this, buffer)) {
|
|
return NULL;
|
|
}
|
|
|
|
window->end_frame(GraphicsOutput::FM_refresh, current_thread);
|
|
|
|
return tex;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::make_cull_result_graph
|
|
// Access: Published
|
|
// Description: Returns a special scene graph constructed to
|
|
// represent the results of the last frame's cull
|
|
// operation.
|
|
//
|
|
// This will be a hierarchy of nodes, one node for each
|
|
// bin, each of which will in term be a parent of a
|
|
// number of GeomNodes, representing the geometry drawn
|
|
// in each bin.
|
|
//
|
|
// This is useful mainly for high-level debugging and
|
|
// abstraction tools; it should not be mistaken for the
|
|
// low-level cull result itself, which is constructed
|
|
// and maintained internally. No such scene graph is
|
|
// normally constructed during the rendering of a frame;
|
|
// this is an artificial construct created for the
|
|
// purpose of making it easy to analyze the results of
|
|
// the cull operation.
|
|
////////////////////////////////////////////////////////////////////
|
|
PT(PandaNode) DisplayRegion::
|
|
make_cull_result_graph() {
|
|
CullResult *cull_result = get_cull_result(Thread::get_current_thread());
|
|
if (cull_result == (CullResult *)NULL) {
|
|
return NULL;
|
|
}
|
|
return cull_result->make_result_graph();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::compute_pixels
|
|
// Access: Public
|
|
// Description: Computes the pixel locations of the DisplayRegion
|
|
// within its window. The DisplayRegion will request
|
|
// the size from the window.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DisplayRegion::
|
|
compute_pixels() {
|
|
if (_window != (GraphicsOutput *)NULL) {
|
|
CDWriter cdata(_cycler, false);
|
|
do_compute_pixels(_window->get_fb_x_size(), _window->get_fb_y_size(),
|
|
cdata);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::compute_pixels_all_stages
|
|
// Access: Public
|
|
// Description: Computes the pixel locations of the DisplayRegion
|
|
// within its window. The DisplayRegion will request
|
|
// the size from the window.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DisplayRegion::
|
|
compute_pixels_all_stages() {
|
|
int pipeline_stage = Thread::get_current_pipeline_stage();
|
|
nassertv(pipeline_stage == 0);
|
|
|
|
if (_window != (GraphicsOutput *)NULL) {
|
|
OPEN_ITERATE_ALL_STAGES(_cycler) {
|
|
CDStageWriter cdata(_cycler, pipeline_stage);
|
|
do_compute_pixels(_window->get_fb_x_size(), _window->get_fb_y_size(),
|
|
cdata);
|
|
}
|
|
CLOSE_ITERATE_ALL_STAGES(_cycler);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::compute_pixels
|
|
// Access: Public
|
|
// Description: Computes the pixel locations of the DisplayRegion
|
|
// within its window, given the size of the window in
|
|
// pixels.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DisplayRegion::
|
|
compute_pixels(int x_size, int y_size) {
|
|
CDWriter cdata(_cycler, false);
|
|
do_compute_pixels(x_size, y_size, cdata);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::compute_pixels_all_stages
|
|
// Access: Public
|
|
// Description: Performs a compute_pixels() operation for all stages
|
|
// of the pipeline. This is appropriate, for instance,
|
|
// when a window changes sizes, since this is a global
|
|
// operation; and you want the new window size to be
|
|
// immediately available even to the downstream stages.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DisplayRegion::
|
|
compute_pixels_all_stages(int x_size, int y_size) {
|
|
OPEN_ITERATE_ALL_STAGES(_cycler) {
|
|
CDStageWriter cdata(_cycler, pipeline_stage);
|
|
do_compute_pixels(x_size, y_size, cdata);
|
|
}
|
|
CLOSE_ITERATE_ALL_STAGES(_cycler);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::supports_pixel_zoom
|
|
// Access: Public, Virtual
|
|
// Description: Returns true if a call to set_pixel_zoom() will be
|
|
// respected, false if it will be ignored. If this
|
|
// returns false, then get_pixel_factor() will always
|
|
// return 1.0, regardless of what value you specify for
|
|
// set_pixel_zoom().
|
|
//
|
|
// This may return false if the underlying renderer
|
|
// doesn't support pixel zooming, or if you have called
|
|
// this on a DisplayRegion that doesn't have both
|
|
// set_clear_color() and set_clear_depth() enabled.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DisplayRegion::
|
|
supports_pixel_zoom() const {
|
|
if (_window != (GraphicsOutput *)NULL) {
|
|
if (_window->supports_pixel_zoom()) {
|
|
return get_clear_color_active() && get_clear_depth_active();
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::win_display_regions_changed
|
|
// Access: Private
|
|
// 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. It is assumed the lock is already
|
|
// held.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DisplayRegion::
|
|
win_display_regions_changed() {
|
|
if (_window != (GraphicsOutput *)NULL) {
|
|
_window->win_display_regions_changed();
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::do_compute_pixels
|
|
// Access: Private
|
|
// Description: The private implementation of compute_pixels, this
|
|
// assumes that we already have the lock.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DisplayRegion::
|
|
do_compute_pixels(int x_size, int y_size, CData *cdata) {
|
|
if (display_cat.is_debug()) {
|
|
display_cat.debug()
|
|
<< "DisplayRegion::do_compute_pixels(" << x_size << ", " << y_size << ")\n";
|
|
}
|
|
|
|
int old_w = cdata->_pr - cdata->_pl;
|
|
int old_h = cdata->_pt - cdata->_pb;
|
|
|
|
cdata->_pl = int((cdata->_dimensions[0] * x_size) + 0.5);
|
|
cdata->_pr = int((cdata->_dimensions[1] * x_size) + 0.5);
|
|
|
|
nassertv(_window != (GraphicsOutput *)NULL);
|
|
if (_window->get_inverted()) {
|
|
// The window is inverted; compute the DisplayRegion accordingly.
|
|
cdata->_pb = int(((1.0f - cdata->_dimensions[3]) * y_size) + 0.5);
|
|
cdata->_pt = int(((1.0f - cdata->_dimensions[2]) * y_size) + 0.5);
|
|
cdata->_pbi = int((cdata->_dimensions[3] * y_size) + 0.5);
|
|
cdata->_pti = int((cdata->_dimensions[2] * y_size) + 0.5);
|
|
|
|
} else {
|
|
// The window is normal.
|
|
cdata->_pb = int((cdata->_dimensions[2] * y_size) + 0.5);
|
|
cdata->_pt = int((cdata->_dimensions[3] * y_size) + 0.5);
|
|
cdata->_pbi = int(((1.0f - cdata->_dimensions[2]) * y_size) + 0.5);
|
|
cdata->_pti = int(((1.0f - cdata->_dimensions[3]) * y_size) + 0.5);
|
|
}
|
|
|
|
int w = cdata->_pr - cdata->_pl;
|
|
int h = cdata->_pt - cdata->_pb;
|
|
if (old_w != w || old_h != h) {
|
|
pixel_size_changed(w, h);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::set_active_index
|
|
// Access: Private
|
|
// Description: This is called by GraphicsOutput to indicate that the
|
|
// index of this DisplayRegion within the window's list
|
|
// of active DisplayRegions might have changed. The
|
|
// index number will be -1 if the DisplayRegion is not
|
|
// active.
|
|
//
|
|
// This is primarily intended only for updating the
|
|
// PStatCollector name appropriately.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DisplayRegion::
|
|
set_active_index(int index) {
|
|
#ifdef DO_PSTATS
|
|
ostringstream strm;
|
|
strm << "dr_" << index;
|
|
string name = strm.str();
|
|
|
|
_cull_region_pcollector = PStatCollector(_window->get_cull_window_pcollector(), name);
|
|
_draw_region_pcollector = PStatCollector(_window->get_draw_window_pcollector(), name);
|
|
#endif // DO_PSTATS
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::do_cull
|
|
// Access: Protected, Virtual
|
|
// Description: Performs a cull traversal. The default
|
|
// implementation simply calls GraphicsEngine::do_cull.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DisplayRegion::
|
|
do_cull(CullHandler *cull_handler, SceneSetup *scene_setup,
|
|
GraphicsStateGuardian *gsg, Thread *current_thread) {
|
|
|
|
GraphicsEngine::do_cull(cull_handler, scene_setup, gsg, current_thread);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::CData::Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
DisplayRegion::CData::
|
|
CData() :
|
|
_dimensions(0.0f, 1.0f, 0.0f, 1.0f),
|
|
_pl(0), _pr(0), _pb(0), _pt(0),
|
|
_pbi(0), _pti(0), _lens_index(0),
|
|
_camera_node((Camera *)NULL),
|
|
_active(true),
|
|
_sort(0),
|
|
_stereo_channel(Lens::SC_mono),
|
|
_tex_view_offset(0),
|
|
_cube_map_index(-1)
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::CData::Copy Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
DisplayRegion::CData::
|
|
CData(const DisplayRegion::CData ©) :
|
|
_dimensions(copy._dimensions),
|
|
_pl(copy._pl),
|
|
_pr(copy._pr),
|
|
_pb(copy._pb),
|
|
_pt(copy._pt),
|
|
_pbi(copy._pbi),
|
|
_pti(copy._pti),
|
|
_lens_index(copy._lens_index),
|
|
_camera(copy._camera),
|
|
_camera_node(copy._camera_node),
|
|
_active(copy._active),
|
|
_sort(copy._sort),
|
|
_stereo_channel(copy._stereo_channel),
|
|
_tex_view_offset(copy._tex_view_offset),
|
|
_cube_map_index(copy._cube_map_index)
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::CData::make_copy
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
CycleData *DisplayRegion::CData::
|
|
make_copy() const {
|
|
return new CData(*this);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegion::CDataCull::make_copy
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
CycleData *DisplayRegion::CDataCull::
|
|
make_copy() const {
|
|
return new CDataCull(*this);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DisplayRegionPipelineReader::get_pipe
|
|
// Access: Public
|
|
// Description: Returns the GraphicsPipe that this DisplayRegion is
|
|
// ultimately associated with, or NULL if no pipe is
|
|
// associated.
|
|
////////////////////////////////////////////////////////////////////
|
|
GraphicsPipe *DisplayRegionPipelineReader::
|
|
get_pipe() const {
|
|
return (_object->_window != (GraphicsOutput *)NULL) ? _object->_window->get_pipe() : NULL;
|
|
}
|