Blender V2.61 - r43446

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