#pragma once #ifndef _NB_VERTEX_ARRAY #define _NB_VERTEX_ARRAY #include "GLLoad.hpp" #include #include "Buffers.hpp" #include "OGLObjects.hpp" namespace nb { static uint8_t GLSLTypeSize(GLenum type) { switch(type) { case GL_SHORT: case GL_UNSIGNED_SHORT: case GL_HALF_FLOAT: return 2; break; case GL_INT: case GL_UNSIGNED_INT: case GL_FLOAT: return 4; break; case GL_DOUBLE: return 8; break; default: return 1; break; } } 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 }; static const std::string type; static const ErrorCodeMap ErrorMessages; }; 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(OGLError( OGLError::Codes::INVALID_OBJECT, "w/ VertexArrayObject" )); } } 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); } bind(); return _id; } }; class VertexError : public Error { protected: using Base = Error; public: using Base::Base; enum Codes : unsigned int { UNDEFINED, MISALIGNED_DATA }; static const std::string type; static const ErrorCodeMap ErrorMessages; }; using VBO = ArrayBuffer; using VertBufVec = SharedVector; using EBO = ElementBuffer; struct VertexData { std::shared_ptr vbo; VertexAttributeList attrs; }; using VertexDataVec = std::vector; class VertexGroup { protected: using Codes = VertexError::Codes; VertexDataVec _vertex_data; std::shared_ptr _ebo; std::shared_ptr _vao; GLenum _primitive; public: GLenum primitive=GL_TRIANGLES; VertexGroup(VertexGroup&&); VertexGroup& operator=(VertexGroup&&); VertexGroup( const VertexDataVec& vertex_data, const std::shared_ptr& ebo ) : _vao(std::make_shared()), _ebo(ebo) { setBuffers(vertex_data); } template VertexGroup( const VertexDataVec& vertex_data, T... args ) : VertexGroup(vertex_data, std::make_shared(args...)) { setBuffers(vertex_data); } template VertexGroup( const VertexData& vertex_data, T... args ) : VertexGroup(VertexDataVec{vertex_data}, args...) {} template VertexGroup( const ByteVector& vertex_data, const VertexAttributeList& vertex_specification, T... args ) : VertexGroup({ std::make_shared(vertex_data), vertex_specification}, args... ) {} void bind() const { _vao->bind(); _ebo->bind(); } void unbind() const { _vao->unbind(); _ebo->unbind(); } void draw() const; VertexDataVec getBuffers(); VertexData getBuffers(size_t); size_t setBuffers(const VertexDataVec&); size_t addBuffer(const VertexData&); size_t addBuffer(const ByteVector& data, const VertexAttributeList& attrs); VertexDataVec dropBuffers(); VertexData 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(); std::shared_ptr indices() const; std::shared_ptr indices(const std::vector& data); std::shared_ptr indices(std::shared_ptr buffer); }; } // namespace nb #endif // _NB_VERTEX_ARRAY