164 lines
4.9 KiB
C++
164 lines
4.9 KiB
C++
#pragma once
|
|
#ifndef _NB_BUFFER
|
|
#define _NB_BUFFER
|
|
|
|
#include <exception>
|
|
#include <map>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <glad/glad.h>
|
|
#include <GLFW/glfw3.h>
|
|
#include "Shader.h"
|
|
|
|
static unsigned int __NB_GL_DEBUG_ERROR_CODE__;
|
|
#define __NB_GL_DEBUG_THROW__(cmd, when) while(__NB_GL_DEBUG_ERROR_CODE__=glGetError()){\
|
|
std::cout << "[GL ERROR]: " << __NB_GL_DEBUG_ERROR_CODE__;\
|
|
std::cout << " " << when << " " << cmd << "\n";\
|
|
}
|
|
#define __NB_GL_DEBUG__(cmd) __NB_GL_DEBUG_THROW__(#cmd, "before"); cmd; __NB_GL_DEBUG_THROW__(#cmd, "after");
|
|
|
|
namespace NB{
|
|
|
|
class BufferWarning : public std::runtime_error {
|
|
public:
|
|
BufferWarning(const std::string& msg) : std::runtime_error(msg) {}
|
|
};
|
|
|
|
static unsigned int getBound(GLenum buffer) {
|
|
int ret;
|
|
__NB_GL_DEBUG__(glGetIntegerv(buffer, &ret));
|
|
return ret;
|
|
}
|
|
|
|
template<typename T>
|
|
class BufferManager {
|
|
public:
|
|
BufferManager(
|
|
GLenum buffer_type,
|
|
bool keep_local=true,
|
|
GLenum usage=GL_STATIC_DRAW
|
|
) : _buffer_type(buffer_type), _initialized(false), _keep_local(keep_local), _usage(usage),
|
|
_size(0), _max_size(0) {}
|
|
BufferManager(
|
|
GLenum buffer_type,
|
|
const std::vector<T>& data,
|
|
bool keep_local=true,
|
|
GLenum usage=GL_STATIC_DRAW
|
|
) : _buffer_type(buffer_type), _keep_local(keep_local), _usage(usage) {
|
|
setData(data);
|
|
}
|
|
BufferManager(
|
|
GLenum buffer_type,
|
|
unsigned int size,
|
|
bool keep_local=true,
|
|
GLenum usage=GL_STATIC_DRAW
|
|
) : BufferManager<T>(buffer_type, std::vector<T>(size), keep_local, usage) {}
|
|
|
|
GLenum bufferType() const { return _buffer_type; }
|
|
GLenum usageType() const { return _usage; }
|
|
unsigned int id() const { return _id; }
|
|
unsigned int size() const { return _size; }
|
|
unsigned int capacity() const { return _max_size; }
|
|
bool isInitialized() const { return _initialized; }
|
|
bool keepLocal() const { return _keep_local; }
|
|
std::vector<T> getDataDirect() const {
|
|
std::vector<T> ret(_size);
|
|
bind();
|
|
glGetBufferSubData(_buffer_type, 0, sizeof(T)*_size, ret.data());
|
|
|
|
return ret;
|
|
}
|
|
std::vector<T> getData() const {
|
|
if(_keep_local) {
|
|
return _data;
|
|
} else {
|
|
return getDataDirect();
|
|
}
|
|
}
|
|
unsigned int bind() const { glBindBuffer(_buffer_type, _id); return _id;}
|
|
void unbind() const { glBindBuffer(_buffer_type, 0); }
|
|
|
|
GLenum usageType(GLenum usage) { _usage=usage; return usageType(); }
|
|
bool keepLocal(bool keep_local) {
|
|
if(keep_local && !_keep_local) {
|
|
_data = getDataDirect();
|
|
}
|
|
_keep_local = keep_local;
|
|
return _keep_local;
|
|
}
|
|
bool initialize(unsigned int n=1) {
|
|
if (!_initialized) {
|
|
setData(std::vector<T>(n));
|
|
}
|
|
return _initialized;
|
|
}
|
|
void loadData(const std::vector<T>& newData, unsigned int offset=0) {
|
|
if ( newData.size()+offset > _max_size ) {
|
|
throw BufferWarning("Attempting to overflow buffer of capacity " + std::to_string(_max_size) + ".");
|
|
}
|
|
bind();
|
|
glBufferSubData(_buffer_type, offset*sizeof(T), sizeof(T)*newData.size(), newData.data());
|
|
if(_keep_local) {
|
|
memcpy(_data.data()+offset*sizeof(T), newData.data(), sizeof(T)*newData.size());
|
|
}
|
|
}
|
|
void setData(const std::vector<T>& set_data) {
|
|
if (_keep_local) {_data = set_data;}
|
|
if (!_initialized) {
|
|
glGenBuffers(1, &_id);
|
|
_initialized = true;
|
|
}
|
|
bind();
|
|
if (set_data.size() <= _max_size) {
|
|
glBufferSubData(_buffer_type, 0, sizeof(T)*_size, _data.data());
|
|
_size = _data.size();
|
|
} else {
|
|
_size = _data.size();
|
|
_max_size = _size;
|
|
glBufferData(_buffer_type, sizeof(T)*_max_size, _data.data(), _usage);
|
|
}
|
|
}
|
|
unsigned int resize(unsigned int n) {
|
|
if (_keep_local) { _data.resize(n); }
|
|
if (n > _max_size) {
|
|
_max_size = n;
|
|
if (_initialized) {
|
|
bind();
|
|
glBufferData(_buffer_type, sizeof(T)*_max_size, _data.data(), _usage);
|
|
}
|
|
}
|
|
_size = n;
|
|
return _size;
|
|
}
|
|
unsigned int shrink_to_fit() {
|
|
if (_size < _max_size) {
|
|
if (_keep_local) {
|
|
_data.shrink_to_fit();
|
|
_size = _data.size();
|
|
bind();
|
|
glBufferData(_buffer_type, _size*sizeof(T), _data.data(),_usage);
|
|
_max_size = _size;
|
|
} else {
|
|
_data = getDataDirect();
|
|
_size = _data.data();
|
|
_max_size = _size;
|
|
}
|
|
}
|
|
return _size;
|
|
}
|
|
|
|
private:
|
|
const GLenum _buffer_type;
|
|
|
|
GLenum _usage;
|
|
std::vector<T> _data;
|
|
unsigned int _id, _size, _max_size;
|
|
bool _initialized;
|
|
bool _keep_local;
|
|
};
|
|
|
|
|
|
}
|
|
|
|
#endif |