#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, INVALID_VAO }; 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(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; } }; using VBO = ArrayBuffer; using VertBufVec = SharedVector; using EBO = ElementBuffer; struct VertexData { std::shared_ptr vbo; VertexAttributeList attrs; }; using VertexDataVec = std::vector; class VertexGroup { public: VertexGroup(VertexGroup&&); VertexGroup& operator=(VertexGroup&&); VertexGroup(const VertexData&); VertexGroup(const VertexDataVec&); VertexGroup(const ByteVector&, const VertexAttributeList&); void bind() const { _ebo->bind(); _vao->bind(); } void unbind() const { _vao->unbind(); _ebo->unbind(); } VertexDataVec getBuffers(); VertexData getBuffers(size_t); size_t setBuffers(const VertexDataVec&); size_t addBuffer(const VertexData&); 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(); protected: VertexDataVec _vertex_data; std::shared_ptr _ebo; std::shared_ptr _vao; }; } // namespace nb #endif // _NB_VERTEX_ARRAY