From 60072c1d8089ffd3294e76636198d14710be95b8 Mon Sep 17 00:00:00 2001 From: Yann Herklotz Date: Sat, 9 Sep 2017 07:55:22 +0100 Subject: Restructuring --- yage/base/glslprogram.cpp | 162 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 yage/base/glslprogram.cpp (limited to 'yage/base/glslprogram.cpp') diff --git a/yage/base/glslprogram.cpp b/yage/base/glslprogram.cpp new file mode 100644 index 00000000..11a3191e --- /dev/null +++ b/yage/base/glslprogram.cpp @@ -0,0 +1,162 @@ +/* ---------------------------------------------------------------------------- + * glslprogram.cpp + * + * Copyright (c) 2017 Yann Herklotz Grave -- MIT License + * See file LICENSE for more details + * ---------------------------------------------------------------------------- + */ + +#include + +#include +#include +#include + +namespace yage +{ + +GlslProgram::~GlslProgram() +{ + // cleanup all the shaders and the program + if (fragment_shader_id_ != 0) { + glDeleteShader(fragment_shader_id_); + } + + if (vertex_shader_id_ != 0) { + glDeleteShader(vertex_shader_id_); + } + + if (program_id_ != 0) { + glDeleteProgram(program_id_); + } +} + +void GlslProgram::compileShader(const GLuint &shader, + const std::string &file_path) +{ + // get a string with the input from the shader file + std::ifstream file(file_path); + if (!file.is_open()) { + throw std::runtime_error("Failed to open '" + file_path + "'"); + } + + std::string content = ""; + std::string line; + + while (std::getline(file, line)) { + content += line + "\n"; + } + file.close(); + + // cast source to a c string to get the address of it and input it for + // compilation + const auto *vertex_source = (const GLchar *)content.c_str(); + glShaderSource(shader, 1, &vertex_source, nullptr); + glCompileShader(shader); + + // check if compilation was successful + GLint is_compiled = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, (int *)&is_compiled); + + // if it isn't compiled throw exception to clean up + if (is_compiled == GL_FALSE) { + GLint max_length = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &max_length); + + std::vector error_log(max_length); + glGetShaderInfoLog(shader, max_length, &max_length, &error_log[0]); + std::string error_log_str((const char *)&error_log[0]); + + throw std::runtime_error("Couldn't compile " + file_path + " : " + + error_log_str); + } +} + +void GlslProgram::compileShaders(const std::string &vertex_shader_path, + const std::string &fragment_shader_path) +{ + // create the program that will be run on GPU + program_id_ = glCreateProgram(); + + // create vertex shader + vertex_shader_id_ = glCreateShader(GL_VERTEX_SHADER); + if (vertex_shader_id_ == 0) { + throw std::runtime_error("Vertex shader failed to be created"); + } + + // create fragment shader + fragment_shader_id_ = glCreateShader(GL_FRAGMENT_SHADER); + if (fragment_shader_id_ == 0) { + throw std::runtime_error("Fragment shader failed to be created"); + } + + // compile the two shaders + compileShader(vertex_shader_id_, vertex_shader_path); + compileShader(fragment_shader_id_, fragment_shader_path); +} + +void GlslProgram::linkShaders() +{ + // attach the shaders that we want + glAttachShader(program_id_, vertex_shader_id_); + glAttachShader(program_id_, fragment_shader_id_); + + // link our program + glLinkProgram(program_id_); + + GLint is_linked = 0; + glGetProgramiv(program_id_, GL_LINK_STATUS, (int *)&is_linked); + if (is_linked == GL_FALSE) { + GLint max_length = 0; + glGetProgramiv(program_id_, GL_INFO_LOG_LENGTH, &max_length); + + std::vector error_log(max_length); + glGetProgramInfoLog(program_id_, max_length, &max_length, + &error_log[0]); + + std::string error_log_str((const char *)&error_log[0]); + + throw std::runtime_error("Could not link program : " + error_log_str); + } + + // detach shaders after successful link + glDetachShader(program_id_, fragment_shader_id_); + glDetachShader(program_id_, vertex_shader_id_); + + // we can then delete the shaders once we have the program + glDeleteShader(fragment_shader_id_); + glDeleteShader(vertex_shader_id_); +} + +void GlslProgram::addAttribute(const std::string &attribute_name) +{ + glBindAttribLocation(program_id_, attribute_index_++, + attribute_name.c_str()); +} + +GLint GlslProgram::getUniformLocation(const std::string &uniform_name) +{ + GLint location = glGetUniformLocation(program_id_, uniform_name.c_str()); + if ((GLuint)location == GL_INVALID_INDEX) { + throw std::runtime_error("'" + uniform_name + "' not found"); + } + return location; +} + +void GlslProgram::use() +{ + glUseProgram(program_id_); + for (int i = 0; i < attribute_index_; ++i) { + glEnableVertexAttribArray(i); + } +} + +void GlslProgram::unuse() +{ + for (int i = 0; i < attribute_index_; ++i) { + glDisableVertexAttribArray(i); + } + glUseProgram(0); +} + +} // namespace yage -- cgit