4f14c1c2 |
#ifndef GLOBJECT_HPP_
#define GLOBJECT_HPP_
#include <array>
#include <functional>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
#ifndef GLOBJECT_LOADER
#define GLOBJECT_LOADER <GL/glew.h>
#endif
// cppcheck-suppress preprocessorErrorDirective
#include GLOBJECT_LOADER
/// Getters and setters
#define GLOBJECT_GET_(TYPE, NAME, STATIC, CONST) \
TYPE STATIC const & NAME() CONST \
{ \
return NAME##_; \
}
#define GLOBJECT_SET_(TYPE, NAME, STATIC, CONST) \
template<typename Type> \
TYPE STATIC NAME(Type && NAME) \
{ \
auto NAME##_old = std::move (NAME##_); \
NAME##_ = std::forward<Type>(NAME); \
return NAME##_old; \
}
#define GLOBJECT_THREAD(NAME, INIT) \
decltype(NAME) thread_local NAME INIT;
#define GLOBJECT_GET( TYPE, NAME) GLOBJECT_GET_(TYPE, NAME,, const)
#define GLOBJECT_SET( TYPE, NAME) GLOBJECT_SET_(TYPE, NAME,, const)
#define GLOBJECT_GET_THREAD(TYPE, NAME) GLOBJECT_GET_(TYPE, NAME, static,)
#define GLOBJECT_SET_THREAD(TYPE, NAME) GLOBJECT_SET_(TYPE, NAME, static,)
#define GLOBJECT_ACCESS(TYPE, NAME) \
GLOBJECT_GET(TYPE, NAME) \
GLOBJECT_SET(TYPE, NAME)
#define GLOBJECT_ACCESS_THREAD(TYPE, NAME) \
GLOBJECT_GET_THREAD(TYPE, NAME) \
GLOBJECT_SET_THREAD(TYPE, NAME)
/// Debug
#ifndef GLOBJECT_DEBUG
#define GLOBJECT_DEBUG 1
#endif
#if GLOBJECT_DEBUG
#define GLOBJECT_DEBUG_IF(D) if (GLObject::debug() >= D)
#else
#define GLOBJECT_DEBUG_IF(D) if (false)
#endif
/// Class
class GLObject
{
public:
/// Core
using Version = std::array<GLint, 2>;
bool static supported(
Version version_min,
std::string const & extension = {}
);
GLint static get_integer(GLenum name);
GLOBJECT_GET(GLuint, object)
operator GLuint() const { return object(); }
/// Data
template<typename Data>
struct DataTraits;
/// Path
using Path = std::string;
using Paths = std::vector<Path>;
/// Debug
using DebugCallback = std::function<void (std::string const & message)>;
using DebugObjects = std::vector<GLObject *>;
GLOBJECT_ACCESS_THREAD(int, debug)
GLOBJECT_ACCESS_THREAD(DebugCallback, debug_callback)
GLOBJECT_GET_THREAD (DebugObjects, debug_objects)
std::string debug_name() const;
std::string virtual debug_info() const;
std::string static debug_objects_name();
std::string static debug_objects_info();
/// Exceptions
struct Exception : std::runtime_error
{
using std::runtime_error::runtime_error;
};
protected:
/// Special member functions
using GLGenObjects = void (*)(GLsizei n, GLuint * objects);
using GLDeleteObjects = void (*)(GLsizei n, GLuint const * objects);
using GLCreateObject = GLuint (*)();
using GLDeleteObject = void (*)(GLuint);
template<GLCreateObject gl_create_object>
void static gl_create_object_(GLsizei n, GLuint * objects);
template<GLDeleteObject gl_delete_object>
void static gl_delete_object_(GLsizei n, GLuint * objects);
explicit GLObject(
GLGenObjects gl_gen_objects,
GLDeleteObjects gl_delete_objects,
GLenum object_type,
std::string object_label
);
virtual ~GLObject();
GLObject(GLObject && other) noexcept;
GLObject(GLObject const &) = delete;
GLObject & operator=(GLObject &&) = delete;
GLObject & operator=(GLObject const &) = delete;
/// Path
Path static path_prefix_(
Path const & path,
Path const & prefix
);
/// TGA
class TGA
{
public:
using Size = std::array<GLsizei, 2>;
using Data = std::vector<GLubyte>;
explicit TGA(Size size, Data data);
TGA static read (Path const & path);
void write(Path const & path) const;
Size size() const;
Data const & data();
private:
std::string static str_size_(Size size);
void check_header_() const;
void check_data_() const;
private:
// NOLINTNEXTLINE
struct Header : std::array<GLubyte, 18>
{
explicit Header(Size size);
};
Header header_;
Data data_;
};
/// Check
void static check_path_(Path const & path);
void static check_error_(GLenum error);
void static check_supported_(
Version version_min,
std::string const & extension = {}
);
void static check_format_(
GLenum format,
GLenum format_expected
);
void static check_type_(
GLenum type,
GLenum type_expected
);
void static check_internal_format_(
GLenum internal_format
);
/// Fail
[[noreturn]] void fail_action_(std::string const & action) const;
/// String
std::string static str_path_ (Path const & path);
std::string static str_paths_ (Paths const & paths);
std::string static str_enum_ (GLenum name);
std::string static str_error_ (GLenum error);
std::string static str_format_ (GLenum format);
std::string static str_type_ (GLenum type);
std::string static str_internal_format_(GLenum internal_format);
private:
/// Debug
void debug_label_() const;
void static debug_objects_push_back_(GLObject * debug_object);
void static debug_objects_erase_ (GLObject * debug_object);
/// String
std::string static str_object_type_(GLenum object_type);
private:
/// Special member functions
GLDeleteObjects const gl_delete_objects_;
/// Core
auto static constexpr object_pseudo_ = (GLuint)-1;
GLenum const object_type_;
std::string object_label_;
GLuint object_;
/// Debug
int static thread_local debug_;
DebugCallback static thread_local debug_callback_;
DebugObjects static thread_local debug_objects_;
};
/// Special member functions
template<GLObject::GLCreateObject gl_create_object>
void GLObject::gl_create_object_(GLsizei n, GLuint * objects)
{
for (auto i = GLsizei{0}; i < n; ++i)
objects[i] = gl_create_object();
}
template<GLObject::GLDeleteObject gl_delete_object>
void GLObject::gl_delete_object_(GLsizei n, GLuint * objects)
{
for (auto i = GLsizei{0}; i < n; ++i)
gl_delete_object(objects[i]);
}
/// Data
#define GLOBJECT_DATA( \
DATA, \
V1A, \
V2A, \
V1U, \
V2U, \
COLUMNS, \
ROWS, \
ATTRIB, \
UNIFORM, \
SUFFIX, \
FORMAT, \
TYPE, \
INTERNAL_FORMAT, \
VALUE, \
FOR_COLUMNS, \
PLUS_COLUMN, \
PLUS_COLUMN_TIMES_ROWS, \
... \
) \
template<> \
struct GLObject::DataTraits<DATA> \
{ \
auto static constexpr name = #DATA; \
auto static constexpr columns = GLint {COLUMNS}; \
auto static constexpr rows = GLint {ROWS}; \
auto static constexpr format = GLenum{FORMAT}; \
auto static constexpr type = GLenum{TYPE}; \
auto static constexpr internal_format = GLenum{INTERNAL_FORMAT}; \
void static attrib(GLuint index, DATA const & value) \
{ \
GLOBJECT_DEBUG_IF(1) \
check_supported_({V1A, V2A}); \
FOR_COLUMNS \
glVertexAttrib##ATTRIB##SUFFIX( \
index PLUS_COLUMN, \
VALUE PLUS_COLUMN_TIMES_ROWS \
); \
} \
void static uniform(GLint location, DATA const & value) \
{ \
GLOBJECT_DEBUG_IF(1) \
check_supported_({V1U, V2U}); \
glUniform##UNIFORM##SUFFIX( \
location, \
__VA_ARGS__ \
VALUE \
); \
} \
};
// GLOBJECT_DATA(DATA , V1A, V2A, V1U, V2U, COLUMNS, ROWS, ATTRIB, UNIFORM , SUFFIX , FORMAT, TYPE, INTERNAL_FORMAT , VALUE, FOR_COLUMNS , PLUS_COLUMN, PLUS_COLUMN_TIMES_ROWS, ... )
#define GLOBJECT_DATA_SCALAR( DATA, V1A, V2A, V1U, V2U, ATTRIB, SUFFIX, INTERNAL, TYPE ) GLOBJECT_DATA(DATA , V1A, V2A, V1U, V2U, 1 , 1 , ATTRIB, , 1##SUFFIX , GL_RED, TYPE, GL_R ##INTERNAL, value, , , , )
#define GLOBJECT_DATA_VECTOR_N( DATA, V1A, V2A, V1U, V2U, ATTRIB, SUFFIX, INTERNAL, TYPE, VALUE, FORMAT, N ) GLOBJECT_DATA(DATA##N , V1A, V2A, V1U, V2U, 1 , N , ATTRIB, , N##SUFFIX##v, FORMAT, TYPE, FORMAT##INTERNAL, VALUE, , , , 1, )
#define GLOBJECT_DATA_MATRIX_N( DATA, V1A, V2A, V1U, V2U, ATTRIB, SUFFIX, INTERNAL, TYPE, VALUE, TRANSPOSE, FORMAT, N ) GLOBJECT_DATA(DATA##N , V1A, V2A, V1U, V2U, N , N , ATTRIB, Matrix , N##SUFFIX##v, FORMAT, TYPE, FORMAT##INTERNAL, VALUE, for (auto column = GLuint{0}; column < columns; ++column), + column , + (column * rows) , 1, TRANSPOSE,)
#define GLOBJECT_DATA_MATRIX_N_M(DATA, V1A, V2A, V1U, V2U, ATTRIB, SUFFIX, INTERNAL, TYPE, VALUE, TRANSPOSE, FORMAT, N, M) GLOBJECT_DATA(DATA##N##x##M, V1A, V2A, V1U, V2U, N , M , ATTRIB, Matrix##N##x, M##SUFFIX##v, FORMAT, TYPE, FORMAT##INTERNAL, VALUE, for (auto column = GLuint{0}; column < columns; ++column), + column , + (column * rows) , 1, TRANSPOSE,)
#define GLOBJECT_DATA_VECTOR( DATA, V1A, V2A, V1U, V2U, ATTRIB, SUFFIX, INTERNAL, TYPE, VALUE ) \
GLOBJECT_DATA_VECTOR_N( DATA, V1A, V2A, V1U, V2U, ATTRIB, SUFFIX, INTERNAL, TYPE, VALUE, GL_RG, 2 ) \
GLOBJECT_DATA_VECTOR_N( DATA, V1A, V2A, V1U, V2U, ATTRIB, SUFFIX, INTERNAL, TYPE, VALUE, GL_RGB, 3 ) \
GLOBJECT_DATA_VECTOR_N( DATA, V1A, V2A, V1U, V2U, ATTRIB, SUFFIX, INTERNAL, TYPE, VALUE, GL_RGBA, 4 )
#define GLOBJECT_DATA_MATRIX( DATA, ATTRIB, SUFFIX, INTERNAL, TYPE, VALUE, TRANSPOSE ) \
GLOBJECT_DATA_MATRIX_N( DATA, 2, 0, 2, 0, ATTRIB, SUFFIX, INTERNAL, TYPE, VALUE, TRANSPOSE, GL_RG, 2 ) \
GLOBJECT_DATA_MATRIX_N_M( DATA, 2, 0, 2, 1, ATTRIB, SUFFIX, INTERNAL, TYPE, VALUE, TRANSPOSE, GL_RGB, 2, 3) \
GLOBJECT_DATA_MATRIX_N_M( DATA, 2, 0, 2, 1, ATTRIB, SUFFIX, INTERNAL, TYPE, VALUE, TRANSPOSE, GL_RGBA, 2, 4) \
GLOBJECT_DATA_MATRIX_N_M( DATA, 2, 0, 2, 1, ATTRIB, SUFFIX, INTERNAL, TYPE, VALUE, TRANSPOSE, GL_RG, 3, 2) \
GLOBJECT_DATA_MATRIX_N( DATA, 2, 0, 2, 0, ATTRIB, SUFFIX, INTERNAL, TYPE, VALUE, TRANSPOSE, GL_RGB, 3 ) \
GLOBJECT_DATA_MATRIX_N_M( DATA, 2, 0, 2, 1, ATTRIB, SUFFIX, INTERNAL, TYPE, VALUE, TRANSPOSE, GL_RGBA, 3, 4) \
GLOBJECT_DATA_MATRIX_N_M( DATA, 2, 0, 2, 1, ATTRIB, SUFFIX, INTERNAL, TYPE, VALUE, TRANSPOSE, GL_RG, 4, 2) \
GLOBJECT_DATA_MATRIX_N_M( DATA, 2, 0, 2, 1, ATTRIB, SUFFIX, INTERNAL, TYPE, VALUE, TRANSPOSE, GL_RGB, 4, 3) \
GLOBJECT_DATA_MATRIX_N( DATA, 2, 0, 2, 0, ATTRIB, SUFFIX, INTERNAL, TYPE, VALUE, TRANSPOSE, GL_RGBA, 4 )
GLOBJECT_DATA_SCALAR( GLfloat, 2, 0, 2, 0, , f, 32F, GL_FLOAT )
GLOBJECT_DATA_SCALAR( GLbyte, 3, 0, 2, 0, I, i, 8I, GL_BYTE )
GLOBJECT_DATA_SCALAR( GLshort, 3, 0, 2, 0, I, i, 16I, GL_SHORT )
GLOBJECT_DATA_SCALAR( GLint, 3, 0, 2, 0, I, i, 32I, GL_INT )
GLOBJECT_DATA_SCALAR( GLubyte, 3, 0, 3, 0, I, ui, 8UI, GL_UNSIGNED_BYTE )
GLOBJECT_DATA_SCALAR( GLushort, 3, 0, 3, 0, I, ui, 16UI, GL_UNSIGNED_SHORT )
GLOBJECT_DATA_SCALAR( GLuint, 3, 0, 3, 0, I, ui, 32UI, GL_UNSIGNED_INT )
#ifdef GLM_VERSION
#include <glm/gtc/type_ptr.hpp>
GLOBJECT_DATA_VECTOR( glm::vec, 2, 0, 2, 0, , f, 32F, GL_FLOAT, glm::value_ptr(value) )
GLOBJECT_DATA_VECTOR( glm::ivec, 3, 0, 2, 0, I, i, 32I, GL_INT, glm::value_ptr(value) )
GLOBJECT_DATA_VECTOR( glm::uvec, 3, 0, 3, 0, I, ui, 32UI, GL_UNSIGNED_INT, glm::value_ptr(value) )
GLOBJECT_DATA_MATRIX( glm::mat, , f, 32F, GL_FLOAT, glm::value_ptr(value), GL_FALSE )
#endif
#endif // GLOBJECT_HPP_
|