From d07541e8eaa4c3040e1baf6b2d457ffc29dc38ac Mon Sep 17 00:00:00 2001 From: Anselme Date: Tue, 29 Mar 2016 15:44:33 +0200 Subject: [PATCH] added Buffer class to handle VBOs, EBOs and UBOs --- src/buffer.cpp | 85 +++++++++++++++++ src/buffer.h | 47 ++++++++++ src/mesh.cpp | 195 +++++++++++++++------------------------ src/mesh.h | 43 ++++----- src/posteffectmodule.cpp | 2 +- 5 files changed, 223 insertions(+), 149 deletions(-) create mode 100644 src/buffer.cpp create mode 100644 src/buffer.h diff --git a/src/buffer.cpp b/src/buffer.cpp new file mode 100644 index 0000000..3a7a840 --- /dev/null +++ b/src/buffer.cpp @@ -0,0 +1,85 @@ +#include "buffer.h" +#include "glassert.h" +#include + +#define BUFFER_OFFSET(i) ((char *)NULL + (i)) + +template +GLenum Buffer::getGLEnum(BufferType type) +{ + GLenum typeEnum; + + switch(m_type) + { + case VBO : + typeEnum = GL_ARRAY_BUFFER; + break; + case EBO : + typeEnum = GL_ELEMENT_ARRAY_BUFFER; + break; + case UBO : + typeEnum = GL_UNIFORM_BUFFER; + break; + } + + return typeEnum; +} + +template +Buffer::BufferEditor::BufferEditor(Buffer *b) +{ + if(b->isDynamic()) + { + GLenum m_typeEnum = getGLEnum(b->getType()); + glAssert(glBindBuffer(m_typeEnum, b->getId())); + glAssert(ptr = (T*)glMapBuffer(m_typeEnum, GL_WRITE_ONLY)); + } + else + { + fprintf(stderr, "Buffer data can't be edited, this buffer is static\n"); + ptr = NULL; + } +} + +template +Buffer::BufferEditor::~BufferEditor() +{ + glUnmapBuffer(m_typeEnum); + glAssert(glBindBuffer(m_typeEnum, 0)); +} + +template +Buffer::Buffer(const std::vector &data, BufferType type, bool isDynamic) : + m_type(type), + m_isDynamic(isDynamic) +{ + // TODO : allow stream draw + GLenum draw_type = isDynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW; + GLenum typeEnum = getGLEnum(m_type); + glAssert(glGenBuffers(1, m_id)); + glAssert(glBindBuffer(typeEnum, m_id)); + glAssert(glBufferData(typeEnum, data.size() * sizeof(T), data.data(), draw_type)); + glAssert(glBindBuffer(typeEnum, 0)); +} + +template +void Buffer::setVertexAttrib(int location, int nbComponents, int offset, int instanceDivisor) +{ + if(m_type == VBO) + { + glAssert(glBindBuffer(GL_ARRAY_BUFFER, m_id)); + glAssert(glEnableVertexAttribArray(location)); + if(instanceDivisor) + glAssert(glVertexAttribDivisor(location, instanceDivisor)); + glAssert(glVertexAttribPointer(location, nbComponents, GL_FLOAT, GL_FALSE, sizeof(T), BUFFER_OFFSET(offset))); + glAssert(glBindBuffer(GL_ARRAY_BUFFER, 0)); + } + else + fprintf(stderr, "WTF\n"); +} + +template +Buffer::~Buffer() +{ + glAssert(glDeleteBuffers(1, m_id)); +} diff --git a/src/buffer.h b/src/buffer.h new file mode 100644 index 0000000..5572d65 --- /dev/null +++ b/src/buffer.h @@ -0,0 +1,47 @@ +#ifndef BUFFER_H +#define BUFFER_H + +#include "glew.h" +#include + +template +class Buffer +{ +public: + enum BufferType + { + VBO, + EBO, + UBO + }; + + class BufferEditor + { + GLenum m_typeEnum; + T *ptr; + + public: + BufferEditor(Buffer *b); + ~BufferEditor(); + + T* getPointer(); + }; + + Buffer(const std::vector &data, BufferType type, bool isDynamic = false); + ~Buffer(); + + void setVertexAttrib(int location, int nbComponents, int offset = 0, int instanceDivisor = 0); + + GLuint getId() {return m_id;} + BufferType getType() {return m_type;} + bool isDynamic() {return m_isDynamic;} + +private: + GLuint m_id; + BufferType m_type; + bool m_isDynamic; + + GLenum getGLEnum(BufferType type); +}; + +#endif // BUFFER_H diff --git a/src/mesh.cpp b/src/mesh.cpp index 07ec6b3..57cff3c 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -4,8 +4,7 @@ #include "glassert.h" #include "sparrowrenderer.h" #include "material.h" - -#define BUFFER_OFFSET(i) ((char *)NULL + (i)) +#include "buffer.h" const char* const Mesh::flagStr[Mesh::NB_FLAGS] = { @@ -33,8 +32,9 @@ const char* const Mesh::flagStr[Mesh::NB_FLAGS] = Mesh::Mesh() : material(NULL), isDoubleSided(false), + isBillboard(false), + depth(0), vao(0), - nb_buffers(0), primitive_type(GL_TRIANGLES) {} @@ -43,59 +43,75 @@ Mesh::~Mesh() destroyGL(); } -void Mesh::initGL(bool isDynamic) +void Mesh::initGL() { destroyGL(); - GLenum buffer_type = isDynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW; - // create VAO glAssert(glGenVertexArrays(1, &vao)); glAssert(glBindVertexArray(vao)); - // create VBOs - glAssert(glGenBuffers(NB_BUFFERS, vbo)); + Buffer *b; - // init indices vbos - glAssert(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[INDICES_BUFFER])); - glAssert(glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLuint), indices.data(), buffer_type)); - - // init positions vbo - glAssert(glBindBuffer(GL_ARRAY_BUFFER, vbo[POSITION_BUFFER])); - glAssert(glBufferData(GL_ARRAY_BUFFER, positions3D.size() * sizeof(glm::vec3), positions3D.data(), buffer_type)); - - if(hasNormals()) + // init positions VBO + if(!positions3D.empty()) { + b = new Buffer(positions3D, Buffer::VBO); + b->setVertexAttrib(0, 3); + buffers.push_back(b); + // init normals vbo - glAssert(glBindBuffer(GL_ARRAY_BUFFER, vbo[NORMAL_BUFFER])); - glAssert(glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), normals.data(), buffer_type)); - } - - if(hasTexCoords()) - { - // init texCoords vbo - glAssert(glBindBuffer(GL_ARRAY_BUFFER, vbo[TEXCOORD_BUFFER])); - glAssert(glBufferData(GL_ARRAY_BUFFER, texCoords.size() * sizeof(glm::vec2), texCoords.data(), buffer_type)); - } - - if(hasTangents()) - { + if(!normals.empty()) + { + b = new Buffer(normals, Buffer::VBO); + b->setVertexAttrib(1, 3); + buffers.push_back(b); + } // init tangents vbo - glAssert(glBindBuffer(GL_ARRAY_BUFFER, vbo[TANGENT_BUFFER])); - glAssert(glBufferData(GL_ARRAY_BUFFER, tangents.size() * sizeof(glm::vec3)*2, tangents.data(), buffer_type)); + if(!tangents.empty()) + { + b = new Buffer(tangents, Buffer::VBO); + b->setVertexAttrib(3, 3); + b->setVertexAttrib(4, 3); + buffers.push_back(b); + } } - - if(hasInstances() && SparrowRenderer::isModernOpenGLAvailable()) + else if(!positions2D.empty()) { - // init instances vbo - glAssert(glBindBuffer(GL_ARRAY_BUFFER, vbo[INSTANCE_BUFFER])); - glAssert(glBufferData(GL_ARRAY_BUFFER, instances_offsets.size() * sizeof(glm::vec3), instances_offsets.data(), GL_DYNAMIC_DRAW)); + b = new Buffer(positions2D, Buffer::VBO); + b->setVertexAttrib(0, 2); + buffers.push_back(b); + } + else + { + fprintf(stderr, "ERROR : Mesh can't be initialized without position data"); + return; + } + // init texCoords vbo + if(!texCoords.empty()) + { + b = new Buffer(texCoords, Buffer::VBO); + b->setVertexAttrib(2, 2); + buffers.push_back(b); + } + + // init instances vbo + if(!instances_offsets.empty()) + { + b = new Buffer(instances_offsets, Buffer::VBO); + b->setVertexAttrib(5, 3, 0, 1); + buffers.push_back(b); + } + + // init EBO + if(!indices.empty()) + { + b = new Buffer(indices, Buffer::EBO); + buffers.push_back(b); } // unbind vao glAssert(glBindVertexArray(0)); - glAssert(glBindBuffer(GL_ARRAY_BUFFER, 0)); - glAssert(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); } void Mesh::draw(Shader* shader, bool drawNormals, bool drawTexCoord, bool drawTangents) @@ -107,75 +123,41 @@ void Mesh::draw(Shader* shader, bool drawNormals, bool drawTexCoord, bool drawTa bool crappy = (shader == NULL); material->bindAttributes(shader); glAssert(glBindVertexArray(vao)); - glAssert(glBindBuffer(GL_ARRAY_BUFFER, vbo[POSITION_BUFFER])); + if(crappy) { + glAssert(glBindBuffer(GL_ARRAY_BUFFER, vbo[POSITION_BUFFER])); glAssert(glEnableClientState(GL_VERTEX_ARRAY)); - glAssert(glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0))); - } - else - { - glAssert(glEnableVertexAttribArray(0)); - glAssert(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), BUFFER_OFFSET(0))); - } - if(hasNormals() && drawNormals) - { - glAssert(glBindBuffer(GL_ARRAY_BUFFER, vbo[NORMAL_BUFFER])); - if(crappy) - { - glAssert(glEnableClientState(GL_NORMAL_ARRAY)); - glAssert(glNormalPointer(GL_FLOAT, 0, BUFFER_OFFSET(0))); - } - else - { - glAssert(glEnableVertexAttribArray(1)); - glAssert(glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), BUFFER_OFFSET(0))); - } - } - if(hasTexCoords() && drawTexCoord) - { - glAssert(glBindBuffer(GL_ARRAY_BUFFER, vbo[TEXCOORD_BUFFER])); - if(crappy) + glAssert(glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0))); // TODO : check 2D positions + if(!texCoords.empty() && drawTexCoord) { + glAssert(glBindBuffer(GL_ARRAY_BUFFER, vbo[TEXCOORD_BUFFER])); glAssert(glEnableClientState(GL_TEXTURE_COORD_ARRAY)); glAssert(glTexCoordPointer(2, GL_FLOAT, 0, BUFFER_OFFSET(0))); } - else + if(!normals.empty() && drawNormals) { - glAssert(glEnableVertexAttribArray(2)); - glAssert(glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec2), BUFFER_OFFSET(0))); + glAssert(glBindBuffer(GL_ARRAY_BUFFER, vbo[NORMAL_BUFFER])); + glAssert(glEnableClientState(GL_NORMAL_ARRAY)); + glAssert(glNormalPointer(GL_FLOAT, 0, BUFFER_OFFSET(0))); } + glAssert(glBindBuffer(GL_ARRAY_BUFFER, 0)); } - if(hasTangents() && drawTangents && !crappy) - { - glAssert(glBindBuffer(GL_ARRAY_BUFFER, vbo[TANGENT_BUFFER])); - glAssert(glEnableVertexAttribArray(3)); - glAssert(glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Mesh::Tangents), BUFFER_OFFSET(0))); - glAssert(glEnableVertexAttribArray(4)); - glAssert(glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Mesh::Tangents), BUFFER_OFFSET(sizeof(glm::vec3)))); - } + glAssert(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, getEBO())); if(!instances_offsets.empty() && !crappy) - { - glAssert(glBindBuffer(GL_ARRAY_BUFFER, vbo[INSTANCE_BUFFER])); - glAssert(glEnableVertexAttribArray(5)); - glAssert(glVertexAttribPointer(5, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), BUFFER_OFFSET(0))); - glAssert(glVertexAttribDivisor(5, 1)); - glAssert(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[INDICES_BUFFER])); glAssert(glDrawElementsInstanced(primitive_type, indices.size(), GL_UNSIGNED_INT, NULL, instances_offsets.size())); - } else - { - glAssert(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[INDICES_BUFFER])); glAssert(glDrawElements(primitive_type, indices.size(), GL_UNSIGNED_INT, NULL)); - } + if(crappy) { glAssert(glDisableClientState(GL_VERTEX_ARRAY)); - if(hasNormals() && drawNormals) + if(!normals.empty() && drawNormals) glAssert(glDisableClientState(GL_NORMAL_ARRAY)); - if(hasTexCoords() && drawTexCoord) + if(!texCoords.empty() && drawTexCoord) glAssert(glDisableClientState(GL_TEXTURE_COORD_ARRAY)); } + glAssert(glBindVertexArray(0)); if(isDoubleSided) { @@ -187,27 +169,17 @@ void Mesh::destroyGL() { if(vao != 0) { - glAssert(glDeleteBuffers(NB_BUFFERS, vbo)); glAssert(glDeleteVertexArrays(1, &vao)); vao = 0; } -} - -glm::vec3* Mesh::beginUpdateBuffer(int buffer) -{ - glAssert(glBindBuffer(GL_ARRAY_BUFFER, vbo[buffer])); - glAssert(glm::vec3* ptr = (glm::vec3*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY)); - return ptr; -} - -void Mesh::endUpdateBuffer() -{ - glUnmapBuffer(GL_ARRAY_BUFFER); + for(Buffer *b : buffers) + delete(b); + buffers.clear(); } unsigned int Mesh::getFlags() { - unsigned int flags = material->getFlags() << MESH_NB_FLAGS; + unsigned int flags = material->getFlags(); if(!indices.empty()) flags |= 1 << MESH_INDEXED; @@ -228,26 +200,7 @@ unsigned int Mesh::getFlags() else flags |= 1 << MESH_2D; - return flags; - - // Mesh type - MESH_3D, - MESH_2D, - - // 3D Geometric properties - MESH_TANGENT_SPACE, - MESH_BILLBOARD, - - // simple textures properties - MATERIAL_DIFFUSE_TEXTURE, - MATERIAL_ALPHA_MASK, - - // 3D phong-like materials : - MATERIAL_AMBIENT_TEXTURE, - MATERIAL_SPECULAR_TEXTURE, - MATERIAL_NORMAL_MAP, - MATERIAL_BUMP_MAP, } struct VertexComparator diff --git a/src/mesh.h b/src/mesh.h index 0e9b14b..b0448f6 100644 --- a/src/mesh.h +++ b/src/mesh.h @@ -6,11 +6,10 @@ #include #include +class Buffer; class Material; class Shader; - - struct Mesh { public: @@ -70,27 +69,31 @@ public: std::vector instances_offsets; std::vector tangents; std::vector indices; - + + std::vector buffers; + enum { - // required buffers + // required buffer POSITION_BUFFER, + // indices buffers INDICES_BUFFER, + // optionnal buffers : - NORMAL_BUFFER, TEXCOORD_BUFFER, TANGENT_BUFFER, + NORMAL_BUFFER, + TEXCOORD_BUFFER, + TANGENT_BUFFER, // instanciation buffer INSTANCE_BUFFER, NB_BUFFERS }; - - GLuint vao; // TODO : this is supposed to be protected + + GLuint vao; protected: - int nb_buffers; - GLuint vbo[NB_BUFFERS]; GLenum primitive_type; public: @@ -98,28 +101,19 @@ public: Mesh(); virtual ~Mesh(); - void initGL(bool isDynamic = false); + void initGL(); void draw(Shader* shader = NULL, bool drawNormals = true, bool drawTexCoord = true, bool drawTangents = true); void destroyGL(); - /** - * @brief beginUpdateBuffer can be used to change the contents of a VBO dynamically - * @return a pointer to the buffer's data - * - * endUpdateBuffer() must be called when the modifications are over - */ - glm::vec3* beginUpdateBuffer(int buffer); - void endUpdateBuffer(); - /** * @brief getFlags returns the flags that defines the specificities of the mesh and his material */ unsigned int getFlags(); /** - * this class is intended to be used with the default GL_TRIANGLES primitive, - * the methods mergeVertices, computeNormals, and computeTangents will probably have - * unpredictable behavior with other primitive types. + * this class is intended to be used with a 3D mesh of the default GL_TRIANGLES primitives, + * the methods mergeVertices, computeNormals, and computeTangents will not + * work with other primitive types. */ void setPrimitiveType(GLenum type) {primitive_type = type;} @@ -137,11 +131,6 @@ public: * compute tangent space from a textured indexed mesh (positions + normals + texcoords + indices) */ void computeTangents(); - - bool hasNormals() const {return !normals.empty();} - bool hasTexCoords() const {return !texCoords.empty();} - bool hasTangents() const {return !tangents.empty();} - bool hasInstances() const {return !instances_offsets.empty();} }; #endif // MESH_H diff --git a/src/posteffectmodule.cpp b/src/posteffectmodule.cpp index 5b97c48..01ec2ee 100644 --- a/src/posteffectmodule.cpp +++ b/src/posteffectmodule.cpp @@ -126,7 +126,7 @@ void PostEffectModule::renderGL(Camera* myCamera, Scene* scene) glAssert(glBindVertexArray(vao)); - // threasholding the luminance to isolate high luminance pixels for bloom + // thresholding the luminance to isolate high luminance pixels for bloom luminanceStep(); // blur the high luminance pixels