Commit 26fb00d2 authored by Christopher Tenter's avatar Christopher Tenter
Browse files

Snapshot fix, Post-Processing was ignored in snapshots

git-svn-id: http://www.openflipper.org/svnrepo/OpenFlipper/branches/Free@17797 383ad7c9-94d9-4d36-a494-682f7c89f535
parent 68058dd6
......@@ -8,6 +8,7 @@
#include "FBO.hh"
#include "GLState.hh"
#include "GLError.hh"
//== NAMESPACES ===============================================================
......@@ -19,7 +20,7 @@ namespace ACG
FBO::FBO()
: fbo_(0), depthbuffer_(0), stencilbuffer_(0), width_(0), height_(0)
: fbo_(0), depthbuffer_(0), stencilbuffer_(0), width_(0), height_(0), samples_(0), fixedsamplelocation_(GL_TRUE), prevFbo_(0)
{
}
......@@ -69,13 +70,15 @@ init()
void
FBO::
attachTexture2D( GLenum _attachment, GLuint _texture )
attachTexture2D( GLenum _attachment, GLuint _texture, GLenum _target )
{
// bind fbo
bind();
// add texture to frame buffer object
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, _attachment, GL_TEXTURE_2D, _texture, 0 );
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, _attachment, _target, _texture, 0 );
checkGLError();
// check status
checkFramebufferStatus();
......@@ -84,7 +87,7 @@ attachTexture2D( GLenum _attachment, GLuint _texture )
unbind();
// track texture id
attachments_[_attachment] = _texture;
attachments_[_attachment] = std::pair<GLuint, GLenum>(_texture, _target);
}
//-----------------------------------------------------------------------------
......@@ -95,32 +98,41 @@ void FBO::attachTexture2D( GLenum _attachment, GLsizei _width, GLsizei _height,
GLuint texID;
glGenTextures(1, &texID);
GLenum target = samples_ ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
// store texture id in internal array
RenderTexture intID;
intID.id = texID;
intID.internalFormat = _internalFmt;
intID.format = _format;
intID.target = target;
internalTextures_.push_back(intID);
// specify texture
glBindTexture(GL_TEXTURE_2D, texID);
glBindTexture(target, texID);
glTexParameteri(target, GL_TEXTURE_WRAP_S, _wrapMode);
glTexParameteri(target, GL_TEXTURE_WRAP_T, _wrapMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, _wrapMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, _wrapMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _minFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _magFilter);
if (!samples_)
{
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, _minFilter);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, _magFilter);
glTexImage2D(target, 0, _internalFmt, _width, _height, 0, _format, GL_FLOAT, 0);
}
else
glTexImage2DMultisample(target, samples_, _internalFmt, _width, _height, fixedsamplelocation_);
glTexImage2D(GL_TEXTURE_2D, 0, _internalFmt, _width, _height, 0, _format, GL_FLOAT, 0);
checkGLError();
width_ = _width;
height_ = _height;
glBindTexture(GL_TEXTURE_2D, 0);
glBindTexture(target, 0);
// attach
attachTexture2D(_attachment, texID);
attachTexture2D(_attachment, texID, target);
}
//-----------------------------------------------------------------------------
......@@ -131,32 +143,41 @@ void FBO::attachTexture2DDepth( GLsizei _width, GLsizei _height, GLuint _interna
GLuint texID;
glGenTextures(1, &texID);
GLenum target = samples_ ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
// store texture id in internal array
RenderTexture intID;
intID.id = texID;
intID.internalFormat = _internalFmt;
intID.format = _format;
intID.target = target;
internalTextures_.push_back(intID);
// specify texture
glBindTexture(GL_TEXTURE_2D, texID);
glBindTexture(target, texID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, _internalFmt, _width, _height, 0, _format, GL_FLOAT, 0);
if (!samples_)
{
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(target, 0, _internalFmt, _width, _height, 0, _format, _format == GL_DEPTH_STENCIL ? GL_UNSIGNED_INT_24_8 : GL_FLOAT, 0);
}
else
glTexImage2DMultisample(target, samples_, _internalFmt, _width, _height, fixedsamplelocation_);
checkGLError();
width_ = _width;
height_ = _height;
glBindTexture(GL_TEXTURE_2D, 0);
glBindTexture(target, 0);
// attach
attachTexture2D(GL_DEPTH_ATTACHMENT, texID);
attachTexture2D(GL_DEPTH_ATTACHMENT, texID, target);
}
//-----------------------------------------------------------------------------
......@@ -222,6 +243,9 @@ bind()
if ( !fbo_ )
return false;
// save previous fbo id
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, (GLint*)&prevFbo_);
// bind framebuffer object
ACG::GLState::bindFramebuffer( GL_FRAMEBUFFER_EXT, fbo_ );
......@@ -235,7 +259,7 @@ FBO::
unbind()
{
//set to normal rendering
ACG::GLState::bindFramebuffer( GL_FRAMEBUFFER_EXT, 0 );
ACG::GLState::bindFramebuffer( GL_FRAMEBUFFER_EXT, prevFbo_ );
}
//-----------------------------------------------------------------------------
......@@ -285,29 +309,53 @@ checkFramebufferStatus()
GLuint FBO::getAttachment( GLenum _attachment )
{
return attachments_[_attachment];
return attachments_[_attachment].first;
}
//-----------------------------------------------------------------------------
void FBO::resize( GLsizei _width, GLsizei _height )
void FBO::resize( GLsizei _width, GLsizei _height, bool _forceResize )
{
if (_width != width_ ||_height != height_)
if (_width != width_ ||_height != height_ || _forceResize)
{
bool reattachTextures = false;
// resize every texture stored in internal array
for (size_t i = 0; i < internalTextures_.size(); ++i)
{
RenderTexture* rt = &internalTextures_[i];
glBindTexture(GL_TEXTURE_2D, rt->id);
glTexImage2D(GL_TEXTURE_2D, 0, rt->internalFormat, _width, _height, 0, rt->format, GL_FLOAT, 0);
// check if we have to convert to multisampling
if (rt->target != GL_TEXTURE_2D_MULTISAMPLE && samples_ > 0)
{
rt->target = GL_TEXTURE_2D_MULTISAMPLE;
reattachTextures = true;
}
glBindTexture(rt->target, rt->id);
if (!samples_)
glTexImage2D(rt->target, 0, rt->internalFormat, _width, _height, 0, rt->format, rt->format == GL_DEPTH_STENCIL ? GL_UNSIGNED_INT_24_8 : GL_FLOAT, 0);
else
glTexImage2DMultisample(rt->target, samples_, rt->internalFormat, _width, _height, fixedsamplelocation_);
}
// store new size
width_ = _width;
height_ = _height;
if (reattachTextures)
{
for (AttachmentList::iterator it = attachments_.begin(); it != attachments_.end(); ++it)
{
attachTexture2D( it->first, it->second.first, it->second.second );
}
}
glBindTexture(GL_TEXTURE_2D, 0);
}
......@@ -319,6 +367,26 @@ GLuint FBO::getFboID()
return fbo_;
}
void FBO::setMultisampling( GLsizei _samples, GLboolean _fixedsamplelocations /*= GL_TRUE*/ )
{
// clamp sample count to max supported
GLint maxSamples;
glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
if (_samples > maxSamples) _samples = maxSamples;
// issue texture reloading when params changed
bool reloadTextures = (samples_ != _samples || fixedsamplelocation_ != _fixedsamplelocations);
samples_ = _samples;
fixedsamplelocation_ = _fixedsamplelocations;
// force a texture reloading to apply new multisampling
if (reloadTextures)
resize(width_, height_, true);
}
//=============================================================================
} // namespace ACG
......
......@@ -52,6 +52,12 @@ public:
/// function to generate the framebuffer object
void init();
/// enable/disable multisampling
void setMultisampling(GLsizei _samples, GLboolean _fixedsamplelocations = GL_TRUE);
/// get number of samples
GLsizei getMultisamplingCount() const {return samples_;}
/// function to attach a texture to fbo
void attachTexture2D( GLenum _attachment,
GLsizei _width, GLsizei _height,
......@@ -60,8 +66,9 @@ public:
GLint _minFilter = GL_NEAREST,
GLint _magFilter = GL_NEAREST);
/// function to attach a texture to fbo
void attachTexture2D( GLenum _attachment, GLuint _texture );
void attachTexture2D( GLenum _attachment, GLuint _texture, GLenum _target = GL_TEXTURE_2D );
/// function to attach a depth-buffer texture to fbo (using GL_DEPTH_ATTACHMENT)
void attachTexture2DDepth( GLsizei _width, GLsizei _height, GLuint _internalFmt = GL_DEPTH_COMPONENT32, GLenum _format = GL_DEPTH_COMPONENT );
......@@ -79,7 +86,13 @@ public:
GLuint getFboID();
/// resize function (if textures created by this class)
void resize(GLsizei _width, GLsizei _height);
void resize(GLsizei _width, GLsizei _height, bool _forceResize = false);
/// get width of fbo texture
GLsizei width() const {return width_;}
/// get height of fbo texture
GLsizei height() const {return height_;}
/// bind the fbo and sets it as rendertarget
bool bind();
......@@ -102,11 +115,17 @@ private:
GLuint stencilbuffer_;
/// attached textures
std::map<GLenum, GLuint> attachments_; // key: attachment index
typedef std::map<GLenum, std::pair<GLuint, GLenum> > AttachmentList;
AttachmentList attachments_; // key: attachment index, value: <tex_id, target>
struct RenderTexture
{
// opengl buf id
GLuint id;
// GL_TEXTURE_2D, GL_TEXTURE_2D_MULTISAMPLE..
GLenum target;
GLenum internalFormat, format;
};
/// textures created by this class
......@@ -114,6 +133,16 @@ private:
/// width and height of render textures
GLsizei width_, height_;
/// sample count if multisampling
GLsizei samples_;
/// enable fixed sample location if multisampling
GLboolean fixedsamplelocation_;
/// handle of previously bound fbo
GLuint prevFbo_;
};
......
......@@ -250,9 +250,6 @@ void IRenderer::prepareRenderingPipeline(ACG::GLState* _glState, ACG::SceneGraph
void IRenderer::finishRenderingPipeline()
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDrawBuffer(GL_BACK);
glDepthMask(1);
glColorMask(1,1,1,1);
......
......@@ -61,6 +61,8 @@
#include <ACG/Scenegraph/CoordsysNode.hh>
#include <ACG/Scenegraph/SceneGraphAnalysis.hh>
#include <ACG/GL/gl.hh>
#include <ACG/GL/GLError.hh>
#include <ACG/GL/FBO.hh>
#include <iostream>
#include <string>
......@@ -166,8 +168,7 @@ glViewer::glViewer( QGraphicsScene* _scene,
flyAnimationOrthogonal_(0),
flyAngle_(0.0),
currentAnimationPos_(0.0),
flyMoveBack_(false),
sceneTexReadBackWidth_(0), sceneTexReadBackHeight_(0)
flyMoveBack_(false)
{
// widget stuff
......@@ -636,76 +637,64 @@ void glViewer::drawScene()
// }
// QGLFramebufferObject fbo( glstate_->viewport_width(),glstate_->viewport_height(),QGLFramebufferObject::CombinedDepthStencil );
//
// fbo.bind();
updatePostProcessingBufs(glstate_->viewport_width(),glstate_->viewport_height());
// glBindFramebuffer(GL_FRAMEBUFFER, postProcessFBO_);
// Check if we use build in default renderer
if ( renderManager().activeId( properties_.viewerId() ) == 0 ) {
drawScene_mono();
} else {
renderManager().active( properties_.viewerId() )->plugin->render(glstate_,properties_);
}
// glBindFramebuffer(GL_FRAMEBUFFER, 0);
checkGLError();
// =================================================================================
// Post-Processing pipeline
const int numPostProcessors = postProcessorManager().numActive(properties_.viewerId());
// =================================================================================
// Post-Processing pipeline
if (numPostProcessors)
{
GLuint backbufferFbo = 0;
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, (GLint*)&backbufferFbo);
readBackBuffer(glstate_);
int numPostProcessors = postProcessorManager().numActive(properties_.viewerId());
updatePostProcessingBufs(glstate_->viewport_width(),glstate_->viewport_height());
// // DEBUG testing post processor chain
// if (numPostProcessors == 1)
// {
// postProcessorManager().append("Grayscale Postprocessor Plugin", properties_.viewerId());
// postProcessorManager().append("Red Postprocessor Plugin", properties_.viewerId());
//
// numPostProcessors += 2;
// }
readBackBuffer(glstate_);
// 1st post processing source: back buffer
int postProcSrc = 1;
PostProcessorInput postProcInput;
postProcInput.colorTex_ = sceneTexReadBack_.id();
postProcInput.depthTex_ = depthTexReadBack_.id();
postProcInput.width = sceneTexReadBackWidth_;
postProcInput.height = sceneTexReadBackHeight_;
// 1st post processing source: active fbo
int postProcSrc = 1;
PostProcessorInput postProcInput;
postProcInput.colorTex_ = readBackFbo_.getAttachment(GL_COLOR_ATTACHMENT0);
postProcInput.depthTex_ = readBackFbo_.getAttachment(GL_DEPTH_ATTACHMENT);
postProcInput.width = readBackFbo_.width();
postProcInput.height = readBackFbo_.height();
// execute post processing chain with 2 FBOs
for (int i = 0; i < numPostProcessors; ++i) {
// execute post processing chain with 2 FBOs
for (int i = 0; i < numPostProcessors; ++i) {
int postProcTarget = 1 - postProcSrc;
int postProcTarget = 1 - postProcSrc;
GLuint targetFBO = postProcessFBO_[postProcTarget].getFboID();
GLuint targetFBO = postProcessFBO_[postProcTarget].getFboID();
// write to back buffer in last step
if (i + 1 == numPostProcessors)
targetFBO = 0;
// write to back buffer in last step
if (i + 1 == numPostProcessors)
targetFBO = backbufferFbo;
// apply post processor
PostProcessorInfo* proc = postProcessorManager().active( properties_.viewerId(), i );
if (proc && proc->plugin)
proc->plugin->postProcess(glstate_, postProcInput, targetFBO);
// apply post processor
PostProcessorInfo* proc = postProcessorManager().active( properties_.viewerId(), i );
if (proc && proc->plugin)
proc->plugin->postProcess(glstate_, postProcInput, targetFBO);
// swap target/source fbo
postProcSrc = postProcTarget;
// swap target/source fbo
postProcSrc = postProcTarget;
postProcInput.colorTex_ = postProcessFBO_[postProcSrc].getAttachment(GL_COLOR_ATTACHMENT0);
postProcInput.colorTex_ = postProcessFBO_[postProcSrc].getAttachment(GL_COLOR_ATTACHMENT0);
}
}
// =================================================================================
......@@ -2118,7 +2107,7 @@ void glViewer::applyProperties() {
// Make sure the right buffer is used in non stereo setup
makeCurrent();
ACG::GLState::drawBuffer(GL_BACK);
ACG::GLState::drawBuffer(ACG::GLState::getFramebufferDraw() ? GL_COLOR_ATTACHMENT0 : GL_BACK);
// Required for stereo toggling
updateProjectionMatrix ();
......@@ -2166,17 +2155,18 @@ void glViewer::snapshot(QImage& _image, int _width, int _height, bool _alpha, bo
format.setTextureTarget(GL_TEXTURE_2D);
// set the attachments as in the standard rendering
format.setAttachment(QFramebufferObject::CombinedDepthStencil);
// format.setAttachment(QFramebufferObject::CombinedDepthStencil);
// 16 samples per pixel as we want a nice snapshot. If this is not supported
// it will fall back to the maximal supported number of samples
format.setSamples(samples);
QFramebufferObject fb(w,h,format);
if ( fb.isValid() ){
const GLuint prevFbo = ACG::GLState::getFramebufferDraw();
ACG::GLState::bindFramebuffer(GL_FRAMEBUFFER_EXT,fb.handle());
makeCurrent();
ACG::GLState::bindFramebuffer(GL_FRAMEBUFFER_EXT, fb.handle());
// Turn alpha on if demanded
ACG::Vec4f backColorBak;
......@@ -2197,16 +2187,24 @@ void glViewer::snapshot(QImage& _image, int _width, int _height, bool _alpha, bo
}
backColorBak = properties()->backgroundColor();
newBack = ACG::Vec4f(backColorBak[0], backColorBak[1], backColorBak[2], (_alpha ? 0.0f : 1.0f));
properties()->backgroundColor(newBack);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_MULTISAMPLE);
paintGL();
glFinish();
glDisable(GL_MULTISAMPLE);
ACG::GLState::bindFramebuffer(GL_FRAMEBUFFER_EXT, prevFbo);
// Reset alpha settings
if(_alpha)
properties()->backgroundColor(backColorBak);
......@@ -2219,8 +2217,9 @@ void glViewer::snapshot(QImage& _image, int _width, int _height, bool _alpha, bo
node->show();
}
}
_image = fb.toImage().copy(0, 0, w, h);
_image = fb.toImage().copy(0, 0, w, h);
}
if(_width != 0 || _height != 0) {
......@@ -2435,88 +2434,37 @@ void glViewer::strafeRight() {
void glViewer::readBackBuffer(ACG::GLState* _glstate)
{
int width, height, x, y;
_glstate->get_viewport(x, y, width, height);
if (!sceneTexReadBack_.is_valid())
{
// create r8g8b8a8 color texture
GLint curFbo = 0;
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &curFbo);
sceneTexReadBack_.enable();
sceneTexReadBack_.bind();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
sceneTexReadBackWidth_ = width;
sceneTexReadBackHeight_ = height;
}
if (!depthTexReadBack_.is_valid())
{
// create D24S8 texture
ACG::GLState::bindFramebuffer(GL_READ_FRAMEBUFFER, curFbo);
ACG::GLState::bindFramebuffer(GL_DRAW_FRAMEBUFFER, readBackFbo_.getFboID());
depthTexReadBack_.enable();
depthTexReadBack_.bind();
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8_EXT, width, height, 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, 0);
glBlitFramebuffer(0, 0, readBackFbo_.width(), readBackFbo_.height(),
0, 0, readBackFbo_.width(), readBackFbo_.height(),
GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
checkGLError();
sceneTexReadBackWidth_ = width;
sceneTexReadBackHeight_ = height;
}
// Resize if already exists
if (width != sceneTexReadBackWidth_ || height != sceneTexReadBackHeight_)
{
sceneTexReadBack_.enable();
sceneTexReadBack_.bind();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
depthTexReadBack_.enable();
depthTexReadBack_.bind();
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
sceneTexReadBackWidth_ = width;
sceneTexReadBackHeight_ = height;
}
// read back buffer
sceneTexReadBack_.enable();
sceneTexReadBack_.bind();
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, width , height, 0);
sceneTexReadBack_.disable();
depthTexReadBack_.enable();
depthTexReadBack_.bind();
glCopyTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, x, y, width , height, 0);
depthTexReadBack_.disable();
ACG::GLState::bindFramebuffer(GL_FRAMEBUFFER, curFbo);
}
void glViewer::updatePostProcessingBufs(int _width, int _height)
{
for (int i = 0; i < 2; ++i)
ACG::FBO* fbos[] = {postProcessFBO_, postProcessFBO_ + 1, &readBackFbo_};
for (int i = 0; i < 3; ++i)
{
if (!postProcessFBO_[i].getFboID())
if (!fbos[i]->getFboID())
{
postProcessFBO_[i].init();
fbos[i]->init();