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_
|