shader.hpp
e0fdd020
 #ifndef GLSHADER_SHADER_HPP
 #define GLSHADER_SHADER_HPP
 
 
 #include <vector>
 #include <string>
67ab19a4
 #include <unordered_map>
e0fdd020
 
 #include <GL/glew.h>
67ab19a4
 #include <glm/glm.hpp>
 #include <glm/gtc/type_ptr.hpp>
e0fdd020
 
 
 class Shader {
 public:
 
4e6bd516
     Shader() : 
     paths_         {},
     name_          {},
     program_       {},
     location_cache_{},
     index_cache_   {}
     { 
     };
 
     
e0fdd020
     Shader(std::vector<std::string> paths, std::string name = "");
     Shader(Shader &&);
     Shader(Shader const &);
     Shader & operator=(Shader &&);
     Shader & operator=(Shader const &);
     ~Shader();
 
     Shader & use();
     Shader & validate();
67ab19a4
     template<typename Value>
d8d951a6
     Shader & uniform(std::string const & name, Value const & value);
     Shader & uniform(std::string const & name, std::string const & buffer_name);
     template<typename Value>
     static void uniform_buffer(
         std::string const & name,
         Value const & value,
         GLenum usage = GL_DYNAMIC_DRAW
     );
     static void uniform_buffer_delete(std::string const & name);
9b9a6722
     static void ubo_delete(std::string const & name);
     GLuint program(){program_;}
e0fdd020
 
 private:
 
67ab19a4
     template<typename Value>
     using StringCache = std::unordered_map<std::string, Value>;
 
d8d951a6
     struct UniformBuffer {
         GLuint buffer;
         GLsizeiptr size;
         GLenum usage;
         GLuint binding;
     };
 
e0fdd020
     void new_();
     void delete_();
     void ensure_current_(
         std::string const & operation,
         std::string const & name = ""
     );
67ab19a4
     GLint uniform_location_(std::string const & name);
d8d951a6
     GLuint uniform_block_index_(std::string const & name);
     static GLuint uniform_buffer_(
         std::string const & name, GLsizeiptr size, GLenum usage
     );
e0fdd020
 
     GLuint program_;
     std::vector<std::string> paths_;
     std::string name_;
67ab19a4
     StringCache<GLint> uniform_location_cache_;
d8d951a6
     StringCache<GLuint> uniform_block_index_cache_;
     static StringCache<UniformBuffer> uniform_buffer_cache_;
     static GLuint uniform_buffer_binding_next_;
e0fdd020
 };
 
 
 #ifdef NDEBUG
     #define GLSHADER_ENSURE_CURRENT(OPERATION, NAME)
 #else
     #define GLSHADER_ENSURE_CURRENT(OPERATION, NAME) \
         ensure_current_(OPERATION, NAME)
 #endif
 
 
d8d951a6
 template<typename Value>
 inline Shader & Shader::uniform(
     std::string const & name, Value const & value
 ) {
     GLSHADER_ENSURE_CURRENT("set uniform block", name);
     uniform_block_index_(name);
     uniform_buffer(name, value);
     uniform(name, name);
     return *this;
 }
 
 
 template<typename Value>
 inline void Shader::uniform_buffer(
     std::string const & name, Value const & value, GLenum usage
 ) {
     glBindBuffer(
         GL_UNIFORM_BUFFER, uniform_buffer_(name, sizeof(value), usage)
     );
     glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(value), &value);
 }
 
 
67ab19a4
 #define GLSHADER_UNIFORM(VALUE_TYPE, CODE) \
     template<> \
     inline Shader & Shader::uniform( \
         std::string const & name, VALUE_TYPE const & value \
     ) { \
         GLSHADER_ENSURE_CURRENT("set uniform", name); \
         CODE; \
         return *this; \
     }
 
 #define GLSHADER_UNIFORM_SCALAR(VALUE_TYPE, GL_TYPE) \
     GLSHADER_UNIFORM( \
         VALUE_TYPE, \
         glUniform1##GL_TYPE( \
             uniform_location_(name), value \
         ) \
     )
 
 #define GLSHADER_UNIFORM_N(N, GLM_VALUE_TYPE, GL_TYPE) \
     GLSHADER_UNIFORM( \
         glm::GLM_VALUE_TYPE##N, \
         glUniform##N##GL_TYPE##v( \
             uniform_location_(name), 1, glm::value_ptr(value) \
         ) \
     )
 
 #define GLSHADER_UNIFORM_N_BOOL(N) \
     GLSHADER_UNIFORM( \
         glm::bvec##N, \
         GLint int_value[N]; \
         for (auto i = 0; i < N; ++i) \
             int_value[i] = value[i]; \
         glUniform##N##iv( \
             uniform_location_(name), 1, &int_value[0] \
         ) \
     )
 
 #define GLSHADER_UNIFORM_MATRIX_N(N) \
     GLSHADER_UNIFORM( \
         glm::mat##N, \
         glUniformMatrix##N##fv( \
             uniform_location_(name), 1, GL_FALSE, glm::value_ptr(value) \
         ) \
     )
 
 #define GLSHADER_UNIFORM_MATRIX_N_M(N, M) \
     GLSHADER_UNIFORM( \
         glm::mat##N##x##M, \
         glUniformMatrix##N##x##M##fv( \
             uniform_location_(name), 1, GL_FALSE, glm::value_ptr(value) \
         ) \
     )
 
 GLSHADER_UNIFORM_SCALAR(bool, i)
 GLSHADER_UNIFORM_SCALAR(int, i)
 GLSHADER_UNIFORM_SCALAR(glm::uint, ui)
 GLSHADER_UNIFORM_SCALAR(float, f)
 GLSHADER_UNIFORM_SCALAR(double, f)
 
 GLSHADER_UNIFORM_N_BOOL(2)
 GLSHADER_UNIFORM_N_BOOL(3)
 GLSHADER_UNIFORM_N_BOOL(4)
 GLSHADER_UNIFORM_N(2, ivec, i)
 GLSHADER_UNIFORM_N(3, ivec, i)
 GLSHADER_UNIFORM_N(4, ivec, i)
 GLSHADER_UNIFORM_N(2, uvec, ui)
 GLSHADER_UNIFORM_N(3, uvec, ui)
 GLSHADER_UNIFORM_N(4, uvec, ui)
 GLSHADER_UNIFORM_N(2, vec, f)
 GLSHADER_UNIFORM_N(3, vec, f)
 GLSHADER_UNIFORM_N(4, vec, f)
 
 GLSHADER_UNIFORM_MATRIX_N(2)
 GLSHADER_UNIFORM_MATRIX_N(3)
 GLSHADER_UNIFORM_MATRIX_N(4)
 
 GLSHADER_UNIFORM_MATRIX_N_M(2, 3)
 GLSHADER_UNIFORM_MATRIX_N_M(2, 4)
 GLSHADER_UNIFORM_MATRIX_N_M(3, 2)
 GLSHADER_UNIFORM_MATRIX_N_M(3, 4)
 GLSHADER_UNIFORM_MATRIX_N_M(4, 2)
 GLSHADER_UNIFORM_MATRIX_N_M(4, 3)
 
 
e0fdd020
 #endif // GLSHADER_SHADER_HPP