Huge graphics overhaul

This commit is contained in:
NaifBanana
2026-07-19 22:20:05 -05:00
parent 8d9d6e0e66
commit e8a82bca90
19 changed files with 1534 additions and 252 deletions
+83 -6
View File
@@ -12,15 +12,92 @@ const std::string BufferError::type = "nb::BufferError";
const ErrorCodeMap BufferError::ErrorMessages = {
{ BufferErrorCodes::UNDEFINED, "Error" },
{ BufferErrorCodes::DATA_OVERFLOW, "Attempting buffer overflow" },
{ BufferErrorCodes::INVALID_BUFFER, "Attempting operation on invalid buffer" },
{ BufferErrorCodes::HANDLE_OVERWRITE, "Attempting to overwrite active buffer"}
{BufferErrorCodes::DATA_ERROR, "Invalid memory operation"}
};
template<>
ArrayBuffer<false>::ArrayBuffer(const ByteVector& data_, GLenum usage_)
: BufferType() {
data(data_, usage_);
Buffer::Buffer(Buffer&& rval) : Target(rval.Target) {
*this = std::move(rval);
}
Buffer& Buffer::operator=(Buffer&& rhs) {
if (Target != rhs.Target) {
auto targ_name = BufferTypes.at(Target);
THROW(OGLError(
OGLError::Codes::INVALID_OBJECT,
"w/ BufferType "+targ_name+" != BufferType "+BufferTypes.at(rhs.Target)
));
}
OpenGLObject::operator=(std::move(rhs));
_usage = rhs._usage;
_size = rhs._size;
rhs._usage = GL_STATIC_DRAW;
rhs._size = 0;
return *this;
}
GLenum Buffer::usage() const { return _usage; }
size_t Buffer::size() const { return _size; }
ByteVector Buffer::data() const {
bind();
ByteVector ret(_size);
glGetBufferSubData(Target, 0, _size, ret.data());
return ret;
}
void Buffer::data(const void* data_, size_t size_, GLenum usage_) {
declare();
glBufferData(Target, size_, data_, usage_);
_size = size_;
_usage = usage_;
}
void Buffer::data(const ByteVector& data_, GLenum usage_) {
declare();
data(data_.data(), data_.size(), usage_);
}
void Buffer::subdata(const void* data_, size_t size_, GLintptr offset_) {
bind();
if (offset_+size_ <= _size) {
THROW(BufferError(BufferError::Codes::DATA_OVERFLOW));
}
glBufferSubData(Target, offset_, size_, data_);
}
void Buffer::subdata(const ByteVector& data_, GLintptr offset_) {
bind();
size_t size_ = data_.size();
subdata(data_.data(), size_);
}
ElementBuffer::ElementBuffer() : Buffer(GL_ELEMENT_ARRAY_BUFFER) {}
ByteVector ElementBuffer::data() const {
return data();
}
size_t ElementBuffer::size() const { return _size / _typeSize; }
size_t ElementBuffer::typeSize() const { return _typeSize; }
GLenum ElementBuffer::glslType() const { return _glslType; }
template void ElementBuffer::data<uint8_t>(const std::vector<uint8_t>& data, GLenum usage);
template void ElementBuffer::data<uint16_t>(const std::vector<uint16_t>& data, GLenum usage);
template void ElementBuffer::data<uint32_t>(const std::vector<uint32_t>& data, GLenum usage);
template void ElementBuffer::data<uint8_t>(const uint8_t* const data, size_t size, GLenum usage);
template void ElementBuffer::data<uint16_t>(const uint16_t* const data, size_t size, GLenum usage);
template void ElementBuffer::data<uint32_t>(const uint32_t* const data, size_t size, GLenum usage);
template void ElementBuffer::subdata<uint8_t>(const uint8_t* const data, size_t size, size_t offset=0);
template void ElementBuffer::subdata<uint16_t>(const uint16_t* const data, size_t size, size_t offset=0);
template void ElementBuffer::subdata<uint32_t>(const uint32_t* const data, size_t size, size_t offset=0);
template void ElementBuffer::subdata<uint8_t>(const std::vector<uint8_t>& data, size_t offset=0);
template void ElementBuffer::subdata<uint16_t>(const std::vector<uint16_t>& data, size_t offset=0);
template void ElementBuffer::subdata<uint32_t>(const std::vector<uint32_t>& data, size_t offset=0);
}
+342
View File
@@ -0,0 +1,342 @@
#include "FrameBuffers.hpp"
namespace nb {
using FBOErrorCodes = FrameBufferError::Codes;
const std::string FrameBufferError::type = "nb::FrameBufferError";
const ErrorCodeMap FrameBufferError::ErrorMessages = {
{FBOErrorCodes::UNDEFINED, "Error"},
{FBOErrorCodes::INVALID_VALUE, "Invalid value"}
};
GLuint FrameBufferBase::declare() {
if (!_id) {
glGenFramebuffers(1, &_id);
}
bind();
return _id;
}
void FrameBufferBase::remove() {
if (_id) {
unbind();
glDeleteFramebuffers(1, &_id);
_id=0;
}
}
FrameBufferBase::FrameBufferBase(GLenum target) : Target(target) {}
std::shared_ptr<RenderTarget> FrameBufferBase::detach(GLenum attch_) {
bind();
auto ret = _attachments.at(attch_);
_attachments.erase(attch_);
glFramebufferTexture(Target, attch_, 0, 0);
return ret;
}
void FrameBufferBase::attach(
GLenum attachment_,
std::shared_ptr<Texture> texture_,
unsigned int level_,
unsigned int layer_
) {
declare();
if (attachment_ == GL_NONE) {
THROW(FrameBufferError(FrameBufferError::INVALID_VALUE,
"Cannot attach object to `GL_NONE`"
));
}
glFramebufferTextureLayer(
Target,
attachment_,
texture_->id(),
level_,
layer_
);
_attachments[attachment_] = texture_;
}
void FrameBufferBase::attach(
GLenum attachment_,
std::shared_ptr<Texture> texture_,
unsigned int level_
) {
declare();
if (attachment_ == GL_NONE) {
THROW(FrameBufferError(FrameBufferError::INVALID_VALUE,
"Cannot attach object to `GL_NONE`"
));
}
if (texTypeIs2D(texture_->Target)) {
glFramebufferTexture2D(
Target,
attachment_,
texture_->Target,
texture_->id(),
level_
);
} else {
glFramebufferTexture1D(
Target,
attachment_,
texture_->Target,
texture_->id(),
level_
);
}
_attachments[attachment_] = texture_;
}
void FrameBufferBase::bind() const {
if (_id) {
glBindFramebuffer(Target, _id);
} else {
THROW(OGLError(
OGLError::Codes::INVALID_OBJECT,
"w/ FrameBuffer"
));
}
}
void FrameBufferBase::unbind() const {
glBindFramebuffer(Target, 0);
}
GLenum FrameBufferBase::status() const {
bind();
return glCheckFramebufferStatus(Target);
}
FrameBufferBase::AttachmentMap FrameBufferBase::getAllBuffers() const {
return _attachments;
}
std::shared_ptr<RenderTarget> FrameBufferBase::getBuffer(GLenum attch_) const {
try {
return _attachments.at(attch_);
} catch (const std::out_of_range& e) {
THROW(e);
}
}
// class ReadFrameBuffer
ReadFrameBuffer::ReadFrameBuffer()
: _location(GL_NONE), FrameBufferBase(GL_READ_FRAMEBUFFER) {}
ReadFrameBuffer& ReadFrameBuffer::operator=(WriteFrameBuffer&& mv) {
if (mv.id()) {
_attachments = mv.getAllBuffers();
mv.setWriteBuffer(GL_NONE);
mv._attachments = {};
mv._locations = {};
FrameBufferBase::OpenGLObject::operator=(std::move(mv));
}
return *this;
}
ReadFrameBuffer& ReadFrameBuffer::operator=(ReadFrameBuffer&& mv) {
if (mv.id()) {
_attachments = mv._attachments;
_location = mv._location;
mv._attachments = {};
mv._location = GL_NONE;
FrameBufferBase::OpenGLObject::operator=(std::move(mv));
}
return *this;
}
std::shared_ptr<RenderTarget> ReadFrameBuffer::getReadBuffer() const {
if (_location == GL_NONE) { return nullptr; }
return getBuffer(_location);
}
GLenum ReadFrameBuffer::getReadLocation() const { return _location; }
std::shared_ptr<RenderTarget> ReadFrameBuffer::setReadBuffer(GLenum attch_) {
bind();
if (attch_!=GL_NONE) {
try {
const auto& x = _attachments.at(attch_);
} catch (const std::out_of_range& e) {
THROW(FrameBufferError(FrameBufferError::INVALID_VALUE,
"No buffer set at attachment"
));
}
}
_location = attch_;
glReadBuffer(_location);
return getReadBuffer();
}
// class WriteFrameBuffer
WriteFrameBuffer::WriteFrameBuffer()
: FrameBufferBase(GL_DRAW_FRAMEBUFFER) {}
WriteFrameBuffer& WriteFrameBuffer::operator=(ReadFrameBuffer&& rhs) {
if (rhs.id()) {
_attachments = rhs._attachments;
rhs.setReadBuffer(GL_NONE);
rhs._attachments = {};
rhs._location = GL_NONE;
FrameBufferBase::OpenGLObject::operator=(std::move(rhs));
}
return *this;
}
WriteFrameBuffer& WriteFrameBuffer::operator=(WriteFrameBuffer&& rhs) {
if (rhs.id()) {
_attachments = rhs._attachments;
_locations = rhs._locations;
rhs._attachments = {};
rhs._locations = {};
FrameBufferBase::OpenGLObject::operator=(std::move(rhs));
}
return *this;
}
using fRGBA = RGBA<float>;
std::vector<std::shared_ptr<Texture>> WriteFrameBuffer::getWriteBuffers() const {
const size_t count = _locations.size();
std::vector<std::shared_ptr<Texture>> ret(count);
for (int i = 0; i < count; ++i) {
ret[i] = std::static_pointer_cast<Texture>(getBuffer(_locations[i]));
}
return ret;
}
std::vector<GLenum> WriteFrameBuffer::getWriteLocations() const {
return _locations;
}
WriteFrameBuffer::DrawTexVec WriteFrameBuffer::setWriteBuffers(const std::vector<GLenum>& attchs_) {
bind();
for (GLenum loc : attchs_) {
if (getBuffer(loc)->Target == GL_RENDERBUFFER) {
THROW(FrameBufferError(FrameBufferError::INVALID_VALUE,
"Cannot write to renderbuffer [ @ Attachment = "+std::to_string(loc)+" ]"
));
}
}
_locations = attchs_;
glDrawBuffers(_locations.size(), _locations.data());
return getWriteBuffers();
}
std::shared_ptr<Texture> WriteFrameBuffer::setWriteBuffer(GLenum attch_) {
bind();
if (attch_ == GL_NONE) {
std::vector<GLenum> tmp(_locations.size(), GL_NONE);
glDrawBuffers(tmp.size(), tmp.data());
_locations = {};
return nullptr;
}
setWriteBuffers({attch_});
return std::static_pointer_cast<Texture>(getBuffer(attch_));
}
fRGBA WriteFrameBuffer::clearColorValue() const {
bind();
float rgba[4];
glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba);
return fRGBA{rgba[0], rgba[1], rgba[2], rgba[3]};
}
fRGBA WriteFrameBuffer::clearColorValue(const fRGBA& color) {
declare();
glClearColor(color.r, color.g, color.b, color.a);
return color;
}
fRGBA WriteFrameBuffer::clearColorValue(float r, float g, float b, float a) {
return clearColorValue({r, g,b , a});
}
double WriteFrameBuffer::clearDepthValue() const {
bind();
double ret;
glGetDoublev(GL_DEPTH_CLEAR_VALUE, &ret);
return ret;
}
double WriteFrameBuffer::clearDepthValue(double d_) {
declare();
glClearDepth(d_);
return d_;
}
GLint WriteFrameBuffer::clearStencilValue() const {
bind();
GLint ret;
glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &ret);
return ret;
}
GLint WriteFrameBuffer::clearStencilValue(GLint s_) {
declare();
glClearStencil(s_);
return s_;
}
void WriteFrameBuffer::clear(GLbitfield mask_) const {
bind();
glClear(mask_);
}
void WriteFrameBuffer::clearDepth() const {
clear(GL_DEPTH_BUFFER_BIT);
}
void WriteFrameBuffer::clearDepth(float val_) const {
bind();
glClearBufferfv(GL_DEPTH, 0, &val_);
}
void WriteFrameBuffer::clearStencil() const {
clear(GL_STENCIL_BUFFER_BIT);
}
void WriteFrameBuffer::clearStencil(GLint val_) const {
bind();
glClearBufferiv(GL_STENCIL, 0, &val_);
}
void WriteFrameBuffer::clearDepthStencil() const {
clear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
void WriteFrameBuffer::clearDepthStencil(float d_, GLint s_) const {
bind();
glClearBufferfi(GL_DEPTH_STENCIL, 0, d_, s_);
}
FrameBuffer::FrameBuffer()
: FrameBufferBase(GL_FRAMEBUFFER) {}
FrameBuffer& FrameBuffer::operator=(FrameBuffer&& rhs) {
if (rhs.id()) {
_attachments = rhs._attachments;
_location = rhs._location;
_locations = rhs._locations;
rhs._attachments = {};
rhs._locations = {};
rhs._location = GL_NONE;
OpenGLObject::operator=(std::move(rhs));
}
return *this;
}
FrameBuffer& FrameBuffer::operator=(ReadFrameBuffer&& rhs) {
ReadFrameBuffer::operator=(std::move(rhs));
return *this;
}
FrameBuffer& FrameBuffer::operator=(WriteFrameBuffer&& rhs) {
WriteFrameBuffer::operator=(std::move(rhs));
return *this;
}
} // namespace nb
+8
View File
@@ -0,0 +1,8 @@
#include "Image.hpp"
using ImageErrorCodes = nb::ImageError::Codes;
const std::string nb::ImageError::type = "nb::ImageError";
const nb::ErrorCodeMap nb::ImageError::ErrorMessages = {
{ ImageErrorCodes::UNDEFINED, "Error" },
{ImageErrorCodes::OUT_OF_BOUNDS, "Out of bounds"}
};
+13 -1
View File
@@ -5,7 +5,19 @@ namespace nb {
const std::string OGLError::type = "nb::OGLError";
const ErrorCodeMap OGLError::ErrorMessages = {
{ OGLError::Codes::UNDEFINED, "Error" },
{OGLError::Codes::HANGING_OBJECT, "Attempting to leave a hanging OpenGL object"}
{OGLError::Codes::HANGING_OBJECT, "Attempting to leave a hanging OpenGL object"},
{OGLError::Codes::INVALID_OBJECT, "Attempting operation with invalid object"}
};
OpenGLObject::OpenGLObject(OpenGLObject&& rval) {
*this = std::move(rval);
}
OpenGLObject& OpenGLObject::operator=(OpenGLObject&& rhs) {
if (_id) { THROW(OGLError(Codes::HANGING_OBJECT)); }
_id = rhs._id;
rhs._id = 0;
return *this;
}
} // namespace nb
+17 -10
View File
@@ -15,22 +15,29 @@ const ErrorCodeMap ProgramError::ErrorMessages = {
{ProgramErrCodes::LINKING_ERROR, "Linker error"}
};
Shader::Shader(GLenum target_, const std::string& source_) : target(target_) {
Shader::Shader(GLenum target_, const std::string& source_)
: Shader(target_, std::vector<std::string>({source_})) {}
Shader::Shader(GLenum target_, const std::vector<std::string>& strings_)
: target(target_), _sources(strings_) {
declare();
const char* src_ptr= source_.data();
glShaderSource(_id, 1, &src_ptr, NULL);
glCompileShader(_id);
_success = status(GL_COMPILE_STATUS);
if (!_success) {
WARN(log(), 0x0FE);
}
compile();
}
Shader::Shader(Shader&& cpy) : target(cpy.target) {
Shader::Shader(Shader&& cpy)
: target(cpy.target), _success(cpy._success), _sources(cpy._sources) {
_id = cpy._id;
cpy._success = false;
cpy._sources = {};
cpy._id = 0;
}
Shader::operator bool() { return _success; }
Shader::operator bool() { return success(); }
bool Shader::success() const {
return _success;
}
GLint Shader::status(GLenum parameter) const {
GLint param = 0;
+2 -5
View File
@@ -1,10 +1,7 @@
#include "Textures.hpp"
namespace nb{
Texture::Texture(GLenum target_) : target(target_) {
glGenTextures(1, &_id);
}
namespace nb {
Texture::Texture(GLenum target_) : Base(target_) {}
} // namespace nb
+41 -21
View File
@@ -6,8 +6,14 @@ using VAOErrorCodes = VAOError::Codes;
const std::string VAOError::type = "nb::VAOError";
const ErrorCodeMap VAOError::ErrorMessages = {
{ VAOErrorCodes::UNDEFINED, "Error" },
{ VAOErrorCodes::INVALID_ATTRIBUTE, "Targeting invalid attribute"},
{ VAOErrorCodes::INVALID_VAO, "Targeting invalid VAO" }
{ VAOErrorCodes::INVALID_ATTRIBUTE, "Targeting invalid attribute"}
};
using VertexCodes = VertexError::Codes;
const std::string VertexError::type = "nb::VertexError";
const ErrorCodeMap VertexError::ErrorMessages = {
{ VertexError::UNDEFINED, "Error" },
{ VertexError::MISALIGNED_DATA, "Data does not match vertex layout"}
};
VAO::VAO(const VertexAttributePointerList& attr_ptrs) {
@@ -19,12 +25,9 @@ VAO::VAO(VAO&& other) {
}
VAO& VAO::operator=(VAO&& rhs) {
_id = rhs._id;
OpenGLObject::operator=(std::move(rhs));
_attrs = rhs._attrs;
rhs._id = 0;
rhs._attrs = {};
return *this;
}
@@ -115,25 +118,17 @@ VertexGroup& VertexGroup::operator=(VertexGroup&& rhs) {
return *this;
}
VertexGroup::VertexGroup(const VertexDataVec& vertex_data_)
: _vao(std::make_shared<VAO>()), _ebo(std::make_shared<EBO>()) {
setBuffers(vertex_data_);
void VertexGroup::draw() const {
bind();
glDrawElements(primitive, _ebo->size(), _ebo->glslType(), 0);
}
VertexGroup::VertexGroup(const VertexData& vertex_data_)
: VertexGroup(VertexDataVec({vertex_data_})) {}
VertexGroup::VertexGroup(
const ByteVector& data_,
const VertexAttributeList& attrs_
) : VertexGroup({std::make_shared<VBO>(data_), attrs_}) {}
size_t VertexGroup::addBuffer(const VertexData& vertex_data_) {
VertexData data = vertex_data_;
_vertex_data.emplace_back(data);
VertexAttributePointerList attrs = _vao->attributes();
GLuint idx = attrs.size();
for (auto attr : data.attrs) {
for (const auto& attr : data.attrs) {
attrs.emplace_back(
VertexAttributePointer{attr, data.vbo->id(),idx}
);
@@ -143,6 +138,13 @@ size_t VertexGroup::addBuffer(const VertexData& vertex_data_) {
return _vertex_data.size();
}
size_t VertexGroup::addBuffer(const ByteVector& data_, const VertexAttributeList& attrs_) {
return addBuffer({
std::make_shared<VBO>(data_),
attrs_
});
}
VertexData VertexGroup::getBuffers(size_t idx) {
return _vertex_data[idx];
}
@@ -155,8 +157,8 @@ size_t VertexGroup::setBuffers(const VertexDataVec& vertex_data_) {
_vertex_data = vertex_data_;
VertexAttributePointerList attr_ptrs;
GLuint idx = 0;
for (auto data : _vertex_data) {
for (auto attr : data.attrs) {
for (const auto& data : _vertex_data) {
for (const auto& attr : data.attrs) {
attr_ptrs.emplace_back(
VertexAttributePointer{attr, data.vbo->id(), idx}
);
@@ -167,9 +169,15 @@ size_t VertexGroup::setBuffers(const VertexDataVec& vertex_data_) {
return _vertex_data.size();
}
VertexDataVec VertexGroup::dropBuffers() {
auto ret = _vertex_data;
setBuffers({});
return ret;
}
VertexData VertexGroup::dropBuffer(size_t idx) {
if (idx >= _vertex_data.size()) {
THROW(BufferError(BufferError::Codes::INVALID_BUFFER));
THROW(NBError(NBError::INDEX_ERROR));
}
VertexDataVec tmp;
VertexData ret;
@@ -228,4 +236,16 @@ void VertexGroup::enable() { _vao->enable(); }
void VertexGroup::disable() { _vao->disable(); }
std::shared_ptr<EBO> VertexGroup::indices() const { return _ebo; }
std::shared_ptr<EBO> VertexGroup::indices(const std::vector<uint32_t>& data) {
_ebo->data(data);
return _ebo;
}
std::shared_ptr<EBO> VertexGroup::indices(std::shared_ptr<EBO> buffer) {
_ebo = buffer;
return _ebo;
}
} // namespace nb