#include "VAOManager.hpp" namespace NB { using BufferManagerPointer = std::shared_ptr; VAOManager::VAOManager() { glGenVertexArrays(1, &_id); } VAOManager::VAOManager( std::vector vert_bufs, BufferManagerPointer elmt_buf, const VertexAttributeList& vert_attrs ) : VAOManager() { _elmt_buffer = elmt_buf; for (BufferManagerPointer vb : vert_bufs) { _vert_buffers[vb->id()] = vb; } if (vert_attrs.size()!=0) { generate(vert_attrs); } } VAOManager::VAOManager(VAOManager&& rhs) { *this = std::move(rhs); } VAOManager& VAOManager::operator=(VAOManager&& rhs) { remove(); _vert_buffers = rhs._vert_buffers; _elmt_buffer = rhs._elmt_buffer; _vert_attrs = rhs._vert_attrs; return *this; } VertexAttributeList VAOManager::getLayout() const { return _vert_attrs; } GLuint VAOManager::id() const { return _id; } bool VAOManager::isInitialized() const { return _id && glIsVertexArray(_id); } void VAOManager::remove() const { bind(); for (int i{0}; i < _vert_attrs.size(); ++i) { glDisableVertexAttribArray(i); } unbind(); glDisableVertexAttribArray(_id); } unsigned int VAOManager::vertSize(GLuint id) const { unsigned int size = 0; for (const VertexAttribute& va : _vert_attrs) { if (va.ptr.buffer == id) { size += va.GLSLSize * GLSLTypeSize(va.GLSLType); } } return size; } std::vector VAOManager::getVertexBuffers() const { std::vector ret; for (const auto& i : _vert_buffers) { ret.emplace_back(i.second); } return ret; } RawVec VAOManager::attributeData(unsigned int i) { if (i <= _vert_attrs.size()) { throw std::out_of_range("No vertex attribute exists for specified index"); } VertexAttribute attr = _vert_attrs[i]; BufferManagerPointer buffer = _vert_buffers[attr.ptr.buffer]; RawVec data = buffer->data(); unsigned int attr_size = attr.GLSLSize*GLSLTypeSize(attr.GLSLType); RawVec ret((buffer->size()-attr.ptr.offset-attr_size)*attr_size/attr.ptr.stride); int data_size = data.size(); for (int i{0}; i < data_size; ++i) { if (isIndexInVertexAttribute(i, attr)) { ret[i] = data[i]; } } return ret; } RawVec VAOManager::attributeData(unsigned int i, const RawVec& new_data) { if (i >= _vert_attrs.size()) { throw std::out_of_range("No vertex attribute exists for specified index."); } VertexAttribute attr = _vert_attrs[i]; BufferManagerPointer buffer = _vert_buffers[attr.ptr.buffer]; unsigned int attr_size = attr.GLSLSize*GLSLTypeSize(attr.GLSLType); unsigned int offset = attr.ptr.offset; unsigned int num_verts = buffer->size() / vertSize(buffer->id()); if (num_verts*attr_size != new_data.size()) { // WHY HERE???? THROW_VAO_ERROR( "Input data size of " + std::to_string(new_data.size()) + " does not match data size for requested vertex attribute of total size " + std::to_string(num_verts*attr_size) + "." ); } uint64_t pos = uint64_t(new_data.data()); for (int i{0}; idata((void*)(pos+i*attr_size), offset+i*attr.ptr.stride, attr_size); } return RawVec(new_data); } void VAOManager::bind() const { glBindVertexArray(_id); if (_elmt_buffer) { _elmt_buffer->bind(); } } void VAOManager::unbind() const { glBindVertexArray(0); if (_elmt_buffer) { _elmt_buffer->unbind(); } } void VAOManager::addVBO(BufferManagerPointer vert_buf) { GLuint vert_id = vert_buf->id(); if (_vert_buffers.find(vert_id) == _vert_buffers.end()) { _vert_buffers[vert_buf->id()] = vert_buf; } else { THROW_VAO_ERROR("Attempting to add identical VBO id of " + std::to_string(vert_id) + "."); } } void VAOManager::changeEBO(BufferManagerPointer ebo) { _elmt_buffer = ebo; } VertexAttributeList VAOManager::addVertexAttributes(const VertexAttributeList& vert_attrs) { VertexAttributeList curr_vas = _vert_attrs; curr_vas.insert(curr_vas.end(), vert_attrs.begin(), vert_attrs.end()); try { throw checkValid(curr_vas); } catch (VAOError vaoe) { if (vaoe.error) { THROW_VAO_ERROR(vaoe.what()); } } _vert_attrs = curr_vas; generate(); return _vert_attrs; } VertexAttributeList VAOManager::addVertexAttributes(VertexAttribute vert_attr) { return addVertexAttributes({vert_attr}); } VertexAttributeList VAOManager::generate() { bind(); unsigned int num_attrs = _vert_attrs.size(); VertexAttribute* va; for (int i = 0; i < num_attrs; ++i) { va = &(_vert_attrs[i]); _vert_buffers[va->ptr.buffer]->bind(); glVertexAttribPointer( i, va->GLSLSize, va->GLSLType, va->GLSLNormalization, va->ptr.stride, (void*)va->ptr.offset ); glVertexAttribDivisor(i, va->ptr.divisor); glEnableVertexAttribArray(i); } if (_elmt_buffer != nullptr) { _elmt_buffer->bind(); } unbind(); return _vert_attrs; } VertexAttributeList VAOManager::generate(VertexAttributeList vert_attrs) { try { throw checkValid(vert_attrs); } catch (VAOError vaoe) { if (vaoe.error) { THROW_VAO_ERROR(vaoe.what()); } } _vert_attrs.swap(vert_attrs); return generate(); } VertexAttributeList VAOManager::changeLayout(unsigned int i, VertexAttributePointer vap) { _vert_attrs[i].ptr = vap; bind(); const VertexAttribute* va = &(_vert_attrs[i]); glDisableVertexAttribArray(i); _vert_buffers[va->ptr.buffer]->bind(); glVertexAttribPointer( _id, va->GLSLSize, va->GLSLType, va->GLSLNormalization, va->ptr.stride, (void*)va->ptr.offset ); glVertexAttribDivisor(i, va->ptr.divisor); glEnableVertexAttribArray(i); unbind(); return _vert_attrs; } VAOError VAOManager::checkValid(const VertexAttributeList& vert_attrs) { GLuint va_id; unsigned int num_attrs = vert_attrs.size(); for (int i = 0; i < num_attrs; ++i) { va_id = vert_attrs[i].ptr.buffer; if (_vert_buffers.find(va_id) == _vert_buffers.cend()) { return VAOError("Attempting to point to unknown VBO of id " + std::to_string(va_id) + " at Vertex Attribute " + std::to_string(i) + "."); } if (vert_attrs[i].ptr.stride<0) { return VAOError("Invalid stride value at Vertex Attribute " + std::to_string(i) + "."); } } return VAOError(false); } } // namespace NB