132001f49Smrg/** 232001f49Smrg * Utilities for OpenGL shading language 332001f49Smrg * 432001f49Smrg * Brian Paul 532001f49Smrg * 9 April 2008 632001f49Smrg */ 732001f49Smrg 832001f49Smrg 932001f49Smrg#include <assert.h> 1032001f49Smrg#include <stdio.h> 1132001f49Smrg#include <stdlib.h> 1232001f49Smrg#include <string.h> 1332001f49Smrg#include <GL/glew.h> 1432001f49Smrg#include "glut_wrap.h" 1532001f49Smrg#include "shaderutil.h" 1632001f49Smrg 1732001f49Smrg/** time to compile previous shader */ 1832001f49Smrgstatic GLdouble CompileTime = 0.0; 1932001f49Smrg 2032001f49Smrg/** time to linke previous program */ 2132001f49Smrgstatic GLdouble LinkTime = 0.0; 2232001f49Smrg 2332001f49SmrgPFNGLCREATESHADERPROC CreateShader = NULL; 2432001f49SmrgPFNGLDELETESHADERPROC DeleteShader = NULL; 2532001f49SmrgPFNGLSHADERSOURCEPROC ShaderSource = NULL; 2632001f49SmrgPFNGLGETSHADERIVPROC GetShaderiv = NULL; 2732001f49SmrgPFNGLGETSHADERINFOLOGPROC GetShaderInfoLog = NULL; 2832001f49SmrgPFNGLCREATEPROGRAMPROC CreateProgram = NULL; 2932001f49SmrgPFNGLDELETEPROGRAMPROC DeleteProgram = NULL; 3032001f49SmrgPFNGLATTACHSHADERPROC AttachShader = NULL; 3132001f49SmrgPFNGLLINKPROGRAMPROC LinkProgram = NULL; 3232001f49SmrgPFNGLUSEPROGRAMPROC UseProgram = NULL; 3332001f49SmrgPFNGLGETPROGRAMIVPROC GetProgramiv = NULL; 3432001f49SmrgPFNGLGETPROGRAMINFOLOGPROC GetProgramInfoLog = NULL; 3532001f49SmrgPFNGLVALIDATEPROGRAMARBPROC ValidateProgramARB = NULL; 3632001f49SmrgPFNGLUNIFORM1IPROC Uniform1i = NULL; 3732001f49SmrgPFNGLUNIFORM1FVPROC Uniform1fv = NULL; 3832001f49SmrgPFNGLUNIFORM2FVPROC Uniform2fv = NULL; 3932001f49SmrgPFNGLUNIFORM3FVPROC Uniform3fv = NULL; 4032001f49SmrgPFNGLUNIFORM4FVPROC Uniform4fv = NULL; 4132001f49SmrgPFNGLUNIFORMMATRIX4FVPROC UniformMatrix4fv = NULL; 4232001f49SmrgPFNGLGETACTIVEATTRIBPROC GetActiveAttrib = NULL; 4332001f49SmrgPFNGLGETATTRIBLOCATIONPROC GetAttribLocation = NULL; 4432001f49Smrg 4532001f49Smrgstatic void GLAPIENTRY 4632001f49Smrgfake_ValidateProgram(GLuint prog) 4732001f49Smrg{ 4832001f49Smrg (void) prog; 4932001f49Smrg} 5032001f49Smrg 5132001f49SmrgGLboolean 5232001f49SmrgShadersSupported(void) 5332001f49Smrg{ 5432001f49Smrg if (GLEW_VERSION_2_0) { 5532001f49Smrg CreateShader = glCreateShader; 5632001f49Smrg DeleteShader = glDeleteShader; 5732001f49Smrg ShaderSource = glShaderSource; 5832001f49Smrg GetShaderiv = glGetShaderiv; 5932001f49Smrg GetShaderInfoLog = glGetShaderInfoLog; 6032001f49Smrg CreateProgram = glCreateProgram; 6132001f49Smrg DeleteProgram = glDeleteProgram; 6232001f49Smrg AttachShader = glAttachShader; 6332001f49Smrg LinkProgram = glLinkProgram; 6432001f49Smrg UseProgram = glUseProgram; 6532001f49Smrg GetProgramiv = glGetProgramiv; 6632001f49Smrg GetProgramInfoLog = glGetProgramInfoLog; 6732001f49Smrg ValidateProgramARB = (GLEW_ARB_shader_objects) 6832001f49Smrg ? glValidateProgramARB : fake_ValidateProgram; 6932001f49Smrg Uniform1i = glUniform1i; 7032001f49Smrg Uniform1fv = glUniform1fv; 7132001f49Smrg Uniform2fv = glUniform2fv; 7232001f49Smrg Uniform3fv = glUniform3fv; 7332001f49Smrg Uniform4fv = glUniform4fv; 7432001f49Smrg UniformMatrix4fv = glUniformMatrix4fv; 7532001f49Smrg GetActiveAttrib = glGetActiveAttrib; 7632001f49Smrg GetAttribLocation = glGetAttribLocation; 7732001f49Smrg return GL_TRUE; 7832001f49Smrg } 7932001f49Smrg else if (GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader 8032001f49Smrg && GLEW_ARB_shader_objects) { 8132001f49Smrg fprintf(stderr, "Warning: Trying ARB GLSL instead of OpenGL 2.x. This may not work.\n"); 8232001f49Smrg CreateShader = glCreateShaderObjectARB; 8332001f49Smrg DeleteShader = glDeleteObjectARB; 8432001f49Smrg ShaderSource = glShaderSourceARB; 8532001f49Smrg GetShaderiv = glGetObjectParameterivARB; 8632001f49Smrg GetShaderInfoLog = glGetInfoLogARB; 8732001f49Smrg CreateProgram = glCreateProgramObjectARB; 8832001f49Smrg DeleteProgram = glDeleteObjectARB; 8932001f49Smrg AttachShader = glAttachObjectARB; 9032001f49Smrg LinkProgram = glLinkProgramARB; 9132001f49Smrg UseProgram = glUseProgramObjectARB; 9232001f49Smrg GetProgramiv = glGetObjectParameterivARB; 9332001f49Smrg GetProgramInfoLog = glGetInfoLogARB; 9432001f49Smrg ValidateProgramARB = glValidateProgramARB; 9532001f49Smrg Uniform1i = glUniform1iARB; 9632001f49Smrg Uniform1fv = glUniform1fvARB; 9732001f49Smrg Uniform2fv = glUniform2fvARB; 9832001f49Smrg Uniform3fv = glUniform3fvARB; 9932001f49Smrg Uniform4fv = glUniform4fvARB; 10032001f49Smrg UniformMatrix4fv = glUniformMatrix4fvARB; 10132001f49Smrg GetActiveAttrib = glGetActiveAttribARB; 10232001f49Smrg GetAttribLocation = glGetAttribLocationARB; 10332001f49Smrg return GL_TRUE; 10432001f49Smrg } 10532001f49Smrg fprintf(stderr, "Sorry, GLSL not supported with this OpenGL.\n"); 10632001f49Smrg return GL_FALSE; 10732001f49Smrg} 10832001f49Smrg 10932001f49Smrg 11032001f49SmrgGLuint 11132001f49SmrgCompileShaderText(GLenum shaderType, const char *text) 11232001f49Smrg{ 11332001f49Smrg GLuint shader; 11432001f49Smrg GLint stat; 11532001f49Smrg GLdouble t0, t1; 11632001f49Smrg 11732001f49Smrg shader = CreateShader(shaderType); 11832001f49Smrg ShaderSource(shader, 1, (const GLchar **) &text, NULL); 11932001f49Smrg 12032001f49Smrg t0 = glutGet(GLUT_ELAPSED_TIME) * 0.001; 12132001f49Smrg glCompileShader(shader); 12232001f49Smrg t1 = glutGet(GLUT_ELAPSED_TIME) * 0.001; 12332001f49Smrg 12432001f49Smrg CompileTime = t1 - t0; 12532001f49Smrg 12632001f49Smrg GetShaderiv(shader, GL_COMPILE_STATUS, &stat); 12732001f49Smrg if (!stat) { 12832001f49Smrg GLchar log[1000]; 12932001f49Smrg GLsizei len; 13032001f49Smrg GetShaderInfoLog(shader, 1000, &len, log); 13132001f49Smrg fprintf(stderr, "Error: problem compiling shader: %s\n", log); 13232001f49Smrg exit(1); 13332001f49Smrg } 13432001f49Smrg else { 13532001f49Smrg /*printf("Shader compiled OK\n");*/ 13632001f49Smrg } 13732001f49Smrg return shader; 13832001f49Smrg} 13932001f49Smrg 14032001f49Smrg 14132001f49Smrg/** 14232001f49Smrg * Read a shader from a file. 14332001f49Smrg */ 14432001f49SmrgGLuint 14532001f49SmrgCompileShaderFile(GLenum shaderType, const char *filename) 14632001f49Smrg{ 14732001f49Smrg const int max = 100*1000; 14832001f49Smrg int n; 14932001f49Smrg char *buffer = (char*) malloc(max); 15032001f49Smrg GLuint shader; 15132001f49Smrg FILE *f; 15232001f49Smrg 15332001f49Smrg f = fopen(filename, "r"); 15432001f49Smrg if (!f) { 15532001f49Smrg fprintf(stderr, "Unable to open shader file %s\n", filename); 15632001f49Smrg free(buffer); 15732001f49Smrg return 0; 15832001f49Smrg } 15932001f49Smrg 16032001f49Smrg n = fread(buffer, 1, max, f); 16132001f49Smrg /*printf("read %d bytes from shader file %s\n", n, filename);*/ 16232001f49Smrg if (n > 0) { 16332001f49Smrg buffer[n] = 0; 16432001f49Smrg shader = CompileShaderText(shaderType, buffer); 16532001f49Smrg } 16632001f49Smrg else { 16732001f49Smrg fclose(f); 16832001f49Smrg free(buffer); 16932001f49Smrg return 0; 17032001f49Smrg } 17132001f49Smrg 17232001f49Smrg fclose(f); 17332001f49Smrg free(buffer); 17432001f49Smrg 17532001f49Smrg return shader; 17632001f49Smrg} 17732001f49Smrg 17832001f49Smrg 17932001f49SmrgGLuint 18032001f49SmrgLinkShaders(GLuint vertShader, GLuint fragShader) 18132001f49Smrg{ 18232001f49Smrg return LinkShaders3(vertShader, 0, fragShader); 18332001f49Smrg} 18432001f49Smrg 18532001f49Smrg 18632001f49SmrgGLuint 18732001f49SmrgLinkShaders3(GLuint vertShader, GLuint geomShader, GLuint fragShader) 18832001f49Smrg{ 18932001f49Smrg GLuint program = CreateProgram(); 19032001f49Smrg GLdouble t0, t1; 19132001f49Smrg 19232001f49Smrg assert(vertShader || fragShader); 19332001f49Smrg 19432001f49Smrg if (vertShader) 19532001f49Smrg AttachShader(program, vertShader); 19632001f49Smrg if (geomShader) 19732001f49Smrg AttachShader(program, geomShader); 19832001f49Smrg if (fragShader) 19932001f49Smrg AttachShader(program, fragShader); 20032001f49Smrg 20132001f49Smrg t0 = glutGet(GLUT_ELAPSED_TIME) * 0.001; 20232001f49Smrg LinkProgram(program); 20332001f49Smrg t1 = glutGet(GLUT_ELAPSED_TIME) * 0.001; 20432001f49Smrg 20532001f49Smrg LinkTime = t1 - t0; 20632001f49Smrg 20732001f49Smrg /* check link */ 20832001f49Smrg { 20932001f49Smrg GLint stat; 21032001f49Smrg GetProgramiv(program, GL_LINK_STATUS, &stat); 21132001f49Smrg if (!stat) { 21232001f49Smrg GLchar log[1000]; 21332001f49Smrg GLsizei len; 21432001f49Smrg GetProgramInfoLog(program, 1000, &len, log); 21532001f49Smrg fprintf(stderr, "Shader link error:\n%s\n", log); 21632001f49Smrg return 0; 21732001f49Smrg } 21832001f49Smrg } 21932001f49Smrg 22032001f49Smrg return program; 22132001f49Smrg} 22232001f49Smrg 22332001f49Smrg 22432001f49SmrgGLuint 22532001f49SmrgLinkShaders3WithGeometryInfo(GLuint vertShader, GLuint geomShader, GLuint fragShader, 22632001f49Smrg GLint verticesOut, GLenum inputType, GLenum outputType) 22732001f49Smrg{ 22832001f49Smrg GLuint program = CreateProgram(); 22932001f49Smrg GLdouble t0, t1; 23032001f49Smrg 23132001f49Smrg assert(vertShader || fragShader); 23232001f49Smrg 23332001f49Smrg if (vertShader) 23432001f49Smrg AttachShader(program, vertShader); 23532001f49Smrg if (geomShader) { 23632001f49Smrg AttachShader(program, geomShader); 23732001f49Smrg glProgramParameteriARB(program, GL_GEOMETRY_VERTICES_OUT_ARB, verticesOut); 23832001f49Smrg glProgramParameteriARB(program, GL_GEOMETRY_INPUT_TYPE_ARB, inputType); 23932001f49Smrg glProgramParameteriARB(program, GL_GEOMETRY_OUTPUT_TYPE_ARB, outputType); 24032001f49Smrg } 24132001f49Smrg if (fragShader) 24232001f49Smrg AttachShader(program, fragShader); 24332001f49Smrg 24432001f49Smrg t0 = glutGet(GLUT_ELAPSED_TIME) * 0.001; 24532001f49Smrg LinkProgram(program); 24632001f49Smrg t1 = glutGet(GLUT_ELAPSED_TIME) * 0.001; 24732001f49Smrg 24832001f49Smrg LinkTime = t1 - t0; 24932001f49Smrg 25032001f49Smrg /* check link */ 25132001f49Smrg { 25232001f49Smrg GLint stat; 25332001f49Smrg GetProgramiv(program, GL_LINK_STATUS, &stat); 25432001f49Smrg if (!stat) { 25532001f49Smrg GLchar log[1000]; 25632001f49Smrg GLsizei len; 25732001f49Smrg GetProgramInfoLog(program, 1000, &len, log); 25832001f49Smrg fprintf(stderr, "Shader link error:\n%s\n", log); 25932001f49Smrg return 0; 26032001f49Smrg } 26132001f49Smrg } 26232001f49Smrg 26332001f49Smrg return program; 26432001f49Smrg} 26532001f49Smrg 26632001f49Smrg 26732001f49SmrgGLboolean 26832001f49SmrgValidateShaderProgram(GLuint program) 26932001f49Smrg{ 27032001f49Smrg GLint stat; 27132001f49Smrg ValidateProgramARB(program); 27232001f49Smrg GetProgramiv(program, GL_VALIDATE_STATUS, &stat); 27332001f49Smrg 27432001f49Smrg if (!stat) { 27532001f49Smrg GLchar log[1000]; 27632001f49Smrg GLsizei len; 27732001f49Smrg GetProgramInfoLog(program, 1000, &len, log); 27832001f49Smrg fprintf(stderr, "Program validation error:\n%s\n", log); 2797ec3b29aSmrg fflush(stderr); 28032001f49Smrg return 0; 28132001f49Smrg } 28232001f49Smrg 28332001f49Smrg return (GLboolean) stat; 28432001f49Smrg} 28532001f49Smrg 28632001f49Smrg 28732001f49SmrgGLdouble 28832001f49SmrgGetShaderCompileTime(void) 28932001f49Smrg{ 29032001f49Smrg return CompileTime; 29132001f49Smrg} 29232001f49Smrg 29332001f49Smrg 29432001f49SmrgGLdouble 29532001f49SmrgGetShaderLinkTime(void) 29632001f49Smrg{ 29732001f49Smrg return LinkTime; 29832001f49Smrg} 29932001f49Smrg 30032001f49Smrg 30132001f49Smrgvoid 30232001f49SmrgSetUniformValues(GLuint program, struct uniform_info uniforms[]) 30332001f49Smrg{ 30432001f49Smrg GLuint i; 30532001f49Smrg 30632001f49Smrg for (i = 0; uniforms[i].name; i++) { 30732001f49Smrg uniforms[i].location 30832001f49Smrg = glGetUniformLocation(program, uniforms[i].name); 30932001f49Smrg 31032001f49Smrg switch (uniforms[i].type) { 31132001f49Smrg case GL_INT: 31232001f49Smrg case GL_SAMPLER_1D: 31332001f49Smrg case GL_SAMPLER_2D: 31432001f49Smrg case GL_SAMPLER_3D: 31532001f49Smrg case GL_SAMPLER_CUBE: 31632001f49Smrg case GL_SAMPLER_2D_RECT_ARB: 31732001f49Smrg case GL_SAMPLER_1D_SHADOW: 31832001f49Smrg case GL_SAMPLER_2D_SHADOW: 31932001f49Smrg case GL_SAMPLER_1D_ARRAY: 32032001f49Smrg case GL_SAMPLER_2D_ARRAY: 32132001f49Smrg case GL_SAMPLER_1D_ARRAY_SHADOW: 32232001f49Smrg case GL_SAMPLER_2D_ARRAY_SHADOW: 32332001f49Smrg assert(uniforms[i].value[0] >= 0.0F); 32432001f49Smrg Uniform1i(uniforms[i].location, 32532001f49Smrg (GLint) uniforms[i].value[0]); 32632001f49Smrg break; 32732001f49Smrg case GL_FLOAT: 32832001f49Smrg Uniform1fv(uniforms[i].location, 1, uniforms[i].value); 32932001f49Smrg break; 33032001f49Smrg case GL_FLOAT_VEC2: 33132001f49Smrg Uniform2fv(uniforms[i].location, 1, uniforms[i].value); 33232001f49Smrg break; 33332001f49Smrg case GL_FLOAT_VEC3: 33432001f49Smrg Uniform3fv(uniforms[i].location, 1, uniforms[i].value); 33532001f49Smrg break; 33632001f49Smrg case GL_FLOAT_VEC4: 33732001f49Smrg Uniform4fv(uniforms[i].location, 1, uniforms[i].value); 33832001f49Smrg break; 33932001f49Smrg case GL_FLOAT_MAT4: 34032001f49Smrg UniformMatrix4fv(uniforms[i].location, 1, GL_FALSE, 34132001f49Smrg uniforms[i].value); 34232001f49Smrg break; 34332001f49Smrg default: 34432001f49Smrg if (strncmp(uniforms[i].name, "gl_", 3) == 0) { 34532001f49Smrg /* built-in uniform: ignore */ 34632001f49Smrg } 34732001f49Smrg else { 34832001f49Smrg fprintf(stderr, 34932001f49Smrg "Unexpected uniform data type in SetUniformValues\n"); 35032001f49Smrg abort(); 35132001f49Smrg } 35232001f49Smrg } 35332001f49Smrg } 35432001f49Smrg} 35532001f49Smrg 35632001f49Smrg 35732001f49Smrg/** Get list of uniforms used in the program */ 35832001f49SmrgGLuint 35932001f49SmrgGetUniforms(GLuint program, struct uniform_info uniforms[]) 36032001f49Smrg{ 36132001f49Smrg GLint n, max, i; 36232001f49Smrg 36332001f49Smrg GetProgramiv(program, GL_ACTIVE_UNIFORMS, &n); 36432001f49Smrg GetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max); 36532001f49Smrg 36632001f49Smrg for (i = 0; i < n; i++) { 36732001f49Smrg GLint size, len; 36832001f49Smrg GLenum type; 36932001f49Smrg char name[100]; 37032001f49Smrg 37132001f49Smrg glGetActiveUniform(program, i, 100, &len, &size, &type, name); 37232001f49Smrg 37332001f49Smrg uniforms[i].name = strdup(name); 37432001f49Smrg uniforms[i].size = size; 37532001f49Smrg uniforms[i].type = type; 37632001f49Smrg uniforms[i].location = glGetUniformLocation(program, name); 37732001f49Smrg } 37832001f49Smrg 37932001f49Smrg uniforms[i].name = NULL; /* end of list */ 38032001f49Smrg 38132001f49Smrg return n; 38232001f49Smrg} 38332001f49Smrg 38432001f49Smrg 38532001f49Smrgvoid 38632001f49SmrgPrintUniforms(const struct uniform_info uniforms[]) 38732001f49Smrg{ 38832001f49Smrg GLint i; 38932001f49Smrg 39032001f49Smrg printf("Uniforms:\n"); 39132001f49Smrg 39232001f49Smrg for (i = 0; uniforms[i].name; i++) { 39332001f49Smrg printf(" %d: %s size=%d type=0x%x loc=%d value=%g, %g, %g, %g\n", 39432001f49Smrg i, 39532001f49Smrg uniforms[i].name, 39632001f49Smrg uniforms[i].size, 39732001f49Smrg uniforms[i].type, 39832001f49Smrg uniforms[i].location, 39932001f49Smrg uniforms[i].value[0], 40032001f49Smrg uniforms[i].value[1], 40132001f49Smrg uniforms[i].value[2], 40232001f49Smrg uniforms[i].value[3]); 40332001f49Smrg } 40432001f49Smrg} 40532001f49Smrg 40632001f49Smrg 40732001f49Smrg/** Get list of attribs used in the program */ 40832001f49SmrgGLuint 40932001f49SmrgGetAttribs(GLuint program, struct attrib_info attribs[]) 41032001f49Smrg{ 41132001f49Smrg GLint n, max, i; 41232001f49Smrg 41332001f49Smrg GetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &n); 41432001f49Smrg GetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max); 41532001f49Smrg 41632001f49Smrg for (i = 0; i < n; i++) { 41732001f49Smrg GLint size, len; 41832001f49Smrg GLenum type; 41932001f49Smrg char name[100]; 42032001f49Smrg 42132001f49Smrg GetActiveAttrib(program, i, 100, &len, &size, &type, name); 42232001f49Smrg 42332001f49Smrg attribs[i].name = strdup(name); 42432001f49Smrg attribs[i].size = size; 42532001f49Smrg attribs[i].type = type; 42632001f49Smrg attribs[i].location = GetAttribLocation(program, name); 42732001f49Smrg } 42832001f49Smrg 42932001f49Smrg attribs[i].name = NULL; /* end of list */ 43032001f49Smrg 43132001f49Smrg return n; 43232001f49Smrg} 43332001f49Smrg 43432001f49Smrg 43532001f49Smrgvoid 43632001f49SmrgPrintAttribs(const struct attrib_info attribs[]) 43732001f49Smrg{ 43832001f49Smrg GLint i; 43932001f49Smrg 44032001f49Smrg printf("Attribs:\n"); 44132001f49Smrg 44232001f49Smrg for (i = 0; attribs[i].name; i++) { 44332001f49Smrg printf(" %d: %s size=%d type=0x%x loc=%d\n", 44432001f49Smrg i, 44532001f49Smrg attribs[i].name, 44632001f49Smrg attribs[i].size, 44732001f49Smrg attribs[i].type, 44832001f49Smrg attribs[i].location); 44932001f49Smrg } 45032001f49Smrg} 451