GraphicsTest/include/Buffers.h

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