Files
flightgear/3rdparty/osgXR/src/XRFramebuffer.cpp
2022-10-20 20:29:11 +08:00

152 lines
4.3 KiB
C++

// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2021 James Hogan <james@albanarts.com>
#include "XRFramebuffer.h"
#include <osg/FrameBufferObject>
#include <osg/Image>
#include <osg/State>
#include <osg/Version>
using namespace osgXR;
#if(OSG_VERSION_GREATER_OR_EQUAL(3, 4, 0))
typedef osg::GLExtensions OSG_GLExtensions;
#else
typedef osg::FBOExtensions OSG_GLExtensions;
#endif
static const OSG_GLExtensions* getGLExtensions(const osg::State& state)
{
#if(OSG_VERSION_GREATER_OR_EQUAL(3, 4, 0))
return state.get<osg::GLExtensions>();
#else
return osg::FBOExtensions::instance(state.getContextID(), true);
#endif
}
XRFramebuffer::XRFramebuffer(uint32_t width, uint32_t height,
GLuint texture, GLuint depthTexture) :
_width(width),
_height(height),
_depthFormat(GL_DEPTH_COMPONENT16),
_fbo(0),
_texture(texture),
_depthTexture(depthTexture),
_generated(false),
_boundTexture(false),
_boundDepthTexture(false),
_deleteDepthTexture(false)
{
}
XRFramebuffer::~XRFramebuffer()
{
}
bool XRFramebuffer::valid(osg::State &state) const
{
if (!_fbo)
return false;
const OSG_GLExtensions *fbo_ext = getGLExtensions(state);
GLenum complete = fbo_ext->glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
switch (complete)
{
case GL_FRAMEBUFFER_COMPLETE_EXT:
return true;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
OSG_WARN << "FBO Incomplete attachment" << std::endl;
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
OSG_WARN << "FBO Incomplete missing attachment" << std::endl;
break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
OSG_WARN << "FBO Incomplete draw buffer" << std::endl;
break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
OSG_WARN << "FBO Incomplete read buffer" << std::endl;
break;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
OSG_WARN << "FBO Incomplete unsupported" << std::endl;
break;
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT:
OSG_WARN << "FBO Incomplete multisample" << std::endl;
break;
default:
OSG_WARN << "FBO Incomplete ??? (0x" << std::hex << complete << std::dec << ")" << std::endl;
break;
}
return false;
}
void XRFramebuffer::bind(osg::State &state)
{
const OSG_GLExtensions *fbo_ext = getGLExtensions(state);
if (!_fbo && !_generated)
{
fbo_ext->glGenFramebuffers(1, &_fbo);
_generated = true;
}
if (_fbo)
{
fbo_ext->glBindFramebuffer(GL_FRAMEBUFFER_EXT, _fbo);
if (!_boundTexture && _texture)
{
fbo_ext->glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, _texture, 0);
_boundTexture = true;
}
if (!_boundDepthTexture)
{
if (!_depthTexture)
{
glGenTextures(1, &_depthTexture);
glBindTexture(GL_TEXTURE_2D, _depthTexture);
glTexImage2D(GL_TEXTURE_2D, 0, _depthFormat, _width, _height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, nullptr);
glBindTexture(GL_TEXTURE_2D, 0);
_deleteDepthTexture = true;
}
fbo_ext->glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, _depthTexture, 0);
_boundDepthTexture = true;
valid(state);
}
}
}
void XRFramebuffer::unbind(osg::State &state)
{
const OSG_GLExtensions *fbo_ext = getGLExtensions(state);
if (_fbo && _generated)
fbo_ext->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
}
void XRFramebuffer::releaseGLObjects(osg::State &state)
{
// FIXME can we do it like RenderBuffer::releaseGLObjects?
// FIXME better yet, switch to use FrameBufferObject, dynamically bound
// GL context must be current
if (_fbo)
{
/*
unsigned int contextID = state->getContextID();
osg::get<GLFrameBufferObjectManager>(contextID)->scheduleGLObjectForDeletion(_fbo);
*/
const OSG_GLExtensions *fbo_ext = getGLExtensions(state);
fbo_ext->glDeleteFramebuffers(1, &_fbo);
_fbo = 0;
}
if (_deleteDepthTexture)
{
glDeleteTextures(1, &_depthTexture);
_depthTexture = 0;
_deleteDepthTexture = false;
}
}