583 lines
18 KiB
C++
583 lines
18 KiB
C++
// Filename: frameBufferProperties.cxx
|
|
// Created by: drose (27Jan03)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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 "frameBufferProperties.h"
|
|
#include "string_utils.h"
|
|
#include "renderBuffer.h"
|
|
#include "config_display.h"
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: FrameBufferProperties::Constructor
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
FrameBufferProperties::
|
|
FrameBufferProperties() {
|
|
clear();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: FrameBufferProperties::Copy Assignment Operator
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void FrameBufferProperties::
|
|
operator = (const FrameBufferProperties ©) {
|
|
for (int i=0; i<FBP_COUNT; i++) {
|
|
_specified[i] = copy._specified[i];
|
|
_property[i] = copy._property[i];
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: FrameBufferProperties::subsumes
|
|
// Access: Public
|
|
// Description: Returns true if this set of properties makes
|
|
// strictly greater or equal demands of the framebuffer
|
|
// than the other set of framebuffer properties.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool FrameBufferProperties::
|
|
subsumes(const FrameBufferProperties &other) const {
|
|
for (int i=0; i<FBP_COUNT; i++) {
|
|
if (other._property[i] > _property[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: FrameBufferProperties::get_default
|
|
// Access: Published, Static
|
|
// Description: Returns a FrameBufferProperties structure with all of
|
|
// the default values filled in according to the user's
|
|
// config file.
|
|
////////////////////////////////////////////////////////////////////
|
|
const FrameBufferProperties &FrameBufferProperties::
|
|
get_default() {
|
|
static bool default_ready = false;
|
|
static FrameBufferProperties default_props;
|
|
|
|
if (default_ready) {
|
|
return default_props;
|
|
}
|
|
|
|
default_props.set_rgb_color(1);
|
|
default_props.set_back_buffers(back_buffers);
|
|
|
|
int num_words = framebuffer_mode.get_num_words();
|
|
if (num_words > 0) {
|
|
display_cat.error()
|
|
<< "The config-variable 'framebuffer-mode' no longer functions.\n";
|
|
display_cat.error()
|
|
<< "Instead, use one or more of these:\n";
|
|
display_cat.error() << " framebuffer-hardware #t\n";
|
|
display_cat.error() << " framebuffer-software #t\n";
|
|
display_cat.error() << " framebuffer-depth #t\n";
|
|
display_cat.error() << " framebuffer-alpha #t\n";
|
|
display_cat.error() << " framebuffer-stencil #t\n";
|
|
display_cat.error() << " framebuffer-multisample #t\n";
|
|
display_cat.error() << " framebuffer-stereo #t\n";
|
|
display_cat.error() << " depth-bits N\n";
|
|
display_cat.error() << " color-bits N\n";
|
|
display_cat.error() << " alpha-bits N\n";
|
|
display_cat.error() << " stencil-bits N\n";
|
|
display_cat.error() << " multisamples N\n";
|
|
display_cat.error() << " back-buffers N\n";
|
|
}
|
|
|
|
if (framebuffer_hardware) {
|
|
default_props.set_force_hardware(1);
|
|
}
|
|
if (framebuffer_software) {
|
|
default_props.set_force_software(1);
|
|
}
|
|
if (framebuffer_depth) {
|
|
default_props.set_depth_bits(1);
|
|
}
|
|
if (framebuffer_alpha) {
|
|
default_props.set_alpha_bits(1);
|
|
}
|
|
if (framebuffer_stencil) {
|
|
default_props.set_stencil_bits(1);
|
|
}
|
|
if (framebuffer_multisample) {
|
|
default_props.set_multisamples(1);
|
|
}
|
|
if (framebuffer_stereo) {
|
|
default_props.set_stereo(1);
|
|
}
|
|
if (depth_bits > 0) {
|
|
default_props.set_depth_bits(depth_bits);
|
|
}
|
|
if (color_bits > 0) {
|
|
default_props.set_color_bits(color_bits);
|
|
}
|
|
if (alpha_bits > 0) {
|
|
default_props.set_alpha_bits(alpha_bits);
|
|
}
|
|
if (stencil_bits > 0) {
|
|
default_props.set_stencil_bits(stencil_bits);
|
|
}
|
|
if (multisamples > 0) {
|
|
default_props.set_multisamples(multisamples);
|
|
}
|
|
|
|
if ((default_props._property[FBP_force_software])&&
|
|
(default_props._property[FBP_force_hardware])) {
|
|
default_props._property[FBP_force_software] = 0;
|
|
default_props._property[FBP_force_hardware] = 0;
|
|
}
|
|
|
|
default_ready = true;
|
|
return default_props;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: FrameBufferProperties::operator ==
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
bool FrameBufferProperties::
|
|
operator == (const FrameBufferProperties &other) const {
|
|
for (int i=0; i<FBP_COUNT; i++) {
|
|
if (_specified[i] != other._specified[i]) {
|
|
return false;
|
|
}
|
|
if (_property[i] != other._property[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: FrameBufferProperties::clear
|
|
// Access: Published
|
|
// Description: Unsets all properties that have been specified so
|
|
// far, and resets the FrameBufferProperties structure to its
|
|
// initial empty state.
|
|
////////////////////////////////////////////////////////////////////
|
|
void FrameBufferProperties::
|
|
clear() {
|
|
for (int i=0; i<FBP_COUNT; i++) {
|
|
_specified[i] = 0;
|
|
_property[i] = 0;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: FrameBufferProperties::add_properties
|
|
// Access: Published
|
|
// Description: Sets any properties that are explicitly specified in
|
|
// other on this object. Leaves other properties
|
|
// unchanged.
|
|
////////////////////////////////////////////////////////////////////
|
|
void FrameBufferProperties::
|
|
add_properties(const FrameBufferProperties &other) {
|
|
for (int i=0; i<FBP_COUNT; i++) {
|
|
if (other._specified[i]) {
|
|
_property[i] = other._property[i];
|
|
_specified[i] = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: FrameBufferProperties::output
|
|
// Access: Published
|
|
// Description: Sets any properties that are explicitly specified in
|
|
// other on this object. Leaves other properties
|
|
// unchanged.
|
|
////////////////////////////////////////////////////////////////////
|
|
void FrameBufferProperties::
|
|
output(ostream &out) const {
|
|
if (_property[FBP_depth_bits] > 0) {
|
|
out << "depth_bits=" << _property[FBP_depth_bits] << " ";
|
|
}
|
|
if (_property[FBP_color_bits] > 0) {
|
|
out << "color_bits=" << _property[FBP_color_bits] << " ";
|
|
}
|
|
if (_property[FBP_alpha_bits] > 0) {
|
|
out << "alpha_bits=" << _property[FBP_alpha_bits] << " ";
|
|
}
|
|
if (_property[FBP_stencil_bits] > 0) {
|
|
out << "stencil_bits=" << _property[FBP_stencil_bits] << " ";
|
|
}
|
|
if (_property[FBP_accum_bits] > 0) {
|
|
out << "accum_bits=" << _property[FBP_accum_bits] << " ";
|
|
}
|
|
if (_property[FBP_aux_rgba] > 0) {
|
|
out << "aux_rgba=" << _property[FBP_aux_rgba] << " ";
|
|
}
|
|
if (_property[FBP_aux_hrgba] > 0) {
|
|
out << "aux_hrgba=" << _property[FBP_aux_hrgba] << " ";
|
|
}
|
|
if (_property[FBP_aux_float] > 0) {
|
|
out << "aux_float=" << _property[FBP_aux_float] << " ";
|
|
}
|
|
if (_property[FBP_multisamples] > 0) {
|
|
out << "multisamples=" << _property[FBP_multisamples] << " ";
|
|
}
|
|
if (_property[FBP_back_buffers] > 0) {
|
|
out << "back_buffers=" << _property[FBP_back_buffers] << " ";
|
|
}
|
|
if (_property[FBP_indexed_color] > 0) {
|
|
out << "indexed_color=" << _property[FBP_indexed_color] << " ";
|
|
}
|
|
if (_property[FBP_stereo] > 0) {
|
|
out << "stereo=" << _property[FBP_stereo] << " ";
|
|
}
|
|
if (_property[FBP_force_hardware] > 0) {
|
|
out << "force_hardware=" << _property[FBP_force_hardware] << " ";
|
|
}
|
|
if (_property[FBP_force_software] > 0) {
|
|
out << "force_software=" << _property[FBP_force_software] << " ";
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: FrameBufferProperties::get_aux_mask
|
|
// Access: Published
|
|
// Description: Converts the aux bitplanes of the
|
|
// framebuffer into a RenderBuffer::Type.
|
|
////////////////////////////////////////////////////////////////////
|
|
int FrameBufferProperties::
|
|
get_aux_mask() const {
|
|
int mask = 0;
|
|
for (int i=0; i<_property[FBP_aux_rgba]; i++) {
|
|
mask |= (RenderBuffer::T_aux_rgba_0 << i);
|
|
}
|
|
for (int i=0; i<_property[FBP_aux_hrgba]; i++) {
|
|
mask |= (RenderBuffer::T_aux_hrgba_0 << i);
|
|
}
|
|
for (int i=0; i<_property[FBP_aux_float]; i++) {
|
|
mask |= (RenderBuffer::T_aux_float_0 << i);
|
|
}
|
|
return mask;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: FrameBufferProperties::get_buffer_mask
|
|
// Access: Private
|
|
// Description: Converts the non-aux bitplanes of the
|
|
// framebuffer into a RenderBuffer::Type.
|
|
////////////////////////////////////////////////////////////////////
|
|
int FrameBufferProperties::
|
|
get_buffer_mask() const {
|
|
int mask = 0;
|
|
|
|
if (_property[FBP_back_buffers] > 0) {
|
|
mask = RenderBuffer::T_front | RenderBuffer::T_back;
|
|
} else {
|
|
mask = RenderBuffer::T_front;
|
|
}
|
|
if (_property[FBP_depth_bits] > 0) {
|
|
mask |= RenderBuffer::T_depth;
|
|
}
|
|
if (_property[FBP_stencil_bits] > 0) {
|
|
mask |= RenderBuffer::T_stencil;
|
|
}
|
|
return mask;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: FrameBufferProperties::is_any_specified
|
|
// Access: Published
|
|
// Description: Returns true if any properties have been specified,
|
|
// false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool FrameBufferProperties::
|
|
is_any_specified() const {
|
|
for (int i=0; i<FBP_COUNT; i++) {
|
|
if (_specified[i]) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: FrameBufferProperties::set_all_specified
|
|
// Access: Published
|
|
// Description: sets all the specified bits.
|
|
////////////////////////////////////////////////////////////////////
|
|
void FrameBufferProperties::
|
|
set_all_specified() {
|
|
for (int i=0; i<FBP_COUNT; i++) {
|
|
_specified[i] = true;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: FrameBufferProperties::is_basic
|
|
// Access: Published
|
|
// Description: Returns true if the properties are extremely basic.
|
|
// The following count as basic: rgb or rgba, depth.
|
|
// If anything else is specified, the properties are
|
|
// non-basic.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool FrameBufferProperties::
|
|
is_basic() const {
|
|
if (_property[FBP_depth_bits] > 1) {
|
|
return false;
|
|
}
|
|
if (_property[FBP_color_bits] > 1) {
|
|
return false;
|
|
}
|
|
if (_property[FBP_alpha_bits] > 1) {
|
|
return false;
|
|
}
|
|
if (_property[FBP_stencil_bits] > 0) {
|
|
return false;
|
|
}
|
|
if (_property[FBP_aux_rgba] > 0) {
|
|
return false;
|
|
}
|
|
if (_property[FBP_aux_hrgba] > 0) {
|
|
return false;
|
|
}
|
|
if (_property[FBP_aux_float] > 0) {
|
|
return false;
|
|
}
|
|
if (_property[FBP_multisamples] > 1) {
|
|
return false;
|
|
}
|
|
if (_property[FBP_back_buffers] > 0) {
|
|
return false;
|
|
}
|
|
if (_property[FBP_indexed_color] > 0) {
|
|
return false;
|
|
}
|
|
if (_property[FBP_force_hardware] > 0) {
|
|
return false;
|
|
}
|
|
if (_property[FBP_force_software] > 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: FrameBufferProperties::set_one_bit_per_channel
|
|
// Access: Published
|
|
// Description: If any of the depth, color, alpha, accum, or
|
|
// stencil properties is set to more than one,
|
|
// then they are reduced to one.
|
|
////////////////////////////////////////////////////////////////////
|
|
void FrameBufferProperties::
|
|
set_one_bit_per_channel() {
|
|
for (int prop=FBP_depth_bits; prop<=FBP_accum_bits; ++prop) {
|
|
if (_property[prop] > 1) {
|
|
_property[prop] = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: FrameBufferProperties::get_quality
|
|
// Access: Published
|
|
// Description: Assumes that these properties are a description of
|
|
// a window.
|
|
//
|
|
// Measures how well this window satisfies a specified
|
|
// set of requirements. A higher quality number means
|
|
// that more requirements were satisfied. A quality of
|
|
// zero means that the window is unsuitable.
|
|
//
|
|
// The routine deducts a lot if the window fails to
|
|
// provide a requested feature. It deducts less
|
|
// if the window provides a feature, but at a degraded
|
|
// level of functionality (ie, the user asks for rgba8,
|
|
// color, but the window only provides rgba4). The
|
|
// routine also deducts a small amount for unnecessary
|
|
// features. For example, if the window has an
|
|
// accumulation buffer when one is not requested will
|
|
// reduce quality slightly. Maximum quality is obtained
|
|
// when the window exactly matches the request.
|
|
//
|
|
// If you want to know whether the window satisfies
|
|
// all of the requirements, use the "subsumes" function.
|
|
////////////////////////////////////////////////////////////////////
|
|
int FrameBufferProperties::
|
|
get_quality(const FrameBufferProperties &reqs) const {
|
|
|
|
if ((_property[FBP_indexed_color]==0) && (_property[FBP_rgb_color]==0)) {
|
|
// Nonfunctioning window.
|
|
return 0;
|
|
}
|
|
|
|
if ((reqs._property[FBP_rgb_color] > _property[FBP_rgb_color])||
|
|
(reqs._property[FBP_indexed_color] > _property[FBP_indexed_color])) {
|
|
// These properties are nonnegotiable.
|
|
return 0;
|
|
}
|
|
|
|
int quality = 100000000;
|
|
|
|
// Deduct for using the wrong kind of renderer (hardware or software).
|
|
// Cost: 10,000,000
|
|
|
|
if ((reqs._property[FBP_force_hardware] > _property[FBP_force_hardware])||
|
|
(reqs._property[FBP_force_software] > _property[FBP_force_software])) {
|
|
quality -= 10000000;
|
|
}
|
|
|
|
// Deduct for missing depth, color, alpha, stencil, or accum.
|
|
// Cost: 1,000,000
|
|
|
|
for (int prop=FBP_depth_bits; prop<=FBP_accum_bits; prop++) {
|
|
if ((reqs._property[prop]) && (_property[prop]==0)) {
|
|
quality -= 1000000;
|
|
}
|
|
}
|
|
|
|
// Deduct for missing aux bitplanes.
|
|
// Cost: 100,000
|
|
|
|
for (int prop=FBP_aux_rgba; prop<=FBP_aux_float; prop++) {
|
|
if (reqs._property[prop] > _property[prop]) {
|
|
quality -= 100000;
|
|
}
|
|
}
|
|
|
|
// Deduct for stereo not enabled.
|
|
// Cost: 100,000
|
|
|
|
if (reqs._property[FBP_stereo] > _property[FBP_stereo]) {
|
|
quality -= 100000;
|
|
}
|
|
|
|
// Deduct for insufficient back-buffers.
|
|
// Cost: 100,000
|
|
|
|
if (reqs._property[FBP_back_buffers] > _property[FBP_back_buffers]) {
|
|
quality -= 100000;
|
|
}
|
|
|
|
// Deduct for lacking multisamples altogether.
|
|
// Cost: 100,000
|
|
if (reqs._property[FBP_multisamples] != 0 && _property[FBP_multisamples] == 0) {
|
|
quality -= 100000;
|
|
}
|
|
|
|
// Deduct for not enough bits in depth, color, alpha, stencil, or accum.
|
|
// Cost: 10,000
|
|
|
|
for (int prop=FBP_depth_bits; prop<=FBP_accum_bits; prop++) {
|
|
if (_property[prop] != 0 && reqs._property[prop] > _property[prop]) {
|
|
quality -= 10000;
|
|
}
|
|
}
|
|
|
|
// deduct for insufficient multisamples.
|
|
// Cost: 1,000
|
|
|
|
if (_property[FBP_multisamples] != 0 &&
|
|
reqs._property[FBP_multisamples] > _property[FBP_multisamples]) {
|
|
quality -= 1000;
|
|
}
|
|
|
|
// Deduct for unrequested bitplanes.
|
|
// Cost: 50
|
|
|
|
for (int prop=FBP_depth_bits; prop<=FBP_accum_bits; prop++) {
|
|
if ((_property[prop]) && (reqs._property[prop] == 0)) {
|
|
quality -= 50;
|
|
}
|
|
}
|
|
for (int prop=FBP_aux_rgba; prop<=FBP_aux_float; prop++) {
|
|
int extra = _property[prop] > reqs._property[prop];
|
|
if (extra > 0) {
|
|
extra = min(extra, 3);
|
|
quality -= extra*50;
|
|
}
|
|
}
|
|
|
|
// Deduct for excessive resolution in any bitplane (unless we asked
|
|
// for only 1 bit, which is the convention for any amount).
|
|
|
|
// Cost: 50
|
|
|
|
for (int prop=FBP_depth_bits; prop<=FBP_accum_bits; prop++) {
|
|
if (reqs._property[prop] > 1 &&
|
|
_property[prop] > reqs._property[prop]) {
|
|
quality -= 50;
|
|
}
|
|
}
|
|
|
|
// Bonus for each depth bit.
|
|
// Extra: 2 per bit.
|
|
if (reqs._property[FBP_depth_bits] != 0) {
|
|
quality += 2 * _property[FBP_depth_bits];
|
|
}
|
|
|
|
// Bonus for each multisample.
|
|
// Extra: 2 per sample.
|
|
if (reqs._property[FBP_multisamples] != 0) {
|
|
quality += 2 * _property[FBP_multisamples];
|
|
}
|
|
|
|
// Bonus for each color, alpha, stencil, and accum.
|
|
// Extra: 1 per bit.
|
|
for (int prop=FBP_color_bits; prop<=FBP_accum_bits; prop++) {
|
|
if (reqs._property[prop] != 0) {
|
|
quality += _property[prop];
|
|
}
|
|
}
|
|
|
|
return quality;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: FrameBufferProperties::verify_hardware_software
|
|
// Access: Public
|
|
// Description: Validates that the properties represent the desired
|
|
// kind of renderer (hardware or software). If not,
|
|
// prints out an error message and returns false.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool FrameBufferProperties::
|
|
verify_hardware_software(const FrameBufferProperties &props, const string &renderer) const {
|
|
|
|
if (get_force_hardware() < props.get_force_hardware()) {
|
|
display_cat.error()
|
|
<< "The application requested harware acceleration, but your OpenGL\n";
|
|
display_cat.error()
|
|
<< "driver, " << renderer << ", only supports software rendering.\n";
|
|
display_cat.error()
|
|
<< "You need to install a hardware-accelerated OpenGL driver, or,\n";
|
|
display_cat.error()
|
|
<< "if you actually *want* to use a software renderer, then\n";
|
|
display_cat.error()
|
|
<< "alter the hardware/software configuration in your Config.prc file.\n";
|
|
return false;
|
|
}
|
|
|
|
if (get_force_software() < props.get_force_software()) {
|
|
display_cat.error()
|
|
<< "The application requested a software renderer, but your OpenGL\n";
|
|
display_cat.error()
|
|
<< "driver, " << renderer << ", is probably hardware-accelerated.\n";
|
|
display_cat.error()
|
|
<< "If you want to allow hardware acceleration, then alter the\n";
|
|
display_cat.error()
|
|
<< "hardware/software configuration in your Config.prc file.\n";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|