087412d73a
- demos_text_editor.cpp: split horizontal con editor GLSL precargado a la izquierda (boton Save to /tmp/fn_demo.glsl + dirty indicator) y panel de eventos a la derecha (path, active flag, lista scrollable, boton clear). Watcher activo sobre /tmp/fn_demo.glsl; reintenta el add() tras el primer Save si el archivo no existia al iniciar. - demos.h: declaracion de gallery::demo_text_editor() - main.cpp: entry "text_editor"/"text_editor + watcher" en categoria Core - CMakeLists.txt: anade demos_text_editor.cpp + sources de text_editor, file_watcher y vendor TextEditor.cpp + include path de imgui_text_edit Nota: la primitives_gallery NO se construye en este branch (sus deps — button.cpp, toolbar.cpp, etc. — son untracked en master). El subdirectorio se anade pero protegido por FN_BUILD_GALLERY=OFF para no romper builds. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
124 lines
3.6 KiB
C++
124 lines
3.6 KiB
C++
// Demos del dominio gfx — primitivos OpenGL/shader que viven en
|
|
// cpp/functions/gfx/. La pieza distintiva de shaders_lab es el
|
|
// shader_canvas: framebuffer + fullscreen quad + programa GL animado por
|
|
// time/resolution/mouse.
|
|
|
|
#include "demos.h"
|
|
#include "demo.h"
|
|
|
|
#include "gfx/shader_canvas.h"
|
|
#include "gfx/gl_shader.h"
|
|
#include "gfx/gl_loader.h"
|
|
|
|
#include <imgui.h>
|
|
#include <chrono>
|
|
|
|
namespace gallery {
|
|
|
|
namespace {
|
|
|
|
// Fragment shader sintetico — gradiente animado con celdas. Usa los uniforms
|
|
// estandar que compile_fragment inyecta: u_resolution, u_time, u_mouse.
|
|
const char* kShaderSrc = R"(
|
|
void mainImage() {
|
|
vec2 uv = gl_FragCoord.xy / u_resolution;
|
|
vec2 cell = uv * 8.0;
|
|
vec2 ipos = floor(cell);
|
|
vec2 fpos = fract(cell) - 0.5;
|
|
|
|
float t = u_time * 0.6;
|
|
float wave = sin(ipos.x * 0.7 + ipos.y * 0.5 + t);
|
|
float dist = length(fpos);
|
|
|
|
vec3 a = vec3(0.30, 0.43, 0.96); // indigo
|
|
vec3 b = vec3(0.95, 0.45, 0.85); // pink
|
|
vec3 col = mix(a, b, 0.5 + 0.5 * wave);
|
|
|
|
// Mouse focus: oscurecemos celdas lejanas al cursor.
|
|
vec2 m = u_mouse / u_resolution;
|
|
float fm = 1.0 - smoothstep(0.0, 0.6, length(uv - m));
|
|
col *= 0.6 + 0.4 * fm;
|
|
|
|
// Disco interior por celda con borde suave.
|
|
col *= smoothstep(0.5, 0.45, dist);
|
|
|
|
fragColor = vec4(col, 1.0);
|
|
}
|
|
|
|
void main() {
|
|
mainImage();
|
|
}
|
|
)";
|
|
|
|
struct CanvasState {
|
|
fn::gfx::ShaderCanvas canvas;
|
|
bool compiled = false;
|
|
bool compile_failed = false;
|
|
std::string err_msg;
|
|
std::chrono::steady_clock::time_point t0;
|
|
};
|
|
|
|
CanvasState& state() {
|
|
static CanvasState s;
|
|
return s;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
void demo_shader_canvas() {
|
|
demo_header("shader_canvas", "v1.0.0",
|
|
"Framebuffer + fullscreen quad + shader GLSL animado. La misma pieza "
|
|
"que usa shaders_lab para el preview en vivo. Uniforms u_time / u_resolution / u_mouse "
|
|
"los inyecta gl_shader::compile_fragment automaticamente.");
|
|
|
|
auto& s = state();
|
|
|
|
// Compilacion lazy (en el primer frame ya hay contexto GL valido).
|
|
if (!s.compiled && !s.compile_failed) {
|
|
fn::gfx::gl_loader_init();
|
|
fn::gfx::canvas_init(s.canvas);
|
|
|
|
auto cr = fn::gfx::compile_fragment(kShaderSrc);
|
|
if (!cr.ok) {
|
|
s.compile_failed = true;
|
|
s.err_msg = cr.err_msg;
|
|
} else {
|
|
fn::gfx::canvas_set_program(s.canvas, cr.program);
|
|
s.t0 = std::chrono::steady_clock::now();
|
|
s.compiled = true;
|
|
}
|
|
}
|
|
|
|
if (s.compile_failed) {
|
|
ImGui::TextColored(ImVec4(1, 0.4f, 0.4f, 1),
|
|
"Compilacion del fragment shader fallo:\n%s",
|
|
s.err_msg.c_str());
|
|
return;
|
|
}
|
|
|
|
section("Live preview");
|
|
|
|
// Render del shader en un panel ~480x300 px. canvas_render hace resize
|
|
// automatico segun GetContentRegionAvail si lo dejas crecer.
|
|
ImGui::BeginChild("##shader_preview", ImVec2(480, 300),
|
|
ImGuiChildFlags_Borders);
|
|
const float dt = std::chrono::duration<float>(
|
|
std::chrono::steady_clock::now() - s.t0).count();
|
|
fn::gfx::canvas_render(s.canvas, dt);
|
|
ImGui::EndChild();
|
|
|
|
code_block(
|
|
"#include \"gfx/shader_canvas.h\"\n"
|
|
"#include \"gfx/gl_shader.h\"\n\n"
|
|
"static fn::gfx::ShaderCanvas canvas;\n"
|
|
"// Setup (una vez):\n"
|
|
"fn::gfx::canvas_init(canvas);\n"
|
|
"auto cr = fn::gfx::compile_fragment(user_glsl);\n"
|
|
"if (cr.ok) fn::gfx::canvas_set_program(canvas, cr.program);\n\n"
|
|
"// Cada frame, dentro de un Begin/End:\n"
|
|
"fn::gfx::canvas_render(canvas, time_seconds);"
|
|
);
|
|
}
|
|
|
|
} // namespace gallery
|