#include "renderer.h" #include "../util/util.h" #include #include #define MAX_HASH_SHADER 16 static Shader *shader_hash_table[MAX_HASH_SHADER]; static void CompileShader(const char *source, GLuint shaderID) { glShaderSource(shaderID, 1, &source, 0); glCompileShader(shaderID); GLint error; glGetShaderiv(shaderID, GL_COMPILE_STATUS, &error); if(error != GL_TRUE) { GLint logLenth; glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &logLenth); GLchar buffer[logLenth]; glGetShaderInfoLog(shaderID, logLenth, &logLenth, buffer); glDeleteShader(shaderID); Util_FatalError("Some shader failed to compile:\n%s", buffer); } } Shader *shader_new(const char *name, const char *vertexShaderPath, const char *fragShaderPath) { if(strlen(name) >= MAX_PATH_LENGTH) Util_FatalError("File following shader name is too long: %s", name); Shader *s; s = shader_get(name); if(s != NULL) return s; char *vertexShaderSource = Util_LoadFile(vertexShaderPath); char *fragmentShaderSource = Util_LoadFile(fragShaderPath); GLuint vs = 0, fs = 0, program; vs = glCreateShader(GL_VERTEX_SHADER); fs = glCreateShader(GL_FRAGMENT_SHADER); if(vs == 0 || fs == 0) Util_FatalError("Shaders could not be created\n"); program = glCreateProgram(); CompileShader(vertexShaderSource, vs); CompileShader(fragmentShaderSource, fs); glAttachShader(program, vs); glAttachShader(program, fs); glLinkProgram(program); GLint error; glGetProgramiv(program, GL_LINK_STATUS, &error); if(error != GL_TRUE) { GLint logLength; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength); GLchar buffer[logLength]; glGetProgramInfoLog(program, logLength, &logLength, buffer); glDeleteProgram(program); glDeleteShader(vs); glDeleteShader(fs); Util_FatalError("Shader program failed to link!:\n%s", buffer); } /** Free some usless resources **/ glDetachShader(program, vs); glDetachShader(program, fs); glDeleteShader(vs); glDeleteShader(fs); free(vertexShaderSource); free(fragmentShaderSource); /** Alloc the new texture **/ s = malloc( sizeof(Shader) ); memset(s, 0, sizeof(Shader) ); s->id = program; /** Register inside the resource manager **/ unsigned int hash_ = Util_Hash( name ); hash_ %= MAX_HASH_SHADER; render.shaders[render.num_shaders] = s; render.num_shaders += 1; strcpy(s->name, name); s->_hash_next = shader_hash_table[hash_]; shader_hash_table[hash_] = s; s->_hash = hash_; /** Return the final result **/ return s; } Shader *shader_get(const char *name) { Shader *s; unsigned int hash_ = Util_Hash( name ); hash_ %= MAX_HASH_SHADER; if(shader_hash_table[hash_] != NULL) { for(s = shader_hash_table[hash_]; s; s = s->_hash_next) { if( s->_hash == hash_ ) return s; } } return NULL; } void shader_purge(Shader *shader) { /** Purge the opengl data **/ if(shader->id != 0) { glUseProgram(0); glDeleteProgram(shader->id); shader->id = 0; } } GLint shader_get_uniform_location( Shader *s, const char *uniformName ) { GLint u = glGetUniformLocation(s->id, uniformName); if(u == GL_INVALID_INDEX) Util_FatalError("Uniform \"%s\" could not be found!", uniformName); else return u; return 0; } GLint shader_get_attrib_location( Shader *s, const char *attributeName ) { GLint attrLocation = glGetAttribLocation(s->id, attributeName); if(attrLocation < 0) Util_FatalError("Attribute \"%s\" could not be found!\n", attributeName); return attrLocation; } void shader_set_uniform_mat4( Shader *s, const char *name, const float matrix[16] ) { GLint location = shader_get_uniform_location(s, name); glUniformMatrix4fv(location, 1, GL_FALSE, matrix); } void shader_set_uniform_float( Shader *s, const char *name, const float val ) { GLint location = shader_get_uniform_location(s, name); glUniform1f(location, val); } void shader_set_uniform_vec2( Shader *s, const char *name, const float vec[2] ) { GLint location = shader_get_uniform_location(s, name); glUniform2fv(location, 1, vec); } void shader_set_uniform_vec3( Shader *s, const char *name, const float vec[3] ) { GLint location = shader_get_uniform_location(s, name); glUniform3fv(location, 1, vec); } void shader_set_uniform_vec4( Shader *s, const char *name, const float vec[4] ) { GLint location = shader_get_uniform_location(s, name); glUniform4fv(location, 1, vec); } void shader_set_uniform_int( Shader *s, const char *name, const int val ) { GLint location = shader_get_uniform_location(s, name); glUniform1i(location, val); }