X-Git-Url: https://git.ucc.asn.au/?p=ipdf%2Fcode.git;a=blobdiff_plain;f=src%2Fshaderprogram.cpp;h=68a4767d648f26fc3c5514ac4c3cc8ab1f4dfde2;hp=7ccb9706f542e56da53629c5be4f19f56a3e34d1;hb=0ce8df17fae3ec986bd9570e5552aed92c080088;hpb=a851cf197844a2eb15fd5ee2c350ee296e415dca diff --git a/src/shaderprogram.cpp b/src/shaderprogram.cpp index 7ccb970..68a4767 100644 --- a/src/shaderprogram.cpp +++ b/src/shaderprogram.cpp @@ -1,55 +1,137 @@ #include "shaderprogram.h" +#include "log.h" using namespace IPDF; +/** + * Initialise a shader program using GLSL source files + * @param geometry_file GLSL source for Geometry shader (optional) + * @param vertex_file GLSL source for vertex shader + * @param fragment_file GLSL source for fragment shader + * If a filename is the empty string it will be ignored + */ +bool ShaderProgram::InitialiseShaders(const char * vertex_file, const char * fragment_file, const char * geometry_file) +{ + if (m_valid) + { + Error("Shader already valid?"); + } + m_program = glCreateProgram(); + if (m_program == 0) + { + Error("glCreateProgram failed"); + m_valid = false; + return m_valid; + } + m_valid = true; + if (geometry_file != NULL && geometry_file[0] != '\0') + m_valid &= AttachShader(geometry_file, GL_GEOMETRY_SHADER); + if (vertex_file != NULL && vertex_file[0] != '\0') + m_valid &= AttachShader(vertex_file, GL_VERTEX_SHADER); + if (fragment_file != NULL && fragment_file[0] != '\0') + m_valid &= AttachShader(fragment_file, GL_FRAGMENT_SHADER); + + if (!m_valid) + { + Warn("One or more AttachShader calls failed but we will link the shader anyway"); + } + glLinkProgram(m_program); + return m_valid; +} + + + +/** + * Destroy a shader program + */ ShaderProgram::~ShaderProgram() { - for(auto shader : m_shaders) + m_valid = false; + for(auto shader = m_shaders.begin(); shader != m_shaders.end(); ++shader) { - glDetachShader(m_program, shader.obj); - glDeleteShader(shader.obj); + glDetachShader(m_program, shader->obj); + glDeleteShader(shader->obj); } if (m_program) glDeleteProgram(m_program); } -void ShaderProgram::LazyCreateProgram() +/** + * Get GLSL shader source from a file as a string + * @param src_file filename to get the shader source from + * @returns a char* string allocated with new[] (remember to delete[] it) + */ +char * ShaderProgram::GetShaderSource(const char * src_file) const { - if (!m_program) + char * src = NULL; + FILE * file = fopen(src_file, "r"); + if (file == NULL) { - m_program = glCreateProgram(); + Error("Could not open shader source file \"%s\": %s", src_file, strerror(errno)); + return NULL; } + long start = ftell(file); + + if (fseek(file, 0, SEEK_END) != 0) + { + Error("Couldn't seek to end of file \"%s\": %s", src_file, strerror(errno)); + return NULL; + } + long end = ftell(file); + if (start < 0 || end < 0 || end < start) + { + // I bet that now I've put this message here, it will occur at least once in the life of this code + Error("Insane results from ftell(3) on file \"%s\"", src_file); + return NULL; + } + size_t size = end - start; + src = new char[size+1]; // Warning! Allocation of memory occuring! We might all die! + rewind(file); + if (fread(src, 1,size, file) != size) + { + Error("Error in fread on \"%s\": %s", src_file, strerror(errno)); + fclose(file); + delete [] src; + return NULL; + } + src[size] = '\0'; + fclose(file); + return src; + } -bool ShaderProgram::AttachShader(const char *src, GLenum type) +bool ShaderProgram::AttachShader(const char * src_file, GLenum type) { GLuint shader_obj = glCreateShader(type); + glObjectLabel(GL_SHADER, shader_obj, -1, src_file); + char * src = GetShaderSource(src_file); + if (src == NULL) + { + Error("Couldn't get shader source."); + return false; + } + + glShaderSource(shader_obj, 1, &src, 0); glCompileShader(shader_obj); + int did_compile = 0; + glGetShaderiv(shader_obj, GL_COMPILE_STATUS, &did_compile); + delete [] src; // Oh my goodness memory management is hard guys + if (!did_compile) + { + char info_log[2048]; + + glGetShaderInfoLog(shader_obj, 2048, NULL, info_log); + Error("Shader compile error (file \"%s\"): %s (type %d)", src_file, info_log, type); + return false; + } m_shaders.push_back(Shader{type, shader_obj}); - LazyCreateProgram(); glAttachShader(m_program, shader_obj); return true; } -bool ShaderProgram::AttachVertexProgram(const char *src) -{ - return AttachShader(src, GL_VERTEX_SHADER); -} - -bool ShaderProgram::AttachFragmentProgram(const char *src) -{ - return AttachShader(src, GL_FRAGMENT_SHADER); -} - -bool ShaderProgram::Link() -{ - glLinkProgram(m_program); - return true; -} - const void ShaderProgram::Use() const { glUseProgram(m_program);