e9ab4ccca8dd03e984d8ce1cf966754910f34d2f
[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 texname(-1), 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         }
76
77 }
78
79 RAS_2DFilterManager::~RAS_2DFilterManager()
80 {
81 }
82
83 unsigned int RAS_2DFilterManager::CreateShaderProgram(char* shadersource)
84 {
85                 GLuint program = 0;     
86                 GLuint fShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER);
87         GLint success;
88
89                 glShaderSourceARB(fShader, 1, (const char**)&shadersource, NULL);
90
91                 glCompileShaderARB(fShader);
92
93                 glGetObjectParameterivARB(fShader, GL_COMPILE_STATUS, &success);
94                 if(!success)
95                 {
96                         /*Shader Comile Error*/
97                         std::cout << "2dFilters - Shader compile error" << std::endl;
98                         return 0;
99                 }
100                     
101                 program = glCreateProgramObjectARB();
102                 glAttachObjectARB(program, fShader);
103
104                 glLinkProgramARB(program);
105                 glGetObjectParameterivARB(program, GL_LINK_STATUS, &success);
106                 if (!success)
107                 {
108                         /*Program Link Error*/
109                         std::cout << "2dFilters - Shader program link error" << std::endl;
110                         return 0;
111                 }
112                 
113                 glValidateProgramARB(program);
114                 glGetObjectParameterivARB(program, GL_VALIDATE_STATUS, &success);
115         if (!success)
116                 {
117                         /*Program Validation Error*/
118                         std::cout << "2dFilters - Shader program validation error" << std::endl;
119                         return 0;
120                 }
121
122                 return program;
123 }
124
125 unsigned int RAS_2DFilterManager::CreateShaderProgram(int filtermode)
126 {
127                 switch(filtermode)
128                 {
129                         case RAS_2DFILTER_BLUR:
130                                 return CreateShaderProgram(BlurFragmentShader);
131                         case RAS_2DFILTER_SHARPEN:
132                                 return CreateShaderProgram(SharpenFragmentShader);
133                         case RAS_2DFILTER_DILATION:
134                                 return CreateShaderProgram(DilationFragmentShader);
135                         case RAS_2DFILTER_EROSION:
136                                 return CreateShaderProgram(ErosionFragmentShader);
137                         case RAS_2DFILTER_LAPLACIAN:
138                                 return CreateShaderProgram(LaplacionFragmentShader);
139                         case RAS_2DFILTER_SOBEL:
140                                 return CreateShaderProgram(SobelFragmentShader);
141                         case RAS_2DFILTER_PREWITT:
142                                 return CreateShaderProgram(PrewittFragmentShader);
143                         case RAS_2DFILTER_GRAYSCALE:
144                                 return CreateShaderProgram(GrayScaleFragmentShader);
145                         case RAS_2DFILTER_SEPIA:
146                                 return CreateShaderProgram(SepiaFragmentShader);
147                         case RAS_2DFILTER_INVERT:
148                                 return CreateShaderProgram(InvertFragmentShader);
149                 }
150                 return 0;
151 }
152
153 void RAS_2DFilterManager::StartShaderProgram(unsigned int shaderprogram)
154 {
155         GLint uniformLoc;
156         glUseProgramObjectARB(shaderprogram);
157         uniformLoc = glGetUniformLocationARB(shaderprogram, "bgl_RenderedTexture");
158         glActiveTextureARB(GL_TEXTURE0);
159         //glActiveTexture(GL_TEXTURE0);
160         glBindTexture(GL_TEXTURE_2D, texname);
161
162     if (uniformLoc != -1)
163     {
164                 glUniform1iARB(uniformLoc, 0);
165     }
166         uniformLoc = glGetUniformLocationARB(shaderprogram, "bgl_TextureCoordinateOffset");
167     if (uniformLoc != -1)
168     {
169         glUniform2fvARB(uniformLoc, 9, textureoffsets);
170     }
171         uniformLoc = glGetUniformLocationARB(shaderprogram, "bgl_RenderedTextureWidth");
172     if (uniformLoc != -1)
173     {
174                 glUniform1fARB(uniformLoc,texturewidth);
175     }
176         uniformLoc = glGetUniformLocationARB(shaderprogram, "bgl_RenderedTextureHeight");
177     if (uniformLoc != -1)
178     {
179                 glUniform1fARB(uniformLoc,textureheight);
180     }
181 }
182
183 void RAS_2DFilterManager::EndShaderProgram()
184 {
185         glUseProgramObjectARB(0);
186 }
187
188 void RAS_2DFilterManager::SetupTexture()
189 {
190         if(texname!=-1)
191         {
192                 glDeleteTextures(1,(const GLuint *)&texname);
193         }
194         glGenTextures(1, (GLuint *)&texname);
195         glBindTexture(GL_TEXTURE_2D, texname);
196         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texturewidth, textureheight, 0, GL_RGB,
197                 GL_UNSIGNED_BYTE, 0);
198         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
199         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
200         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
201         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
202 }
203
204 void RAS_2DFilterManager::UpdateOffsetMatrix(int width, int height)
205 {
206         canvaswidth = texturewidth = width;
207         canvasheight = textureheight = height;
208
209         GLint i,j;
210         i = 0;
211     while ((1 << i) <= texturewidth)
212         i++;
213     texturewidth = (1 << (i));
214
215     // Now for height
216     i = 0;
217     while ((1 << i) <= textureheight)
218         i++;
219     textureheight = (1 << (i));
220
221         GLfloat xInc = 1.0f / (GLfloat)texturewidth;
222         GLfloat yInc = 1.0f / (GLfloat)textureheight;
223         
224         for (i = 0; i < 3; i++)
225         {
226                 for (j = 0; j < 3; j++)
227                 {
228                         textureoffsets[(((i*3)+j)*2)+0] = (-1.0f * xInc) + ((GLfloat)i * xInc);
229                         textureoffsets[(((i*3)+j)*2)+1] = (-1.0f * yInc) + ((GLfloat)j * yInc);
230                 }
231         }
232
233         SetupTexture();
234 }
235
236 void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas)
237 {
238         if(!isshadersupported)
239                 return;
240
241         if(canvaswidth != canvas->GetWidth() || canvasheight != canvas->GetHeight())
242         {
243                 UpdateOffsetMatrix(canvas->GetWidth(), canvas->GetHeight());
244         }
245         GLuint  viewport[4]={0};
246
247         int passindex;
248         bool first = true;
249         for(passindex =0; passindex<MAX_RENDER_PASS; passindex++)
250         {
251                 if(m_filters[passindex] && m_enabled[passindex])
252                 {
253                         if(first)
254                         {
255                                 glGetIntegerv(GL_VIEWPORT,(GLint *)viewport);
256                                 glViewport(0, 0, texturewidth, textureheight);
257
258                                 glDisable(GL_DEPTH_TEST);
259                                 glMatrixMode(GL_PROJECTION);
260                                 glLoadIdentity();
261                                 glMatrixMode(GL_MODELVIEW);
262                                 glLoadIdentity();
263                                 first = false;
264                         }
265                         
266                         StartShaderProgram(m_filters[passindex]);
267
268                         glBindTexture(GL_TEXTURE_2D, texname);
269                         glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, texturewidth, textureheight, 0);
270
271                         glClear(GL_COLOR_BUFFER_BIT);
272
273                         glBegin(GL_QUADS);
274                                 glColor4f(1.f, 1.f, 1.f, 1.f);
275                                 glTexCoord2f(1.0, 1.0); glVertex2f(1,1);
276                                 glTexCoord2f(0.0, 1.0); glVertex2f(-1,1);
277                                 glTexCoord2f(0.0, 0.0); glVertex2f(-1,-1);
278                                 glTexCoord2f(1.0, 0.0); glVertex2f(1,-1);
279                         glEnd();
280                 }
281         }
282
283         if(!first)
284         {
285                 glEnable(GL_DEPTH_TEST);
286                 glViewport(viewport[0],viewport[1],viewport[2],viewport[3]);
287                 EndShaderProgram();     
288         }
289 }
290
291 void RAS_2DFilterManager::EnableFilter(RAS_2DFILTER_MODE mode, int pass, STR_String& text)
292 {
293         if(!isshadersupported)
294                 return;
295         if(pass<0 || pass>=MAX_RENDER_PASS)
296                 return;
297
298         if(mode == RAS_2DFILTER_DISABLED)
299         {
300                 m_enabled[pass] = 0;
301                 return;
302         }
303
304         if(mode == RAS_2DFILTER_ENABLED)
305         {
306                 m_enabled[pass] = 1;
307                 return;
308         }
309
310         if(mode == RAS_2DFILTER_NOFILTER)
311         {
312                 if(m_filters[pass])
313                         glDeleteObjectARB(m_filters[pass]);
314                 m_enabled[pass] = 0;
315                 m_filters[pass] = 0;
316                 return;
317         }
318         
319         if(mode == RAS_2DFILTER_CUSTOMFILTER)
320         {
321                 if(m_filters[pass])
322                         glDeleteObjectARB(m_filters[pass]);
323                 m_filters[pass] = CreateShaderProgram(text.Ptr());
324                 m_enabled[pass] = 1;
325                 return;
326         }
327
328         if(mode>=RAS_2DFILTER_MOTIONBLUR && mode<=RAS_2DFILTER_INVERT)
329         {
330                 if(m_filters[pass])
331                         glDeleteObjectARB(m_filters[pass]);
332                 m_filters[pass] = CreateShaderProgram(mode);
333                 m_enabled[pass] = 1;
334         }
335 }