added Buffer class to handle VBOs, EBOs and UBOs

This commit is contained in:
Anselme 2016-03-29 15:44:33 +02:00
parent 4dcef0d4e3
commit d07541e8ea
5 changed files with 223 additions and 149 deletions

85
src/buffer.cpp Normal file
View File

@ -0,0 +1,85 @@
#include "buffer.h"
#include "glassert.h"
#include <cstdio>
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
template <typename T>
GLenum Buffer<T>::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 <typename T>
Buffer<T>::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 <typename T>
Buffer<T>::BufferEditor::~BufferEditor()
{
glUnmapBuffer(m_typeEnum);
glAssert(glBindBuffer(m_typeEnum, 0));
}
template <typename T>
Buffer<T>::Buffer(const std::vector<T> &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 <typename T>
void Buffer<T>::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 <typename T>
Buffer<T>::~Buffer()
{
glAssert(glDeleteBuffers(1, m_id));
}

47
src/buffer.h Normal file
View File

@ -0,0 +1,47 @@
#ifndef BUFFER_H
#define BUFFER_H
#include "glew.h"
#include <vector>
template <typename T>
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<T> &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

View File

@ -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

View File

@ -6,11 +6,10 @@
#include <glm/vec3.hpp>
#include <glm/vec2.hpp>
class Buffer;
class Material;
class Shader;
struct Mesh
{
public:
@ -70,27 +69,31 @@ public:
std::vector<glm::vec3> instances_offsets;
std::vector<Tangents> tangents;
std::vector<GLuint> indices;
std::vector<Buffer*> 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

View File

@ -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