Files
wc3re/src/render/ProgramProvider.cc

100 lines
2.4 KiB
C++

#include "common.hh"
#include <glbinding/gl/gl.h>
#include "ProgramProvider.hh"
#include "util.hh"
using namespace gl;
template<>
std::unique_ptr<render::ProgramProvider> Singleton<render::ProgramProvider>::instance{nullptr};
template<>
std::once_flag Singleton<render::ProgramProvider>::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();
}
}