2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version. The Blender
8 * Foundation also sells licenses for use in proprietary software under
9 * the Blender License. See http://www.blender.org/BL/ for information
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
22 * All rights reserved.
24 * The Original Code is: all of this file.
26 * Contributor(s): none yet.
28 * ***** END GPL LICENSE BLOCK *****
31 #define STRINGIFY(A) #A
33 #include "RAS_OpenGLFilters/RAS_Blur2DFilter.h"
34 #include "RAS_OpenGLFilters/RAS_Sharpen2DFilter.h"
35 #include "RAS_OpenGLFilters/RAS_Dilation2DFilter.h"
36 #include "RAS_OpenGLFilters/RAS_Erosion2DFilter.h"
37 #include "RAS_OpenGLFilters/RAS_Laplacian2DFilter.h"
38 #include "RAS_OpenGLFilters/RAS_Sobel2DFilter.h"
39 #include "RAS_OpenGLFilters/RAS_Prewitt2DFilter.h"
40 #include "RAS_OpenGLFilters/RAS_GrayScale2DFilter.h"
41 #include "RAS_OpenGLFilters/RAS_Sepia2DFilter.h"
42 #include "RAS_OpenGLFilters/RAS_Invert2DFilter.h"
44 #include "STR_String.h"
45 #include "RAS_ICanvas.h"
47 #include "RAS_2DFilterManager.h"
58 RAS_2DFilterManager::RAS_2DFilterManager():
59 texturewidth(-1), textureheight(-1),
60 canvaswidth(-1), canvasheight(-1),
61 numberoffilters(0), need_tex_update(true)
63 isshadersupported = GLEW_ARB_shader_objects &&
64 GLEW_ARB_fragment_shader && GLEW_ARB_multitexture;
66 if(!isshadersupported)
68 std::cout<<"shaders not supported!" << std::endl;
73 for(passindex =0; passindex<MAX_RENDER_PASS; passindex++)
75 m_filters[passindex] = 0;
76 m_enabled[passindex] = 0;
77 texflag[passindex] = 0;
78 m_gameObjects[passindex] = NULL;
80 texname[0] = texname[1] = texname[2] = -1;
84 RAS_2DFilterManager::~RAS_2DFilterManager()
89 void RAS_2DFilterManager::PrintShaderErrors(unsigned int shader, const char *task, const char *code)
93 const char *c, *pos, *end;
101 glGetInfoLogARB(shader, sizeof(log), &length, log);
102 end = code + strlen(code);
104 printf("2D Filter GLSL Shader: %s error:\n", task);
107 while ((c < end) && (pos = strchr(c, '\n'))) {
108 printf("%2d ", line);
109 fwrite(c, (pos+1)-c, 1, stdout);
118 unsigned int RAS_2DFilterManager::CreateShaderProgram(const char* shadersource)
121 GLuint fShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER);
124 glShaderSourceARB(fShader, 1, (const char**)&shadersource, NULL);
126 glCompileShaderARB(fShader);
129 glGetObjectParameterivARB(fShader, GL_COMPILE_STATUS, &success);
132 /*Shader Comile Error*/
133 PrintShaderErrors(fShader, "compile", shadersource);
137 program = glCreateProgramObjectARB();
138 glAttachObjectARB(program, fShader);
140 glLinkProgramARB(program);
141 glGetObjectParameterivARB(program, GL_LINK_STATUS, &success);
144 /*Program Link Error*/
145 PrintShaderErrors(fShader, "link", shadersource);
149 glValidateProgramARB(program);
150 glGetObjectParameterivARB(program, GL_VALIDATE_STATUS, &success);
153 /*Program Validation Error*/
154 PrintShaderErrors(fShader, "validate", shadersource);
161 unsigned int RAS_2DFilterManager::CreateShaderProgram(int filtermode)
165 case RAS_2DFILTER_BLUR:
166 return CreateShaderProgram(BlurFragmentShader);
167 case RAS_2DFILTER_SHARPEN:
168 return CreateShaderProgram(SharpenFragmentShader);
169 case RAS_2DFILTER_DILATION:
170 return CreateShaderProgram(DilationFragmentShader);
171 case RAS_2DFILTER_EROSION:
172 return CreateShaderProgram(ErosionFragmentShader);
173 case RAS_2DFILTER_LAPLACIAN:
174 return CreateShaderProgram(LaplacionFragmentShader);
175 case RAS_2DFILTER_SOBEL:
176 return CreateShaderProgram(SobelFragmentShader);
177 case RAS_2DFILTER_PREWITT:
178 return CreateShaderProgram(PrewittFragmentShader);
179 case RAS_2DFILTER_GRAYSCALE:
180 return CreateShaderProgram(GrayScaleFragmentShader);
181 case RAS_2DFILTER_SEPIA:
182 return CreateShaderProgram(SepiaFragmentShader);
183 case RAS_2DFILTER_INVERT:
184 return CreateShaderProgram(InvertFragmentShader);
189 void RAS_2DFilterManager::AnalyseShader(int passindex, vector<STR_String>& propNames)
191 texflag[passindex] = 0;
192 if(glGetUniformLocationARB(m_filters[passindex], "bgl_DepthTexture") != -1)
194 if(GLEW_ARB_depth_texture)
195 texflag[passindex] |= 0x1;
197 if(glGetUniformLocationARB(m_filters[passindex], "bgl_LuminanceTexture") != -1)
199 texflag[passindex] |= 0x2;
202 if(m_gameObjects[passindex])
204 int objProperties = propNames.size();
206 for(i=0; i<objProperties; i++)
207 if(glGetUniformLocationARB(m_filters[passindex], propNames[i]) != -1)
208 m_properties[passindex].push_back(propNames[i]);
212 void RAS_2DFilterManager::StartShaderProgram(int passindex)
215 glUseProgramObjectARB(m_filters[passindex]);
216 uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_RenderedTexture");
217 glActiveTextureARB(GL_TEXTURE0);
218 glBindTexture(GL_TEXTURE_2D, texname[0]);
220 if (uniformLoc != -1)
222 glUniform1iARB(uniformLoc, 0);
225 /* send depth texture to glsl program if it needs */
226 if(texflag[passindex] & 0x1){
227 uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_DepthTexture");
228 glActiveTextureARB(GL_TEXTURE1);
229 glBindTexture(GL_TEXTURE_2D, texname[1]);
231 if (uniformLoc != -1)
233 glUniform1iARB(uniformLoc, 1);
237 /* send luminance texture to glsl program if it needs */
238 if(texflag[passindex] & 0x2){
239 uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_LuminanceTexture");
240 glActiveTextureARB(GL_TEXTURE2);
241 glBindTexture(GL_TEXTURE_2D, texname[2]);
243 if (uniformLoc != -1)
245 glUniform1iARB(uniformLoc, 2);
249 uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_TextureCoordinateOffset");
250 if (uniformLoc != -1)
252 glUniform2fvARB(uniformLoc, 9, textureoffsets);
254 uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_RenderedTextureWidth");
255 if (uniformLoc != -1)
257 glUniform1fARB(uniformLoc,texturewidth);
259 uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_RenderedTextureHeight");
260 if (uniformLoc != -1)
262 glUniform1fARB(uniformLoc,textureheight);
265 int i, objProperties = m_properties[passindex].size();
266 for(i=0; i<objProperties; i++)
268 uniformLoc = glGetUniformLocationARB(m_filters[passindex], m_properties[passindex][i]);
271 float value = ((CValue*)m_gameObjects[passindex])->GetPropertyNumber(m_properties[passindex][i], 0.0);
272 glUniform1fARB(uniformLoc,value);
277 void RAS_2DFilterManager::EndShaderProgram()
279 glUseProgramObjectARB(0);
282 void RAS_2DFilterManager::FreeTextures()
284 if(texname[0]!=(unsigned int)-1)
285 glDeleteTextures(1, (GLuint*)&texname[0]);
286 if(texname[1]!=(unsigned int)-1)
287 glDeleteTextures(1, (GLuint*)&texname[1]);
288 if(texname[2]!=(unsigned int)-1)
289 glDeleteTextures(1, (GLuint*)&texname[2]);
292 void RAS_2DFilterManager::SetupTextures(bool depth, bool luminance)
296 glGenTextures(1, (GLuint*)&texname[0]);
297 glBindTexture(GL_TEXTURE_2D, texname[0]);
298 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texturewidth, textureheight, 0, GL_RGBA,
299 GL_UNSIGNED_BYTE, 0);
300 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
301 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
302 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
303 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
306 glGenTextures(1, (GLuint*)&texname[1]);
307 glBindTexture(GL_TEXTURE_2D, texname[1]);
308 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, texturewidth,textureheight,
309 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE,NULL);
310 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE,
312 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
313 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
314 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
315 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
319 glGenTextures(1, (GLuint*)&texname[2]);
320 glBindTexture(GL_TEXTURE_2D, texname[2]);
321 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE16, texturewidth, textureheight,
322 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0);
323 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
324 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
325 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
326 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
330 void RAS_2DFilterManager::UpdateOffsetMatrix(RAS_ICanvas* canvas)
332 RAS_Rect canvas_rect = canvas->GetWindowArea();
333 canvaswidth = canvas->GetWidth();
334 canvasheight = canvas->GetHeight();
336 texturewidth = canvaswidth + canvas_rect.GetLeft();
337 textureheight = canvasheight + canvas_rect.GetBottom();
340 while ((1 << i) <= texturewidth)
342 texturewidth = (1 << (i));
346 while ((1 << i) <= textureheight)
348 textureheight = (1 << (i));
350 GLfloat xInc = 1.0f / (GLfloat)texturewidth;
351 GLfloat yInc = 1.0f / (GLfloat)textureheight;
353 for (i = 0; i < 3; i++)
355 for (j = 0; j < 3; j++)
357 textureoffsets[(((i*3)+j)*2)+0] = (-1.0f * xInc) + ((GLfloat)i * xInc);
358 textureoffsets[(((i*3)+j)*2)+1] = (-1.0f * yInc) + ((GLfloat)j * yInc);
363 void RAS_2DFilterManager::UpdateCanvasTextureCoord(unsigned int * viewport)
366 This function update canvascoord[].
367 These parameters are used to create texcoord[1]
368 That way we can access the texcoord relative to the canvas:
369 (0.0,0.0) bottom left, (1.0,1.0) top right, (0.5,0.5) center
371 canvascoord[0] = (GLfloat) viewport[0] / viewport[2];
372 canvascoord[0] *= -1;
373 canvascoord[1] = (GLfloat) (texturewidth - viewport[0]) / viewport[2];
375 canvascoord[2] = (GLfloat) viewport[1] / viewport[3];
376 canvascoord[2] *= -1;
377 canvascoord[3] = (GLfloat)(textureheight - viewport[1]) / viewport[3];
380 void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas)
382 bool need_depth=false;
383 bool need_luminance=false;
388 if(!isshadersupported)
391 for(passindex =0; passindex<MAX_RENDER_PASS; passindex++)
393 if(m_filters[passindex] && m_enabled[passindex]){
395 if(texflag[passindex] & 0x1)
397 if(texflag[passindex] & 0x2)
398 need_luminance = true;
399 if(need_depth && need_luminance)
407 GLuint viewport[4]={0};
408 glGetIntegerv(GL_VIEWPORT,(GLint *)viewport);
410 if(canvaswidth != canvas->GetWidth() || canvasheight != canvas->GetHeight())
412 UpdateOffsetMatrix(canvas);
413 UpdateCanvasTextureCoord((unsigned int*)viewport);
414 need_tex_update = true;
419 SetupTextures(need_depth, need_luminance);
420 need_tex_update = false;
424 glActiveTextureARB(GL_TEXTURE1);
425 glBindTexture(GL_TEXTURE_2D, texname[1]);
426 glCopyTexImage2D(GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT, 0, 0, texturewidth,textureheight, 0);
430 glActiveTextureARB(GL_TEXTURE2);
431 glBindTexture(GL_TEXTURE_2D, texname[2]);
432 glCopyTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE16, 0, 0, texturewidth,textureheight, 0);
435 glViewport(0,0, texturewidth, textureheight);
437 glDisable(GL_DEPTH_TEST);
438 glPushMatrix(); //GL_MODELVIEW
439 glLoadIdentity(); // GL_MODELVIEW
440 glMatrixMode(GL_TEXTURE);
442 glMatrixMode(GL_PROJECTION);
446 for(passindex =0; passindex<MAX_RENDER_PASS; passindex++)
448 if(m_filters[passindex] && m_enabled[passindex])
450 StartShaderProgram(passindex);
452 glActiveTextureARB(GL_TEXTURE0);
453 glBindTexture(GL_TEXTURE_2D, texname[0]);
454 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, texturewidth, textureheight, 0);
455 glClear(GL_COLOR_BUFFER_BIT);
458 glColor4f(1.f, 1.f, 1.f, 1.f);
459 glTexCoord2f(1.0, 1.0); glMultiTexCoord2fARB(GL_TEXTURE3_ARB, canvascoord[1], canvascoord[3]); glVertex2f(1,1);
460 glTexCoord2f(0.0, 1.0); glMultiTexCoord2fARB(GL_TEXTURE3_ARB, canvascoord[0], canvascoord[3]); glVertex2f(-1,1);
461 glTexCoord2f(0.0, 0.0); glMultiTexCoord2fARB(GL_TEXTURE3_ARB, canvascoord[0], canvascoord[2]); glVertex2f(-1,-1);
462 glTexCoord2f(1.0, 0.0); glMultiTexCoord2fARB(GL_TEXTURE3_ARB, canvascoord[1], canvascoord[2]); glVertex2f(1,-1);
467 glEnable(GL_DEPTH_TEST);
468 glViewport(viewport[0],viewport[1],viewport[2],viewport[3]);
471 glMatrixMode(GL_MODELVIEW);
475 void RAS_2DFilterManager::EnableFilter(vector<STR_String>& propNames, void* gameObj, RAS_2DFILTER_MODE mode, int pass, STR_String& text)
477 if(!isshadersupported)
479 if(pass<0 || pass>=MAX_RENDER_PASS)
481 need_tex_update = true;
482 if(mode == RAS_2DFILTER_DISABLED)
488 if(mode == RAS_2DFILTER_ENABLED)
494 if(mode == RAS_2DFILTER_NOFILTER)
497 glDeleteObjectARB(m_filters[pass]);
500 m_gameObjects[pass] = NULL;
501 m_properties[pass].clear();
506 if(mode == RAS_2DFILTER_CUSTOMFILTER)
509 glDeleteObjectARB(m_filters[pass]);
510 m_filters[pass] = CreateShaderProgram(text.Ptr());
511 m_gameObjects[pass] = gameObj;
512 AnalyseShader(pass, propNames);
517 if(mode>=RAS_2DFILTER_MOTIONBLUR && mode<=RAS_2DFILTER_INVERT)
520 glDeleteObjectARB(m_filters[pass]);
521 m_filters[pass] = CreateShaderProgram(mode);