diff options
Diffstat (limited to 'source/gameengine/Rasterizer/RAS_2DFilterManager.cpp')
-rw-r--r-- | source/gameengine/Rasterizer/RAS_2DFilterManager.cpp | 500 |
1 files changed, 500 insertions, 0 deletions
diff --git a/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp new file mode 100644 index 00000000000..d2cfa7d07f9 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp @@ -0,0 +1,500 @@ +/** + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#define STRINGIFY(A) #A + +#include "RAS_OpenGLFilters/RAS_Blur2DFilter.h" +#include "RAS_OpenGLFilters/RAS_Sharpen2DFilter.h" +#include "RAS_OpenGLFilters/RAS_Dilation2DFilter.h" +#include "RAS_OpenGLFilters/RAS_Erosion2DFilter.h" +#include "RAS_OpenGLFilters/RAS_Laplacian2DFilter.h" +#include "RAS_OpenGLFilters/RAS_Sobel2DFilter.h" +#include "RAS_OpenGLFilters/RAS_Prewitt2DFilter.h" +#include "RAS_OpenGLFilters/RAS_GrayScale2DFilter.h" +#include "RAS_OpenGLFilters/RAS_Sepia2DFilter.h" +#include "RAS_OpenGLFilters/RAS_Invert2DFilter.h" + +#include "STR_String.h" +#include "RAS_ICanvas.h" +#include "RAS_Rect.h" +#include "RAS_2DFilterManager.h" +#include <iostream> + +#include "GL/glew.h" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "Value.h" + +RAS_2DFilterManager::RAS_2DFilterManager(): +texturewidth(-1), textureheight(-1), +canvaswidth(-1), canvasheight(-1), +numberoffilters(0) +{ + isshadersupported = GLEW_ARB_shader_objects && + GLEW_ARB_fragment_shader && GLEW_ARB_multitexture; + + if(!isshadersupported) + { + std::cout<<"shaders not supported!" << std::endl; + return; + } + + int passindex; + for(passindex =0; passindex<MAX_RENDER_PASS; passindex++) + { + m_filters[passindex] = 0; + m_enabled[passindex] = 0; + texflag[passindex] = 0; + m_gameObjects[passindex] = NULL; + } + texname[0] = texname[1] = texname[2] = -1; + errorprinted= false; +} + +RAS_2DFilterManager::~RAS_2DFilterManager() +{ + FreeTextures(); +} + +void RAS_2DFilterManager::PrintShaderErrors(unsigned int shader, const char *task, const char *code) +{ + GLcharARB log[5000]; + GLsizei length = 0; + const char *c, *pos, *end; + int line = 1; + + if(errorprinted) + return; + + errorprinted= true; + + glGetInfoLogARB(shader, sizeof(log), &length, log); + end = code + strlen(code); + + printf("2D Filter GLSL Shader: %s error:\n", task); + + c = code; + while ((c < end) && (pos = strchr(c, '\n'))) { + printf("%2d ", line); + fwrite(c, (pos+1)-c, 1, stdout); + c = pos+1; + line++; + } + printf("%s", c); + + printf("%s\n", log); +} + +unsigned int RAS_2DFilterManager::CreateShaderProgram(const char* shadersource) +{ + GLuint program = 0; + GLuint fShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER); + GLint success; + + glShaderSourceARB(fShader, 1, (const char**)&shadersource, NULL); + + glCompileShaderARB(fShader); + + + glGetObjectParameterivARB(fShader, GL_COMPILE_STATUS, &success); + if(!success) + { + /*Shader Comile Error*/ + PrintShaderErrors(fShader, "compile", shadersource); + return 0; + } + + program = glCreateProgramObjectARB(); + glAttachObjectARB(program, fShader); + + glLinkProgramARB(program); + glGetObjectParameterivARB(program, GL_LINK_STATUS, &success); + if (!success) + { + /*Program Link Error*/ + PrintShaderErrors(fShader, "link", shadersource); + return 0; + } + + glValidateProgramARB(program); + glGetObjectParameterivARB(program, GL_VALIDATE_STATUS, &success); + if (!success) + { + /*Program Validation Error*/ + PrintShaderErrors(fShader, "validate", shadersource); + return 0; + } + + return program; +} + +unsigned int RAS_2DFilterManager::CreateShaderProgram(int filtermode) +{ + switch(filtermode) + { + case RAS_2DFILTER_BLUR: + return CreateShaderProgram(BlurFragmentShader); + case RAS_2DFILTER_SHARPEN: + return CreateShaderProgram(SharpenFragmentShader); + case RAS_2DFILTER_DILATION: + return CreateShaderProgram(DilationFragmentShader); + case RAS_2DFILTER_EROSION: + return CreateShaderProgram(ErosionFragmentShader); + case RAS_2DFILTER_LAPLACIAN: + return CreateShaderProgram(LaplacionFragmentShader); + case RAS_2DFILTER_SOBEL: + return CreateShaderProgram(SobelFragmentShader); + case RAS_2DFILTER_PREWITT: + return CreateShaderProgram(PrewittFragmentShader); + case RAS_2DFILTER_GRAYSCALE: + return CreateShaderProgram(GrayScaleFragmentShader); + case RAS_2DFILTER_SEPIA: + return CreateShaderProgram(SepiaFragmentShader); + case RAS_2DFILTER_INVERT: + return CreateShaderProgram(InvertFragmentShader); + } + return 0; +} + +void RAS_2DFilterManager::AnalyseShader(int passindex, vector<STR_String>& propNames) +{ + texflag[passindex] = 0; + if(glGetUniformLocationARB(m_filters[passindex], "bgl_DepthTexture") != -1) + { + if(GLEW_ARB_depth_texture) + texflag[passindex] |= 0x1; + } + if(glGetUniformLocationARB(m_filters[passindex], "bgl_LuminanceTexture") != -1) + { + texflag[passindex] |= 0x2; + } + + if(m_gameObjects[passindex]) + { + int objProperties = propNames.size(); + int i; + for(i=0; i<objProperties; i++) + if(glGetUniformLocationARB(m_filters[passindex], propNames[i]) != -1) + m_properties[passindex].push_back(propNames[i]); + } +} + +void RAS_2DFilterManager::StartShaderProgram(int passindex) +{ + GLint uniformLoc; + glUseProgramObjectARB(m_filters[passindex]); + uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_RenderedTexture"); + glActiveTextureARB(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texname[0]); + + if (uniformLoc != -1) + { + glUniform1iARB(uniformLoc, 0); + } + + /* send depth texture to glsl program if it needs */ + if(texflag[passindex] & 0x1){ + uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_DepthTexture"); + glActiveTextureARB(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, texname[1]); + + if (uniformLoc != -1) + { + glUniform1iARB(uniformLoc, 1); + } + } + + /* send luminance texture to glsl program if it needs */ + if(texflag[passindex] & 0x2){ + uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_LuminanceTexture"); + glActiveTextureARB(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, texname[2]); + + if (uniformLoc != -1) + { + glUniform1iARB(uniformLoc, 2); + } + } + + uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_TextureCoordinateOffset"); + if (uniformLoc != -1) + { + glUniform2fvARB(uniformLoc, 9, textureoffsets); + } + uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_RenderedTextureWidth"); + if (uniformLoc != -1) + { + glUniform1fARB(uniformLoc,texturewidth); + } + uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_RenderedTextureHeight"); + if (uniformLoc != -1) + { + glUniform1fARB(uniformLoc,textureheight); + } + + int i, objProperties = m_properties[passindex].size(); + for(i=0; i<objProperties; i++) + { + uniformLoc = glGetUniformLocationARB(m_filters[passindex], m_properties[passindex][i]); + if(uniformLoc != -1) + { + float value = ((CValue*)m_gameObjects[passindex])->GetPropertyNumber(m_properties[passindex][i], 0.0); + glUniform1fARB(uniformLoc,value); + } + } +} + +void RAS_2DFilterManager::EndShaderProgram() +{ + glUseProgramObjectARB(0); +} + +void RAS_2DFilterManager::FreeTextures() +{ + if(texname[0]!=(unsigned int)-1) + glDeleteTextures(1, (GLuint*)&texname[0]); + if(texname[1]!=(unsigned int)-1) + glDeleteTextures(1, (GLuint*)&texname[1]); + if(texname[2]!=(unsigned int)-1) + glDeleteTextures(1, (GLuint*)&texname[2]); +} + +void RAS_2DFilterManager::SetupTextures(bool depth, bool luminance) +{ + FreeTextures(); + + glGenTextures(1, (GLuint*)&texname[0]); + glBindTexture(GL_TEXTURE_2D, texname[0]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texturewidth, textureheight, 0, GL_RGBA, + GL_UNSIGNED_BYTE, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + + if(depth){ + glGenTextures(1, (GLuint*)&texname[1]); + glBindTexture(GL_TEXTURE_2D, texname[1]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, texturewidth,textureheight, + 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE,NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, + GL_NONE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + } + + if(luminance){ + glGenTextures(1, (GLuint*)&texname[2]); + glBindTexture(GL_TEXTURE_2D, texname[2]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE16, texturewidth, textureheight, + 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + } +} + +void RAS_2DFilterManager::UpdateOffsetMatrix(RAS_ICanvas* canvas) +{ + RAS_Rect canvas_rect = canvas->GetWindowArea(); + canvaswidth = canvas->GetWidth(); + canvasheight = canvas->GetHeight(); + texturewidth = canvaswidth; + textureheight = canvasheight; + + GLint i,j; + i = 0; + while ((1 << i) <= texturewidth) + i++; + texturewidth = (1 << (i)); + + // Now for height + i = 0; + while ((1 << i) <= textureheight) + i++; + textureheight = (1 << (i)); + + GLfloat xInc = 1.0f / (GLfloat)texturewidth; + GLfloat yInc = 1.0f / (GLfloat)textureheight; + + for (i = 0; i < 3; i++) + { + for (j = 0; j < 3; j++) + { + textureoffsets[(((i*3)+j)*2)+0] = (-1.0f * xInc) + ((GLfloat)i * xInc); + textureoffsets[(((i*3)+j)*2)+1] = (-1.0f * yInc) + ((GLfloat)j * yInc); + } + } +} + +void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas) +{ + bool need_depth=false; + bool need_luminance=false; + int num_filters = 0; + + int passindex; + + if(!isshadersupported) + return; + + for(passindex =0; passindex<MAX_RENDER_PASS; passindex++) + { + if(m_filters[passindex] && m_enabled[passindex]){ + num_filters ++; + if(texflag[passindex] & 0x1) + need_depth = true; + if(texflag[passindex] & 0x2) + need_luminance = true; + if(need_depth && need_luminance) + break; + } + } + + if(num_filters <= 0) + return; + + if(canvaswidth != canvas->GetWidth() || canvasheight != canvas->GetHeight()) + { + UpdateOffsetMatrix(canvas); + SetupTextures(need_depth, need_luminance); + } + GLuint viewport[4]={0}; + + if(need_depth){ + glActiveTextureARB(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, texname[1]); + glCopyTexImage2D(GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT, viewport[0], viewport[1], texturewidth,textureheight, 0); + } + + if(need_luminance){ + glActiveTextureARB(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, texname[2]); + glCopyTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE16, viewport[0], viewport[1] , texturewidth,textureheight, 0); + } + + glGetIntegerv(GL_VIEWPORT,(GLint *)viewport); + glViewport(viewport[0],viewport[1], texturewidth, textureheight); + + glDisable(GL_DEPTH_TEST); + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + for(passindex =0; passindex<MAX_RENDER_PASS; passindex++) + { + if(m_filters[passindex] && m_enabled[passindex]) + { + StartShaderProgram(passindex); + + glActiveTextureARB(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texname[0]); + glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, viewport[0], viewport[1], texturewidth, textureheight, 0); + glClear(GL_COLOR_BUFFER_BIT); + + float canvascoordx, canvascoordy; + + canvascoordx = (GLfloat) texturewidth / canvaswidth; + canvascoordy = (GLfloat) textureheight / canvasheight; + + glBegin(GL_QUADS); + glColor4f(1.f, 1.f, 1.f, 1.f); + glTexCoord2f(1.0, 1.0); glMultiTexCoord2fARB(GL_TEXTURE1_ARB, canvascoordx, canvascoordy); glVertex2f(1,1); + glTexCoord2f(0.0, 1.0); glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0, canvascoordy); glVertex2f(-1,1); + glTexCoord2f(0.0, 0.0); glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0, 0.0); glVertex2f(-1,-1); + glTexCoord2f(1.0, 0.0); glMultiTexCoord2fARB(GL_TEXTURE1_ARB, canvascoordx, 0.0); glVertex2f(1,-1); + glEnd(); + } + } + + glEnable(GL_DEPTH_TEST); + glViewport(viewport[0],viewport[1],viewport[2],viewport[3]); + EndShaderProgram(); +} + +void RAS_2DFilterManager::EnableFilter(vector<STR_String>& propNames, void* gameObj, RAS_2DFILTER_MODE mode, int pass, STR_String& text) +{ + if(!isshadersupported) + return; + if(pass<0 || pass>=MAX_RENDER_PASS) + return; + + if(mode == RAS_2DFILTER_DISABLED) + { + m_enabled[pass] = 0; + return; + } + + if(mode == RAS_2DFILTER_ENABLED) + { + m_enabled[pass] = 1; + return; + } + + if(mode == RAS_2DFILTER_NOFILTER) + { + if(m_filters[pass]) + glDeleteObjectARB(m_filters[pass]); + m_enabled[pass] = 0; + m_filters[pass] = 0; + m_gameObjects[pass] = NULL; + m_properties[pass].clear(); + texflag[pass] = 0; + return; + } + + if(mode == RAS_2DFILTER_CUSTOMFILTER) + { + if(m_filters[pass]) + glDeleteObjectARB(m_filters[pass]); + m_filters[pass] = CreateShaderProgram(text.Ptr()); + m_gameObjects[pass] = gameObj; + AnalyseShader(pass, propNames); + m_enabled[pass] = 1; + return; + } + + if(mode>=RAS_2DFILTER_MOTIONBLUR && mode<=RAS_2DFILTER_INVERT) + { + if(m_filters[pass]) + glDeleteObjectARB(m_filters[pass]); + m_filters[pass] = CreateShaderProgram(mode); + m_enabled[pass] = 1; + } +} |