diff --git a/CMakeLists.txt b/CMakeLists.txt index 34e75ee..2c750cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.25) -set(BLT_GRAPHICS_VERSION 0.9.17) +set(BLT_GRAPHICS_VERSION 0.10.1) set(BLT_GRAPHICS_TEST_VERSION 0.0.1) project(BLT_WITH_GRAPHICS VERSION ${BLT_GRAPHICS_VERSION}) diff --git a/include/blt/gfx/framebuffer.h b/include/blt/gfx/framebuffer.h index 512a272..3701631 100644 --- a/include/blt/gfx/framebuffer.h +++ b/include/blt/gfx/framebuffer.h @@ -42,6 +42,7 @@ namespace blt::gfx GLuint rboID; GLuint storage_type; blt::i32 width_, height_; + blt::i32 samples = 0; public: rbo_t(): rboID(0), storage_type(0), width_(-1), height_(-1) {} @@ -52,14 +53,21 @@ namespace blt::gfx void setStorage(GLuint storage_type, blt::i32 width, blt::i32 height); + void setStorageMultiSampled(GLuint storage_type, blt::i32 width, blt::i32 height, blt::i32 samples); + void updateStorage(blt::i32 width, blt::i32 height); + void updateStorageMultiSampled(blt::i32 width, blt::i32 height, blt::i32 samples); + void resize(blt::i32 width, blt::i32 height); + static void unbind(); void destroy(); static rbo_t make_render_buffer(GLuint storage_type, blt::i32 width, blt::i32 height); + + static rbo_t make_render_buffer(GLuint storage_type, blt::i32 width, blt::i32 height, blt::i32 samples); }; class fbo_t @@ -99,18 +107,42 @@ namespace blt::gfx // this function takes ownership of the render buffer void attachRenderBuffer(rbo_t rbo, attachment_t attachment); - void blitTexture(const fbo_t& draw, blt::i32 srcX_off = 0, blt::i32 srcY_off = 0, blt::i32 destX_off = 0, blt::i32 destY_off = 0, GLuint filter = GL_NEAREST) const; + void blitTexture(const fbo_t& draw, blt::i32 srcX_off = 0, blt::i32 srcY_off = 0, blt::i32 destX_off = 0, blt::i32 destY_off = 0, + GLuint filter = GL_NEAREST, attachment_t attachment_read = attachment_t::COLOR0, + attachment_t attachment_write = attachment_t::COLOR0) const; + void blitToScreen(blt::i32 width, blt::i32 height) const; - void blitDepth(const fbo_t& draw, blt::i32 srcX_off = 0, blt::i32 srcY_off = 0, blt::i32 destX_off = 0, blt::i32 destY_off = 0, GLuint filter = GL_NEAREST) const; + + void blitDepth(const fbo_t& draw, blt::i32 srcX_off = 0, blt::i32 srcY_off = 0, blt::i32 destX_off = 0, blt::i32 destY_off = 0, + GLuint filter = GL_NEAREST) const; + + void blitStencil(const fbo_t& draw, blt::i32 srcX_off = 0, blt::i32 srcY_off = 0, blt::i32 destX_off = 0, blt::i32 destY_off = 0, + GLuint filter = GL_NEAREST) const; static bool validate(); static void unbind(); void destroy(); + + [[nodiscard]] i32 getHeight() const + { + return height_; + } + + [[nodiscard]] i32 getWidth() const + { + return width_; + } public: static fbo_t make_render_texture(blt::i32 width, blt::i32 height); + + static fbo_t make_multisample_render_texture(blt::i32 width, blt::i32 height, blt::i32 samples); + + static fbo_t make_render_target(blt::i32 width, blt::i32 height); + + static fbo_t make_multisample_render_target(blt::i32 width, blt::i32 height, blt::i32 samples); }; #undef C diff --git a/src/blt/gfx/framebuffer.cpp b/src/blt/gfx/framebuffer.cpp index 63765c3..5cafbc7 100644 --- a/src/blt/gfx/framebuffer.cpp +++ b/src/blt/gfx/framebuffer.cpp @@ -43,13 +43,15 @@ namespace blt::gfx { width_ = width; height_ = height; + samples = 0; glRenderbufferStorage(GL_RENDERBUFFER, storage_type, width, height); } - void rbo_t::updateStorageMultiSampled(blt::i32 width, blt::i32 height, blt::i32 samples) + void rbo_t::updateStorageMultiSampled(blt::i32 width, blt::i32 height, blt::i32 s) { width_ = width; height_ = height; + samples = s; glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, storage_type, width, height); } @@ -59,6 +61,20 @@ namespace blt::gfx updateStorage(width, height); } + void rbo_t::setStorageMultiSampled(GLuint s_type, blt::i32 width, blt::i32 height, blt::i32 s) + { + storage_type = s_type; + updateStorageMultiSampled(width, height, s); + } + + void rbo_t::resize(blt::i32 width, blt::i32 height) + { + if (samples > 0) + updateStorageMultiSampled(width, height, samples); + else + updateStorage(width, height); + } + rbo_t rbo_t::make_render_buffer(GLuint storage_type, blt::i32 width, blt::i32 height) { rbo_t rbo{}; @@ -69,6 +85,16 @@ namespace blt::gfx return rbo; } + rbo_t rbo_t::make_render_buffer(GLuint storage_type, blt::i32 width, blt::i32 height, blt::i32 samples) + { + rbo_t rbo{}; + rbo.create(); + rbo.bind(); + rbo.setStorageMultiSampled(storage_type, width, height, samples); + rbo_t::unbind(); + return rbo; + } + void fbo_t::create(fbo_t::draw_t type) { generic_bind_type = static_cast(type); @@ -131,17 +157,20 @@ namespace blt::gfx for (auto& rbo : render_buffers) { rbo.bind(); - rbo.updateStorage(width, height); + rbo.resize(width, height); } for (auto& texture : texture_buffers) texture->updateSize(width, height); } - void fbo_t::blitTexture(const fbo_t& draw, blt::i32 srcX, blt::i32 srcY, blt::i32 destX, blt::i32 destY, GLuint filter) const + void fbo_t::blitTexture(const fbo_t& draw, blt::i32 srcX, blt::i32 srcY, blt::i32 destX, blt::i32 destY, GLuint filter, + attachment_t attachment_read, attachment_t attachment_write) const { glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, draw.fboID); + glReadBuffer(static_cast(attachment_read)); + glDrawBuffer(static_cast(attachment_write)); glBlitFramebuffer(srcX, srcY, width_, height_, destX, destY, draw.width_, draw.height_, GL_COLOR_BUFFER_BIT, filter); } @@ -152,6 +181,22 @@ namespace blt::gfx glBlitFramebuffer(srcX, srcY, width_, height_, destX, destY, draw.width_, draw.height_, GL_DEPTH_BUFFER_BIT, filter); } + void fbo_t::blitStencil(const fbo_t& draw, blt::i32 srcX, blt::i32 srcY, blt::i32 destX, blt::i32 destY, GLuint filter) const + { + glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, draw.fboID); + glBlitFramebuffer(srcX, srcY, width_, height_, destX, destY, draw.width_, draw.height_, GL_STENCIL_BUFFER_BIT, filter); + } + + void fbo_t::blitToScreen(blt::i32 width, blt::i32 height) const + { + glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + //glReadBuffer(GL_COLOR_ATTACHMENT0); + //glDrawBuffer(GL_COLOR_ATTACHMENT0); + glBlitFramebuffer(0, 0, width_, height_, 0, 0, width, height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); + } + fbo_t fbo_t::make_render_texture(blt::i32 width, blt::i32 height) { fbo_t fbo; @@ -162,11 +207,7 @@ namespace blt::gfx auto* texture = new texture_gl2D(width, height); fbo.attachTexture(texture, attachment_t::COLOR0); - rbo_t depth_rbo; - depth_rbo.create(); - depth_rbo.bind(); - depth_rbo.setStorage(GL_DEPTH24_STENCIL8, width, height); - + rbo_t depth_rbo = rbo_t::make_render_buffer(GL_DEPTH24_STENCIL8, width, height); fbo.attachRenderBuffer(depth_rbo, attachment_t::DEPTH_STENCIL); if (!fbo_t::validate()) @@ -176,10 +217,63 @@ namespace blt::gfx return fbo; } - void fbo_t::blitToScreen(blt::i32 width, blt::i32 height) const + fbo_t fbo_t::make_multisample_render_texture(blt::i32 width, blt::i32 height, blt::i32 samples) { - glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - glBlitFramebuffer(0, 0, width_, height_, 0, 0, width, height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); + fbo_t fbo; + + fbo.create(); + fbo.bind(); + + auto* texture = new texture_gl2D_multisample(width, height, samples); + fbo.attachTexture(texture, attachment_t::COLOR0); + + rbo_t depth_rbo = rbo_t::make_render_buffer(GL_DEPTH24_STENCIL8, width, height, samples); + fbo.attachRenderBuffer(depth_rbo, attachment_t::DEPTH_STENCIL); + + if (!fbo_t::validate()) + BLT_ERROR("Failed to create render texture framebuffer!"); + fbo_t::unbind(); + + return fbo; + } + + fbo_t fbo_t::make_multisample_render_target(blt::i32 width, blt::i32 height, blt::i32 samples) + { + fbo_t fbo; + + fbo.create(); + fbo.bind(); + + rbo_t color_rbo = rbo_t::make_render_buffer(GL_RGBA8, width, height, samples); + rbo_t depth_rbo = rbo_t::make_render_buffer(GL_DEPTH24_STENCIL8, width, height, samples); + + fbo.attachRenderBuffer(color_rbo, attachment_t::COLOR0); + fbo.attachRenderBuffer(depth_rbo, attachment_t::DEPTH_STENCIL); + + if (!fbo_t::validate()) + BLT_ERROR("Failed to create multi-sampled render texture framebuffer!"); + fbo_t::unbind(); + + return fbo; + } + + fbo_t fbo_t::make_render_target(blt::i32 width, blt::i32 height) + { + fbo_t fbo; + + fbo.create(); + fbo.bind(); + + rbo_t color_rbo = rbo_t::make_render_buffer(GL_RGBA8, width, height); + rbo_t depth_rbo = rbo_t::make_render_buffer(GL_DEPTH24_STENCIL8, width, height); + + fbo.attachRenderBuffer(color_rbo, attachment_t::COLOR0); + fbo.attachRenderBuffer(depth_rbo, attachment_t::DEPTH_STENCIL); + + if (!fbo_t::validate()) + BLT_ERROR("Failed to create multi-sampled render texture framebuffer!"); + fbo_t::unbind(); + + return fbo; } } \ No newline at end of file