aboutsummaryrefslogtreecommitdiffstats
path: root/yage/base/glslprogram.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'yage/base/glslprogram.cpp')
-rw-r--r--yage/base/glslprogram.cpp162
1 files changed, 162 insertions, 0 deletions
diff --git a/yage/base/glslprogram.cpp b/yage/base/glslprogram.cpp
new file mode 100644
index 00000000..cff84e40
--- /dev/null
+++ b/yage/base/glslprogram.cpp
@@ -0,0 +1,162 @@
+/* ----------------------------------------------------------------------------
+ * glslprogram.cpp
+ *
+ * Copyright (c) 2017 Yann Herklotz Grave <ymherklotz@gmail.com> -- MIT License
+ * See file LICENSE for more details
+ * ----------------------------------------------------------------------------
+ */
+
+#include "glslprogram.h"
+
+#include <fstream>
+#include <stdexcept>
+#include <vector>
+
+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<GLchar> 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<GLchar> 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