Files
fn_registry/cpp/functions/gfx/shader_canvas.cpp
T
egutierrez 042bb43b37 feat(shaders_lab): scaffold C++ app with GLSL live-reload canvas
- cpp/functions/gfx: gl_shader, gl_framebuffer, fullscreen_quad, shader_canvas
- cpp/apps/shaders_lab: main + 3 seed shaders (plasma, circle, checker)
- ImGui docking layout: Code | Canvas | Controls

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 20:33:36 +02:00

86 lines
2.4 KiB
C++

#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glext.h>
#include "gfx/shader_canvas.h"
#include "imgui.h"
namespace fn::gfx {
void canvas_init(ShaderCanvas& c) {
if (c.initialized) return;
fb_init(c.fb);
quad_init(c.quad);
c.initialized = true;
}
void canvas_set_program(ShaderCanvas& c, unsigned int program) {
if (c.program) delete_program(c.program);
c.program = program;
}
void canvas_render(ShaderCanvas& c, float time_seconds) {
ImVec2 avail = ImGui::GetContentRegionAvail();
int w = static_cast<int>(avail.x);
int h = static_cast<int>(avail.y);
if (w < 1) w = 1;
if (h < 1) h = 1;
fb_resize(c.fb, w, h);
// Save GL state
GLint prev_fbo = 0;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prev_fbo);
GLint prev_vp[4];
glGetIntegerv(GL_VIEWPORT, prev_vp);
// Render to FBO
glBindFramebuffer(GL_FRAMEBUFFER, c.fb.fbo);
glViewport(0, 0, w, h);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
if (c.program) {
glUseProgram(c.program);
GLint loc_res = glGetUniformLocation(c.program, "u_resolution");
GLint loc_time = glGetUniformLocation(c.program, "u_time");
GLint loc_mouse = glGetUniformLocation(c.program, "u_mouse");
if (loc_res >= 0) glUniform2f(loc_res, static_cast<float>(w), static_cast<float>(h));
if (loc_time >= 0) glUniform1f(loc_time, time_seconds);
if (loc_mouse >= 0) {
ImVec2 mouse = ImGui::GetMousePos();
ImVec2 canvas_pos = ImGui::GetCursorScreenPos();
// cursor pos is AFTER content region starts
float mx = mouse.x - canvas_pos.x;
float my = static_cast<float>(h) - (mouse.y - canvas_pos.y);
glUniform2f(loc_mouse, mx, my);
}
quad_draw(c.quad);
glUseProgram(0);
}
// Restore GL state
glBindFramebuffer(GL_FRAMEBUFFER, static_cast<GLuint>(prev_fbo));
glViewport(prev_vp[0], prev_vp[1], prev_vp[2], prev_vp[3]);
// Draw texture in ImGui panel (flip V: OpenGL origin is bottom-left)
ImGui::Image(
(ImTextureID)(intptr_t)c.fb.tex,
avail,
ImVec2(0, 1), ImVec2(1, 0)
);
}
void canvas_destroy(ShaderCanvas& c) {
if (!c.initialized) return;
if (c.program) { delete_program(c.program); c.program = 0; }
quad_destroy(c.quad);
fb_destroy(c.fb);
c.initialized = false;
}
} // namespace fn::gfx