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