#pragma once #ifndef _NB_VERTEX_ARRAY #define _NB_VERTEX_ARRAY #include "GLLoad.hpp" #include #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 { VertexAttribute attribute; GLuint buffer; GLuint index; }; 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 VertexAttributeList; typedef std::vector VertexAttributePointerList; class VAOError : public Error { using Base = Error; public: using Base::Base; enum Codes : unsigned int { UNDEFINED, INVALID_ATTRIBUTE, INVALID_VAO }; static const std::string type; static const ErrorCodeMap ErrorMessages; }; template class VertexBuffer : public ArrayBuffer{ using Base = ArrayBuffer; public: template VertexBuffer(const VertexAttributeList& vas={}, Args... args) : attributes(vas) { if (sizeof...(Args)) { data(args...); } } VertexBuffer(VertexBuffer&& rhs) : attributes(rhs.attributes), Base(std::move(rhs)){} using Base::Target; const VertexAttributeList attributes; protected: using Base::_usage; }; template <> class VertexBuffer : public virtual VertexBuffer, public virtual ImmutableBuffer> { using Base = ArrayBuffer; using BufferType = ImmutableBuffer>; using BufferType::BufferType; public: using Base::Target; }; 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(VAOError(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& buffer(size_t); size_t buffer(VertexBuffer&&); std::vector>> buffers(); size_t buffers(std::vector>&&); VertexBuffer&& 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>> _vertex_data; ElementBuffer _elmt_buf; VAO _vao; }; } // namespace nb #endif // _NB_VERTEX_ARRAY