$search
00001 /* tgShader 00002 * 00003 * Copyright (C) 2005, Maurizio Monge <maurizio.monge@gmail.com> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License as published by 00007 * the Free Software Foundation; either version 2 of the License, or 00008 * (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License 00016 * along with this program; if not, write to the Free Software 00017 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00018 */ 00019 00020 #include <blort/TomGine/tgShader.h> 00021 #include <string.h> 00022 #include <stdarg.h> 00023 #include <stdexcept> 00024 00025 #ifdef HAVE_GTK 00026 #include <gtk/gtk.h> 00027 #endif 00028 00029 #include <GL/glu.h> 00030 00031 using namespace TomGine; 00032 00033 static const char *gl_type_name(GLenum type) 00034 { 00035 switch(type) 00036 { 00037 case GL_FLOAT: return "float"; 00038 case GL_FLOAT_VEC2_ARB: return "vec2"; 00039 case GL_FLOAT_VEC3_ARB: return "vec3"; 00040 case GL_FLOAT_VEC4_ARB: return "vec4"; 00041 case GL_FLOAT_MAT2_ARB: return "mat2"; 00042 case GL_FLOAT_MAT3_ARB: return "mat3"; 00043 case GL_FLOAT_MAT4_ARB: return "mat4"; 00044 case GL_INT: return "int"; 00045 case GL_INT_VEC2_ARB: return "ivec2"; 00046 case GL_INT_VEC3_ARB: return "ivec3"; 00047 case GL_INT_VEC4_ARB: return "ivec4"; 00048 case GL_BOOL_ARB: return "bool"; 00049 case GL_BOOL_VEC2_ARB: return "bvec2"; 00050 case GL_BOOL_VEC3_ARB: return "bvec3"; 00051 case GL_BOOL_VEC4_ARB: return "bvec4"; 00052 case GL_SAMPLER_1D: return "sampler1D"; 00053 case GL_SAMPLER_2D: return "sampler2D"; 00054 case GL_SAMPLER_3D: return "sampler3D"; 00055 case GL_SAMPLER_CUBE: return "samplerCube"; 00056 case GL_SAMPLER_1D_SHADOW: return "sampler1DShadow"; 00057 case GL_SAMPLER_2D_SHADOW: return "sampler2DShadow"; 00058 default: 00059 { 00060 static char tmp[64]; 00061 snprintf(tmp,64,"?0x%x?", type ); 00062 return tmp; 00063 } 00064 } 00065 } 00066 00067 void tgShader::dumpVars() 00068 { 00069 int nv; 00070 glGetObjectParameterivARB( program, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &nv); 00071 printf("UNIFORM variables (%d):\n",nv); 00072 00073 for(int i=0;i<nv;i++) 00074 { 00075 GLenum type; 00076 int size; 00077 char vname[4096]; 00078 glGetActiveUniformARB(program,i,4096,NULL,&size,&type,vname); 00079 printf(" %s %s;\n", gl_type_name(type),vname); 00080 } 00081 00082 glGetObjectParameterivARB( program, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &nv); 00083 printf("ATTRIBUTE variables (%d):\n",nv); 00084 for(int i=0;i<nv;i++) 00085 { 00086 GLenum type; 00087 int size; 00088 char vname[4096]; 00089 glGetActiveAttribARB(program,i,4096,NULL,&size,&type,vname); 00090 printf(" %s %s;\n", gl_type_name(type),vname); 00091 } 00092 } 00093 00094 void tgShader::printInfoLog(GLhandleARB obj, const char *msg, ...) 00095 { 00096 int infologLength = 0; 00097 int charsWritten = 0; 00098 char *infoLog; 00099 00100 glGetObjectParameterivARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB, 00101 &infologLength); 00102 if(infologLength > 1) 00103 { 00104 va_list va; 00105 va_start(va, msg); 00106 infoLog = (char *)malloc(infologLength); 00107 glGetInfoLogARB(obj, infologLength, &charsWritten, infoLog); 00108 #ifdef HAVE_GTK 00109 char *m = g_strdup_vprintf(msg, va); 00110 GtkWidget *dialog = gtk_message_dialog_new(NULL,GTK_DIALOG_MODAL, 00111 GTK_MESSAGE_ERROR,GTK_BUTTONS_OK,"%s (%d):",m,infologLength); 00112 g_free(m); 00113 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),"%s",infoLog); 00114 gtk_dialog_run(GTK_DIALOG(dialog)); 00115 gtk_widget_destroy(dialog); 00116 #else 00117 vprintf(msg, va); 00118 printf(" (%d):\n",infologLength); 00119 printf("%s",infoLog); 00120 #endif 00121 va_end(va); 00122 free(infoLog); 00123 } 00124 } 00125 00126 bool tgShader::getStatus(){ 00127 if(program) 00128 return true; 00129 00130 return false; 00131 } 00132 00133 tgShader::tgShader(const char *vertex_file, const char *fragment_file, const char *header) 00134 { 00135 GLint status; 00136 const char *vs = read_text_file(vertex_file); 00137 const char *fs = read_text_file(fragment_file); 00138 00139 char charbuffer[512]; 00140 00141 if( vertex_file && !vs ){ 00142 sprintf(charbuffer, "[tgShader::tgShader] Error loading file for vertex shader '%s'.", vertex_file); 00143 throw std::runtime_error(charbuffer); 00144 } 00145 00146 00147 if( fragment_file && !fs ){ 00148 sprintf(charbuffer, "[tgShader::tgShader] Error loading file for fragment shader '%s'.", fragment_file); 00149 throw std::runtime_error(charbuffer); 00150 } 00151 00152 if(header) { 00153 if(vs) { 00154 char *tmp = (char*)malloc(strlen(header)+strlen(vs)+1); 00155 strcpy(tmp,header); 00156 strcat(tmp,vs); 00157 free((void*)vs); 00158 vs = tmp; 00159 } 00160 if(fs) { 00161 char *tmp = (char*)malloc(strlen(header)+strlen(fs)+1); 00162 strcpy(tmp,header); 00163 strcat(tmp,fs); 00164 free((void*)fs); 00165 fs = tmp; 00166 } 00167 } 00168 00169 if(vs) 00170 { 00171 vertex = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); 00172 glShaderSourceARB(vertex, 1, &vs, NULL); 00173 glCompileShaderARB(vertex); 00174 00175 glGetObjectParameterivARB( vertex, GL_OBJECT_COMPILE_STATUS_ARB, &status); 00176 if(!status) 00177 { 00178 printInfoLog(vertex,"[tgShader::tgShader] Error compiling vertex shader \"%s\"",vertex_file); 00179 program = 0; 00180 return; 00181 } 00182 free((void*)vs); 00183 } 00184 else 00185 vertex = 0; 00186 00187 if(fs) 00188 { 00189 fragment = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); 00190 glShaderSourceARB(fragment, 1, &fs,NULL); 00191 glCompileShaderARB(fragment); 00192 00193 glGetObjectParameterivARB( fragment, GL_OBJECT_COMPILE_STATUS_ARB, &status); 00194 if(!status) 00195 { 00196 printInfoLog(fragment,"[tgShader::tgShader] Error compiling fragment shader \"%s\"",fragment_file); 00197 program = 0; 00198 return; 00199 } 00200 free((void*)fs); 00201 } 00202 else 00203 fragment = 0; 00204 00205 if(fragment==0 && vertex==0) 00206 { 00207 program = 0; 00208 return; 00209 } 00210 00211 program = glCreateProgramObjectARB(); 00212 if(vertex!=0) 00213 { 00214 glAttachObjectARB(program,vertex); 00215 glDeleteObjectARB(vertex); 00216 } 00217 if(fragment!=0) 00218 { 00219 glAttachObjectARB(program,fragment); 00220 glDeleteObjectARB(fragment); 00221 } 00222 glLinkProgramARB(program); 00223 00224 glGetObjectParameterivARB( program, GL_OBJECT_LINK_STATUS_ARB, &status); 00225 if(!status) 00226 { 00227 printInfoLog(program,"Error linking program with \"%s\" and \"%s\"", 00228 vertex_file,fragment_file); 00229 glDeleteObjectARB(program); 00230 program = 0; 00231 return; 00232 } 00233 00234 glValidateProgramARB(program); 00235 glGetObjectParameterivARB( program, GL_OBJECT_VALIDATE_STATUS_ARB,&status); 00236 printInfoLog(program,"%s validating program",status?"Information":"Error"); 00237 if(!status) 00238 { 00239 glDeleteObjectARB(program); 00240 program = 0; 00241 } 00242 00243 //dumpVars(); 00244 } 00245 00246 tgShader::~tgShader() 00247 { 00248 if(program!=0){ 00249 glDeleteObjectARB(program); 00250 } 00251 } 00252 00253 void tgShader::bind() 00254 { 00255 if(program) 00256 glUseProgramObjectARB(program); 00257 } 00258 00259 void tgShader::unbind() 00260 { 00261 if(program) 00262 glUseProgramObjectARB(0); 00263 } 00264 00265 GLuint tgShader::getAttribLoc(const char *attr) 00266 { 00267 return glGetAttribLocationARB( program, attr); 00268 } 00269 00270 GLint tgShader::getUniformLoc(const char* var) 00271 { 00272 return glGetUniformLocationARB(program,var); 00273 } 00274 00275 void tgShader::setUniform(const char* var,int f) 00276 { 00277 int loc = glGetUniformLocationARB(program,var); 00278 glUniform1iARB(loc,f); 00279 } 00280 00281 void tgShader::setUniform(const char* var,unsigned f) 00282 { 00283 int loc = glGetUniformLocationARB(program,var); 00284 glUniform1iARB(loc,(int)f); 00285 } 00286 00287 void tgShader::setUniform(const char* var,int n,const int* f) 00288 { 00289 int loc = glGetUniformLocationARB(program,var); 00290 glUniform1ivARB(loc,n,f); 00291 } 00292 00293 void tgShader::setUniform(const char* var,float f) 00294 { 00295 int loc = glGetUniformLocationARB(program,var); 00296 glUniform1fARB(loc,f); 00297 } 00298 00299 void tgShader::setUniform(const char* var,int n,const float* f) 00300 { 00301 int loc = glGetUniformLocationARB(program,var); 00302 glUniform1fvARB(loc,n,f); 00303 //printf("f: %f %f %f\n", f[0],f[1],f[2]); 00304 } 00305 00306 void tgShader::setUniform(const char* var,vec2 f) 00307 { 00308 int loc = glGetUniformLocationARB(program,var); 00309 glUniform2fvARB(loc,1,f.v); 00310 } 00311 00312 void tgShader::setUniform(const char* var,int n,vec2* f) 00313 { 00314 int loc = glGetUniformLocationARB(program,var); 00315 glUniform1fvARB(loc,2*n,f->v); 00316 } 00317 00318 void tgShader::setUniform(const char* var,vec3 f) 00319 { 00320 int loc = glGetUniformLocationARB(program,var); 00321 glUniform3fvARB(loc,1,f.v); 00322 } 00323 00324 void tgShader::setUniform(const char* var,int n,vec3* f) 00325 { 00326 int loc = glGetUniformLocationARB(program,var); 00327 glUniform1fvARB(loc,3*n,f->v); 00328 } 00329 00330 void tgShader::setUniform(const char* var,vec4 f) 00331 { 00332 int loc = glGetUniformLocationARB(program,var); 00333 glUniform4fv(loc,1,f.v); 00334 } 00335 00336 void tgShader::setUniform(const char* var,int n,vec4* f) 00337 { 00338 int loc = glGetUniformLocationARB(program,var); 00339 glUniform1fvARB(loc,4*n,f->v); 00340 } 00341 00342 void tgShader::setUniform(const char* var,mat3 f,bool transpose) 00343 { 00344 int loc = glGetUniformLocationARB(program,var); 00345 glUniformMatrix3fvARB(loc,1,transpose,f.mat); 00346 } 00347 00348 void tgShader::setUniform(const char* var,int n,mat3* f,bool transpose) 00349 { 00350 int loc = glGetUniformLocationARB(program,var); 00351 glUniformMatrix3fvARB(loc,n,transpose,f->mat); 00352 } 00353 00354 void tgShader::setUniform(const char* var,mat4 f,bool transpose) 00355 { 00356 int loc = glGetUniformLocationARB(program,var); 00357 glUniformMatrix4fvARB(loc,1,transpose,f.mat); 00358 } 00359 00360 void tgShader::setUniform(const char* var,int n,mat4* f,bool transpose) 00361 { 00362 int loc = glGetUniformLocationARB(program,var); 00363 glUniformMatrix4fvARB(loc,n,transpose,f->mat); 00364 } 00365 00366 void* TomGine::malloc_align(size_t size, int align) 00367 { 00368 char *tmp = (char*)malloc(size+align-1+sizeof(void*)); 00369 char *addr = tmp+align-1+sizeof(void*); 00370 addr -= (long)addr & (align-1); 00371 ((void**)addr)[-1] = tmp; 00372 return addr; 00373 } 00374 00375 void TomGine::free_align(void *addr) 00376 { 00377 void *tmp = ((void**)addr)[-1]; 00378 free(tmp); 00379 } 00380 00381 char* TomGine::read_text_file(const char* file) 00382 { 00383 if(!file) return NULL; 00384 00385 FILE *f = fopen(file ,"r"); 00386 if(!f) return NULL; 00387 00388 fseek(f, 0, SEEK_END); 00389 int sz = ftell(f); 00390 fseek(f, 0, SEEK_SET); 00391 00392 char *retv = (char*)malloc(sz+1); 00393 const size_t size = fread(retv, sz, 1, f); 00394 retv[sz] = size; 00395 retv[sz] = 0; 00396 fclose(f); 00397 00398 return retv; 00399 } 00400