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