From bd57f345ed9dbed1d81683e48199626de2ea9044 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Fri, 27 Jun 2025 10:18:39 -0700 Subject: Restructure project --- src/core/framebuffer.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 src/core/framebuffer.c (limited to 'src/core/framebuffer.c') diff --git a/src/core/framebuffer.c b/src/core/framebuffer.c new file mode 100644 index 0000000..76d9002 --- /dev/null +++ b/src/core/framebuffer.c @@ -0,0 +1,151 @@ +#include "framebuffer.h" + +#include "renderbuffer.h" +#include "texture.h" + +#include + +#include + +static void framebuffer_attach_colour( + FrameBuffer* framebuffer, const FrameBufferAttachment* attachment) { + assert(framebuffer); + assert(attachment); + + switch (attachment->type) { + case FrameBufferNoAttachment: + break; + case FrameBufferTexture: + glFramebufferTexture2D( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + attachment->texture.texture->id, attachment->texture.mip_level); + break; + case FrameBufferCubemapTexture: + glFramebufferTexture2D( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + to_GL_cubemap_face(attachment->cubemap.face), + attachment->cubemap.texture->id, attachment->cubemap.mip_level); + break; + case FrameBufferRenderBuffer: + glFramebufferRenderbuffer( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, + attachment->renderbuffer->id); + break; + } + + ASSERT_GL; +} + +static void framebuffer_attach_depth( + FrameBuffer* framebuffer, const FrameBufferAttachment* attachment) { + assert(framebuffer); + assert(attachment); + + switch (attachment->type) { + case FrameBufferNoAttachment: + break; + case FrameBufferTexture: + glFramebufferTexture2D( + GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_DEPTH_COMPONENT, + attachment->texture.texture->id, attachment->texture.mip_level); + break; + // TODO: Could distinguish between colour and depth attachment types to make + // this a compile-time error. + case FrameBufferCubemapTexture: + log_error("Cannot use a cubemap texture as a depth framebuffer attachment"); + break; + case FrameBufferRenderBuffer: + glFramebufferRenderbuffer( + GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, + attachment->renderbuffer->id); + break; + } + + ASSERT_GL; +} + +bool gfx_init_framebuffer( + FrameBuffer* framebuffer, const FrameBufferDesc* desc) { + assert(framebuffer); + assert(desc); + + glGenFramebuffers(1, &framebuffer->id); + if (!framebuffer->id) { + log_error("glGenFramebuffers() failed"); + return false; + } + + // Allow incomplete framebuffers for flexibility. + // Attach buffers and check the framebuffer status only if buffers are given + // up front. + if (desc->colour.type != FrameBufferNoAttachment || + desc->depth.type != FrameBufferNoAttachment) { + // TODO: Could use the "named" API to avoid having to bind the framebuffer. + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer->id); + framebuffer_attach_colour(framebuffer, &desc->colour); + framebuffer_attach_depth(framebuffer, &desc->depth); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + log_error("glCheckFramebufferStatus() failed"); + gfx_del_framebuffer(framebuffer); + return false; + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + ASSERT_GL; + return true; +} + +bool gfx_framebuffer_attach_colour( + FrameBuffer* framebuffer, const FrameBufferAttachment* attachment) { + assert(framebuffer); + assert(attachment); + + // TODO: Could use the "named" API to avoid having to bind the framebuffer. + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer->id); + framebuffer_attach_colour(framebuffer, attachment); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + log_error("glCheckFramebufferStatus() failed"); + return false; + } + return true; +} + +bool gfx_framebuffer_attach_depth( + FrameBuffer* framebuffer, const FrameBufferAttachment* attachment) { + assert(framebuffer); + assert(attachment); + + // TODO: Could use the "named" API to avoid having to bind the framebuffer. + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer->id); + framebuffer_attach_depth(framebuffer, attachment); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + log_error("glCheckFramebufferStatus() failed"); + return false; + } + return true; +} + +void gfx_del_framebuffer(FrameBuffer* framebuffer) { + assert(framebuffer); + if (framebuffer->id) { + glDeleteFramebuffers(1, &framebuffer->id); + framebuffer->id = 0; + } +} + +void gfx_activate_framebuffer(const FrameBuffer* framebuffer) { + assert(framebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer->id); +} + +void gfx_deactivate_framebuffer(const FrameBuffer* framebuffer) { + assert(framebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +void gfx_framebuffer_set_viewport( + FrameBuffer* framebuffer, int x, int y, int width, int height) { + assert(framebuffer); + glViewport(x, y, width, height); +} -- cgit v1.2.3