#include "common.hh" #include #include "ProgramProvider.hh" #include "util.hh" using namespace gl; template<> std::unique_ptr Singleton::instance{nullptr}; template<> std::once_flag Singleton::instance_flag{}; namespace render { namespace { class ShaderException : public Exception { public: ShaderException(std::string const& msg) : Exception(msg) { } std::string toString() const override { return "ShaderException: " + msg_; } }; } ProgramProvider::ProgramProvider() { } void shaderCompile_(std::string const& shaderName, ShaderResource& shader) { std::string prog = fileToString("shaders/" + shaderName); const char* const arr[] = {prog.c_str()}; glShaderSource(shader, 1, arr, NULL); glCompileShader(shader); int state; glGetShaderiv(shader, GL_COMPILE_STATUS, &state); if (state == 0) { int logLength; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength); char *log = new char[logLength]; glGetShaderInfoLog(shader, logLength, NULL, log); std::string msg(log); delete[] log; throw ShaderException(msg); } } GLuint ProgramProvider::getProgram(std::string const& vertexShader, std::string const& fragShader) { auto key = make_tuple(vertexShader, fragShader); auto it = programCache_.find(key); if (it != programCache_.end()) return it->second.get(); ShaderResource vs(glCreateShader(GL_VERTEX_SHADER)), fs(glCreateShader(GL_FRAGMENT_SHADER)); shaderCompile_(vertexShader + ".vert", vs); shaderCompile_(fragShader + ".frag", fs); ProgramResource prog(glCreateProgram()); glAttachShader(prog, vs); glAttachShader(prog, fs); glLinkProgram(prog); int state; glGetProgramiv(prog, GL_LINK_STATUS, &state); if (state == 0) { int logLength; glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength); char *log = new char[logLength]; glGetProgramInfoLog(prog, logLength, NULL, log); std::string msg(log); delete[] log; throw ShaderException(msg); } glDetachShader(prog, vs); glDetachShader(prog, fs); std::tie(it, std::ignore) = programCache_.insert(make_pair(key, std::move(prog))); return it->second.get(); } }