mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 02:42:49 -04:00
558 lines
19 KiB
C++
558 lines
19 KiB
C++
// Filename: glGraphicsBuffer_src.cxx
|
|
// Created by: jyelon (15Jan06)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
|
|
//
|
|
// To contact the maintainers of this program write to
|
|
// panda3d-general@lists.sourceforge.net .
|
|
//
|
|
|
|
TypeHandle CLP(GraphicsBuffer)::_type_handle;
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: glGraphicsBuffer::Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
CLP(GraphicsBuffer)::
|
|
CLP(GraphicsBuffer)(GraphicsPipe *pipe,
|
|
const string &name,
|
|
const FrameBufferProperties &fb_prop,
|
|
const WindowProperties &win_prop,
|
|
int flags,
|
|
GraphicsStateGuardian *gsg,
|
|
GraphicsOutput *host) :
|
|
GraphicsBuffer(pipe, name, fb_prop, win_prop, flags, gsg, host)
|
|
{
|
|
// An FBO doesn't have a back buffer.
|
|
_draw_buffer_type = RenderBuffer::T_front;
|
|
_screenshot_buffer_type = RenderBuffer::T_front;
|
|
|
|
// Initialize these.
|
|
_fbo = 0;
|
|
_rb_size_x = 0;
|
|
_rb_size_y = 0;
|
|
_cube_face_active = 0;
|
|
for (int i=0; i<RTP_COUNT; i++) {
|
|
_rb[i] = 0;
|
|
_tex[i] = 0;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: glGraphicsBuffer::Destructor
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
CLP(GraphicsBuffer)::
|
|
~CLP(GraphicsBuffer)() {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: glGraphicsBuffer::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 CLP(GraphicsBuffer)::
|
|
begin_frame(FrameMode mode, Thread *current_thread) {
|
|
if (!_is_valid) {
|
|
return false;
|
|
}
|
|
|
|
if (!_host->begin_frame(FM_parasite, current_thread)) {
|
|
return false;
|
|
}
|
|
|
|
// Figure out the desired size of the buffer.
|
|
if (mode == FM_render) {
|
|
rebuild_bitplanes();
|
|
clear_cube_map_selection();
|
|
if (!check_fbo()) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
_gsg->set_current_properties(&get_fb_properties());
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: glGraphicsBuffer::check_fbo
|
|
// Access: Private
|
|
// Description: Calls 'glCheckFramebufferStatus'. On error,
|
|
// prints out an appropriate error message and unbinds
|
|
// the fbo. Returns true for OK or false for error.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool CLP(GraphicsBuffer)::
|
|
check_fbo() {
|
|
CLP(GraphicsStateGuardian) *glgsg;
|
|
DCAST_INTO_R(glgsg, _gsg, false);
|
|
|
|
GLenum status = glgsg->_glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
|
|
if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
|
|
GLCAT.error() << "EXT_framebuffer_object reports non-framebuffer-completeness.\n";
|
|
switch(status) {
|
|
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
|
|
GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT\n"; break;
|
|
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
|
|
GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT\n"; break;
|
|
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
|
|
GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT\n"; break;
|
|
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
|
|
GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_FORMATS_EXT\n"; break;
|
|
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
|
|
GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT\n"; break;
|
|
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
|
|
GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT\n"; break;
|
|
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
|
|
GLCAT.error() << "FRAMEBUFFER_UNSUPPORTED_EXT\n"; break;
|
|
default:
|
|
GLCAT.error() << "OTHER PROBLEM\n"; break;
|
|
}
|
|
|
|
glgsg->bind_fbo(0);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: glGraphicsBuffer::rebuild_bitplanes
|
|
// Access: Public, Virtual
|
|
// Description: This function will be called within the draw thread
|
|
// to allocate/reallocate the fbo and all the associated
|
|
// renderbuffers, just before rendering a frame.
|
|
////////////////////////////////////////////////////////////////////
|
|
void CLP(GraphicsBuffer)::
|
|
rebuild_bitplanes() {
|
|
|
|
CLP(GraphicsStateGuardian) *glgsg;
|
|
DCAST_INTO_V(glgsg, _gsg);
|
|
|
|
// Bind the FBO
|
|
|
|
if (_fbo == 0) {
|
|
glgsg->_glGenFramebuffers(1, &_fbo);
|
|
if (_fbo == 0) {
|
|
glgsg->report_my_gl_errors();
|
|
return;
|
|
}
|
|
}
|
|
glgsg->bind_fbo(_fbo);
|
|
|
|
// Calculate bitplane size. This can be larger than the buffer.
|
|
|
|
if (_creation_flags & GraphicsPipe::BF_size_track_host) {
|
|
if ((_host->get_x_size() != _x_size)||
|
|
(_host->get_y_size() != _y_size)) {
|
|
set_size_and_recalc(_host->get_x_size(),
|
|
_host->get_y_size());
|
|
}
|
|
}
|
|
int bitplane_x = _x_size;
|
|
int bitplane_y = _y_size;
|
|
if (!glgsg->get_supports_tex_non_pow2()) {
|
|
bitplane_x = Texture::up_to_power_2(bitplane_x);
|
|
bitplane_y = Texture::up_to_power_2(bitplane_y);
|
|
}
|
|
bool rb_resize = false;
|
|
if ((bitplane_x != _rb_size_x)||
|
|
(bitplane_y != _rb_size_y)) {
|
|
_rb_size_x = bitplane_x;
|
|
_rb_size_y = bitplane_y;
|
|
rb_resize = true;
|
|
}
|
|
|
|
// These variables indicate what should be bound to each bitplane.
|
|
|
|
Texture *attach[RTP_COUNT];
|
|
attach[RTP_color] = 0;
|
|
attach[RTP_depth_stencil] = 0;
|
|
for (int i=0; i<_fb_properties.get_aux_rgba(); i++) {
|
|
attach[RTP_aux_rgba_0+i] = 0;
|
|
}
|
|
for (int i=0; i<_fb_properties.get_aux_hrgba(); i++) {
|
|
attach[RTP_aux_hrgba_0+i] = 0;
|
|
}
|
|
for (int i=0; i<_fb_properties.get_aux_float(); i++) {
|
|
attach[RTP_aux_float_0+i] = 0;
|
|
}
|
|
|
|
// Sort the textures list into appropriate slots.
|
|
|
|
for (int i=0; i<count_textures(); i++) {
|
|
if (get_rtm_mode(i) != RTM_bind_or_copy) {
|
|
continue;
|
|
}
|
|
Texture *tex = get_texture(i);
|
|
RenderTexturePlane plane = get_texture_plane(i);
|
|
|
|
// If it's a not a 2D texture or a cube map, punt it.
|
|
if ((tex->get_texture_type() != Texture::TT_2d_texture)&&
|
|
(tex->get_texture_type() != Texture::TT_cube_map)) {
|
|
_textures[i]._rtm_mode = RTM_copy_texture;
|
|
continue;
|
|
}
|
|
|
|
// If I can't find an appropriate slot, or if there's
|
|
// already a texture bound to this slot, then punt
|
|
// this texture.
|
|
|
|
if (attach[plane]) {
|
|
_textures[i]._rtm_mode = RTM_copy_texture;
|
|
continue;
|
|
}
|
|
|
|
// Assign the texture to this slot.
|
|
attach[plane] = tex;
|
|
}
|
|
|
|
|
|
// For all slots, update the slot.
|
|
|
|
bind_slot(rb_resize, attach, RTP_depth_stencil, GL_DEPTH_ATTACHMENT_EXT);
|
|
bind_slot(rb_resize, attach, RTP_color, GL_COLOR_ATTACHMENT0_EXT);
|
|
int next = GL_COLOR_ATTACHMENT1_EXT;
|
|
for (int i=0; i<_fb_properties.get_aux_rgba(); i++) {
|
|
bind_slot(rb_resize, attach, (RenderTexturePlane)(RTP_aux_rgba_0+i), next);
|
|
next += 1;
|
|
}
|
|
for (int i=0; i<_fb_properties.get_aux_hrgba(); i++) {
|
|
bind_slot(rb_resize, attach, (RenderTexturePlane)(RTP_aux_hrgba_0+i), next);
|
|
next += 1;
|
|
}
|
|
for (int i=0; i<_fb_properties.get_aux_float(); i++) {
|
|
bind_slot(rb_resize, attach, (RenderTexturePlane)(RTP_aux_float_0+i), next);
|
|
next += 1;
|
|
}
|
|
_cube_face_active = 0;
|
|
|
|
glgsg->report_my_gl_errors();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: glGraphicsBuffer::bind_slot
|
|
// Access: Private
|
|
// Description: Attaches either a texture or a renderbuffer to the
|
|
// specified bitplane.
|
|
////////////////////////////////////////////////////////////////////
|
|
void CLP(GraphicsBuffer)::
|
|
bind_slot(bool rb_resize, Texture **attach, RenderTexturePlane slot, GLenum attachpoint) {
|
|
|
|
CLP(GraphicsStateGuardian) *glgsg;
|
|
DCAST_INTO_V(glgsg, _gsg);
|
|
|
|
Texture *tex = attach[slot];
|
|
if (tex) {
|
|
// If the texture is already bound to the slot, and it's
|
|
// the right size, then no update of this slot is needed.
|
|
if ((_tex[slot] == tex)&&
|
|
(tex->get_x_size() == _rb_size_x)&&
|
|
(tex->get_y_size() == _rb_size_y)) {
|
|
return;
|
|
}
|
|
|
|
// Bind the texture to the slot.
|
|
tex->set_x_size(_rb_size_x);
|
|
tex->set_y_size(_rb_size_y);
|
|
if (attachpoint == GL_DEPTH_ATTACHMENT_EXT) {
|
|
tex->set_format(Texture::F_depth_stencil);
|
|
TextureContext *tc = tex->prepare_now(glgsg->get_prepared_objects(), glgsg);
|
|
nassertv(tc != (TextureContext *)NULL);
|
|
CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
|
|
glgsg->apply_texture(tc);
|
|
if (tex->get_texture_type() == Texture::TT_2d_texture) {
|
|
glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
|
|
GL_TEXTURE_2D, gtc->_index, 0);
|
|
} else {
|
|
glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
|
|
GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
|
|
gtc->_index, 0);
|
|
}
|
|
if (_gsg->get_supports_depth_stencil()) {
|
|
if (tex->get_texture_type() == Texture::TT_2d_texture) {
|
|
glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
|
|
GL_TEXTURE_2D, gtc->_index, 0);
|
|
} else {
|
|
glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
|
|
GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
|
|
gtc->_index, 0);
|
|
}
|
|
}
|
|
} else {
|
|
tex->set_format(Texture::F_rgba);
|
|
TextureContext *tc = tex->prepare_now(glgsg->get_prepared_objects(), glgsg);
|
|
nassertv(tc != (TextureContext *)NULL);
|
|
CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
|
|
glgsg->apply_texture(tc);
|
|
if (tex->get_texture_type() == Texture::TT_2d_texture) {
|
|
glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, attachpoint,
|
|
GL_TEXTURE_2D, gtc->_index, 0);
|
|
} else {
|
|
glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, attachpoint,
|
|
GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
|
|
gtc->_index, 0);
|
|
}
|
|
}
|
|
|
|
_tex[slot] = tex;
|
|
_attach_point[slot] = attachpoint;
|
|
|
|
// If there was a renderbuffer bound to this slot, delete it.
|
|
if (_rb[slot] != 0) {
|
|
glgsg->_glDeleteRenderbuffers(1, &(_rb[slot]));
|
|
_rb[slot] = 0;
|
|
}
|
|
|
|
} else {
|
|
|
|
// If a renderbuffer is already attached to the slot, and it's
|
|
// the right size, then no update of this slot is needed.
|
|
if ((_rb[slot] != 0)&&(!rb_resize)) {
|
|
return;
|
|
}
|
|
|
|
// If there's no renderbuffer for this slot, create one.
|
|
if (_rb[slot] == 0) {
|
|
glgsg->_glGenRenderbuffers(1, &(_rb[slot]));
|
|
}
|
|
|
|
// Allocate and bind the renderbuffer.
|
|
glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, _rb[slot]);
|
|
if (attachpoint == GL_DEPTH_ATTACHMENT_EXT) {
|
|
if (_gsg->get_supports_depth_stencil()) {
|
|
glgsg->_glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT,
|
|
_rb_size_x, _rb_size_y);
|
|
glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
|
|
glgsg->_glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
|
|
GL_RENDERBUFFER_EXT, _rb[slot]);
|
|
glgsg->_glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
|
|
GL_RENDERBUFFER_EXT, _rb[slot]);
|
|
} else {
|
|
glgsg->_glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT,
|
|
_rb_size_x, _rb_size_y);
|
|
glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
|
|
glgsg->_glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
|
|
GL_RENDERBUFFER_EXT, _rb[slot]);
|
|
}
|
|
} else {
|
|
glgsg->_glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_RGBA,
|
|
_rb_size_x, _rb_size_y);
|
|
glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
|
|
glgsg->_glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, attachpoint,
|
|
GL_RENDERBUFFER_EXT, _rb[slot]);
|
|
}
|
|
|
|
// Toss any texture that was connected to the slot.
|
|
_tex[slot] = 0;
|
|
_attach_point[slot] = attachpoint;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: glGraphicsBuffer::generate_mipmaps
|
|
// Access: Private
|
|
// Description: This function will be called within the draw thread
|
|
// after rendering is completed for a given frame.
|
|
// If we've just rendered into level zero of a mipmapped
|
|
// texture, then all subsequent mipmap levels will now
|
|
// be calculated.
|
|
////////////////////////////////////////////////////////////////////
|
|
void CLP(GraphicsBuffer)::
|
|
generate_mipmaps() {
|
|
CLP(GraphicsStateGuardian) *glgsg;
|
|
DCAST_INTO_V(glgsg, _gsg);
|
|
|
|
for (int slot=0; slot<RTP_COUNT; slot++) {
|
|
Texture *tex = _tex[slot];
|
|
if ((tex != 0) && (tex->uses_mipmaps())) {
|
|
glgsg->_state._texture = 0;
|
|
TextureContext *tc = tex->prepare_now(glgsg->get_prepared_objects(), glgsg);
|
|
nassertv(tc != (TextureContext *)NULL);
|
|
CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
|
|
GLenum target = glgsg->get_texture_target(tex->get_texture_type());
|
|
GLP(BindTexture)(target, gtc->_index);
|
|
glgsg->_glGenerateMipmap(target);
|
|
GLP(BindTexture)(target, 0);
|
|
}
|
|
}
|
|
glgsg->report_my_gl_errors();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: glGraphicsBuffer::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 CLP(GraphicsBuffer)::
|
|
end_frame(FrameMode mode, Thread *current_thread) {
|
|
end_frame_spam();
|
|
nassertv(_gsg != (GraphicsStateGuardian *)NULL);
|
|
|
|
if (mode == FM_render) {
|
|
copy_to_textures();
|
|
}
|
|
|
|
// Unbind the FBO
|
|
CLP(GraphicsStateGuardian) *glgsg;
|
|
DCAST_INTO_V(glgsg, _gsg);
|
|
glgsg->bind_fbo(0);
|
|
|
|
if (mode == FM_render) {
|
|
generate_mipmaps();
|
|
}
|
|
|
|
_host->end_frame(FM_parasite, current_thread);
|
|
|
|
if (mode == FM_render) {
|
|
trigger_flip();
|
|
if (_one_shot) {
|
|
prepare_for_deletion();
|
|
}
|
|
clear_cube_map_selection();
|
|
}
|
|
glgsg->report_my_gl_errors();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: glGraphicsBuffer::select_cube_map
|
|
// Access: Public, Virtual
|
|
// Description: Called internally when the window is in
|
|
// render-to-a-texture mode and we are in the process of
|
|
// rendering the six faces of a cube map. This should
|
|
// do whatever needs to be done to switch the buffer to
|
|
// the indicated face.
|
|
////////////////////////////////////////////////////////////////////
|
|
void CLP(GraphicsBuffer)::
|
|
select_cube_map(int cube_map_index) {
|
|
if (cube_map_index == _cube_face_active) {
|
|
return;
|
|
}
|
|
_cube_face_active = cube_map_index;
|
|
|
|
CLP(GraphicsStateGuardian) *glgsg;
|
|
DCAST_INTO_V(glgsg, _gsg);
|
|
|
|
for (int i=0; i<RTP_COUNT; i++) {
|
|
Texture *tex = _tex[i];
|
|
if ((tex == 0) ||
|
|
(tex->get_texture_type() != Texture::TT_cube_map)) {
|
|
continue;
|
|
}
|
|
TextureContext *tc = tex->prepare_now(glgsg->get_prepared_objects(), glgsg);
|
|
nassertv(tc != (TextureContext *)NULL);
|
|
CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
|
|
glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, _attach_point[i],
|
|
GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + cube_map_index,
|
|
gtc->_index, 0);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: glGraphicsBuffer::open_buffer
|
|
// 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 CLP(GraphicsBuffer)::
|
|
open_buffer() {
|
|
|
|
// Double check that we have a host
|
|
nassertr(_host != 0, false);
|
|
|
|
// Check for support of relevant extensions.
|
|
CLP(GraphicsStateGuardian) *glgsg;
|
|
DCAST_INTO_R(glgsg, _gsg, false);
|
|
if ((!glgsg->_supports_framebuffer_object)||
|
|
(glgsg->_glDrawBuffers == 0)) {
|
|
return false;
|
|
}
|
|
|
|
// Describe the framebuffer properties of the FBO.
|
|
//
|
|
// The rule is that the properties should be as close
|
|
// as possible to those requested, subject to the limits
|
|
// of the implementation. This particular implementation
|
|
// is fairly limited. But that's okay, we just have to
|
|
// tell the truth about what we actually provide by setting
|
|
// the _fb_properties accurately.
|
|
|
|
_fb_properties.set_depth_bits(1);
|
|
_fb_properties.set_color_bits(1);
|
|
_fb_properties.set_alpha_bits(1);
|
|
if (_gsg->get_supports_depth_stencil()) {
|
|
_fb_properties.set_stencil_bits(1);
|
|
} else {
|
|
_fb_properties.set_stencil_bits(0);
|
|
}
|
|
_fb_properties.set_accum_bits(0);
|
|
_fb_properties.set_multisamples(0);
|
|
_fb_properties.set_back_buffers(0);
|
|
_fb_properties.set_indexed_color(0);
|
|
_fb_properties.set_rgb_color(1);
|
|
_fb_properties.set_stereo(0);
|
|
_fb_properties.set_force_hardware(_host->get_fb_properties().get_force_hardware());
|
|
_fb_properties.set_force_software(_host->get_fb_properties().get_force_software());
|
|
|
|
_is_valid = true;
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: glGraphicsBuffer::close_buffer
|
|
// Access: Protected, Virtual
|
|
// Description: Closes the buffer right now. Called from the window
|
|
// thread.
|
|
////////////////////////////////////////////////////////////////////
|
|
void CLP(GraphicsBuffer)::
|
|
close_buffer() {
|
|
|
|
_active = false;
|
|
if (_gsg == 0) {
|
|
return;
|
|
}
|
|
|
|
// Get the glgsg.
|
|
CLP(GraphicsStateGuardian) *glgsg;
|
|
DCAST_INTO_V(glgsg, _gsg);
|
|
|
|
// Delete the renderbuffers.
|
|
for (int i=0; i<RTP_COUNT; i++) {
|
|
if (_rb[i] != 0) {
|
|
glgsg->_glDeleteRenderbuffers(1, &(_rb[i]));
|
|
_rb[i] = 0;
|
|
}
|
|
_tex[i] = 0;
|
|
}
|
|
_rb_size_x = 0;
|
|
_rb_size_y = 0;
|
|
|
|
// Delete the FBO itself.
|
|
if (_fbo != 0) {
|
|
glgsg->_glDeleteFramebuffers(1, &_fbo);
|
|
_fbo = 0;
|
|
}
|
|
|
|
// Release the Gsg
|
|
_gsg.clear();
|
|
|
|
_is_valid = false;
|
|
}
|
|
|