text: #include "Shader.hpp"
  #include <glm/gtc/type_ptr.hpp>
  #include <fstream>
  #include <sstream>
  
  Shader::Shader(const GLchar *vertexPath, const GLchar *fragmentPath)
  {
      // 1. Retrieve the vertex/fragment source code from filePath
      std::string vertexCode;
      std::string fragmentCode;
      std::ifstream vShaderFile;
      std::ifstream fShaderFile;
      // ensures ifstream objects can throw exceptions:
      vShaderFile.exceptions(std::ifstream::badbit);
      fShaderFile.exceptions(std::ifstream::badbit);
      try {
          // Open files
          vShaderFile.open(vertexPath);
          fShaderFile.open(fragmentPath);
          std::stringstream vShaderStream, fShaderStream;
          // Read file's buffer contents into streams
          vShaderStream << vShaderFile.rdbuf();
          fShaderStream << fShaderFile.rdbuf();
          // close file handlers
          vShaderFile.close();
          fShaderFile.close();
          // Convert stream into string
          vertexCode = vShaderStream.str();
          fragmentCode = fShaderStream.str();
      } catch (std::ifstream::failure e) {
          std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
      }
      const GLchar *vShaderCode = vertexCode.c_str();
      const GLchar *fShaderCode = fragmentCode.c_str();
      // 2. Compile shaders
      GLuint vertex, fragment;
      GLint success;
      GLchar infoLog[512];
      // Vertex Shader
      vertex = glCreateShader(GL_VERTEX_SHADER);
      glShaderSource(vertex, 1, &vShaderCode, NULL);
      glCompileShader(vertex);
      // Print compile errors if any
      glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
      if (!success) {
          glGetShaderInfoLog(vertex, 512, NULL, infoLog);
          std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
      }
      // Fragment Shader
      fragment = glCreateShader(GL_FRAGMENT_SHADER);
      glShaderSource(fragment, 1, &fShaderCode, NULL);
      glCompileShader(fragment);
      // Print compile errors if any
      glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
      if (!success) {
          glGetShaderInfoLog(fragment, 512, NULL, infoLog);
          std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
      }
      // Shader Program
      program_ = glCreateProgram();
      glAttachShader(program_, vertex);
      glAttachShader(program_, fragment);
      glLinkProgram(program_);
      // Print linking errors if any
      glGetProgramiv(program_, GL_LINK_STATUS, &success);
      if (!success) {
          glGetProgramInfoLog(program_, 512, NULL, infoLog);
          std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
      }
      // Delete the shaders as they're linked into our program now and no longer necessery
      glDeleteShader(vertex);
      glDeleteShader(fragment);
  }
  
  void Shader::setUniform(const std::string &name, GLuint x)
  {
      GLint vertexColorLocation = glGetUniformLocation(program_, name.c_str());
      glUniform1i(vertexColorLocation, x);
  }
  
  void Shader::setUniform(const std::string &name, int x)
  {
      GLint vertexColorLocation = glGetUniformLocation(program_, name.c_str());
      glUniform1i(vertexColorLocation, x);
  }
  
  void Shader::setUniform(const std::string &name, float x)
  {
      GLint vertexColorLocation = glGetUniformLocation(program_, name.c_str());
      glUniform1f(vertexColorLocation, x);
  }
  
  void Shader::setUniform(const std::string &name, glm::mat4 trans)
  {
      GLint vertexColorLocation = glGetUniformLocation(program_, name.c_str());
      glUniformMatrix4fv(vertexColorLocation, 1, GL_FALSE, glm::value_ptr(trans));
  }
  
  void Shader::setUniform(const std::string &name, glm::vec3 vec)
  {
      GLint vertexColorLocation = glGetUniformLocation(program_, name.c_str());
      glUniform3f(vertexColorLocation, vec.x, vec.y, vec.z);
  }
  
  void Shader::bind()
  {
      glUseProgram(program_);
  }
  
  void Shader::unbind()
  {
      glUseProgram(0);
  }