1 /** 2 * Utilities for OpenGL shading language 3 * 4 * Brian Paul 5 * 9 April 2008 6 */ 7 8 9 #include <assert.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 // #include <GL/glew.h> 14 #include <GL/glut.h> 15 #include "shaderutil.h" 16 17 /** time to compile previous shader */ 18 static GLdouble CompileTime = 0.0; 19 20 /** time to linke previous program */ 21 static GLdouble LinkTime = 0.0; 22 23 24 GLboolean 25 ShadersSupported(void) 26 { 27 const char *version = (const char *) glGetString(GL_VERSION); 28 29 /* NVIDIA binary drivers will return "3.0.0", and they clearly support 30 * shaders. 31 */ 32 if (version[0] >= '2' && version[1] == '.') { 33 return GL_TRUE; 34 } 35 else if (glutExtensionSupported("GL_ARB_vertex_shader") 36 && glutExtensionSupported("GL_ARB_fragment_shader") 37 && glutExtensionSupported("GL_ARB_shader_objects")) { 38 fprintf(stderr, "Warning: Trying ARB GLSL instead of OpenGL 2.x. This may not work.\n"); 39 return GL_TRUE; 40 } 41 fprintf(stderr, "Sorry, GLSL not supported with this OpenGL.\n"); 42 return GL_FALSE; 43 } 44 45 46 GLuint 47 CompileShaderText(GLenum shaderType, const char *text) 48 { 49 GLuint shader; 50 GLint stat; 51 GLdouble t0, t1; 52 53 shader = glCreateShader(shaderType); 54 glShaderSource(shader, 1, (const GLchar **) &text, NULL); 55 56 t0 = glutGet(GLUT_ELAPSED_TIME) * 0.001; 57 glCompileShader(shader); 58 t1 = glutGet(GLUT_ELAPSED_TIME) * 0.001; 59 60 CompileTime = t1 - t0; 61 62 glGetShaderiv(shader, GL_COMPILE_STATUS, &stat); 63 if (!stat) { 64 GLchar log[1000]; 65 GLsizei len; 66 glGetShaderInfoLog(shader, 1000, &len, log); 67 fprintf(stderr, "Error: problem compiling shader: %s\n", log); 68 exit(1); 69 } 70 else { 71 /*printf("Shader compiled OK\n");*/ 72 } 73 return shader; 74 } 75 76 77 /** 78 * Read a shader from a file. 79 */ 80 GLuint 81 CompileShaderFile(GLenum shaderType, const char *filename) 82 { 83 const int max = 100*1000; 84 int n; 85 char *buffer = (char*) malloc(max); 86 GLuint shader; 87 FILE *f; 88 89 f = fopen(filename, "r"); 90 if (!f) { 91 fprintf(stderr, "Unable to open shader file %s\n", filename); 92 free(buffer); 93 return 0; 94 } 95 96 n = fread(buffer, 1, max, f); 97 /*printf("read %d bytes from shader file %s\n", n, filename);*/ 98 if (n > 0) { 99 buffer[n] = 0; 100 shader = CompileShaderText(shaderType, buffer); 101 } 102 else { 103 fclose(f); 104 free(buffer); 105 return 0; 106 } 107 108 fclose(f); 109 free(buffer); 110 111 return shader; 112 } 113 114 115 GLuint 116 LinkShaders(GLuint vertShader, GLuint fragShader) 117 { 118 GLuint program = glCreateProgram(); 119 GLdouble t0, t1; 120 121 assert(vertShader || fragShader); 122 123 if (fragShader) 124 glAttachShader(program, fragShader); 125 if (vertShader) 126 glAttachShader(program, vertShader); 127 128 t0 = glutGet(GLUT_ELAPSED_TIME) * 0.001; 129 glLinkProgram(program); 130 t1 = glutGet(GLUT_ELAPSED_TIME) * 0.001; 131 132 LinkTime = t1 - t0; 133 134 /* check link */ 135 { 136 GLint stat; 137 glGetProgramiv(program, GL_LINK_STATUS, &stat); 138 if (!stat) { 139 GLchar log[1000]; 140 GLsizei len; 141 glGetProgramInfoLog(program, 1000, &len, log); 142 fprintf(stderr, "Shader link error:\n%s\n", log); 143 return 0; 144 } 145 } 146 147 return program; 148 } 149 150 151 GLboolean 152 ValidateShaderProgram(GLuint program) 153 { 154 GLint stat; 155 glValidateProgramARB(program); 156 glGetProgramiv(program, GL_VALIDATE_STATUS, &stat); 157 158 if (!stat) { 159 GLchar log[1000]; 160 GLsizei len; 161 glGetProgramInfoLog(program, 1000, &len, log); 162 fprintf(stderr, "Program validation error:\n%s\n", log); 163 return 0; 164 } 165 166 return (GLboolean) stat; 167 } 168 169 170 GLdouble 171 GetShaderCompileTime(void) 172 { 173 return CompileTime; 174 } 175 176 177 GLdouble 178 GetShaderLinkTime(void) 179 { 180 return LinkTime; 181 } 182 183 184 void 185 SetUniformValues(GLuint program, struct uniform_info uniforms[]) 186 { 187 GLuint i; 188 189 for (i = 0; uniforms[i].name; i++) { 190 uniforms[i].location 191 = glGetUniformLocation(program, uniforms[i].name); 192 193 switch (uniforms[i].type) { 194 case GL_INT: 195 case GL_SAMPLER_1D: 196 case GL_SAMPLER_2D: 197 case GL_SAMPLER_3D: 198 case GL_SAMPLER_CUBE: 199 case GL_SAMPLER_2D_RECT_ARB: 200 assert(uniforms[i].value[0] >= 0.0F); 201 glUniform1i(uniforms[i].location, 202 (GLint) uniforms[i].value[0]); 203 break; 204 case GL_FLOAT: 205 glUniform1fv(uniforms[i].location, 1, uniforms[i].value); 206 break; 207 case GL_FLOAT_VEC2: 208 glUniform2fv(uniforms[i].location, 1, uniforms[i].value); 209 break; 210 case GL_FLOAT_VEC3: 211 glUniform3fv(uniforms[i].location, 1, uniforms[i].value); 212 break; 213 case GL_FLOAT_VEC4: 214 glUniform4fv(uniforms[i].location, 1, uniforms[i].value); 215 break; 216 default: 217 if (strncmp(uniforms[i].name, "gl_", 3) == 0) { 218 /* built-in uniform: ignore */ 219 } 220 else { 221 fprintf(stderr, 222 "Unexpected uniform data type in SetUniformValues\n"); 223 abort(); 224 } 225 } 226 } 227 } 228 229 230 /** Get list of uniforms used in the program */ 231 GLuint 232 GetUniforms(GLuint program, struct uniform_info uniforms[]) 233 { 234 GLint n, max, i; 235 236 glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &n); 237 glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max); 238 239 for (i = 0; i < n; i++) { 240 GLint size, len; 241 GLenum type; 242 char name[100]; 243 244 glGetActiveUniform(program, i, 100, &len, &size, &type, name); 245 246 uniforms[i].name = strdup(name); 247 uniforms[i].size = size; 248 uniforms[i].type = type; 249 uniforms[i].location = glGetUniformLocation(program, name); 250 } 251 252 uniforms[i].name = NULL; /* end of list */ 253 254 return n; 255 } 256 257 258 void 259 PrintUniforms(const struct uniform_info uniforms[]) 260 { 261 GLint i; 262 263 printf("Uniforms:\n"); 264 265 for (i = 0; uniforms[i].name; i++) { 266 printf(" %d: %s size=%d type=0x%x loc=%d value=%g, %g, %g, %g\n", 267 i, 268 uniforms[i].name, 269 uniforms[i].size, 270 uniforms[i].type, 271 uniforms[i].location, 272 uniforms[i].value[0], 273 uniforms[i].value[1], 274 uniforms[i].value[2], 275 uniforms[i].value[3]); 276 } 277 } 278 279 280 /** Get list of attribs used in the program */ 281 GLuint 282 GetAttribs(GLuint program, struct attrib_info attribs[]) 283 { 284 GLint n, max, i; 285 286 glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &n); 287 glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max); 288 289 for (i = 0; i < n; i++) { 290 GLint size, len; 291 GLenum type; 292 char name[100]; 293 294 glGetActiveAttrib(program, i, 100, &len, &size, &type, name); 295 296 attribs[i].name = strdup(name); 297 attribs[i].size = size; 298 attribs[i].type = type; 299 attribs[i].location = glGetAttribLocation(program, name); 300 } 301 302 attribs[i].name = NULL; /* end of list */ 303 304 return n; 305 } 306 307 308 void 309 PrintAttribs(const struct attrib_info attribs[]) 310 { 311 GLint i; 312 313 printf("Attribs:\n"); 314 315 for (i = 0; attribs[i].name; i++) { 316 printf(" %d: %s size=%d type=0x%x loc=%d\n", 317 i, 318 attribs[i].name, 319 attribs[i].size, 320 attribs[i].type, 321 attribs[i].location); 322 } 323 } 324