/** * projectM -- Milkdrop-esque visualisation SDK * Copyright (C)2003-2004 projectM Team * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * See 'LICENSE.txt' included within this release * */ /** * $Id: FBO.c,v 1.1.1.1 2005/12/23 18:05:00 psperl Exp $ * * Render this methods */ #include //#include #include #include "Common.hpp" #include "FBO.hpp" RenderTarget::~RenderTarget() { glDeleteTextures( 1, &this->textureID[0]); #ifdef USE_FBO if (useFBO) { glDeleteTextures( 1, &this->textureID[1] ); glDeleteRenderbuffersEXT(1, &this->depthb[0]); glDeleteFramebuffersEXT(1, &this->fbuffer[0]); if(renderToTexture) { glDeleteTextures( 1, &this->textureID[2] ); glDeleteRenderbuffersEXT(1, &this->depthb[1]); glDeleteFramebuffersEXT(1, &this->fbuffer[1]); } } #endif } GLuint RenderTarget::initRenderToTexture() { #ifdef USE_FBO if (this->useFBO==1) { this->renderToTexture=1; GLuint fb2, depth_rb2; glGenFramebuffersEXT(1, &fb2); glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, fb2 ); glGenRenderbuffersEXT(1, &depth_rb2); glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, depth_rb2 ); glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, this->texsize,this->texsize ); glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_rb2 ); this->fbuffer[1] = fb2; this->depthb[1]= depth_rb2; glGenTextures(1, &this->textureID[2]); glBindTexture(GL_TEXTURE_2D, this->textureID[2]); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, texsize, texsize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, this->textureID[2], 0 ); return this->textureID[2]; } #endif return -1; } /** Creates new pbuffers */ RenderTarget::RenderTarget(int texsize, int width, int height) : useFBO(false) { int mindim = 0; int origtexsize = 0; this->renderToTexture = 0; this->texsize = texsize; #ifdef USE_FBO glewInit(); // Forceably disable FBO if user requested it but the video card / driver lacks // the appropraite frame buffer extension. if (useFBO = glewIsSupported("GL_EXT_framebuffer_object")) { GLuint fb, depth_rb, rgba_tex, other_tex; glGenFramebuffersEXT(1, &fb); glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, fb ); glGenRenderbuffersEXT(1, &depth_rb); glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, depth_rb ); glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, this->texsize,this->texsize ); glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_rb ); this->fbuffer[0] = fb; this->depthb[0]= depth_rb; glGenTextures(1, &other_tex); glBindTexture(GL_TEXTURE_2D,other_tex); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, texsize, texsize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL ); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); //glGenerateMipmapEXT(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glGenTextures(1, &rgba_tex); glBindTexture(GL_TEXTURE_2D, rgba_tex); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, texsize, texsize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); //glGenerateMipmapEXT(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, rgba_tex, 0 ); this->textureID[0] = rgba_tex; this->textureID[1] = other_tex; GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); if (status == GL_FRAMEBUFFER_COMPLETE_EXT) { return; } std::cerr << "[projecM] warning: FBO support not detected. Using fallback." << std::endl; } #endif // Can reach here via two code paths: // (1) useFBO was set to false externally by cmake / system setting / etc. // (2) useFBO was true but forced to false as it failed to pass all the GLU extension checks. /** Fallback pbuffer creation via teximage hack */ /** Check the texture size against the viewport size */ /** If the viewport is smaller, then we'll need to scale the texture size down */ /** If the viewport is larger, scale it up */ mindim = width < height ? width : height; origtexsize = this->texsize; this->texsize = nearestPower2( mindim, SCALE_MINIFY ); glGenTextures(1, &this->textureID[0] ); glBindTexture(GL_TEXTURE_2D, this->textureID[0] ); //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, this->texsize, this->texsize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); return; } void RenderTarget::fallbackRescale(int width, int height) { int mindim = width < height ? width : height; int origtexsize = this->texsize; this->texsize = nearestPower2( mindim, SCALE_MINIFY ); /* Create the texture that will be bound to the render this */ /* if ( this->texsize != origtexsize ) { glDeleteTextures( 1, &this->textureID[0] ); } */ glGenTextures(1, &this->textureID[0] ); glBindTexture(GL_TEXTURE_2D, this->textureID[0] ); //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, this->texsize, this->texsize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); } /** Destroys the pbuffer */ /** Locks the pbuffer */ void RenderTarget::lock() { #ifdef USE_FBO if(this->useFBO) { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, this->fbuffer[0]); } #endif } /** Unlocks the pbuffer */ void RenderTarget::unlock() { #ifdef USE_FBO if(this->useFBO) { glBindTexture( GL_TEXTURE_2D, this->textureID[1] ); glCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, this->texsize, this->texsize ); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); return; } #endif /** Fallback texture path */ glBindTexture( GL_TEXTURE_2D, this->textureID[0] ); glCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, this->texsize, this->texsize ); } /** * Calculates the nearest power of two to the given number using the * appropriate rule */ int RenderTarget::nearestPower2( int value, TextureScale scaleRule ) { int x = value; int power = 0; while ( ( x & 0x01 ) != 1 ) { x >>= 1; } if ( x == 1 ) { return value; } else { x = value; while ( x != 0 ) { x >>= 1; power++; } switch ( scaleRule ) { case SCALE_NEAREST: if ( ( ( 1 << power ) - value ) <= ( value - ( 1 << ( power - 1 ) ) ) ) { return 1 << power; } else { return 1 << ( power - 1 ); } case SCALE_MAGNIFY: return 1 << power; case SCALE_MINIFY: return 1 << ( power - 1 ); default: break; } } return 0; }