#include "Draw.h" namespace NB{ DrawWarning::DrawWarning(const std::string& msg) : std::runtime_error(msg) {} 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; } } uint8_t GLSLPrimitiveVertexSize(GLenum type, unsigned int num_prims) { switch(type) { case GL_POINTS: return num_prims; case GL_LINES: return num_prims*2; break; case GL_LINE_STRIP: return num_prims+1; break; case GL_LINE_LOOP: return num_prims; break; case GL_TRIANGLES: return num_prims*3; break; case GL_TRIANGLE_STRIP: case GL_TRIANGLE_FAN: return num_prims+2; break; case GL_QUADS: return 4*num_prims; break; case GL_QUAD_STRIP: return 2*num_prims+2; break; default: return num_prims; break; } } DrawBuffer::DrawBuffer( std::vector vas, const Shader& shader ) : _vertex_attributes(vas), _shader(shader), _vert_data(GL_ARRAY_BUFFER), _elmt_data(GL_ELEMENT_ARRAY_BUFFER) {} unsigned int DrawBuffer::vertSize() const { size_t num_attrs = _vertex_attributes.size(); size_t vert_size = 0; for (int i = 0; i < num_attrs; ++i) { vert_size += _vertex_attributes[i].GLSLSize*GLSLTypeSize(_vertex_attributes[i].GLSLType); } return vert_size; } std::vector DrawBuffer::getLayout() const { unsigned int num_attrs = _vertex_attributes.size(); std::vector ret(num_attrs); for (int i = 0; i < num_attrs; ++i) { ret[i] = _vertex_attributes[i].ptr; } return ret; } void DrawBuffer::draw() const { _shader.use(); glBindVertexArray(_VAO); glDrawElements(_gl_primitive_type, _elmt_data.size(), GL_UNSIGNED_INT, 0); glBindVertexArray(0); } const Shader DrawBuffer::shader() const { return _shader; } bool DrawBuffer::keepLocalElement() const { return _elmt_data.keepLocal(); } bool DrawBuffer::keepLocalVertex() const { return _vert_data.keepLocal(); } unsigned int DrawBuffer::elementBufferID() const { return _elmt_data.id(); } unsigned int DrawBuffer::vertexBufferID() const { return _vert_data.id(); } bool DrawBuffer::keepLocalElement(bool keep) { return _elmt_data.keepLocal(keep); } bool DrawBuffer::keepLocalVertex(bool keep) { return _vert_data.keepLocal(keep); } const Shader DrawBuffer::shader(const Shader& new_shader) { _shader = new_shader; return _shader; } std::vector DrawBuffer::setLayout() { int vert_size = vertSize(); unsigned int num_attrs = _vertex_attributes.size(); std::vector ret(num_attrs); unsigned int curr_byte = 0; for (int i = 0; i < num_attrs; ++i) { _vertex_attributes[i].ptr.stride = vert_size; _vertex_attributes[i].ptr.offset = curr_byte; curr_byte += _vertex_attributes[i].GLSLSize * GLSLTypeSize(_vertex_attributes[i].GLSLType); ret[i] = _vertex_attributes[i].ptr; } return getLayout(); } std::vector DrawBuffer::setLayout(std::vector vap) { unsigned int num_attrs = _vertex_attributes.size(); if (vap.size() != num_attrs) { throw DrawWarning("DrawBuffer Vertex Attributes and passed Vertex Attributes do not match."); } for (int i = 0; i < num_attrs; ++i) { if (vap[i].stride == -1) { throw DrawWarning("Unset Vertex Attribute Pointer in index " + std::to_string(i) + "."); } _vertex_attributes[i].ptr = vap[i]; } return getLayout(); } void DrawBuffer::generateElementBuffer(unsigned int num_prims, GLenum gl_primitive_type) { generateElementBuffer(std::vector(GLSLPrimitiveVertexSize(gl_primitive_type, num_prims))); } void DrawBuffer::generateElementBuffer(std::vector elements, GLenum gl_primitive_type) { _num_prims = elements.size(); _gl_primitive_type = gl_primitive_type; _elmt_data.setData(elements); } void DrawBuffer::generateVertexBuffer(unsigned int num_verts) { generateVertexBuffer(std::vector(num_verts * vertSize())); } void DrawBuffer::generateVertexBuffer(std::vector vert_data) { int vert_size = vertSize(); if (vert_data.size() % vert_size != 0) { throw DrawWarning("Starting data does not match vertex size of " + std::to_string(vert_size) + "."); } _num_verts = vert_data.size() / vert_size; unsigned int num_attrs = _vertex_attributes.size(); for (int i = 0; i < num_attrs; ++i) { if (_vertex_attributes[i].ptr.stride == -1) { setLayout(); i = num_attrs+1; } } // TODO: Make it not static draw all the time glGenVertexArrays(1, &_VAO); glBindVertexArray(_VAO); _vert_data.setData(vert_data); _elmt_data.bind(); for (GLuint i = 0; i < num_attrs; ++i) { glVertexAttribPointer( i, _vertex_attributes[i].GLSLSize, _vertex_attributes[i].GLSLType, _vertex_attributes[i].GLSLNormalization, _vertex_attributes[i].ptr.stride, (void*)(_vertex_attributes[i].ptr.offset) ); glEnableVertexAttribArray(i); } glBindVertexArray(0); } void DrawBuffer::loadElementBuffer(const std::vector& elements, unsigned int offset, GLenum gl_primitive_type) { glBindVertexArray(_VAO); if (!_elmt_data.isInitialized()) { std::vector load_data(offset); load_data.insert(load_data.end(), elements.begin(), elements.end()); generateElementBuffer(load_data); } else { if (gl_primitive_type != _gl_primitive_type) { throw DrawWarning("Attempting to overload GL primitive type."); } _elmt_data.loadData(elements, offset); } glBindVertexArray(0); } void DrawBuffer::loadVertexBuffer(const std::vector& data, unsigned int offset) { glBindVertexArray(_VAO); if (!_vert_data.isInitialized()) { std::vector load_data(offset); load_data.insert(load_data.end(), data.begin(), data.end()); generateVertexBuffer(load_data); } else { _vert_data.loadData(data, offset); } glBindVertexArray(0); } }