svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r17236:HEAD
[blender-staging.git] / source / gameengine / Rasterizer / RAS_2DFilterManager.cpp
1 /**
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
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
10  * about this.
11  *
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.
16  *
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.
20  *
21  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
22  * All rights reserved.
23  *
24  * The Original Code is: all of this file.
25  *
26  * Contributor(s): none yet.
27  *
28  * ***** END GPL LICENSE BLOCK *****
29  */
30  
31 #define STRINGIFY(A)  #A
32
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"
43
44 #include "STR_String.h"
45 #include "RAS_ICanvas.h"
46 #include "RAS_Rect.h"
47 #include "RAS_2DFilterManager.h"
48 #include <iostream>
49
50 #include "GL/glew.h"
51
52 #ifdef HAVE_CONFIG_H
53 #include <config.h>
54 #endif
55
56 #include "Value.h"
57
58 RAS_2DFilterManager::RAS_2DFilterManager():
59 texturewidth(-1), textureheight(-1),
60 canvaswidth(-1), canvasheight(-1),
61 numberoffilters(0)
62 {
63         isshadersupported = GLEW_ARB_shader_objects &&
64                 GLEW_ARB_fragment_shader && GLEW_ARB_multitexture;
65
66         if(!isshadersupported)
67         {
68                 std::cout<<"shaders not supported!" << std::endl;
69                 return;
70         }
71
72         int passindex;
73         for(passindex =0; passindex<MAX_RENDER_PASS; passindex++)
74         {
75                 m_filters[passindex] = 0;
76                 m_enabled[passindex] = 0;
77                 texflag[passindex] = 0;
78                 m_gameObjects[passindex] = NULL;
79         }
80         texname[0] = texname[1] = texname[2] = -1;
81         errorprinted= false;
82 }
83
84 RAS_2DFilterManager::~RAS_2DFilterManager()
85 {
86         FreeTextures();
87 }
88
89 void RAS_2DFilterManager::PrintShaderErrors(unsigned int shader, const char *task, const char *code)
90 {
91         GLcharARB log[5000];
92         GLsizei length = 0;
93         const char *c, *pos, *end;
94         int line = 1;
95
96         if(errorprinted)
97                 return;
98         
99         errorprinted= true;
100
101         glGetInfoLogARB(shader, sizeof(log), &length, log);
102         end = code + strlen(code);
103
104         printf("2D Filter GLSL Shader: %s error:\n", task);
105
106         c = code;
107         while ((c < end) && (pos = strchr(c, '\n'))) {
108                 printf("%2d  ", line);
109                 fwrite(c, (pos+1)-c, 1, stdout);
110                 c = pos+1;
111                 line++;
112         }
113         printf("%s", c);
114
115         printf("%s\n", log);
116 }
117
118 unsigned int RAS_2DFilterManager::CreateShaderProgram(const char* shadersource)
119 {
120         GLuint program = 0;     
121         GLuint fShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER);
122         GLint success;
123
124         glShaderSourceARB(fShader, 1, (const char**)&shadersource, NULL);
125
126         glCompileShaderARB(fShader);
127
128
129         glGetObjectParameterivARB(fShader, GL_COMPILE_STATUS, &success);
130         if(!success)
131         {
132                 /*Shader Comile Error*/
133                 PrintShaderErrors(fShader, "compile", shadersource);
134                 return 0;
135         }
136                 
137         program = glCreateProgramObjectARB();
138         glAttachObjectARB(program, fShader);
139
140         glLinkProgramARB(program);
141         glGetObjectParameterivARB(program, GL_LINK_STATUS, &success);
142         if (!success)
143         {
144                 /*Program Link Error*/
145                 PrintShaderErrors(fShader, "link", shadersource);
146                 return 0;
147         }
148         
149         glValidateProgramARB(program);
150         glGetObjectParameterivARB(program, GL_VALIDATE_STATUS, &success);
151         if (!success)
152         {
153                 /*Program Validation Error*/
154                 PrintShaderErrors(fShader, "validate", shadersource);
155                 return 0;
156         }
157
158         return program;
159 }
160
161 unsigned int RAS_2DFilterManager::CreateShaderProgram(int filtermode)
162 {
163         switch(filtermode)
164         {
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);
185         }
186         return 0;
187 }
188
189 void RAS_2DFilterManager::AnalyseShader(int passindex, vector<STR_String>& propNames)
190 {
191         texflag[passindex] = 0;
192         if(glGetUniformLocationARB(m_filters[passindex], "bgl_DepthTexture") != -1)
193         {
194                 if(GLEW_ARB_depth_texture)
195                         texflag[passindex] |= 0x1;
196         }
197         if(glGetUniformLocationARB(m_filters[passindex], "bgl_LuminanceTexture") != -1)
198         {
199                 texflag[passindex] |= 0x2;
200         }
201
202         if(m_gameObjects[passindex])
203         {
204                 int objProperties = propNames.size();
205                 int i;
206                 for(i=0; i<objProperties; i++)
207                         if(glGetUniformLocationARB(m_filters[passindex], propNames[i]) != -1)
208                                 m_properties[passindex].push_back(propNames[i]);
209         }
210 }
211
212 void RAS_2DFilterManager::StartShaderProgram(int passindex)
213 {
214         GLint uniformLoc;
215         glUseProgramObjectARB(m_filters[passindex]);
216         uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_RenderedTexture");
217         glActiveTextureARB(GL_TEXTURE0);
218         glBindTexture(GL_TEXTURE_2D, texname[0]);
219
220     if (uniformLoc != -1)
221     {
222                 glUniform1iARB(uniformLoc, 0);
223     }
224
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]);
230
231         if (uniformLoc != -1)
232         {
233                 glUniform1iARB(uniformLoc, 1);
234         }
235     }
236
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]);
242
243         if (uniformLoc != -1)
244         {
245                 glUniform1iARB(uniformLoc, 2);
246         }
247         }
248         
249         uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_TextureCoordinateOffset");
250     if (uniformLoc != -1)
251     {
252         glUniform2fvARB(uniformLoc, 9, textureoffsets);
253     }
254         uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_RenderedTextureWidth");
255     if (uniformLoc != -1)
256     {
257                 glUniform1fARB(uniformLoc,texturewidth);
258     }
259         uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_RenderedTextureHeight");
260     if (uniformLoc != -1)
261     {
262                 glUniform1fARB(uniformLoc,textureheight);
263     }
264
265         int i, objProperties = m_properties[passindex].size();
266         for(i=0; i<objProperties; i++)
267         {
268                 uniformLoc = glGetUniformLocationARB(m_filters[passindex], m_properties[passindex][i]);
269                 if(uniformLoc != -1)
270                 {
271                         float value = ((CValue*)m_gameObjects[passindex])->GetPropertyNumber(m_properties[passindex][i], 0.0);
272                         glUniform1fARB(uniformLoc,value);
273                 }
274         }
275 }
276
277 void RAS_2DFilterManager::EndShaderProgram()
278 {
279         glUseProgramObjectARB(0);
280 }
281
282 void RAS_2DFilterManager::FreeTextures()
283 {
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]);
290 }
291
292 void RAS_2DFilterManager::SetupTextures(bool depth, bool luminance)
293 {
294         FreeTextures();
295         
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);
304
305         if(depth){
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,
311                                 GL_NONE);
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);
316         }
317
318         if(luminance){
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);
327         }
328 }
329
330 void RAS_2DFilterManager::UpdateOffsetMatrix(RAS_ICanvas* canvas)
331 {
332         RAS_Rect canvas_rect = canvas->GetWindowArea();
333         canvaswidth = canvas->GetWidth();
334         canvasheight = canvas->GetHeight();
335         texturewidth = canvaswidth;
336         textureheight = canvasheight;
337
338         GLint i,j;
339         i = 0;
340     while ((1 << i) <= texturewidth)
341         i++;
342     texturewidth = (1 << (i));
343
344     // Now for height
345     i = 0;
346     while ((1 << i) <= textureheight)
347         i++;
348     textureheight = (1 << (i));
349
350         GLfloat xInc = 1.0f / (GLfloat)texturewidth;
351         GLfloat yInc = 1.0f / (GLfloat)textureheight;
352         
353         for (i = 0; i < 3; i++)
354         {
355                 for (j = 0; j < 3; j++)
356                 {
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);
359                 }
360         }
361 }
362
363 void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas)
364 {
365         bool need_depth=false;
366         bool need_luminance=false;
367         int num_filters = 0;
368
369         int passindex;
370
371         if(!isshadersupported)
372                 return;
373
374         for(passindex =0; passindex<MAX_RENDER_PASS; passindex++)
375         {
376                 if(m_filters[passindex] && m_enabled[passindex]){
377                         num_filters ++;
378                         if(texflag[passindex] & 0x1)
379                                 need_depth = true;
380                         if(texflag[passindex] & 0x2)
381                                 need_luminance = true;
382                         if(need_depth && need_luminance)
383                                 break;
384                 }
385         }
386
387         if(num_filters <= 0)
388                 return;
389
390         if(canvaswidth != canvas->GetWidth() || canvasheight != canvas->GetHeight())
391         {
392                 UpdateOffsetMatrix(canvas);
393                 SetupTextures(need_depth, need_luminance);
394         }
395         GLuint  viewport[4]={0};
396
397         if(need_depth){
398                 glActiveTextureARB(GL_TEXTURE1);
399                 glBindTexture(GL_TEXTURE_2D, texname[1]);
400                 glCopyTexImage2D(GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT, viewport[0], viewport[1], texturewidth,textureheight, 0);
401         }
402         
403         if(need_luminance){
404                 glActiveTextureARB(GL_TEXTURE2);
405                 glBindTexture(GL_TEXTURE_2D, texname[2]);
406                 glCopyTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE16, viewport[0], viewport[1] , texturewidth,textureheight, 0);
407         }
408
409         glGetIntegerv(GL_VIEWPORT,(GLint *)viewport);
410         glViewport(viewport[0],viewport[1], texturewidth, textureheight);
411
412         glDisable(GL_DEPTH_TEST);
413         glMatrixMode(GL_TEXTURE);
414         glLoadIdentity();
415         glMatrixMode(GL_PROJECTION);
416         glLoadIdentity();
417         glMatrixMode(GL_MODELVIEW);
418         glLoadIdentity();
419
420         for(passindex =0; passindex<MAX_RENDER_PASS; passindex++)
421         {
422                 if(m_filters[passindex] && m_enabled[passindex])
423                 {
424                         StartShaderProgram(passindex);
425
426                         glActiveTextureARB(GL_TEXTURE0);
427                         glBindTexture(GL_TEXTURE_2D, texname[0]);
428                         glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, viewport[0], viewport[1], texturewidth, textureheight, 0);
429                         glClear(GL_COLOR_BUFFER_BIT);
430
431                         float canvascoordx, canvascoordy;
432
433                         canvascoordx = (GLfloat) texturewidth / canvaswidth;
434                         canvascoordy = (GLfloat) textureheight / canvasheight;
435
436                         glBegin(GL_QUADS);
437                                 glColor4f(1.f, 1.f, 1.f, 1.f);
438                                 glTexCoord2f(1.0, 1.0); glMultiTexCoord2fARB(GL_TEXTURE1_ARB, canvascoordx, canvascoordy); glVertex2f(1,1);
439                                 glTexCoord2f(0.0, 1.0); glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0, canvascoordy);          glVertex2f(-1,1);
440                                 glTexCoord2f(0.0, 0.0); glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0, 0.0);                   glVertex2f(-1,-1);
441                                 glTexCoord2f(1.0, 0.0); glMultiTexCoord2fARB(GL_TEXTURE1_ARB, canvascoordx, 0.0);          glVertex2f(1,-1);
442                         glEnd();
443                 }
444         }
445
446         glEnable(GL_DEPTH_TEST);
447         glViewport(viewport[0],viewport[1],viewport[2],viewport[3]);
448         EndShaderProgram();     
449 }
450
451 void RAS_2DFilterManager::EnableFilter(vector<STR_String>& propNames, void* gameObj, RAS_2DFILTER_MODE mode, int pass, STR_String& text)
452 {
453         if(!isshadersupported)
454                 return;
455         if(pass<0 || pass>=MAX_RENDER_PASS)
456                 return;
457
458         if(mode == RAS_2DFILTER_DISABLED)
459         {
460                 m_enabled[pass] = 0;
461                 return;
462         }
463
464         if(mode == RAS_2DFILTER_ENABLED)
465         {
466                 m_enabled[pass] = 1;
467                 return;
468         }
469
470         if(mode == RAS_2DFILTER_NOFILTER)
471         {
472                 if(m_filters[pass])
473                         glDeleteObjectARB(m_filters[pass]);
474                 m_enabled[pass] = 0;
475                 m_filters[pass] = 0;
476                 m_gameObjects[pass] = NULL;
477                 m_properties[pass].clear();
478                 texflag[pass] = 0;
479                 return;
480         }
481         
482         if(mode == RAS_2DFILTER_CUSTOMFILTER)
483         {
484                 if(m_filters[pass])
485                         glDeleteObjectARB(m_filters[pass]);
486                 m_filters[pass] = CreateShaderProgram(text.Ptr());
487                 m_gameObjects[pass] = gameObj;
488                 AnalyseShader(pass, propNames);
489                 m_enabled[pass] = 1;
490                 return;
491         }
492
493         if(mode>=RAS_2DFILTER_MOTIONBLUR && mode<=RAS_2DFILTER_INVERT)
494         {
495                 if(m_filters[pass])
496                         glDeleteObjectARB(m_filters[pass]);
497                 m_filters[pass] = CreateShaderProgram(mode);
498                 m_enabled[pass] = 1;
499         }
500 }