Blender  V2.59
RAS_2DFilterManager.cpp
Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version. The Blender
00008  * Foundation also sells licenses for use in proprietary software under
00009  * the Blender License.  See http://www.blender.org/BL/ for information
00010  * about this.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software Foundation,
00019  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00022  * All rights reserved.
00023  *
00024  * The Original Code is: all of this file.
00025  *
00026  * Contributor(s): none yet.
00027  *
00028  * ***** END GPL LICENSE BLOCK *****
00029  */
00030 
00036 #define STRINGIFY(A)  #A
00037 
00038 #include "RAS_OpenGLFilters/RAS_Blur2DFilter.h"
00039 #include "RAS_OpenGLFilters/RAS_Sharpen2DFilter.h"
00040 #include "RAS_OpenGLFilters/RAS_Dilation2DFilter.h"
00041 #include "RAS_OpenGLFilters/RAS_Erosion2DFilter.h"
00042 #include "RAS_OpenGLFilters/RAS_Laplacian2DFilter.h"
00043 #include "RAS_OpenGLFilters/RAS_Sobel2DFilter.h"
00044 #include "RAS_OpenGLFilters/RAS_Prewitt2DFilter.h"
00045 #include "RAS_OpenGLFilters/RAS_GrayScale2DFilter.h"
00046 #include "RAS_OpenGLFilters/RAS_Sepia2DFilter.h"
00047 #include "RAS_OpenGLFilters/RAS_Invert2DFilter.h"
00048 
00049 #include "STR_String.h"
00050 #include "RAS_ICanvas.h"
00051 #include "RAS_Rect.h"
00052 #include "RAS_2DFilterManager.h"
00053 #include <iostream>
00054 
00055 #include "GL/glew.h"
00056 
00057 #include <stdio.h>
00058 
00059 #include "Value.h"
00060 
00061 RAS_2DFilterManager::RAS_2DFilterManager():
00062 texturewidth(-1), textureheight(-1),
00063 canvaswidth(-1), canvasheight(-1),
00064 numberoffilters(0), need_tex_update(true)
00065 {
00066         isshadersupported = GLEW_ARB_shader_objects &&
00067                 GLEW_ARB_fragment_shader && GLEW_ARB_multitexture;
00068 
00069         /* used to return before 2.49 but need to initialize values so dont */
00070         if(!isshadersupported)
00071                 std::cout<<"shaders not supported!" << std::endl;
00072 
00073         int passindex;
00074         for(passindex =0; passindex<MAX_RENDER_PASS; passindex++)
00075         {
00076                 m_filters[passindex] = 0;
00077                 m_enabled[passindex] = 0;
00078                 texflag[passindex] = 0;
00079                 m_gameObjects[passindex] = NULL;
00080         }
00081         texname[0] = texname[1] = texname[2] = -1;
00082         errorprinted= false;
00083 }
00084 
00085 RAS_2DFilterManager::~RAS_2DFilterManager()
00086 {
00087         FreeTextures();
00088 }
00089 
00090 void RAS_2DFilterManager::PrintShaderErrors(unsigned int shader, const char *task, const char *code)
00091 {
00092         GLcharARB log[5000];
00093         GLsizei length = 0;
00094         const char *c, *pos, *end;
00095         int line = 1;
00096 
00097         if(errorprinted)
00098                 return;
00099         
00100         errorprinted= true;
00101 
00102         glGetInfoLogARB(shader, sizeof(log), &length, log);
00103         end = code + strlen(code);
00104 
00105         printf("2D Filter GLSL Shader: %s error:\n", task);
00106 
00107         c = code;
00108         while ((c < end) && (pos = strchr(c, '\n'))) {
00109                 printf("%2d  ", line);
00110                 fwrite(c, (pos+1)-c, 1, stdout);
00111                 c = pos+1;
00112                 line++;
00113         }
00114         printf("%s", c);
00115 
00116         printf("%s\n", log);
00117 }
00118 
00119 unsigned int RAS_2DFilterManager::CreateShaderProgram(const char* shadersource)
00120 {
00121         GLuint program = 0;     
00122         GLuint fShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER);
00123         GLint success;
00124 
00125         glShaderSourceARB(fShader, 1, (const char**)&shadersource, NULL);
00126 
00127         glCompileShaderARB(fShader);
00128 
00129 
00130         glGetObjectParameterivARB(fShader, GL_COMPILE_STATUS, &success);
00131         if(!success)
00132         {
00133                 /*Shader Comile Error*/
00134                 PrintShaderErrors(fShader, "compile", shadersource);
00135                 return 0;
00136         }
00137                 
00138         program = glCreateProgramObjectARB();
00139         glAttachObjectARB(program, fShader);
00140 
00141         glLinkProgramARB(program);
00142         glGetObjectParameterivARB(program, GL_LINK_STATUS, &success);
00143         if (!success)
00144         {
00145                 /*Program Link Error*/
00146                 PrintShaderErrors(fShader, "link", shadersource);
00147                 return 0;
00148         }
00149         
00150         glValidateProgramARB(program);
00151         glGetObjectParameterivARB(program, GL_VALIDATE_STATUS, &success);
00152         if (!success)
00153         {
00154                 /*Program Validation Error*/
00155                 PrintShaderErrors(fShader, "validate", shadersource);
00156                 return 0;
00157         }
00158 
00159         return program;
00160 }
00161 
00162 unsigned int RAS_2DFilterManager::CreateShaderProgram(int filtermode)
00163 {
00164         switch(filtermode)
00165         {
00166                 case RAS_2DFILTER_BLUR:
00167                         return CreateShaderProgram(BlurFragmentShader);
00168                 case RAS_2DFILTER_SHARPEN:
00169                         return CreateShaderProgram(SharpenFragmentShader);
00170                 case RAS_2DFILTER_DILATION:
00171                         return CreateShaderProgram(DilationFragmentShader);
00172                 case RAS_2DFILTER_EROSION:
00173                         return CreateShaderProgram(ErosionFragmentShader);
00174                 case RAS_2DFILTER_LAPLACIAN:
00175                         return CreateShaderProgram(LaplacionFragmentShader);
00176                 case RAS_2DFILTER_SOBEL:
00177                         return CreateShaderProgram(SobelFragmentShader);
00178                 case RAS_2DFILTER_PREWITT:
00179                         return CreateShaderProgram(PrewittFragmentShader);
00180                 case RAS_2DFILTER_GRAYSCALE:
00181                         return CreateShaderProgram(GrayScaleFragmentShader);
00182                 case RAS_2DFILTER_SEPIA:
00183                         return CreateShaderProgram(SepiaFragmentShader);
00184                 case RAS_2DFILTER_INVERT:
00185                         return CreateShaderProgram(InvertFragmentShader);
00186         }
00187         return 0;
00188 }
00189 
00190 void RAS_2DFilterManager::AnalyseShader(int passindex, vector<STR_String>& propNames)
00191 {
00192         texflag[passindex] = 0;
00193         if(glGetUniformLocationARB(m_filters[passindex], "bgl_DepthTexture") != -1)
00194         {
00195                 if(GLEW_ARB_depth_texture)
00196                         texflag[passindex] |= 0x1;
00197         }
00198         if(glGetUniformLocationARB(m_filters[passindex], "bgl_LuminanceTexture") != -1)
00199         {
00200                 texflag[passindex] |= 0x2;
00201         }
00202 
00203         if(m_gameObjects[passindex])
00204         {
00205                 int objProperties = propNames.size();
00206                 int i;
00207                 for(i=0; i<objProperties; i++)
00208                         if(glGetUniformLocationARB(m_filters[passindex], propNames[i]) != -1)
00209                                 m_properties[passindex].push_back(propNames[i]);
00210         }
00211 }
00212 
00213 void RAS_2DFilterManager::StartShaderProgram(int passindex)
00214 {
00215         GLint uniformLoc;
00216         glUseProgramObjectARB(m_filters[passindex]);
00217         uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_RenderedTexture");
00218         glActiveTextureARB(GL_TEXTURE0);
00219         glBindTexture(GL_TEXTURE_2D, texname[0]);
00220 
00221         if (uniformLoc != -1)
00222         {
00223                 glUniform1iARB(uniformLoc, 0);
00224         }
00225 
00226         /* send depth texture to glsl program if it needs */
00227         if(texflag[passindex] & 0x1){
00228                 uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_DepthTexture");
00229                 glActiveTextureARB(GL_TEXTURE1);
00230                 glBindTexture(GL_TEXTURE_2D, texname[1]);
00231 
00232                 if (uniformLoc != -1)
00233                 {
00234                         glUniform1iARB(uniformLoc, 1);
00235                 }
00236         }
00237 
00238         /* send luminance texture to glsl program if it needs */
00239         if(texflag[passindex] & 0x2){
00240                 uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_LuminanceTexture");
00241                 glActiveTextureARB(GL_TEXTURE2);
00242                 glBindTexture(GL_TEXTURE_2D, texname[2]);
00243 
00244                 if (uniformLoc != -1)
00245                 {
00246                         glUniform1iARB(uniformLoc, 2);
00247                 }
00248         }
00249         
00250         uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_TextureCoordinateOffset");
00251         if (uniformLoc != -1)
00252         {
00253                 glUniform2fvARB(uniformLoc, 9, textureoffsets);
00254         }
00255         uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_RenderedTextureWidth");
00256         if (uniformLoc != -1)
00257         {
00258                 glUniform1fARB(uniformLoc,texturewidth);
00259         }
00260         uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_RenderedTextureHeight");
00261         if (uniformLoc != -1)
00262         {
00263                 glUniform1fARB(uniformLoc,textureheight);
00264         }
00265 
00266         int i, objProperties = m_properties[passindex].size();
00267         for(i=0; i<objProperties; i++)
00268         {
00269                 uniformLoc = glGetUniformLocationARB(m_filters[passindex], m_properties[passindex][i]);
00270                 if(uniformLoc != -1)
00271                 {
00272                         float value = ((CValue*)m_gameObjects[passindex])->GetPropertyNumber(m_properties[passindex][i], 0.0);
00273                         glUniform1fARB(uniformLoc,value);
00274                 }
00275         }
00276 }
00277 
00278 void RAS_2DFilterManager::EndShaderProgram()
00279 {
00280         glUseProgramObjectARB(0);
00281 }
00282 
00283 void RAS_2DFilterManager::FreeTextures()
00284 {
00285         if(texname[0]!=(unsigned int)-1)
00286                 glDeleteTextures(1, (GLuint*)&texname[0]);
00287         if(texname[1]!=(unsigned int)-1)
00288                 glDeleteTextures(1, (GLuint*)&texname[1]);
00289         if(texname[2]!=(unsigned int)-1)
00290                 glDeleteTextures(1, (GLuint*)&texname[2]);
00291 }
00292 
00293 void RAS_2DFilterManager::SetupTextures(bool depth, bool luminance)
00294 {
00295         FreeTextures();
00296         
00297         glGenTextures(1, (GLuint*)&texname[0]);
00298         glBindTexture(GL_TEXTURE_2D, texname[0]);
00299         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texturewidth, textureheight, 0, GL_RGBA,
00300                         GL_UNSIGNED_BYTE, 0);
00301         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00302         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00303         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
00304         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
00305 
00306         if(depth){
00307                 glGenTextures(1, (GLuint*)&texname[1]);
00308                 glBindTexture(GL_TEXTURE_2D, texname[1]);
00309                 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, texturewidth,textureheight, 
00310                         0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE,NULL);
00311                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE,
00312                                 GL_NONE);
00313                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00314                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00315                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
00316                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
00317         }
00318 
00319         if(luminance){
00320                 glGenTextures(1, (GLuint*)&texname[2]);
00321                 glBindTexture(GL_TEXTURE_2D, texname[2]);
00322                 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE16, texturewidth, textureheight,
00323                          0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0);
00324                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00325                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00326                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
00327                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
00328         }
00329 }
00330 
00331 void RAS_2DFilterManager::UpdateOffsetMatrix(RAS_ICanvas* canvas)
00332 {
00333         RAS_Rect canvas_rect = canvas->GetWindowArea();
00334         canvaswidth = canvas->GetWidth();
00335         canvasheight = canvas->GetHeight();
00336 
00337         texturewidth = canvaswidth + canvas_rect.GetLeft();
00338         textureheight = canvasheight + canvas_rect.GetBottom();
00339         GLint i,j;
00340         i = 0;
00341         while ((1 << i) <= texturewidth)
00342                 i++;
00343         texturewidth = (1 << (i));
00344 
00345         // Now for height
00346         i = 0;
00347         while ((1 << i) <= textureheight)
00348                 i++;
00349         textureheight = (1 << (i));
00350 
00351         GLfloat xInc = 1.0f / (GLfloat)texturewidth;
00352         GLfloat yInc = 1.0f / (GLfloat)textureheight;
00353         
00354         for (i = 0; i < 3; i++)
00355         {
00356                 for (j = 0; j < 3; j++)
00357                 {
00358                         textureoffsets[(((i*3)+j)*2)+0] = (-1.0f * xInc) + ((GLfloat)i * xInc);
00359                         textureoffsets[(((i*3)+j)*2)+1] = (-1.0f * yInc) + ((GLfloat)j * yInc);
00360                 }
00361         }
00362 }
00363 
00364 void RAS_2DFilterManager::UpdateCanvasTextureCoord(unsigned int * viewport)
00365 {
00366         /*
00367         This function update canvascoord[].
00368         These parameters are used to create texcoord[1]
00369         That way we can access the texcoord relative to the canvas:
00370         (0.0,0.0) bottom left, (1.0,1.0) top right, (0.5,0.5) center
00371         */
00372         canvascoord[0] = (GLfloat) viewport[0] / viewport[2];
00373         canvascoord[0] *= -1;
00374         canvascoord[1] = (GLfloat) (texturewidth - viewport[0]) / viewport[2];
00375  
00376         canvascoord[2] = (GLfloat) viewport[1] / viewport[3];
00377         canvascoord[2] *= -1;
00378         canvascoord[3] = (GLfloat)(textureheight - viewport[1]) / viewport[3];
00379 }
00380 
00381 void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas)
00382 {
00383         bool need_depth=false;
00384         bool need_luminance=false;
00385         int num_filters = 0;
00386 
00387         int passindex;
00388 
00389         if(!isshadersupported)
00390                 return;
00391 
00392         for(passindex =0; passindex<MAX_RENDER_PASS; passindex++)
00393         {
00394                 if(m_filters[passindex] && m_enabled[passindex]){
00395                         num_filters ++;
00396                         if(texflag[passindex] & 0x1)
00397                                 need_depth = true;
00398                         if(texflag[passindex] & 0x2)
00399                                 need_luminance = true;
00400                         if(need_depth && need_luminance)
00401                                 break;
00402                 }
00403         }
00404 
00405         if(num_filters <= 0)
00406                 return;
00407 
00408         GLuint  viewport[4]={0};
00409         glGetIntegerv(GL_VIEWPORT,(GLint *)viewport);
00410 
00411         if(canvaswidth != canvas->GetWidth() || canvasheight != canvas->GetHeight())
00412         {
00413                 UpdateOffsetMatrix(canvas);
00414                 UpdateCanvasTextureCoord((unsigned int*)viewport);
00415                 need_tex_update = true;
00416         }
00417         
00418         if(need_tex_update)
00419         {
00420                 SetupTextures(need_depth, need_luminance);
00421                 need_tex_update = false;
00422         }
00423 
00424         if(need_depth){
00425                 glActiveTextureARB(GL_TEXTURE1);
00426                 glBindTexture(GL_TEXTURE_2D, texname[1]);
00427                 glCopyTexImage2D(GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT, 0, 0, texturewidth,textureheight, 0);
00428         }
00429         
00430         if(need_luminance){
00431                 glActiveTextureARB(GL_TEXTURE2);
00432                 glBindTexture(GL_TEXTURE_2D, texname[2]);
00433                 glCopyTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE16, 0, 0, texturewidth,textureheight, 0);
00434         }
00435 
00436         glViewport(0,0, texturewidth, textureheight);
00437 
00438         glDisable(GL_DEPTH_TEST);
00439         // if the last rendered face had alpha add it would messes with the color of the plane we apply 2DFilter to
00440         glDisable(GL_BLEND); 
00441         glPushMatrix();         //GL_MODELVIEW
00442         glLoadIdentity();       // GL_MODELVIEW
00443         glMatrixMode(GL_TEXTURE);
00444         glLoadIdentity();
00445         glMatrixMode(GL_PROJECTION);
00446         glPushMatrix();
00447         glLoadIdentity();
00448 
00449         for(passindex =0; passindex<MAX_RENDER_PASS; passindex++)
00450         {
00451                 if(m_filters[passindex] && m_enabled[passindex])
00452                 {
00453                         StartShaderProgram(passindex);
00454 
00455                         glActiveTextureARB(GL_TEXTURE0);
00456                         glBindTexture(GL_TEXTURE_2D, texname[0]);
00457                         glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, texturewidth, textureheight, 0);
00458                         glClear(GL_COLOR_BUFFER_BIT);
00459 
00460                         glBegin(GL_QUADS);
00461                                 glColor4f(1.f, 1.f, 1.f, 1.f);
00462                                 glTexCoord2f(1.0, 1.0); glMultiTexCoord2fARB(GL_TEXTURE3_ARB, canvascoord[1], canvascoord[3]); glVertex2f(1,1);
00463                                 glTexCoord2f(0.0, 1.0); glMultiTexCoord2fARB(GL_TEXTURE3_ARB, canvascoord[0], canvascoord[3]); glVertex2f(-1,1);
00464                                 glTexCoord2f(0.0, 0.0); glMultiTexCoord2fARB(GL_TEXTURE3_ARB, canvascoord[0], canvascoord[2]); glVertex2f(-1,-1);
00465                                 glTexCoord2f(1.0, 0.0); glMultiTexCoord2fARB(GL_TEXTURE3_ARB, canvascoord[1], canvascoord[2]); glVertex2f(1,-1);
00466                         glEnd();
00467                 }
00468         }
00469 
00470         glEnable(GL_DEPTH_TEST);
00471         glViewport(viewport[0],viewport[1],viewport[2],viewport[3]);
00472         EndShaderProgram();     
00473         glPopMatrix();
00474         glMatrixMode(GL_MODELVIEW);
00475         glPopMatrix();
00476 }
00477 
00478 void RAS_2DFilterManager::EnableFilter(vector<STR_String>& propNames, void* gameObj, RAS_2DFILTER_MODE mode, int pass, STR_String& text)
00479 {
00480         if(!isshadersupported)
00481                 return;
00482         if(pass<0 || pass>=MAX_RENDER_PASS)
00483                 return;
00484         need_tex_update = true;
00485         if(mode == RAS_2DFILTER_DISABLED)
00486         {
00487                 m_enabled[pass] = 0;
00488                 return;
00489         }
00490 
00491         if(mode == RAS_2DFILTER_ENABLED)
00492         {
00493                 m_enabled[pass] = 1;
00494                 return;
00495         }
00496 
00497         if(mode == RAS_2DFILTER_NOFILTER)
00498         {
00499                 if(m_filters[pass])
00500                         glDeleteObjectARB(m_filters[pass]);
00501                 m_enabled[pass] = 0;
00502                 m_filters[pass] = 0;
00503                 m_gameObjects[pass] = NULL;
00504                 m_properties[pass].clear();
00505                 texflag[pass] = 0;
00506                 return;
00507         }
00508         
00509         if(mode == RAS_2DFILTER_CUSTOMFILTER)
00510         {
00511                 if(m_filters[pass])
00512                         glDeleteObjectARB(m_filters[pass]);
00513                 m_filters[pass] = CreateShaderProgram(text.Ptr());
00514                 m_gameObjects[pass] = gameObj;
00515                 AnalyseShader(pass, propNames);
00516                 m_enabled[pass] = 1;
00517                 return;
00518         }
00519 
00520         // We've checked all other cases, which means we must be dealing with a builtin filter
00521         if(m_filters[pass])
00522                 glDeleteObjectARB(m_filters[pass]);
00523         m_filters[pass] = CreateShaderProgram(mode);
00524         m_gameObjects[pass] = NULL;
00525         AnalyseShader(pass, propNames);
00526         m_enabled[pass] = 1;
00527 }