2020-10-21 17:24:01 +02:00

182 lines
5.8 KiB
C++

/****************************************************************************
* MeshLab o o *
* A versatile mesh processing toolbox o o *
* _ O _ *
* Copyright(C) 2005-2008 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
#include "rfx_rendertarget.h"
RfxRenderTarget::RfxRenderTarget(const QString& rtName)
{
name = rtName;
width = 0;
height = 0;
fbo = 0;
depTex = 0;
colTex = 0;
mipmaps = false;
vportdim = false;
initOk = false;
}
RfxRenderTarget::~RfxRenderTarget()
{
if (initOk) {
glDeleteFramebuffersEXT(1, &fbo);
glDeleteRenderbuffersEXT(1, &depTex);
glDeleteTextures(1, &colTex);
}
}
void RfxRenderTarget::SetClear(int pass, float depthClear, float *colorClear)
{
passOptions[pass].clearMask = 0;
passOptions[pass].colorClear = false;
passOptions[pass].depthClear = false;
// valid depth clear values are [0, 1]
// -1.0 disable depth clear
if (depthClear != -1.0) {
passOptions[pass].depthClear = true;
passOptions[pass].depthClearVal = depthClear;
passOptions[pass].clearMask |= GL_DEPTH_BUFFER_BIT;
}
// color should be a 4-elements array.
// NULL disable color clear
if (colorClear != NULL) {
passOptions[pass].colorClear = true;
passOptions[pass].colorClearVal[0] = colorClear[0];
passOptions[pass].colorClearVal[1] = colorClear[1];
passOptions[pass].colorClearVal[2] = colorClear[2];
passOptions[pass].colorClearVal[3] = colorClear[3];
passOptions[pass].clearMask |= GL_COLOR_BUFFER_BIT;
}
}
bool RfxRenderTarget::Setup(int pass)
{
if (!GLEW_EXT_framebuffer_object) {
qWarning("FBO not supported!");
return false;
}
if (initOk)
return true;
glGenFramebuffersEXT(1, &fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
// if "use viewport dimensions" at this point we have a gl context
if (vportdim) {
GLfloat dims[4];
glGetFloatv(GL_VIEWPORT, dims);
width = (int)dims[2];
height = (int)dims[3];
}
// depth buffer
glGenRenderbuffersEXT(1, &depTex);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depTex);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depTex);
// color buffer
glGenTextures(1, &colTex);
glBindTexture(GL_TEXTURE_2D, colTex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, colTex, 0);
// set texture state based on the first uniform that will use RT
QList<int> k = passStates.keys();
for (int i = 0; i < k.size(); ++i) {
if (k.at(i) > pass) {
foreach (RfxState *s, passStates.value(i))
s->SetEnvironment(GL_TEXTURE_2D);
}
}
initOk = (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
return initOk;
}
void RfxRenderTarget::Bind(int pass)
{
assert(initOk);
bool colClear = passOptions.value(pass).colorClear;
bool depClear = passOptions.value(pass).depthClear;
if (colClear) {
const float *cols = passOptions.value(pass).colorClearVal;
glClearColor(cols[0], cols[1], cols[2], cols[3]);
}
if (depClear)
glClearDepth(passOptions.value(pass).depthClearVal);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
glPushAttrib(GL_VIEWPORT_BIT);
glViewport(0, 0, width, height);
if (colClear || depClear)
glClear(passOptions.value(pass).clearMask);
}
void RfxRenderTarget::Unbind()
{
if (!initOk)
return;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glPopAttrib();
}
QImage RfxRenderTarget::GetQImage()
{
if (!initOk)
return QImage();
QImage img(width, height, QImage::Format_RGB32);
unsigned char *tempBuf = new unsigned char[width * height * 3];
unsigned char *tempBufPtr = tempBuf;
glBindTexture(GL_TEXTURE_2D, colTex);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, tempBufPtr);
for (int i = 0; i < height; ++i) {
QRgb *scanLine = (QRgb*)img.scanLine(i);
for (int j = 0; j < width; ++j) {
scanLine[j] = qRgb(tempBufPtr[0], tempBufPtr[1], tempBufPtr[2]);
tempBufPtr += 3;
}
}
delete[] tempBuf;
return img.mirrored();
}