#include "GLProgramLoader.hh" #include #include #include #include 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(); 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> &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 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; }