2024-05-06 17:14:17 +00:00
|
|
|
#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();
|
|
|
|
|
2024-05-06 17:14:17 +00:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2024-05-14 20:48:49 +00:00
|
|
|
for (auto &s:shader_ids) {
|
|
|
|
glDeleteShader(s);
|
|
|
|
}
|
|
|
|
|
2024-05-06 17:14:17 +00:00
|
|
|
return program_id;
|
2024-05-14 20:48:49 +00:00
|
|
|
}
|