1 /****************************************************************************
2 * MeshLab                                                           o o     *
3 * A versatile mesh processing toolbox                             o     o   *
4 *                                                                _   O  _   *
5 * Copyright(C) 2005                                                \/)\/    *
6 * Visual Computing Lab                                            /\/|      *
7 * ISTI - Italian National Research Council                           |      *
8 *                                                                    \      *
9 * All rights reserved.                                                      *
10 *                                                                           *
11 * This program is free software; you can redistribute it and/or modify      *
12 * it under the terms of the GNU General Public License as published by      *
13 * the Free Software Foundation; either version 2 of the License, or         *
14 * (at your option) any later version.                                       *
15 *                                                                           *
16 * This program is distributed in the hope that it will be useful,           *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
19 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt)          *
20 * for more details.                                                         *
21 *                                                                           *
22 ****************************************************************************/
23 #ifndef DECORATE_SHADER_H
24 #define DECORATE_SHADER_H
25 #include <common/GLExtensionsManager.h>
26 #include <QFile>
27 #include <QImage>
28 #include <cassert>
29 
30 //#include <QObject>
31 #include <common/interfaces.h>
32 //#include <meshlab/glarea.h>
33 
34 
35 class GLArea;
36 
37 #define BLUR_COEF 0.4
38 
39 /**
40   * Base abstract class for all the four decorator methods(shadow mapping, VSM shadow mapping, VSM shadow mapping
41   * with blur and Screen Space Ambient Occlusion). It defines the method that should be implemented in the derived
42   * class(init(), runShader() and setup()). It defines a set of methods in common between all the derived class too.
43   */
44 class DecorateShader
45 {
46 public:
DecorateShader()47     DecorateShader(){
48         this->_initOk = false;
49 
50         //default texture size
51         this->_texW = 1024;
52         this->_texH = 1024;
53       }
54 
~DecorateShader()55 	virtual ~DecorateShader() {}
56 
57     /**
58       * Performs init commands.
59       * If something went wrong return false, otherwise true.
60       * @return false if something went wrong, true otherwise.
61       */
62     virtual bool init() = 0;
63 
64     /**
65       * Applies the decoration running the shaders.
66       * @param m the mesh model.
67       * @param gla GLArea reference.
68       */
69     virtual void runShader(MeshDocument&, GLArea*) = 0;
70     virtual void setShadowIntensity(float f) =0;
71 
72 protected:
73     bool _initOk;
74     int _texW,_texH;
75 
76     /** The FrameBufferObject handler */
77     GLuint _fbo;
78 
79     /**
80       * Sets up the needed resources(FBO and textures) to apply the shader.
81       * @return false if something went wrong, true otherwise.
82       */
83     virtual bool setup() = 0;
84 
85     /**
86       * Binds the FBO, clear the color and depth buffer and sets the clear depth value and the viewport size.
87       */
bind()88     void bind()
89     {
90         assert(_initOk);
91         glClearDepth(1.0);
92         glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
93         glPushAttrib(GL_VIEWPORT_BIT);
94         glViewport(0, 0, this->_texW, this->_texH);
95         glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
96     }
97 
98     /**
99       * Performs the glew init. If something went wrong it shows an allert message
100       * and returns false, otherwise returns true;
101       * @return true if no errors happened during the setup, false otherwise.
102       */
initGlew()103     bool initGlew()
104     {
105       return GLExtensionsManager::initializeGLextensions_notThrowing();
106     }
107 
108     /**
109       * Performs the setup of the decorator plugin. If something went wrong
110       * it shows an allert message an returns false, otherwise returns true;
111       * @return true if no errors happened during the setup, false otherwise.
112       */
initSetup()113     bool initSetup()
114 	{
115         return setup();
116     }
117 
118     /**
119     * Unbinds the last frame buffer object attached and pops the viewport attribute.
120     */
unbind()121     void unbind()
122     {
123         if(!_initOk)
124             return;
125 
126         glPopAttrib();
127         glBindFramebuffer(GL_FRAMEBUFFER, 0);
128     }
129 
130     /**
131     * Prints the depth map specified by the handler <b>map<b/> in a file named <b>fname</b>
132     * $$$$$$ FOR DEBUGGING PURPOSES $$$$$$
133     * @param map The handler to the depth map
134     * @param fname The name of the new file
135     */
printDepthMap(GLuint map,const QString & fname)136     void printDepthMap(GLuint map, const QString &fname){
137         if (!this->_initOk)
138                 return;
139         QImage img(this->_texW, this->_texH, QImage::Format_RGB32);
140 
141         float *tempFBuf = new float[this->_texW * this->_texH *1 ];
142         float *tempFBufPtr = tempFBuf;
143         glBindTexture(GL_TEXTURE_2D, map);
144         glGetTexImage(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, GL_FLOAT, tempFBufPtr);
145         for (int i = 0; i < this->_texH; ++i) {
146                 QRgb *scanLine = (QRgb*)img.scanLine(i);
147                 for (int j = 0; j < this->_texW; ++j) {
148                     const unsigned char val = (unsigned char) (tempFBufPtr[0] * 255.0f);
149                         scanLine[j] = qRgb(val, val, val);
150                         tempFBufPtr ++;
151                 }
152         }
153         delete[] tempFBuf;
154         img.mirrored().save(fname, "PNG");
155     }
156 
157     /**
158     * Prints the color texture specified by the handler <b>map<b/> in a file named <b>fname</b>
159     * $$$$$$ FOR DEBUGGING PURPOSES $$$$$$
160     * @param map The handler to the texture
161     * @param fname The name of the new file
162     */
printColorMap(GLuint map,const QString & fname)163     void printColorMap(GLuint map, const QString &fname){
164         if (!this->_initOk)
165                 return;
166 
167         QImage img(this->_texW, this->_texH, QImage::Format_RGB32);
168 
169      unsigned char *tempBuf = new unsigned char[this->_texW * this->_texH * 3];
170         unsigned char *tempBufPtr = tempBuf;
171         glBindTexture(GL_TEXTURE_2D, map);
172         glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, tempBufPtr);
173         for (int i = 0; i < this->_texH; ++i) {
174                 QRgb *scanLine = (QRgb*)img.scanLine(i);
175                 for (int j = 0; j < this->_texW; ++j) {
176                         scanLine[j] = qRgb(tempBufPtr[0], tempBufPtr[1], tempBufPtr[2]);
177                         tempBufPtr += 3;
178                 }
179         }
180 
181         delete[] tempBuf;
182 
183         img.mirrored().save(fname, "PNG");
184     }
185 
186     /**
187       * If something wrong happened during the compilation of the shader,
188       * whose handler is obj, prints the log.
189       * @param obj the shader handler
190       */
printShaderInfoLog(GLuint obj)191     bool printShaderInfoLog(GLuint obj){
192         int infologLength = 0;
193         int charsWritten  = 0;
194         char *infoLog;
195 
196             glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infologLength);
197 
198         if (infologLength > 0)
199         {
200             infoLog = (char *)malloc(infologLength);
201             glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);
202                     printf("%s\n",infoLog);
203             free(infoLog);
204         }
205         return true;
206     }
207 
208     /**
209       * If something wrong happened during the compilation of the shader program,
210       * whose handler is obj, prints the log.
211       * @param obj the shader program handler
212       */
printProgramInfoLog(GLuint obj)213     bool printProgramInfoLog(GLuint obj)
214     {
215         int infologLength = 0;
216         int charsWritten  = 0;
217         char *infoLog;
218 
219             glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infologLength);
220 
221         if (infologLength > 0)
222         {
223             infoLog = (char *)malloc(infologLength);
224             glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);
225                     printf("%s\n",infoLog);
226             free(infoLog);
227         }
228         return true;
229     }
230 
231     /**
232      * It takes a shader,vertex and fragment files that should be named in the same way
233      * except for the extension(e.g. ~/xxxx.vertex ~/xxx.fragment), compile and link it
234      * producing a program that could be executed on the GPU.
235      * @param program The handler to the program
236      * @param vertex The handler to the vertex shader
237      * @param fragment The handler to the fragment shader
238      * @param path The path to the files.
239      * @return true if no errors during compilation and linking occurs
240     */
compileAndLink(GLuint & program,GLuint & vertex,GLuint & fragment,QString & path)241     bool compileAndLink(GLuint& program, GLuint& vertex, GLuint& fragment, QString& path){
242         //load the file containing the vertex shader
243         QFile vertexShaderFile(path + QString(".vert"));
244         bool ret=vertexShaderFile.open(QIODevice::ReadOnly | QIODevice::Text);
245         if(!ret)
246         {
247           qDebug("Unable to open '%s'",qUtf8Printable(path + QString(".vert")));
248           return false;
249         }
250 
251         QByteArray bArray = vertexShaderFile.readAll();
252         GLint ShaderLen = (GLint) bArray.length();
253         GLubyte* ShaderSource = (GLubyte *)bArray.data();
254 
255         //create a new vertex shader
256         if(vertex==0)
257           vertex= glCreateShader(GL_VERTEX_SHADER);
258         glShaderSource(vertex, 1, (const GLchar **)&ShaderSource, &ShaderLen);
259         //compile the vertex shader
260         glCompileShader(vertex);
261         //print info log about the vertex compilaiton
262         if(!this->printShaderInfoLog(vertex))
263             return false;
264 
265         //close the vertex file
266         vertexShaderFile.close();
267 
268         //load the file containing the fragment shader
269         QFile fragmentShaderFile(path + QString(".frag"));
270         fragmentShaderFile.open(QIODevice::ReadOnly | QIODevice::Text);
271 
272         bArray = fragmentShaderFile.readAll();
273         ShaderLen = (GLint) bArray.length();
274         ShaderSource = (GLubyte *)bArray.data();
275 
276         //create a new fragment shader
277         if(fragment==0)
278           fragment= glCreateShader(GL_FRAGMENT_SHADER);
279         glShaderSource(fragment, 1, (const GLchar **)&ShaderSource, &ShaderLen);
280         //compile the fragment shader
281         glCompileShader(fragment);
282         //print info log about the fragment compilaiton
283         if(!this->printShaderInfoLog(fragment))
284             return false;
285 
286         //close the fragment file
287         fragmentShaderFile.close();
288 
289         //create a new shader program with the vertex and fragment shader loaded/compiled above
290         if(program==0)
291           program = glCreateProgram();
292 		else
293 		{
294 			glDetachShader(program,vertex);
295 			glDetachShader(program,fragment);
296 		}
297         glAttachShader(program, vertex);
298         glAttachShader(program, fragment);
299         glLinkProgram(program);
300         if(!this->printProgramInfoLog(program))
301             return false;
302         return true;
303     }
304 
305     /**
306       * Generates a texture color for the handler <b>tex</b> and attaches it to the FBO
307       * at the attachment target defined by <b>attachment</b>. The FBO should be binded before the method is called.
308       * @param tex the texture handler
309       * @param attachment the FBO attachment target.
310       */
genColorTextureEXT(GLuint & tex,GLenum attachment)311     void genColorTextureEXT(GLuint& tex, GLenum attachment){
312         glGenTextures(1, &tex);
313         glBindTexture(GL_TEXTURE_2D, tex);
314         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
315         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
316         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP);
317         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
318         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
319 
320         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,  this->_texW, this->_texH, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
321         glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, tex, 0);
322 
323 
324     }
325 
326     /**
327       * Generates a depth render buffer for the handler <b>tex</b> and attaches it to the FBO.
328       * The FBO should be binded before the method is called.
329       * @param tex the render buffer handler
330       */
genDepthRenderBufferEXT(GLuint & tex)331     void genDepthRenderBufferEXT(GLuint& tex){
332 
333         glGenRenderbuffers(1, &tex);
334         glBindRenderbuffer(GL_RENDERBUFFER, tex);
335         glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, this->_texW, this->_texH);
336         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, tex);
337 
338     }
339 
340     /**
341       * Setup a depth texture and attaches it to the FrameBufferObject. If <b>isShMap</b> is true the texture
342       * generated will be a shadow map, otherwise a depth map.
343       * The texture format will be GL_DEPTH_COMPONENT24. The FBO should be binded before calling the method
344       * @param shmTxt The handler to the texture.
345       */
genDepthMapTexture24(GLuint & tex,bool isShMap)346     void genDepthMapTexture24(GLuint& tex, bool isShMap){
347         glGenTextures(1, &tex);
348         glBindTexture(GL_TEXTURE_2D, tex);
349 
350         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
351         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
352         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP);
353         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
354         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
355         if(isShMap){
356             glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
357             glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
358             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
359             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
360         }
361         glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24,  this->_texW, this->_texH, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
362         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, tex, 0);
363         return;
364     }
365 
366      /**
367       * Setup a depth texture and attaches it to the FrameBufferObject. If <b>isShMap</b> is true the texture
368       * generated will be a shadow map, otherwise a depth map.
369       * The texture format will be GL_DEPTH_COMPONENT16. The FBO should be binded before calling the method
370       * @param shmTxt The handler to the texture.
371       */
genDepthMapTexture16(GLuint & tex,bool isShMap)372     void genDepthMapTexture16(GLuint& tex, bool isShMap){
373         glGenTextures(1, &tex);
374         glBindTexture(GL_TEXTURE_2D, tex);
375 
376         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
377         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
378         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP);
379         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
380         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
381         if(isShMap){
382             glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
383             glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
384             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
385             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
386         }
387 
388         glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16,  this->_texW, this->_texH, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
389         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, tex, 0);
390         return;
391     }
392 };
393 #endif // DECORATE_SHADER_H
394