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