svn merge -r 15392:15551 https://svn.blender.org/svnroot/bf-blender/trunk/blender
[blender.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_2DFilterManager.h"
47 #include <iostream>
48
49 #include "GL/glew.h"
50
51 #ifdef HAVE_CONFIG_H
52 #include <config.h>
53 #endif
54
55 #include "Value.h"
56
57 RAS_2DFilterManager::RAS_2DFilterManager():
58 texturewidth(-1), textureheight(-1),
59 canvaswidth(-1), canvasheight(-1),
60 numberoffilters(0)
61 {
62         isshadersupported = GLEW_ARB_shader_objects &&
63                 GLEW_ARB_fragment_shader && GLEW_ARB_multitexture;
64
65         if(!isshadersupported)
66         {
67                 std::cout<<"shaders not supported!" << std::endl;
68                 return;
69         }
70
71         int passindex;
72         for(passindex =0; passindex<MAX_RENDER_PASS; passindex++)
73         {
74                 m_filters[passindex] = 0;
75                 m_enabled[passindex] = 0;
76                 texflag[passindex] = 0;
77                 m_gameObjects[passindex] = NULL;
78         }
79         texname[0] = texname[1] = texname[2] = -1;
80 }
81
82 RAS_2DFilterManager::~RAS_2DFilterManager()
83 {
84         FreeTextures();
85 }
86
87 unsigned int RAS_2DFilterManager::CreateShaderProgram(char* shadersource)
88 {
89                 GLuint program = 0;     
90                 GLuint fShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER);
91         GLint success;
92
93                 glShaderSourceARB(fShader, 1, (const char**)&shadersource, NULL);
94
95                 glCompileShaderARB(fShader);
96
97                 glGetObjectParameterivARB(fShader, GL_COMPILE_STATUS, &success);
98                 if(!success)
99                 {
100                         /*Shader Comile Error*/
101                         std::cout << "2dFilters - Shader compile error" << std::endl;
102                         return 0;
103                 }
104                     
105                 program = glCreateProgramObjectARB();
106                 glAttachObjectARB(program, fShader);
107
108                 glLinkProgramARB(program);
109                 glGetObjectParameterivARB(program, GL_LINK_STATUS, &success);
110                 if (!success)
111                 {
112                         /*Program Link Error*/
113                         std::cout << "2dFilters - Shader program link error" << std::endl;
114                         return 0;
115                 }
116                 
117                 glValidateProgramARB(program);
118                 glGetObjectParameterivARB(program, GL_VALIDATE_STATUS, &success);
119         if (!success)
120                 {
121                         /*Program Validation Error*/
122                         std::cout << "2dFilters - Shader program validation error" << std::endl;
123                         return 0;
124                 }
125
126                 return program;
127 }
128
129 unsigned int RAS_2DFilterManager::CreateShaderProgram(int filtermode)
130 {
131                 switch(filtermode)
132                 {
133                         case RAS_2DFILTER_BLUR:
134                                 return CreateShaderProgram(BlurFragmentShader);
135                         case RAS_2DFILTER_SHARPEN:
136                                 return CreateShaderProgram(SharpenFragmentShader);
137                         case RAS_2DFILTER_DILATION:
138                                 return CreateShaderProgram(DilationFragmentShader);
139                         case RAS_2DFILTER_EROSION:
140                                 return CreateShaderProgram(ErosionFragmentShader);
141                         case RAS_2DFILTER_LAPLACIAN:
142                                 return CreateShaderProgram(LaplacionFragmentShader);
143                         case RAS_2DFILTER_SOBEL:
144                                 return CreateShaderProgram(SobelFragmentShader);
145                         case RAS_2DFILTER_PREWITT:
146                                 return CreateShaderProgram(PrewittFragmentShader);
147                         case RAS_2DFILTER_GRAYSCALE:
148                                 return CreateShaderProgram(GrayScaleFragmentShader);
149                         case RAS_2DFILTER_SEPIA:
150                                 return CreateShaderProgram(SepiaFragmentShader);
151                         case RAS_2DFILTER_INVERT:
152                                 return CreateShaderProgram(InvertFragmentShader);
153                 }
154                 return 0;
155 }
156 void    RAS_2DFilterManager::AnalyseShader(int passindex, vector<STR_String>& propNames)
157 {
158         texflag[passindex] = 0;
159         if(glGetUniformLocationARB(m_filters[passindex], "bgl_DepthTexture") != -1)
160         {
161                 texflag[passindex] |= 0x1;
162         }
163         if(glGetUniformLocationARB(m_filters[passindex], "bgl_LuminanceTexture") != -1)
164         {
165                 texflag[passindex] |= 0x2;
166         }
167
168         if(m_gameObjects[passindex])
169         {
170                 int objProperties = propNames.size();
171                 int i;
172                 for(i=0; i<objProperties; i++)
173                         if(glGetUniformLocationARB(m_filters[passindex], propNames[i]) != -1)
174                                 m_properties[passindex].push_back(propNames[i]);
175         }
176 }
177
178 void RAS_2DFilterManager::StartShaderProgram(int passindex)
179 {
180         GLint uniformLoc;
181         glUseProgramObjectARB(m_filters[passindex]);
182         uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_RenderedTexture");
183         glActiveTextureARB(GL_TEXTURE0);
184         glBindTexture(GL_TEXTURE_2D, texname[0]);
185
186     if (uniformLoc != -1)
187     {
188                 glUniform1iARB(uniformLoc, 0);
189     }
190
191     /* send depth texture to glsl program if it needs */
192         if(texflag[passindex] & 0x1){
193         uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_DepthTexture");
194         glActiveTextureARB(GL_TEXTURE1);
195         glBindTexture(GL_TEXTURE_2D, texname[1]);
196
197         if (uniformLoc != -1)
198         {
199                 glUniform1iARB(uniformLoc, 1);
200         }
201     }
202
203     /* send luminance texture to glsl program if it needs */
204         if(texflag[passindex] & 0x2){
205         uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_LuminanceTexture");
206         glActiveTextureARB(GL_TEXTURE2);
207         glBindTexture(GL_TEXTURE_2D, texname[2]);
208
209         if (uniformLoc != -1)
210         {
211                 glUniform1iARB(uniformLoc, 2);
212         }
213         }
214         
215         uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_TextureCoordinateOffset");
216     if (uniformLoc != -1)
217     {
218         glUniform2fvARB(uniformLoc, 9, textureoffsets);
219     }
220         uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_RenderedTextureWidth");
221     if (uniformLoc != -1)
222     {
223                 glUniform1fARB(uniformLoc,texturewidth);
224     }
225         uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_RenderedTextureHeight");
226     if (uniformLoc != -1)
227     {
228                 glUniform1fARB(uniformLoc,textureheight);
229     }
230
231         int i, objProperties = m_properties[passindex].size();
232         for(i=0; i<objProperties; i++)
233         {
234                 uniformLoc = glGetUniformLocationARB(m_filters[passindex], m_properties[passindex][i]);
235                 if(uniformLoc != -1)
236                 {
237                         float value = ((CValue*)m_gameObjects[passindex])->GetPropertyNumber(m_properties[passindex][i], 0.0);
238                         glUniform1fARB(uniformLoc,value);
239                 }
240         }
241 }
242
243 void RAS_2DFilterManager::EndShaderProgram()
244 {
245         glUseProgramObjectARB(0);
246 }
247
248 void RAS_2DFilterManager::FreeTextures()
249 {
250         if(texname[0]!=-1)
251                 glDeleteTextures(1, (GLuint*)&texname[0]);
252         if(texname[1]!=-1)
253                 glDeleteTextures(1, (GLuint*)&texname[1]);
254         if(texname[2]!=-1)
255                 glDeleteTextures(1, (GLuint*)&texname[2]);
256 }
257
258 void RAS_2DFilterManager::SetupTextures(bool depth, bool luminance)
259 {
260         FreeTextures();
261         
262         glGenTextures(1, (GLuint*)&texname[0]);
263         glBindTexture(GL_TEXTURE_2D, texname[0]);
264         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texturewidth, textureheight, 0, GL_RGB,
265                         GL_UNSIGNED_BYTE, 0);
266         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
267         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
268         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
269         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
270
271         if(depth){
272                 glGenTextures(1, (GLuint*)&texname[1]);
273                 glBindTexture(GL_TEXTURE_2D, texname[1]);
274                 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, texturewidth,textureheight, 
275                         0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE,NULL);
276                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE,
277                                 GL_NONE);
278                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
279                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
280                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
281                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
282         }
283
284         if(luminance){
285                 glGenTextures(1, (GLuint*)&texname[2]);
286                 glBindTexture(GL_TEXTURE_2D, texname[2]);
287                 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE16, texturewidth, textureheight,
288                          0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0);
289                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
290                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
291                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
292                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
293         }
294 }
295
296 void RAS_2DFilterManager::UpdateOffsetMatrix(int width, int height)
297 {
298         canvaswidth = texturewidth = width;
299         canvasheight = textureheight = height;
300
301         GLint i,j;
302         i = 0;
303     while ((1 << i) <= texturewidth)
304         i++;
305     texturewidth = (1 << (i));
306
307     // Now for height
308     i = 0;
309     while ((1 << i) <= textureheight)
310         i++;
311     textureheight = (1 << (i));
312
313         GLfloat xInc = 1.0f / (GLfloat)texturewidth;
314         GLfloat yInc = 1.0f / (GLfloat)textureheight;
315         
316         for (i = 0; i < 3; i++)
317         {
318                 for (j = 0; j < 3; j++)
319                 {
320                         textureoffsets[(((i*3)+j)*2)+0] = (-1.0f * xInc) + ((GLfloat)i * xInc);
321                         textureoffsets[(((i*3)+j)*2)+1] = (-1.0f * yInc) + ((GLfloat)j * yInc);
322                 }
323         }
324 }
325
326 void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas)
327 {
328         bool need_depth=false;
329         bool need_luminance=false;
330         int num_filters = 0;
331
332         int passindex;
333
334         if(!isshadersupported)
335                 return;
336
337         for(passindex =0; passindex<MAX_RENDER_PASS; passindex++)
338         {
339                 if(m_filters[passindex] && m_enabled[passindex]){
340                         num_filters ++;
341                         if(texflag[passindex] & 0x1)
342                                 need_depth = true;
343                         if(texflag[passindex] & 0x2)
344                                 need_luminance = true;
345                         if(need_depth && need_luminance)
346                                 break;
347                 }
348         }
349
350         if(num_filters <= 0)
351                 return;
352
353         if(canvaswidth != canvas->GetWidth() || canvasheight != canvas->GetHeight())
354         {
355                 UpdateOffsetMatrix(canvas->GetWidth(), canvas->GetHeight());
356                 SetupTextures(need_depth, need_luminance);
357         }
358         GLuint  viewport[4]={0};
359
360         if(need_depth){
361                 glActiveTextureARB(GL_TEXTURE1);
362                 glBindTexture(GL_TEXTURE_2D, texname[1]);
363                 glCopyTexImage2D(GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT, 0,0, texturewidth,textureheight, 0);
364         }
365         
366         if(need_luminance){
367                 glActiveTextureARB(GL_TEXTURE2);
368                 glBindTexture(GL_TEXTURE_2D, texname[2]);
369                 glCopyTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE16, 0,0, texturewidth,textureheight, 0);
370         }
371
372         glGetIntegerv(GL_VIEWPORT,(GLint *)viewport);
373         glViewport(0, 0, texturewidth, textureheight);
374
375         glDisable(GL_DEPTH_TEST);
376         glMatrixMode(GL_PROJECTION);
377         glLoadIdentity();
378         glMatrixMode(GL_MODELVIEW);
379         glLoadIdentity();
380
381         for(passindex =0; passindex<MAX_RENDER_PASS; passindex++)
382         {
383                 if(m_filters[passindex] && m_enabled[passindex])
384                 {
385                         StartShaderProgram(passindex);
386
387                         glActiveTextureARB(GL_TEXTURE0);
388                         glBindTexture(GL_TEXTURE_2D, texname[0]);
389                         glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, texturewidth, textureheight, 0);
390                         glClear(GL_COLOR_BUFFER_BIT);
391
392                         glBegin(GL_QUADS);
393                                 glColor4f(1.f, 1.f, 1.f, 1.f);
394                                 glTexCoord2f(1.0, 1.0); glVertex2f(1,1);
395                                 glTexCoord2f(0.0, 1.0); glVertex2f(-1,1);
396                                 glTexCoord2f(0.0, 0.0); glVertex2f(-1,-1);
397                                 glTexCoord2f(1.0, 0.0); glVertex2f(1,-1);
398                         glEnd();
399                 }
400         }
401
402         glEnable(GL_DEPTH_TEST);
403         glViewport(viewport[0],viewport[1],viewport[2],viewport[3]);
404         EndShaderProgram();     
405 }
406
407 void RAS_2DFilterManager::EnableFilter(vector<STR_String>& propNames, void* gameObj, RAS_2DFILTER_MODE mode, int pass, STR_String& text)
408 {
409         if(!isshadersupported)
410                 return;
411         if(pass<0 || pass>=MAX_RENDER_PASS)
412                 return;
413
414         if(mode == RAS_2DFILTER_DISABLED)
415         {
416                 m_enabled[pass] = 0;
417                 return;
418         }
419
420         if(mode == RAS_2DFILTER_ENABLED)
421         {
422                 m_enabled[pass] = 1;
423                 return;
424         }
425
426         if(mode == RAS_2DFILTER_NOFILTER)
427         {
428                 if(m_filters[pass])
429                         glDeleteObjectARB(m_filters[pass]);
430                 m_enabled[pass] = 0;
431                 m_filters[pass] = 0;
432                 m_gameObjects[pass] = NULL;
433                 m_properties[pass].clear();
434                 texflag[pass] = 0;
435                 return;
436         }
437         
438         if(mode == RAS_2DFILTER_CUSTOMFILTER)
439         {
440                 if(m_filters[pass])
441                         glDeleteObjectARB(m_filters[pass]);
442                 m_filters[pass] = CreateShaderProgram(text.Ptr());
443                 m_gameObjects[pass] = gameObj;
444                 AnalyseShader(pass, propNames);
445                 m_enabled[pass] = 1;
446                 return;
447         }
448
449         if(mode>=RAS_2DFILTER_MOTIONBLUR && mode<=RAS_2DFILTER_INVERT)
450         {
451                 if(m_filters[pass])
452                         glDeleteObjectARB(m_filters[pass]);
453                 m_filters[pass] = CreateShaderProgram(mode);
454                 m_enabled[pass] = 1;
455         }
456 }