100 lines
2.4 KiB
C++
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();
|
|
}
|
|
|
|
}
|