/**************************************************************************** * 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 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(); }