NBEngine/engine/NBGraphics/VertexArray.hpp
2026-06-26 02:44:32 -05:00

176 lines
3.9 KiB
C++

#pragma once
#ifndef _NB_VERTEX_ARRAY
#define _NB_VERTEX_ARRAY
#include "GLLoad.hpp"
#include <NBCore/Errors.hpp>
#include "Buffers.hpp"
#include "OGLObjects.hpp"
namespace nb {
struct VertexAttributeLayout {
int32_t offset = 0;
GLsizei stride = 0;
GLuint divisor = 0;
};
struct VertexAttribute {
GLint GLSLSize;
GLenum GLSLType;
GLboolean GLSLNormalization;
VertexAttributeLayout layout;
};
struct VertexAttributePointer;
static bool isIndexInVertexAttribute(int i, const VertexAttribute& va) {
if ((i -= va.layout.offset) < 0) { return false; }
return (i%va.layout.stride) < GLSLTypeSize(va.GLSLType) * va.GLSLSize;
}
typedef std::vector<VertexAttribute> VertexAttributeList;
typedef std::vector<VertexAttributePointer> VertexAttributePointerList;
class VAOError : public Error<VAOError> {
using Base = Error<VAOError>;
public:
using Base::Base;
enum Codes : unsigned int {
UNDEFINED, INVALID_ATTRIBUTE, INVALID_VAO
};
static const std::string type;
static const ErrorCodeMap ErrorMessages;
};
template <bool Immutable=false>
class VertexBuffer : public ArrayBuffer<false>{
using Base = ArrayBuffer<Immutable>;
public:
template<typename... Args>
VertexBuffer(const VertexAttributeList& vas, Args... args)
: attributes(vas) {
if (sizeof...(Args)) {
data(args...);
}
}
using Base::Target;
const VertexAttributeList attributes;
protected:
using Base::_usage;
};
template <>
class VertexBuffer<true>
: public virtual VertexBuffer<false>, public virtual ImmutableBuffer<ArrayBuffer<true>> {
using Base = ArrayBuffer<false>;
using BufferType = ImmutableBuffer<ArrayBuffer<true>>;
using BufferType::BufferType;
public:
using Base::Target;
};
struct VertexAttributePointer {
VertexAttribute attribute;
VertexBuffer<false>* buffer;
GLuint index;
};
class VAO : public OpenGLObject {
using Base = OpenGLObject;
using Codes = VAOError::Codes;
public:
using Base::Base;
VAO() = default;
VAO(const VertexAttributePointerList&);
VAO(VAO&&);
VAO& operator=(VAO&&);
virtual void bind() const override {
if(_id) {
glBindVertexArray(_id);
} else {
THROW(Codes::INVALID_VAO);
}
}
virtual void unbind() const override { glBindVertexArray(0); }
VertexAttributePointerList attributes() const;
VertexAttributePointerList attributes(const VertexAttributePointerList&);
VertexAttributePointer attr(GLuint) const;
void enable() const;
void enable(GLuint) const;
void disable() const;
void disable(GLuint) const;
protected:
using Base::_id;
VertexAttributePointerList _attrs;
virtual void remove() override {
if(_id) {
disable();
bind();
glDeleteVertexArrays(1, &_id);
_id = 0;
}
}
virtual GLuint declare() override {
if (!_id) {
glGenVertexArrays(1, &_id);
}
return _id;
}
};
class VertexGroup {
public:
VertexGroup(VertexGroup&&);
VertexGroup& operator=(VertexGroup&&);
void bind() const {
_elmt_buf.bind();
_vao.bind();
}
void unbind() const {
_vao.bind();
_elmt_buf.unbind();
}
VertexBuffer<false>& buffer(size_t);
size_t buffer(VertexBuffer<false>&&);
std::vector<std::shared_ptr<VertexBuffer<false>>> buffers();
size_t buffers(std::vector<VertexBuffer<false>>&&);
VertexBuffer<false>&& dropBuffer(size_t);
VertexAttributePointer attribute(size_t) const;
void enableAttr(GLuint);
void disableAttr(GLuint);
void enableBuffer(size_t);
void disableBuffer(size_t);
void enable();
void disable();
protected:
std::vector<std::shared_ptr<VertexBuffer<false>>> _vertex_data;
ElementBuffer<false> _elmt_buf;
VAO _vao;
};
} // namespace nb
#endif // _NB_VERTEX_ARRAY