Exponent/src/GLProgramLoader.cc

88 lines
2.7 KiB
C++
Raw Normal View History

#include "GLProgramLoader.hh"
#include <exception>
#include <format>
#include <fstream>
#include <sstream>
static GLuint compile_shader(GLenum shader_type, const std::string &path) {
if (shader_type != GL_VERTEX_SHADER && shader_type != GL_FRAGMENT_SHADER) {
throw GLProgramException(std::format("Unsupported shader type {} provided.", shader_type));
}
// Check that the path actually exists
std::ifstream shader_file_handle;
shader_file_handle.open(path);
if (!shader_file_handle.is_open()) {
throw GLProgramException(std::format("Failed to open path {}.", path));
}
// Read the data in.
std::stringstream shader_source_stream;
shader_source_stream << shader_file_handle.rdbuf();
std::string shader_source_str = shader_source_stream.str();
const GLchar *shader_source = shader_source_str.c_str();
2024-05-14 20:48:33 +00:00
shader_file_handle.close();
GLuint shader_id = glCreateShader(shader_type);
if (shader_id == 0) {
throw GLProgramException(std::format("Error when creating shader type {}.", shader_type));
}
glShaderSource(shader_id, 1, &shader_source, NULL);
glCompileShader(shader_id);
GLint did_compile;
glGetShaderiv(shader_id, GL_COMPILE_STATUS, &did_compile);
if(!did_compile) {
GLint len = 0;
glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &len);
std::string error_log(len, ' ');
glGetShaderInfoLog(shader_id, len, &len, error_log.data());
glDeleteShader(shader_id);
throw GLProgramException(std::format("Shader {} compilation failed:\n{}", path, error_log));
}
return shader_id;
}
GLuint compile_and_link_program(const std::vector<std::pair<GLuint, std::string>> &shaders) {
// Firstly, compile all the shaders and get all of their ids.
// I would love to use a functional map here, but C++ doesn't really do that.
std::vector<GLuint> shader_ids = {};
for(auto &s:shaders) {
shader_ids.push_back(compile_shader(s.first, s.second));
}
GLuint program_id = glCreateProgram();
for (auto &s:shader_ids) {
glAttachShader(program_id, s);
}
glLinkProgram(program_id);
GLint link_worked;
glGetProgramiv(program_id, GL_LINK_STATUS, &link_worked);
if (!link_worked) {
GLint len = 0;
glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &len);
std::string error_log(len, ' ');
glGetProgramInfoLog(program_id, len, &len, error_log.data());
glDeleteProgram(program_id);
throw GLProgramException(std::format("Program {} link failed:\n{}", program_id, error_log));
}
for (auto &s:shader_ids) {
glDeleteShader(s);
}
return program_id;
}