mirror of
https://github.com/allemangD/toddcox-visualize.git
synced 2025-11-10 12:02:47 -05:00
Add templated wrapper objects
- Shader - Program - Buffer - VertexArray Along with template magic to deduce VertexArray formats - Format, IFormat, LFormat - AutoFormat - Binder - ATTR
This commit is contained in:
48
src/gl/buffer.hpp
Normal file
48
src/gl/buffer.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
template<typename T_>
|
||||
class Buffer {
|
||||
public:
|
||||
using Type = T_;
|
||||
|
||||
private:
|
||||
GLuint id = 0;
|
||||
|
||||
public:
|
||||
Buffer() {
|
||||
glCreateBuffers(1, &id);
|
||||
}
|
||||
|
||||
Buffer(Buffer&& o) noexcept {
|
||||
id = std::exchange(o.id, 0);
|
||||
}
|
||||
|
||||
Buffer(const Buffer&) = delete; // this is doable, but would be slow.
|
||||
|
||||
operator GLuint() const { // NOLINT(google-explicit-constructor)
|
||||
return id;
|
||||
}
|
||||
|
||||
template<typename RandomIt>
|
||||
GLuint upload(RandomIt first, RandomIt last, GLenum mode = GL_STATIC_DRAW) {
|
||||
size_t count = last - first;
|
||||
|
||||
// todo StaticBuffer that uses BufferStorage
|
||||
glNamedBufferData(id, sizeof(Type) * count, nullptr, mode);
|
||||
|
||||
Type* out = (Type*) glMapNamedBuffer(id, GL_WRITE_ONLY);
|
||||
std::copy(first, last, out);
|
||||
glUnmapNamedBuffer(id);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
~Buffer() {
|
||||
// delete silently ignores 0.
|
||||
glDeleteBuffers(1, &id);
|
||||
}
|
||||
};
|
||||
80
src/gl/debug.hpp
Normal file
80
src/gl/debug.hpp
Normal file
@@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
void GLAPIENTRY log_gl_debug_callback(
|
||||
GLenum source,
|
||||
GLenum type,
|
||||
GLuint id,
|
||||
GLenum severity,
|
||||
GLsizei length,
|
||||
const GLchar *message,
|
||||
const void *userParam
|
||||
) {
|
||||
std::string s_source;
|
||||
switch(type){
|
||||
case GL_DEBUG_SOURCE_API:
|
||||
s_source = "API:";
|
||||
case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
|
||||
s_source = "WINDOW:";
|
||||
case GL_DEBUG_SOURCE_SHADER_COMPILER:
|
||||
s_source = "SHADER:";
|
||||
case GL_DEBUG_SOURCE_THIRD_PARTY:
|
||||
s_source = "3P:";
|
||||
case GL_DEBUG_SOURCE_APPLICATION:
|
||||
s_source = "APP:";
|
||||
default:
|
||||
s_source = "";
|
||||
}
|
||||
|
||||
std::string s_type;
|
||||
switch (type) {
|
||||
case GL_DEBUG_TYPE_ERROR:
|
||||
s_type = "ERROR:";
|
||||
break;
|
||||
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
|
||||
s_type = "DEPRECATED:";
|
||||
break;
|
||||
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
|
||||
s_type = "UNDEFINED:";
|
||||
break;
|
||||
case GL_DEBUG_TYPE_PORTABILITY:
|
||||
s_type = "PORTABILITY:";
|
||||
break;
|
||||
case GL_DEBUG_TYPE_PERFORMANCE:
|
||||
s_type = "PERFORMANCE:";
|
||||
break;
|
||||
case GL_DEBUG_TYPE_MARKER:
|
||||
s_type = "MARKER:";
|
||||
break;
|
||||
case GL_DEBUG_TYPE_PUSH_GROUP:
|
||||
s_type = "PUSH_GROUP:";
|
||||
break;
|
||||
case GL_DEBUG_TYPE_POP_GROUP:
|
||||
s_type = "POP_GROUP:";
|
||||
break;
|
||||
default:
|
||||
s_type = "";
|
||||
break;
|
||||
}
|
||||
|
||||
std::string s_severity;
|
||||
switch (severity) {
|
||||
case GL_DEBUG_SEVERITY_HIGH:
|
||||
s_severity = "HIGH:";
|
||||
break;
|
||||
case GL_DEBUG_SEVERITY_MEDIUM:
|
||||
s_severity = "MED:";
|
||||
break;
|
||||
case GL_DEBUG_SEVERITY_LOW:
|
||||
s_severity = "LOW:";
|
||||
break;
|
||||
default:
|
||||
s_severity = "INFO:";
|
||||
break;
|
||||
}
|
||||
|
||||
std::cerr << "GL:" << s_source << s_type << s_severity << " " << message << std::endl;
|
||||
}
|
||||
|
||||
#endif
|
||||
79
src/gl/shader.hpp
Normal file
79
src/gl/shader.hpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
template<GLenum mode>
|
||||
class Shader {
|
||||
public:
|
||||
private:
|
||||
GLuint id = 0;
|
||||
|
||||
public:
|
||||
explicit Shader(const std::string &src) {
|
||||
id = glCreateShader(mode);
|
||||
|
||||
const char *str = src.c_str();
|
||||
glShaderSource(id, 1, &str, nullptr);
|
||||
glCompileShader(id);
|
||||
|
||||
// todo throw if compile failed
|
||||
}
|
||||
|
||||
explicit Shader(std::ifstream source)
|
||||
: Shader(std::string(
|
||||
std::istreambuf_iterator<char>(source),
|
||||
std::istreambuf_iterator<char>()
|
||||
)) {}
|
||||
|
||||
Shader(const Shader &) = delete;
|
||||
|
||||
Shader(Shader &&o) noexcept {
|
||||
id = std::exchange(o.id, 0);
|
||||
}
|
||||
|
||||
~Shader() {
|
||||
glDeleteShader(id);
|
||||
}
|
||||
|
||||
operator GLuint() const { // NOLINT(google-explicit-constructor)
|
||||
return id;
|
||||
}
|
||||
};
|
||||
|
||||
using VertexShader = Shader<GL_VERTEX_SHADER>;
|
||||
using FragmentShader = Shader<GL_FRAGMENT_SHADER>;
|
||||
|
||||
class Program {
|
||||
private:
|
||||
GLuint id = 0;
|
||||
|
||||
public:
|
||||
template<GLenum ...mode>
|
||||
explicit Program(const Shader<mode> &...shader) {
|
||||
id = glCreateProgram();
|
||||
|
||||
(glAttachShader(id, shader), ...);
|
||||
|
||||
glLinkProgram(id);
|
||||
|
||||
// todo throw if link failed
|
||||
}
|
||||
|
||||
Program(const Program &) = delete;
|
||||
|
||||
Program(Program &&o) noexcept {
|
||||
id = std::exchange(o.id, 0);
|
||||
}
|
||||
|
||||
~Program() {
|
||||
glDeleteProgram(id);
|
||||
}
|
||||
|
||||
operator GLuint() const { // NOLINT(google-explicit-constructor)
|
||||
return id;
|
||||
}
|
||||
};
|
||||
113
src/gl/types.hpp
Normal file
113
src/gl/types.hpp
Normal file
@@ -0,0 +1,113 @@
|
||||
#pragma once
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include <Eigen/Eigen>
|
||||
|
||||
template<class T_>
|
||||
struct Buffer;
|
||||
|
||||
template<class ...Fmt_>
|
||||
struct VertexArray;
|
||||
|
||||
|
||||
template<typename ctype, GLenum type, GLint size, GLuint offset = 0, GLboolean norm = GL_FALSE>
|
||||
struct Format {
|
||||
using CType = ctype;
|
||||
static constexpr GLenum Type = type;
|
||||
static constexpr GLint Size = size;
|
||||
static constexpr GLuint Offset = offset;
|
||||
static constexpr GLboolean Norm = norm;
|
||||
|
||||
template<typename ctype_, GLint size_>
|
||||
using As = Format<ctype_, type, size_, offset, norm>;
|
||||
|
||||
static inline constexpr void apply(GLuint vao, GLuint idx) {
|
||||
glEnableVertexArrayAttrib(vao, idx);
|
||||
glVertexArrayAttribFormat(vao, idx, size, type, norm, offset);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ctype, GLenum type, GLint size, GLuint offset = 0>
|
||||
struct IFormat {
|
||||
using CType = ctype;
|
||||
static constexpr GLenum Type = type;
|
||||
static constexpr GLint Size = size;
|
||||
static constexpr GLuint Offset = offset;
|
||||
|
||||
template<typename ctype_, GLint size_>
|
||||
using As = IFormat<ctype_, type, size_, offset>;
|
||||
|
||||
static inline constexpr void apply(GLuint vao, GLuint idx) {
|
||||
glEnableVertexArrayAttrib(vao, idx);
|
||||
glVertexArrayAttribIFormat(vao, idx, size, type, offset);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ctype, GLenum type, GLint size, GLuint offset = 0>
|
||||
struct LFormat {
|
||||
using CType = ctype;
|
||||
static constexpr GLenum Type = type;
|
||||
static constexpr GLint Size = size;
|
||||
static constexpr GLuint Offset = offset;
|
||||
|
||||
template<typename ctype_, GLint size_>
|
||||
using As = LFormat<ctype_, type, size_, offset>;
|
||||
|
||||
static inline constexpr void apply(GLuint vao, GLuint idx) {
|
||||
glEnableVertexArrayAttrib(vao, idx);
|
||||
glVertexArrayAttribLFormat(vao, idx, size, type, offset);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Fmt_>
|
||||
struct AutoFormat {
|
||||
using Fmt = Fmt_;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct AutoFormat<double> {
|
||||
using Fmt = LFormat<double, GL_DOUBLE, 1>;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct AutoFormat<float> {
|
||||
using Fmt = Format<float, GL_FLOAT, 1>;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct AutoFormat<int> {
|
||||
using Fmt = IFormat<int, GL_INT, 1>;
|
||||
};
|
||||
|
||||
template<typename Scalar, int Dim>
|
||||
struct AutoFormat<Eigen::Vector<Scalar, Dim>> {
|
||||
static_assert((Dim >= 1) && (Dim <= 4), "Dim must be in range 1-4");
|
||||
|
||||
using Fmt = typename AutoFormat<Scalar>::Fmt::template As<Eigen::Vector<Scalar, Dim>, Dim>;
|
||||
};
|
||||
|
||||
template<typename Fmt_>
|
||||
struct Binder {
|
||||
using CType = typename AutoFormat<Fmt_>::Fmt::CType;
|
||||
|
||||
const GLuint buf;
|
||||
const GLuint offset;
|
||||
const GLuint stride;
|
||||
|
||||
Binder(const Buffer<CType> &buf) // NOLINT(google-explicit-constructor)
|
||||
: buf((GLuint) buf), offset(0), stride(sizeof(CType)) {}
|
||||
|
||||
template<typename CType_>
|
||||
Binder(const Buffer<CType_> &buf, GLuint offset)
|
||||
: buf((GLuint) buf), offset(offset), stride(sizeof(CType_)) {}
|
||||
|
||||
Binder(const Binder<Fmt_> &o)
|
||||
: buf(o.buf), offset(o.offset), stride(o.stride) {}
|
||||
|
||||
inline void bind(GLuint vao, GLuint idx) const {
|
||||
glVertexArrayVertexBuffer(vao, idx, buf, offset, stride);
|
||||
}
|
||||
};
|
||||
|
||||
#define ATTR(buf, field) Binder<decltype(decltype(buf)::Type::field)>(buf, offsetof(decltype(buf)::Type, field))
|
||||
67
src/gl/vertexarray.hpp
Normal file
67
src/gl/vertexarray.hpp
Normal file
@@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "buffer.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
template<typename ...Fmt_>
|
||||
class VertexArray {
|
||||
public:
|
||||
template<size_t idx>
|
||||
using Fmt = std::tuple_element_t<idx, std::tuple<Fmt_...>>;
|
||||
|
||||
private:
|
||||
GLuint id = 0;
|
||||
|
||||
template<size_t ...idx>
|
||||
inline void formatall(
|
||||
std::integer_sequence<size_t, idx...>
|
||||
) {
|
||||
(AutoFormat<Fmt_>::Fmt::apply(id, idx), ...);
|
||||
}
|
||||
|
||||
template<size_t ...idx>
|
||||
inline void bindall(
|
||||
const Binder<Fmt_> &...buf,
|
||||
std::integer_sequence<size_t, idx...>
|
||||
) {
|
||||
(buf.bind(id, idx), ...);
|
||||
}
|
||||
|
||||
public:
|
||||
explicit VertexArray() {
|
||||
glCreateVertexArrays(1, &id);
|
||||
formatall(std::make_index_sequence<sizeof...(Fmt_)>());
|
||||
}
|
||||
|
||||
explicit VertexArray(const Binder<Fmt_> &...buf)
|
||||
: VertexArray() {
|
||||
bind(buf...);
|
||||
}
|
||||
|
||||
VertexArray(VertexArray &&o) noexcept {
|
||||
id = std::exchange(o.id, 0);
|
||||
}
|
||||
|
||||
VertexArray(const VertexArray &) = delete; // this is doable, but would be slow.
|
||||
|
||||
~VertexArray() {
|
||||
glDeleteVertexArrays(1, &id);
|
||||
}
|
||||
|
||||
operator GLuint() const { // NOLINT(google-explicit-constructor)
|
||||
return id;
|
||||
}
|
||||
|
||||
void bind(const Binder<Fmt_> &...buf) {
|
||||
bindall(buf..., std::make_index_sequence<sizeof...(Fmt_)>());
|
||||
}
|
||||
|
||||
template<size_t idx>
|
||||
void bind(const Binder<Fmt<idx>> &buf) {
|
||||
buf.bind(id, idx);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user