Huge graphics overhaul
This commit is contained in:
+129
-153
@@ -4,7 +4,6 @@
|
||||
|
||||
#include "GLLoad.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <NBCore/Errors.hpp>
|
||||
@@ -17,145 +16,113 @@ namespace nb {
|
||||
|
||||
extern const std::unordered_map<GLenum, std::string> BufferTypes;
|
||||
|
||||
template<GLenum N>
|
||||
struct GLSLEnum;
|
||||
template<typename T>
|
||||
struct GLSLType;
|
||||
|
||||
#define GLSLTypeTraits(type_, size_, value_) \
|
||||
template<>\
|
||||
struct GLSLEnum<value_> {\
|
||||
using type = type_;\
|
||||
static constexpr size_t size = size_;\
|
||||
static constexpr GLenum value=value_;\
|
||||
};\
|
||||
template<>\
|
||||
struct GLSLType<type_> {\
|
||||
using type = type_;\
|
||||
static constexpr size_t size = size_;\
|
||||
static constexpr GLenum value=value_;\
|
||||
};
|
||||
|
||||
#define GLSLTypeEquivalence(original, newtype) \
|
||||
template<>\
|
||||
struct GLSLType<newtype> : public GLSLType<original> {};
|
||||
|
||||
GLSLTypeTraits(uint8_t, 1, GL_UNSIGNED_BYTE);
|
||||
GLSLTypeTraits(uint16_t, 2, GL_UNSIGNED_SHORT);
|
||||
GLSLTypeTraits(uint32_t, 4, GL_UNSIGNED_INT);
|
||||
GLSLTypeTraits(int8_t, 1, GL_BYTE);
|
||||
GLSLTypeTraits(int16_t, 2, GL_SHORT);
|
||||
GLSLTypeTraits(int32_t, 4, GL_INT);
|
||||
GLSLTypeTraits(float, 4, GL_FLOAT);
|
||||
GLSLTypeTraits(double, 8, GL_DOUBLE);
|
||||
|
||||
class BufferError : public Error<BufferError> {
|
||||
protected:
|
||||
using Base = Error<BufferError>;
|
||||
using Base::Base;
|
||||
|
||||
|
||||
public:
|
||||
using Base::Base;
|
||||
enum Codes : unsigned int {
|
||||
UNDEFINED,
|
||||
DATA_OVERFLOW,
|
||||
INVALID_BUFFER,
|
||||
HANDLE_OVERWRITE,
|
||||
DATA_ERROR
|
||||
};
|
||||
static const std::string type;
|
||||
static const ErrorCodeMap ErrorMessages;
|
||||
};
|
||||
|
||||
template <typename BufferType>
|
||||
class Buffer : public OpenGLObject {
|
||||
using Codes = BufferError::Codes;
|
||||
|
||||
public:
|
||||
using OpenGLObject::OpenGLObject;
|
||||
Buffer() = default;
|
||||
Buffer(Buffer&& other) {
|
||||
*this = std::move(other);
|
||||
}
|
||||
Buffer& operator=(Buffer&& rhs) {
|
||||
auto targ_name = BufferTypes.at(Target);
|
||||
if (Target != rhs.Target) {
|
||||
THROW(BufferError(
|
||||
Codes::INVALID_BUFFER,
|
||||
"w/ ("+targ_name+") := ("+BufferTypes.at(rhs.Target)+")"
|
||||
));
|
||||
}
|
||||
//nb::logger.log(std::to_string(_id) + ":=" + std::to_string(rhs._id));
|
||||
if (_id) {
|
||||
THROW(BufferError(
|
||||
Codes::HANDLE_OVERWRITE,
|
||||
"w/ BufferType = " + targ_name
|
||||
));
|
||||
}
|
||||
_id = rhs._id;
|
||||
_usage = rhs._usage;
|
||||
_size = rhs._size;
|
||||
|
||||
rhs._id = 0;
|
||||
rhs._usage = GL_STATIC_DRAW;
|
||||
rhs._size = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual void bind() const override {
|
||||
if (_id) {
|
||||
glBindBuffer(Target, _id);
|
||||
} else {
|
||||
WARN(BufferError(
|
||||
Codes::INVALID_BUFFER,
|
||||
"w/ BufferType " + BufferTypes.at(Target)
|
||||
), 0xFE);
|
||||
}
|
||||
}
|
||||
virtual void unbind() const override { glBindBuffer(Target, 0); }
|
||||
virtual GLenum usage() const { return _usage; }
|
||||
virtual GLenum usage(GLenum usage_) {
|
||||
_usage = usage_;
|
||||
data(data(), _usage);
|
||||
return _usage;
|
||||
}
|
||||
virtual size_t size() const { return _size; }
|
||||
virtual ByteVector data() const {
|
||||
bind();
|
||||
ByteVector ret(_size);
|
||||
glGetBufferSubData(Target, 0, _size, ret.data());
|
||||
return ret;
|
||||
}
|
||||
virtual void data(
|
||||
const void* data_,
|
||||
GLsizei size_,
|
||||
GLenum usage_=GL_STATIC_DRAW
|
||||
) {
|
||||
declare();
|
||||
bind();
|
||||
glBufferData(Target, size_, data_, usage_);
|
||||
_size = size_;
|
||||
_usage = usage_;
|
||||
}
|
||||
virtual void data(const ByteVector& data_, GLenum usage_=GL_STATIC_DRAW) {
|
||||
data(data_.data(), data_.size(), usage_);
|
||||
|
||||
}
|
||||
virtual void subdata(void* data_, GLsizeiptr size_, GLintptr offset_=0) {
|
||||
bind();
|
||||
if (offset_+size_ <= _size) {
|
||||
THROW(BufferError(BufferError::Codes::DATA_OVERFLOW));
|
||||
}
|
||||
glBufferSubData(Target, offset_, size_, data_);
|
||||
}
|
||||
virtual void subdata(ByteVector& data_, GLintptr offset_=0) {
|
||||
bind();
|
||||
size_t size_ = data_.size();
|
||||
if (offset_+size_ <= _size) {
|
||||
THROW(BufferError(BufferError::Codes::DATA_OVERFLOW));
|
||||
}
|
||||
glBufferSubData(Target, offset_, data_.size(), data_.data());
|
||||
}
|
||||
// virtual void clear() const { glClearBufferData(Target, ) }
|
||||
static const GLenum Target;
|
||||
|
||||
protected:
|
||||
using Codes = BufferError::Codes;
|
||||
using OpenGLObject::_id;
|
||||
GLenum _usage = GL_STATIC_DRAW;
|
||||
size_t _size;
|
||||
Buffer(GLenum target) : Target(target) {}
|
||||
virtual GLuint declare() override {
|
||||
if (!_id) {
|
||||
glGenBuffers(1, &_id);
|
||||
}
|
||||
bind();
|
||||
return _id;
|
||||
}
|
||||
virtual void remove() override {
|
||||
if (_id) {
|
||||
unbind();
|
||||
glDeleteBuffers(1, &_id);
|
||||
_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
const GLenum Target;
|
||||
using OpenGLObject::OpenGLObject;
|
||||
Buffer(Buffer&& other);
|
||||
Buffer& operator=(Buffer&& rhs);
|
||||
|
||||
virtual void bind() const override {
|
||||
if (_id) {
|
||||
glBindBuffer(Target, _id);
|
||||
} else {
|
||||
THROW(OGLError(
|
||||
OGLError::Codes::INVALID_OBJECT,
|
||||
"w/ BufferType " + BufferTypes.at(Target)
|
||||
));
|
||||
}
|
||||
}
|
||||
virtual void unbind() const override { glBindBuffer(Target, 0); }
|
||||
GLenum usage() const;
|
||||
size_t size() const;
|
||||
ByteVector data() const;
|
||||
|
||||
void data(const ByteVector& data, GLenum usage=GL_STATIC_DRAW);
|
||||
void data(const void* data, size_t size, GLenum usage=GL_STATIC_DRAW);
|
||||
void subdata(const void* data, size_t size, GLintptr offset=0);
|
||||
void subdata(const ByteVector& data_, GLintptr offset=0);
|
||||
// virtual void clear() const { glClearBufferData(Target, ) }
|
||||
|
||||
};
|
||||
|
||||
template<typename BufferType>
|
||||
const GLenum Buffer<BufferType>::Target = BufferType::Target;
|
||||
|
||||
template <typename BufferType>
|
||||
class ImmutableBuffer : public virtual Buffer<BufferType> {
|
||||
/* template <typename BufferType>
|
||||
class ImmutableBuffer : public virtual Buffer {
|
||||
public:
|
||||
using Base = Buffer<BufferType>;
|
||||
using Base::Target;
|
||||
using Base::bind;
|
||||
|
||||
ImmutableBuffer() = default;
|
||||
ImmutableBuffer(size_t size_, GLenum usage_ = GL_STATIC_DRAW, GLbitfield flags_=0x0) : size(size_), Base::usage(usage_) {
|
||||
ImmutableBuffer(
|
||||
size_t size_,
|
||||
GLenum usage_ = GL_STATIC_DRAW,
|
||||
GLbitfield flags_=0x0
|
||||
) : size(size_), Base::usage(usage_) {
|
||||
glBufferStorage(Target, size, nullptr, flags_);
|
||||
}
|
||||
|
||||
@@ -177,63 +144,72 @@ class ImmutableBuffer : public virtual Buffer<BufferType> {
|
||||
const size_t size;
|
||||
|
||||
protected:
|
||||
using Base::_id;
|
||||
std::shared_ptr<void> _map = nullptr;
|
||||
GLbitfield _mapAccess = 0;
|
||||
|
||||
}; */
|
||||
|
||||
class ArrayBuffer : public Buffer {
|
||||
public:
|
||||
template<typename T>
|
||||
ArrayBuffer(const std::vector<T>& data, GLenum usage=GL_STATIC_DRAW)
|
||||
: Buffer(GL_ARRAY_BUFFER) {
|
||||
Buffer::data(vectorToBytes(data), usage);
|
||||
}
|
||||
};
|
||||
|
||||
template<bool Immutable=false>
|
||||
class ArrayBuffer : public Buffer<ArrayBuffer<false>> {
|
||||
using Base = Buffer<ArrayBuffer<false>>;
|
||||
using BufferType = Base;
|
||||
|
||||
public:
|
||||
using Base::Base;
|
||||
using Base::data;
|
||||
ArrayBuffer(const ByteVector&, GLenum usage_=GL_STATIC_DRAW);
|
||||
|
||||
static const GLenum Target = GL_ARRAY_BUFFER;
|
||||
|
||||
class ElementBuffer : protected Buffer {
|
||||
protected:
|
||||
using Base::_usage;
|
||||
};
|
||||
|
||||
template <>
|
||||
class ArrayBuffer<true>
|
||||
: public virtual ArrayBuffer<false>, public virtual ImmutableBuffer<ArrayBuffer<true>> {
|
||||
using Base = ArrayBuffer<false>;
|
||||
using BufferType = ImmutableBuffer<ArrayBuffer<true>>;
|
||||
using BufferType::BufferType;
|
||||
|
||||
GLenum _glslType;
|
||||
size_t _typeSize;
|
||||
|
||||
public:
|
||||
using Base::Target;
|
||||
|
||||
};
|
||||
|
||||
template<bool Immutable=false>
|
||||
class ElementBuffer : public Buffer<ElementBuffer<false>> {
|
||||
using Base = Buffer<ElementBuffer<false>>;
|
||||
using BufferType = Base;
|
||||
using Buffer::Target;
|
||||
using Buffer::bind;
|
||||
using Buffer::usage;
|
||||
using Buffer::unbind;
|
||||
ElementBuffer();
|
||||
template<typename T>
|
||||
ElementBuffer(const T* const data_ptr, size_t size, GLenum usage=GL_STATIC_DRAW)
|
||||
: Buffer(GL_ELEMENT_ARRAY_BUFFER) {
|
||||
data(data_ptr, size, usage);
|
||||
}
|
||||
template<typename T>
|
||||
ElementBuffer(const std::vector<T>& data_, GLenum usage_=GL_STATIC_DRAW)
|
||||
: ElementBuffer(data_.data(), data_.size(), usage_) {}
|
||||
|
||||
public:
|
||||
using Base::Base;
|
||||
static const GLenum Target = GL_ELEMENT_ARRAY_BUFFER;
|
||||
size_t size() const;
|
||||
size_t typeSize() const;
|
||||
ByteVector data() const;
|
||||
GLenum glslType() const;
|
||||
template<typename T>
|
||||
void data(const T* data_, size_t size_, GLenum usage_=GL_STATIC_DRAW) {
|
||||
declare();
|
||||
using TypeInfo = GLSLType<T>;
|
||||
_typeSize = TypeInfo::size;
|
||||
Buffer::data(data_, size_*_typeSize, usage_);
|
||||
_glslType = TypeInfo::value;
|
||||
}
|
||||
template<typename T>
|
||||
void data(const std::vector<T>& data_, GLenum usage_=GL_STATIC_DRAW) {
|
||||
data(data_.data(), data_.size(), usage_);
|
||||
}
|
||||
template<typename T>
|
||||
void subdata(const T* data, size_t size, size_t offset) {
|
||||
using TypeInfo = GLSLType<T>;
|
||||
if ( _glslType != TypeInfo::value ) {
|
||||
THROW( BufferError(
|
||||
Codes::DATA_ERROR,
|
||||
"Check element buffer data types"
|
||||
) );
|
||||
}
|
||||
Buffer::subdata(data, size*_typeSize, offset);
|
||||
}
|
||||
template<typename T>
|
||||
void subdata(const std::vector<T>& data, size_t offset=0) {
|
||||
subdata(data.data(), data.size(), offset);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
};
|
||||
|
||||
template <>
|
||||
class ElementBuffer<true>
|
||||
: public virtual ElementBuffer<false>, public virtual ImmutableBuffer<ElementBuffer<true>> {
|
||||
using Base = ElementBuffer<false>;
|
||||
using BufferType = ImmutableBuffer<ElementBuffer<true>>;
|
||||
|
||||
public:
|
||||
using BufferType::BufferType;
|
||||
using Base::Target;
|
||||
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user