- OBJ file reading
- VBO memory management - Lighting
This commit is contained in:
181
VBOManager.hh
Normal file
181
VBOManager.hh
Normal file
@@ -0,0 +1,181 @@
|
||||
#ifndef __OPENGLPLAYGROUND_VBOMANAGER_HH__
|
||||
#define __OPENGLPLAYGROUND_VBOMANAGER_HH__
|
||||
|
||||
#include <map>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
#include <glbinding/gl/gl.h>
|
||||
|
||||
using namespace gl;
|
||||
|
||||
class VBOManager {
|
||||
public:
|
||||
VBOManager() {
|
||||
}
|
||||
|
||||
~VBOManager() {
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
class VBO;
|
||||
|
||||
static const size_t default_size = 1048576;
|
||||
static const size_t alignment = 8;
|
||||
|
||||
class AllocFailed {};
|
||||
|
||||
public:
|
||||
class VBOAlloc {
|
||||
public:
|
||||
~VBOAlloc() {
|
||||
if(_vbo)
|
||||
_vbo->free(*this);
|
||||
_vbo = nullptr;
|
||||
}
|
||||
|
||||
VBOAlloc(VBOAlloc&& move) : _vbo(move._vbo), _ofs(move._ofs), _size(move._size) {
|
||||
move._vbo = nullptr;
|
||||
}
|
||||
|
||||
VBOAlloc& operator=(VBOAlloc&& move) {
|
||||
_vbo = move._vbo;
|
||||
_ofs = move._ofs;
|
||||
_size = move._size;
|
||||
move._vbo = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
VBOAlloc() : _vbo(nullptr), _ofs(0), _size(0) {
|
||||
}
|
||||
|
||||
size_t getOfs() const {
|
||||
assert(_vbo);
|
||||
return _ofs;
|
||||
}
|
||||
|
||||
size_t getSize() const {
|
||||
assert(_vbo);
|
||||
return _size;
|
||||
}
|
||||
|
||||
GLuint getVBOId() const {
|
||||
assert(_vbo);
|
||||
return _vbo->getID();
|
||||
}
|
||||
|
||||
private:
|
||||
VBOAlloc(VBO &vbo, size_t ofs, size_t size) : _vbo(&vbo), _ofs(ofs), _size(size) {
|
||||
}
|
||||
|
||||
friend class VBOManager;
|
||||
friend class VBO;
|
||||
|
||||
VBO *_vbo;
|
||||
size_t _ofs, _size;
|
||||
};
|
||||
|
||||
VBOAlloc alloc(size_t size, GLenum type = GL_STATIC_DRAW) {
|
||||
for(auto& vbo : _vbos[type]) {
|
||||
try {
|
||||
return vbo.alloc(size);
|
||||
} catch (AllocFailed &ex) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
_vbos[type].emplace_back((size>default_size)?size:default_size, type);
|
||||
|
||||
return _vbos[type].back().alloc(size);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
class VBO {
|
||||
public:
|
||||
VBO(size_t size = default_size, GLenum type = GL_STATIC_DRAW) : _bufID(0) {
|
||||
glGenBuffers(1, &_bufID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _bufID);
|
||||
glBufferData(GL_ARRAY_BUFFER, size, NULL, type);
|
||||
_allocs.emplace_back(_Entry{size, false});
|
||||
}
|
||||
|
||||
VBO(VBO const& copy) = delete;
|
||||
|
||||
VBO(VBO&& move) : _bufID(move._bufID), _allocs(move._allocs) {
|
||||
move._bufID = 0;
|
||||
}
|
||||
|
||||
~VBO() {
|
||||
for (auto ent : _allocs) {
|
||||
assert(!ent.used);
|
||||
}
|
||||
if (_bufID)
|
||||
glDeleteBuffers(1, &_bufID);
|
||||
_bufID = 0;
|
||||
}
|
||||
|
||||
VBOAlloc alloc(size_t size) {
|
||||
if (size%alignment != 0)
|
||||
size += (alignment - (size%alignment));
|
||||
|
||||
size_t pos = 0;
|
||||
for (auto it = _allocs.begin();it != _allocs.end();++it) {
|
||||
if (!it->used && (it->size >= size)) {
|
||||
size_t leftover = it->size - size;
|
||||
it->used = true;
|
||||
it->size = size;
|
||||
if (leftover > 0)
|
||||
_allocs.insert(++it, _Entry{leftover, false});
|
||||
printf("DEBUG: VBO: Allocated %lu @ %lu in %u\n", size, pos, _bufID);
|
||||
return VBOAlloc(*this, pos, size);
|
||||
}
|
||||
pos += it->size;
|
||||
}
|
||||
|
||||
throw AllocFailed();
|
||||
}
|
||||
|
||||
void free(VBOAlloc& alloc) {
|
||||
size_t pos = 0;
|
||||
for (auto it = _allocs.begin();it != _allocs.end();++it) {
|
||||
if (pos == alloc._ofs) {
|
||||
assert(it->size == alloc._size);
|
||||
printf("DEBUG: VBO: Freed %lu @ %lu in %u\n", alloc._size, pos, _bufID);
|
||||
it->used = false;
|
||||
if ((std::next(it) != _allocs.end()) &&
|
||||
!std::next(it)->used) {
|
||||
it->size += std::next(it)->size;
|
||||
_allocs.erase(std::next(it));
|
||||
}
|
||||
if ((it != _allocs.begin()) &&
|
||||
!std::prev(it)->used) {
|
||||
it->size += std::prev(it)->size;
|
||||
_allocs.erase(std::prev(it));
|
||||
}
|
||||
}
|
||||
pos += it->size;
|
||||
}
|
||||
}
|
||||
|
||||
GLuint getID() const {
|
||||
return _bufID;
|
||||
}
|
||||
|
||||
private:
|
||||
GLuint _bufID;
|
||||
|
||||
struct _Entry {
|
||||
size_t size;
|
||||
bool used;
|
||||
};
|
||||
std::list<_Entry> _allocs;
|
||||
|
||||
};
|
||||
|
||||
std::map<GLenum, std::vector<VBO> > _vbos;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user