fd5787c55f
- .mcp.json - bash/functions/infra/write_mcp_jupyter_config.md - bash/functions/infra/write_mcp_jupyter_config.sh - cpp/CMakeLists.txt - cpp/apps/chart_demo - cpp/apps/shaders_lab - cpp/functions/gfx/gl_framebuffer.cpp - cpp/functions/gfx/gl_framebuffer.h - cpp/functions/gfx/gl_framebuffer.md - cpp/functions/gfx/mesh_gpu.md - ... Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
82 lines
2.9 KiB
C++
82 lines
2.9 KiB
C++
#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
|