#include "gfx/gl_loader.h" #include "gfx/gl_framebuffer.h" namespace fn::gfx { static void create_tex(Framebuffer& f) { glGenTextures(1, &f.tex); glBindTexture(GL_TEXTURE_2D, f.tex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, f.width, f.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glBindTexture(GL_TEXTURE_2D, 0); } static void create_depth_rbo(Framebuffer& f) { glGenRenderbuffers(1, &f.depth_rbo); glBindRenderbuffer(GL_RENDERBUFFER, f.depth_rbo); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, f.width, f.height); glBindRenderbuffer(GL_RENDERBUFFER, 0); } void fb_init(Framebuffer& f) { f.width = 1; f.height = 1; f.has_depth = false; create_tex(f); glGenFramebuffers(1, &f.fbo); glBindFramebuffer(GL_FRAMEBUFFER, f.fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, f.tex, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); } void fb_init_depth(Framebuffer& f) { f.width = 1; f.height = 1; f.has_depth = true; create_tex(f); create_depth_rbo(f); glGenFramebuffers(1, &f.fbo); glBindFramebuffer(GL_FRAMEBUFFER, f.fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, f.tex, 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, f.depth_rbo); glBindFramebuffer(GL_FRAMEBUFFER, 0); } void fb_resize(Framebuffer& f, int w, int h) { if (w == f.width && h == f.height) return; f.width = w; f.height = h; // Recreate color texture. if (f.tex) glDeleteTextures(1, &f.tex); f.tex = 0; create_tex(f); glBindFramebuffer(GL_FRAMEBUFFER, f.fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, f.tex, 0); // Resize depth renderbuffer in-place (no need to recreate). if (f.has_depth && f.depth_rbo) { glBindRenderbuffer(GL_RENDERBUFFER, f.depth_rbo); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, f.width, f.height); glBindRenderbuffer(GL_RENDERBUFFER, 0); // Re-attach in case it was lost (should be stable across storage resize, but be safe). glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, f.depth_rbo); } glBindFramebuffer(GL_FRAMEBUFFER, 0); } void fb_destroy(Framebuffer& f) { if (f.fbo) { glDeleteFramebuffers(1, &f.fbo); f.fbo = 0; } if (f.tex) { glDeleteTextures(1, &f.tex); f.tex = 0; } if (f.depth_rbo) { glDeleteRenderbuffers(1, &f.depth_rbo); f.depth_rbo = 0; } f.width = 0; f.height = 0; f.has_depth = false; } } // namespace fn::gfx