include/glshader.hpp
fa2758de
 #ifndef GLSHADER_SHADER_HPP_
 #define GLSHADER_SHADER_HPP_
 
 
772e8338
 #include <map>
fa2758de
 #include <set>
 #include <string>
7583d2da
 #include <unordered_map>
fa2758de
 
 #include <GL/glew.h>
 
 
 class Shader
 {
 public:
 
     using Paths = std::set<std::string>;
 
     explicit Shader(Paths const & paths);
     virtual ~Shader();
     Shader(Shader &&) noexcept;
     Shader(Shader const &) = delete;
     Shader & operator=(Shader &&) = delete;
     Shader & operator=(Shader const &) = delete;
 
772e8338
     using Defines = std::map<std::string, std::string>;
30b3651e
     using Locations = std::map<std::string, GLuint>;
772e8338
 
fa2758de
     static void root(std::string const & root);
772e8338
     static void defines(Defines const & defines);
30b3651e
     static void verts(Locations const & verts);
     static void frags(Locations const & frags);
fa2758de
 
     GLuint program() const;
 
55f9c41b
     Shader & validate();
9a0c30b8
     Shader & use();
55f9c41b
 
7583d2da
     template<typename Value>
     Shader & uniform(
         std::string const & name,
         Value       const & value,
         bool                required = true
6d54d4c1
     );
     template<typename Value>
     Shader & uniform(
         std::string const & name,
         Value             * value,
         bool                required = true
     ) = delete;
 
     template<typename Value>
     static void uniform_buffer(
         std::string const & name,
         Value       const & value,
         bool                required = true
     );
     template<typename Value>
     static void uniform_buffer(
         std::string const & name,
         Value             * value,
         bool                required = true
7583d2da
     ) = delete;
 
c92d7188
     Shader & texture(
         std::string const & name,
         GLuint              texture,
         GLenum              target,
         bool                required = true
     );
 
fa2758de
 protected:
 
7583d2da
     struct Uniform
     {
         GLint location;
         bool set;
     };
 
6d54d4c1
     struct UniformBuffer
     {
         GLuint buffer;
         GLsizeiptr size;
         GLuint binding;
         bool set;
     };
 
     struct UniformBlock
     {
         UniformBuffer & buffer;
     };
 
55f9c41b
     void validate_() const;
9a0c30b8
     void current_(
         std::string const & error
     ) const;
55f9c41b
 
7583d2da
     static void error_(
         std::string const & error,
         std::string const & error_hint = {}
     );
 
     Uniform * uniform_(
         std::string const & error,
         std::string const & name,
         bool                required
     );
6d54d4c1
     UniformBlock * uniform_block_(
         std::string const & error,
         std::string const & name,
         bool                required,
         GLsizeiptr          size
     );
     static UniformBuffer * uniform_buffer_(
         std::string const & error,
         std::string const & name,
         bool                required,
         GLsizeiptr          size
     );
7583d2da
 
     template<typename Value>
     using ByName = std::unordered_map<std::string, Value>;
 
6d54d4c1
     GLuint                       program_;
     std::string                  program_name_;
     std::string           static root_;
     Defines               static defines_;
     Locations             static verts_;
     Locations             static frags_;
     ByName<Uniform>              uniforms_;
     ByName<UniformBlock>         uniform_blocks_;
     ByName<UniformBuffer> static uniform_buffers_;
fa2758de
 };
 
 
55f9c41b
 // Debug macros.
 
 #ifndef NDEBUG
     #define GLSHADER_DEBUG_(...) __VA_ARGS__
7583d2da
     #define GLSHADER_DEBUG_ERROR_(...) \
         auto error = std::string{} + __VA_ARGS__;
55f9c41b
 #else
     #define GLSHADER_DEBUG_(...)
7583d2da
     #define GLSHADER_DEBUG_ERROR_(...) \
         auto error = std::string{};
55f9c41b
 #endif // NDEBUG
 
 
fa2758de
 // Inline definitions.
 
 #define GLSHADER_SET_(TYPE, NAME) \
     inline void Shader::NAME(TYPE const & NAME) \
     { \
         NAME##_ = NAME; \
     }
 GLSHADER_SET_(std::string, root)
772e8338
 GLSHADER_SET_(Defines, defines)
30b3651e
 GLSHADER_SET_(Locations, verts)
 GLSHADER_SET_(Locations, frags)
fa2758de
 
 inline GLuint Shader::program() const
 {
     return program_;
 }
 
55f9c41b
 inline Shader & Shader::validate()
 {
     GLSHADER_DEBUG_(validate_();)
     return *this;
 }
 
9a0c30b8
 inline Shader & Shader::use()
 {
     glUseProgram(program_);
     return *this;
 }
 
fa2758de
 
6d54d4c1
 // Uniform template definitions.
 
 #define GLSHADER_UNIFORM_BUFFER_(BLOCK_OR_BUFFER, BUFFER, SET) \
     if (auto block_or_buffer = BLOCK_OR_BUFFER( \
         error, name, required, sizeof(value) \
     )) \
     { \
         glBindBuffer(GL_UNIFORM_BUFFER, block_or_buffer->BUFFER); \
         GLSHADER_DEBUG_(error_(error, "unprocessed previous error");) \
         glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(value), &value); \
         GLSHADER_DEBUG_(error_(error);) \
         GLSHADER_DEBUG_(block_or_buffer->SET = true;) \
     }
 
 template<typename Value>
 inline void Shader::uniform_buffer(
     std::string const & name,
     Value       const & value,
     bool                required
 )
 {
     GLSHADER_DEBUG_ERROR_(
         "Failed to set uniform buffer '" + name + "'"
     )
     GLSHADER_UNIFORM_BUFFER_(uniform_buffer_, buffer, set)
 }
 
 template<typename Value>
 inline Shader & Shader::uniform(
     std::string const & name,
     Value       const & value,
     bool                required
 )
 {
     GLSHADER_DEBUG_ERROR_(
         "Failed to set uniform block '" + name + "' of " + program_name_
     )
     GLSHADER_DEBUG_(current_(error);)
     GLSHADER_UNIFORM_BUFFER_(uniform_block_, buffer.buffer, buffer.set)
     return *this;
 }
 
 
7583d2da
 // Uniform template specializations.
 
 #define GLSHADER_UNIFORM_SIGNATURE_(TYPE) \
     template<> \
     inline Shader & Shader::uniform( \
         std::string const & name, \
         TYPE        const & value, \
         bool                required \
     )
 
 #define GLSHADER_UNIFORM_DELETE(TYPE) \
     GLSHADER_UNIFORM_SIGNATURE_(TYPE) = delete;
 
 #define GLSHADER_UNIFORM(TYPE, CODE) \
     GLSHADER_UNIFORM_SIGNATURE_(TYPE) \
     { \
         GLSHADER_DEBUG_ERROR_( \
             "Failed to set uniform '" + name + "' of " + program_name_ \
         ) \
         GLSHADER_DEBUG_(current_(error);) \
         if (auto * uniform = uniform_(error, name, required)) \
         { \
             GLint const & location = uniform->location; \
             GLSHADER_DEBUG_(error_(error, "unprocessed previous error");) \
             CODE \
             GLSHADER_DEBUG_(error_(error, "wrong type?");) \
             GLSHADER_DEBUG_(uniform->set = true;) \
         } \
         return *this; \
     }
 
 
22580999
 // Uniform scalar template specializations.
 
 #define GLSHADER_UNIFORM_SCALAR_(TYPE, SUFFIX) \
     GLSHADER_UNIFORM( \
         TYPE, \
         glUniform1##SUFFIX( \
             location, value \
         ); \
     )
 
 GLSHADER_UNIFORM_SCALAR_(bool,      i)
 GLSHADER_UNIFORM_SCALAR_(GLboolean, i)
 GLSHADER_UNIFORM_SCALAR_(GLint,     i)
 GLSHADER_UNIFORM_SCALAR_(GLuint,    ui)
 GLSHADER_UNIFORM_SCALAR_(GLfloat,   f)
 
 GLSHADER_UNIFORM_DELETE(GLdouble)
 
 
fa2758de
 #endif // GLSHADER_SHADER_HPP_