Commit Graph

56 Commits

Author SHA1 Message Date
egutierrez bcdb51e1b8 merge: issue/0029 — mesh_viewer + obj loader + orbit_camera
# Conflicts:
#	cpp/apps/primitives_gallery/demos.h
#	cpp/apps/primitives_gallery/main.cpp
2026-04-25 21:54:27 +02:00
egutierrez 1fa82447c2 feat(primitives_gallery): demo de mesh_viewer (cubo procedural + .obj loader)
Genera cubo procedural in-line (mesh_obj_parse de string), permite
cargar .obj desde un text input absoluto. Botones: Reload cube,
Wireframe toggle, Load .obj. Status line con tris count y
instrucciones (drag to orbit, wheel to zoom).

issue 0029
2026-04-25 21:51:27 +02:00
egutierrez 281502ac92 feat(viz): mesh_viewer — componente 3D con FBO + Lambert headlight
Compila/cachea por id un programa GLSL (vertex+fragment) con
iluminacion Lambert (luz=camara), gestiona Framebuffer cacheado por
id, dibuja MeshGpu con orbit camera, muestra via ImGui::Image y
maneja drag (mouse) + wheel (zoom). Wireframe opcional via
glPolygonMode.

gl_loader: añade glUniformMatrix4fv (proc requerido en Windows para
subir las matrices view/proj del mesh_viewer).

issue 0029
2026-04-25 21:51:22 +02:00
egutierrez 3b662ac4c3 feat(core): orbit_camera — camara orbital pura (matrices view/proj + drag)
State minimal (azimuth, elevation, distance, fov, aspect, near/far).
orbit_camera_matrices: lookAt+perspective row-major float[16] (subir a
GL con transpose=GL_TRUE). orbit_camera_handle_drag: dx→azimuth,
dy→elevation (clamp ±π/2-eps), wheel→distance (clamp >0.1). Sin glm,
solo <cmath>.

issue 0029
2026-04-25 21:51:15 +02:00
egutierrez 44e189c5cc feat(gfx): mesh_gpu — VAO/VBO/EBO upload para Mesh
mesh_gpu_upload sube positions+normals interleaved (stride 6 floats,
location 0=a_pos, location 1=a_normal) + EBO uint32. mesh_gpu_destroy
libera todo. GL_STATIC_DRAW (mesh inmutable post-upload).

issue 0029
2026-04-25 21:51:10 +02:00
egutierrez 580e4ba1fd feat(gfx): mesh_obj_load — minimal Wavefront .obj parser
mesh_obj_parse (pure) + mesh_obj_load (impure file helper).
Soporta v / vn / f (tris y quads). Genera normales per-face si
faltan (flat shading). Quads se parten en 2 tris; n-gons (>4) se
descartan silenciosamente. Indices 1-based positivos y negativos.

issue 0029
2026-04-25 21:51:05 +02:00
egutierrez d2a244a765 feat(primitives_gallery): demos para surface_plot_3d + scatter_3d
- demos_3d.cpp con dos demos:
  * demo_surface_plot_3d: malla 64x64 de A*sin(fx*x)*cos(fy*y) con
    sliders fx/fy/amp en tiempo real.
  * demo_scatter_3d: 3 clusters gaussianos (N=500) coloreados por
    cluster, semilla fija para reproducibilidad.
- demos.h: declara las dos demos en la seccion Viz.
- main.cpp: dos entradas nuevas en k_demos[] (Viz, tras heatmap /
  table_view).
- CMakeLists.txt: anade demos_3d.cpp + surface_plot_3d.cpp +
  scatter_3d.cpp al target.

Issue 0028.
2026-04-25 21:48:51 +02:00
egutierrez 4268b6f187 feat(viz): surface_plot_3d real (ImPlot3D) + scatter_3d nuevo
surface_plot_3d (v2.0.0): quita el STUB. API basada en
SurfacePlot3DConfig (z[nx*ny] row-major + ranges X/Y) que delega en
ImPlot3D::PlotSurface. Las coordenadas X/Y por vertice se generan
internamente desde [x_min, x_max] x [y_min, y_max].

scatter_3d (v1.0.0): nuevo primitivo. Scatter 3D con tamano y color
opcionales por punto via ImPlot3DSpec::MarkerSizes / MarkerFillColors.
Util para PCA / clustering / nubes de puntos sinteticas.

Ambos namespace fn::, kind component, purity pure. Orbit / zoom / pan
los aporta ImPlot3D nativo.

Issue 0028.
2026-04-25 21:48:43 +02:00
egutierrez 7159ee6dcb feat(framework): inicializar contexto ImPlot3D en app_base
ImPlot3D::CreateContext() / DestroyContext() acoplado al ciclo de
vida de ImPlot. Cualquier app que use fn::run_app obtiene el contexto
3D listo sin codigo extra.

Issue 0028.
2026-04-25 21:48:34 +02:00
egutierrez e7ab06ee29 chore(vendor): vendorear ImPlot3D v0.4 como submodulo + target CMake
- submodule cpp/vendor/implot3d -> github.com/brenocq/implot3d, pinned
  commit 41ae3e447c0de20ecab95d38a4b4dc0835a3efc2 (v0.4).
- target CMake `implot3d` parejo a `implot` (3 sources: implot3d.cpp,
  implot3d_items.cpp, implot3d_meshes.cpp).
- fn_framework linkea implot3d para que cualquier app pueda usar las
  funciones viz/*_3d sin configurar nada extra.
- VENDORING.md externo (no tocamos el README upstream).

Issue 0028.
2026-04-25 21:48:29 +02:00
egutierrez 14cd888c2e feat(primitives_gallery): demos individuales para wave 1 + 5 primitivos viz/core
Cobertura del catalogo visual:
- text_editor (Wave 1, 0025): demo solo del editor con dropdown GLSL/SQL/Cpp/Generic.
- file_watcher (Wave 1, 0025): demo solo del watcher con boton touch + log.
- gl_texture_load (Wave 1, 0026): ya tenia demo (Gfx).
- process_runner: tarea simulada en background con spinner.
- candlestick: 30 dias OHLC sintetico.
- gauge: 3 indicadores con sliders (CPU/MEM/GPU).
- heatmap: gaussiana 12x12.
- table_view: 6 funciones del registry como muestra.

El demo combinado anterior (text_editor + watcher) se separa en dos para
que cada entry del sidebar exhiba un solo primitivo. Mas claro y mas
indexable.

Total entries en gallery: 26 (antes 23).
2026-04-25 21:40:44 +02:00
egutierrez adbe8c889c build(cpp): primitives_gallery activa por defecto
Tras commitear los deps (button, toolbar, modal_dialog, app_settings, etc.)
todos los sources del gallery estan tracked. Quita el gate FN_BUILD_GALLERY
y deja el subdirectorio como add_subdirectory incondicional (igual que
chart_demo y shaders_lab).

Build verificado: cmake --build cpp/build construye chart_demo, shaders_lab,
text_editor_smoke, primitives_gallery y registry_dashboard.
2026-04-25 21:28:24 +02:00
egutierrez f61d2834e8 docs(cpp): añadir DESIGN_SYSTEM.md
Documenta el sistema de design tokens del registry C++:
- Identidad visual unica (Mantine v9 dark + indigo) compartida entre apps
- Como se aplican los tokens via fn::run_app
- Convenciones de uso (cuando usar tokens.colors.surface vs accent, etc.)

Es la fuente de verdad cuando se crean nuevas primitivas o apps fn_ui.
2026-04-25 21:26:09 +02:00
egutierrez 24efee80e2 feat(cpp/gfx): code_to_generator + shaderlab_db
Dos primitivas del pipeline de shaders_lab que ya estaban en uso pero sin
indexar al registry:

- code_to_generator_cpp_gfx (function, pure)
  Traduce un fragment shader GLSL escrito a mano (modo Code, con void main()
  + fragColor = ...) en un body de DAG Gen + DagControl[]. Cada uniform
  anotado se convierte en un control; el body usa el parametro uv y reemplaza
  fragColor= por return. Empaqueta uniforms en vec4 (4 x n_uniforms).

- shaderlab_db_cpp_gfx (function, impure)
  CRUD persistente para generators custom de shaders_lab via sqlite3.
  Guarda el GLSL original, el body traducido para el DAG, los DagControl y
  los param_defaults en una BD local (shaders_lab.db). Soporta open(:memory:)
  para tests.

Ambas se indexan ahora en registry.db y son reusables fuera de shaders_lab
si en el futuro hay otra app que componga DAGs de shaders.
2026-04-25 21:26:03 +02:00
egutierrez d317900eea feat(cpp/core): app framework UI (settings, menubar, layouts)
5 primitivas que componen el chrome de una app fn_ui completa:

- app_settings_cpp_core         (function, impure)  ventana flotante de
  settings globales (Display + Typography + secciones extra registrables) con
  persistencia automatica en app_settings.ini junto al ejecutable.
- app_menubar_cpp_core          (component, pure)   MainMenuBar unificada
  con menu View (toggles de paneles) y Layouts. Punto de entrada de la
  menubar de cualquier app fn_ui.
- layouts_menu_cpp_core         (component, pure)   menu para guardar/aplicar/
  borrar/reset layouts de ImGui via callbacks (no I/O propio).
- panel_menu_cpp_core           (component, pure)   menu checkable para
  abrir/cerrar paneles, composable dentro de la MainMenuBar.
- layout_storage_sqlite_cpp_core (function, impure) primitivas CRUD de bajo
  nivel para persistir blobs INI de ImGui en sqlite (ui_layouts table).

Permiten que apps como shaders_lab y registry_dashboard ofrezcan: panel
toggles, layouts persistentes en BD, ventana de settings con preview en
vivo. Todas usan tokens_cpp_core para el styling.
2026-04-25 21:25:51 +02:00
egutierrez da6a8b5e59 feat(cpp/core): primitivas UI estilo Mantine
Anade 9 primitivas reutilizables al registry C++ que replican el comportamiento
de los componentes correspondientes de @fn_library / Mantine v9, todas
estilizadas con tokens_cpp_core (colores Mantine dark + indigo):

- button_cpp_core         (component, pure)  variantes primary/secondary/subtle/danger + sm/md/lg
- icon_button_cpp_core    (component, pure)  cuadrado 28x28 con glyph centrado + tooltip
- toolbar_cpp_core        (component, pure)  grupo horizontal de acciones con separadores
- modal_dialog_cpp_core   (component, pure)  popup modal centrada + close con Escape
- text_input_cpp_core     (component, impure) InputText con label muted + placeholder
- select_cpp_core         (component, impure) dropdown con label + opcion '(none)' opcional
- toast_cpp_core          (component, impure) notificaciones efimeras + inbox con badge
- tree_view_cpp_core      (component, impure) jerarquia low-level con tree_node_clicked helper
- process_runner_cpp_core (component, impure) tarea en std::thread + spinner inline

Cada primitiva tiene su .md con frontmatter completo (params/output) y se
indexa via fn index. Son la base del primitives_gallery y de cualquier
app fn_ui futura.
2026-04-25 21:25:39 +02:00
egutierrez 5d5b1d3fea feat(cpp/core): icon_font + icons_tabler
icon_font_cpp_core (impure): carga Karla-Regular como texto vectorial y
mergea Tabler Icons al mismo tamano en el atlas de ImGui. Tras el call,
los TI_* renderizan inline con el texto.

icons_tabler.h: header con macros TI_<NAME> que apuntan a los codepoints
del set Tabler (UTF-8 escapado). Generado a partir del CSS del vendor con
cpp/vendor/tabler-icons/gen_header.py — re-ejecutable si se actualiza el
set sin tocar a mano los ~5500 codepoints.

Justifica la regla cpp_icons.md: todas las apps C++ usan TI_* en lugar de
emoji o hex inline.
2026-04-25 21:25:25 +02:00
egutierrez bae4f45268 chore(cpp/vendor): vendor Tabler Icons v3.41.1 (TTF + generador)
Vendorea el set de iconos Tabler (~5500 iconos, MIT) para usar en apps
ImGui via icon_font_cpp_core. Incluye:

- tabler-icons.ttf       — atlas TTF para mergear en ImGui
- tabler-icons.css       — referencia de codepoints (no se compila)
- gen_header.py          — script que regenera cpp/functions/core/icons_tabler.h
                           con macros TI_<NAME> a partir del CSS
- LICENSE / README.md    — atribucion MIT

Versionar el TTF (~700 KB) evita depender de descargas en build. Las apps
usan TI_* en strings y el atlas se carga con icon_font_cpp_core::load().
2026-04-25 21:25:17 +02:00
egutierrez b093c898a8 docs(issues): marcar 0025 y 0026 como completados + WIP master
Wave 1 de parallel-fix-issues integrada a master:
- 0025: text_editor_cpp_core + file_watcher_cpp_core
- 0026: gl_texture_load_cpp_gfx (vendor: stb_image v2.30)

Ademas se commitea WIP previo de master que estaba sin commitear (cambios
en shaders_lab, dag_*, framework, tokens, kpi_card, gl_loader.md, etc.)
para dejar HEAD buildable.

Notas:
- Algunos deps del gallery (button.cpp, toolbar.cpp, modal_dialog.cpp...)
  siguen UNTRACKED — gating con FN_BUILD_GALLERY=ON (default OFF) para
  que master build (sin flag) no los necesite.
- Build OK con y sin flag. fn index registra 904 functions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 21:14:15 +02:00
egutierrez d3d5af51f2 feat(primitives_gallery): wire gl_texture_load demo
Tras integrar 0025 (que trajo la app entera) y 0026 (que solo añadio
demos_gl_texture.cpp + assets/sample.png + cpp/functions/gfx/gl_texture_load.*),
falta wire-up de la entrada nueva en los archivos compartidos del gallery.

- demos.h: declarar gallery::demo_gl_texture()
- main.cpp: entrada en k_demos[] con id "gl_texture", category "Gfx"
- CMakeLists.txt: añadir demos_gl_texture.cpp, gl_texture_load.cpp,
  stb_image_impl.cpp, e include dir vendor/stb

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 21:05:45 +02:00
egutierrez 0c7a8393ab merge: issue/0026 — gl_texture_load (stb_image)
# Conflicts:
#	cpp/CMakeLists.txt
2026-04-25 21:05:11 +02:00
egutierrez 087412d73a feat(primitives_gallery): wire text_editor + file_watcher demo
- 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>
2026-04-25 21:00:55 +02:00
egutierrez 61a238b3fd test(cpp): add text_editor_smoke build gate for issue 0025
App minima (no abre ventana ImGui) que crea/settea/lee text_editor y registra
un watch sobre /tmp/fn_smoke_test.txt para confirmar que TextEditor.cpp del
vendor + text_editor.cpp + file_watcher.cpp enlazan correctamente. Activada
por defecto si la carpeta existe (no requiere la primitives_gallery).

Tambien anade flag FN_BUILD_GALLERY (OFF default) para no romper el build
cuando la primitives_gallery no esta presente — sus deps (button.cpp,
toolbar.cpp...) son sources untracked en algunas branches.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 21:00:47 +02:00
egutierrez 07a653d97d feat(cpp/core): add file_watcher_cpp_core (inotify Linux / RDCW Win)
Watcher de archivos no bloqueante con backend nativo por plataforma:

- Linux: inotify_init1(IN_NONBLOCK | IN_CLOEXEC), inotify_add_watch con
  mascara MODIFY|CREATE|DELETE|CLOSE_WRITE|MOVED_*. Drain en cada poll().
- Windows: ReadDirectoryChangesW overlapped + GetOverlappedResult no
  bloqueante. Para vigilar un archivo, registra el directorio padre y filtra
  por nombre exacto en el poll().
- Otros: stub — poll() devuelve vacio y last_error() reporta no soportado.

API en namespace fn:: con tipos opacos (FileWatcher PIMPL). Errores via
last_error() en vez de excepciones. Documentadas las limitaciones (limite de
inotify watches en Linux, granularidad directorio-level en Windows, no
recursividad).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 21:00:38 +02:00
egutierrez 24905eebc7 feat(cpp/core): add text_editor_cpp_core component (PIMPL)
Wrapper en namespace fn:: sobre ImGuiColorTextEdit. La API publica solo expone
TextEditorState como tipo opaco; el TextEditor del vendor vive dentro del .cpp.

Soporta CodeLang::{Generic, GLSL, SQL, Cpp} (highlighting via las
LanguageDefinition del vendor). text_editor_render() devuelve true en el frame
en que el contenido cambia; flag dirty manejado independientemente para casos
"editado pero aun no guardado".

text_editor_get_text() cachea el resultado en un std::string del state para
mantener el const char* valido entre llamadas (el GetText() del vendor devuelve
std::string por valor).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 21:00:31 +02:00
egutierrez f8a54942ee feat(cpp/vendor): vendor ImGuiColorTextEdit (MIT) for text_editor primitive
Pinneado al commit 0a88824f del upstream. Patches locales aplicados a
TextEditor.cpp para compilar contra ImGui 1.91+ (GetKeyIndex eliminado,
PushAllowKeyboardFocus/PopAllowKeyboardFocus removidos). Documentado en
cpp/vendor/imgui_text_edit/README.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 21:00:22 +02:00
egutierrez 099be06409 feat(primitives_gallery): demo de gl_texture_load + asset PNG
Añade demos_gl_texture.cpp (carga assets/sample.png con la nueva
funcion gl_texture_load_cpp_gfx, muestra w/h/channels y sliders de
tint RGB + zoom UV via ImGui::ImageWithBg) y un PNG damero 256x256
generado para la demo.

Tambien registra apps/primitives_gallery como subdirectorio en
cpp/CMakeLists.txt (la app vive como WIP en master; aqui solo se
añade el hook de build).

Para integrarse, demos.h, main.cpp y CMakeLists.txt de la gallery
deben anadir respectivamente la declaracion gallery::demo_gl_texture(),
la entrada {"gl_texture", "gl_texture_load", "Gfx", &gallery::demo_gl_texture}
en k_demos[], y demos_gl_texture.cpp + cpp/functions/gfx/gl_texture_load.cpp +
cpp/vendor/stb/stb_image_impl.cpp + include de cpp/vendor/stb a sus sources.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:58:50 +02:00
egutierrez d1d20bdc04 feat(gfx): añadir gl_texture_load_cpp_gfx
Funcion impura del registry que carga PNG/JPG/BMP/TGA/HDR a una textura
OpenGL lista para sampler2D. Composable con gl_loader, gl_shader,
shader_canvas. Genera mipmaps, soporta sRGB y HDR (RGBA16F).

API:
  GlTexture gl_texture_load(path, flip_y=true, srgb=false)
  GlTexture gl_texture_load_from_memory(data, size, ...)
  void      gl_texture_destroy(tex)
  const char* gl_texture_last_error()  // thread-local
  void      gl_texture_bind_uniform(prog, name, tex, unit)

Errores via thread_local string accesible por gl_texture_last_error().

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:58:14 +02:00
egutierrez 83f64aa3e1 feat(gl_loader): añadir glActiveTexture y glGenerateMipmap
Necesarios para que gl_texture_load (cpp/functions/gfx/) funcione en
Windows tras wglGetProcAddress. En Linux son simbolos directos via
GL_GLEXT_PROTOTYPES, no afecta.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:58:07 +02:00
egutierrez 30c1289434 chore(vendor): añadir stb_image v2.30 a cpp/vendor/stb/
Header-only image loader (public domain). Pinneado al commit
f0569113c93ad095470c54bf34a17b36646bbbb5 de nothings/stb.

Layout:
- stb_image.h — header (no modificar)
- stb_image_impl.cpp — UNICO TU que define STB_IMAGE_IMPLEMENTATION
- README.md — origen + commit + uso

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:58:02 +02:00
egutierrez ac65791663 feat(shaders_lab): per-node preview thumbnails + double-rclick delete node
- DagStep: preview_open flag (default false).
- dag_compile: emit `uniform int u_preview_target` and a series of
  early-return branches at the start of fragColor selection. -1 (default)
  falls through to the real Output-driven fragColor.
- dag_node_previews (new fn): per-node FBO keyed by editor_uid, lazy
  created. Renders each node with preview_open=true to its FBO by
  setting u_preview_target = step index. Texture exposed via
  dag_preview_texture(uid) for ImGui::Image.
- dag_node_editor: small toggle button "[+] preview"/"[-] preview" in
  each non-Output node; when open, ImGui::Image(96x64, V-flipped).
- dag_node_editor: double right-click on hovered node deletes it
  (Output is protected).
- main.cpp: dag_previews_render after Canvas DAG; dag_previews_destroy
  on shutdown.

Single GL program drives both the canvas and all thumbnails — moving
sliders never recompiles, only the topology change does.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 02:06:50 +02:00
egutierrez a209afa46b feat(shaders_lab): pins straddle node edges (half outside, half inside)
draw_pin_circle takes a PinSide and centers the circle exactly on the
left or right edge of the node. The reserved Dummy is half-width
(PIN_RADIUS instead of PIN_DIAMETER) so the inside layout stays
compact, and ed::PinRect is set to the full circle so the protruding
half is still grabbable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 01:59:01 +02:00
egutierrez 426a842e2b feat(shaders_lab): pins on node edges, neutral color, right-click clears
- Pin radius bumped to 9px (18px diameter). Easier to grab.
- Single neutral pin/cable color across all kinds (data is uniformly
  vec4 — coloring by node kind was misleading).
- ed::StyleVar_NodePadding(0,8,0,8): zero left/right padding so the pin
  circles sit flush with the node's edges, separated from the title
  and controls by 8px gaps.
- Right-click on a pin clears all connections on that pin:
  - input pin → clear that single slot's source_id
  - output pin → clear every source_id across the pipeline pointing
    to this node (fan-out).
- Right-click on a link still deletes that single link (existing).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 01:52:09 +02:00
egutierrez 075088b7aa feat(shaders_lab): big colored pin circles, side layout, right-click delete
- Three-column node layout: input pins on the left edge, controls in
  the middle, output pin on the right edge.
- Pins rendered as 14px filled circles with darker outline. Color is
  the node's kind (gen=blue, op=violet, blend=amber, output=red).
- ed::PinPivotAlignment(0,0.5)/(1,0.5) so the cable starts/ends at
  the circle center.
- Empty columns (gen with no inputs, output with no output) get a
  pin-sized Dummy so column widths stay consistent.
- ed::Link now passes color (= source node kind) and 2.5px thickness.
- Right-click on a link deletes it immediately via
  ed::ShowLinkContextMenu (no popup).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 01:46:17 +02:00
egutierrez 144b15f0ce fix(shaders_lab): cycle check uses real reachability, not vector index
Previously the cycle validator rejected any link whose source had a
vector index >= target's, which silently killed legitimate connections
between nodes added in the wrong drop order.

Switch to a DFS over source_ids: an edge from->to creates a cycle iff
`from` already (transitively) depends on `to`. topo_sort runs after
each topology change so the vector ends up in a consistent order
regardless of how nodes were inserted.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 01:37:50 +02:00
egutierrez c2e4f6a9e1 fix(shaders_lab): Output connectable after drop + working color picker
Two bugs:

1. Dropped nodes were pushed to the end of the pipeline, but the Output
   node already sat there from startup. The cycle validator and the
   compiler only look for sources at indices strictly lower than the
   target, so new nodes were invisible to the Output. Fix: insert
   dropped nodes before the first Output; topo_sort also stable-moves
   Output nodes to the back.

2. ColorEdit3 with default flags rendered RGB text inputs alongside the
   swatch; clicking them dragged the node instead of opening the picker.
   Fix: NoInputs + NoLabel leaves only the swatch (a single item), and
   ed::Suspend/Resume wraps the call so the popup isn't clipped to the
   node or captured by the canvas.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 22:37:56 +02:00
egutierrez e3cfab3dc7 fix(shaders_lab): drop zone no longer eats node/slider input + inline tests
The previous InvisibleButton captured mouse events, so you could drag
from the Functions palette into the canvas, but node dragging and
slider interaction inside the canvas stopped working.

Fix: watch the global drag-drop payload without an explicit target. When
the mouse releases LMB over the DAG window with a "DAG_NODE_TYPE"
payload active, queue an add at that canvas position. No button, no
capture.

Tests (compiled standalone with preprocessor defines):
- dag_compile: 6/6 asserts (empty, single gen, op chain, multi-source
  blend, Output-driven fragColor, unconnected-Output fallback).
- dag_catalog: 8/8 asserts (uniqueness, per-kind input invariants,
  exactly one Output, body_glsl present & returns, control param
  indices valid).
Build with:
  g++ -std=c++17 -Icpp/functions -DDAG_COMPILE_TEST cpp/functions/gfx/dag_compile.cpp cpp/functions/gfx/dag_catalog.cpp -o /tmp/dag_compile_test
  g++ -std=c++17 -Icpp/functions -DDAG_CATALOG_TEST cpp/functions/gfx/dag_catalog.cpp -o /tmp/dag_catalog_test

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 22:24:39 +02:00
egutierrez e828af3ac1 feat(shaders_lab): Output node + Functions palette with drag-drop
- DagKind::Output (new enum): terminal sink; compiler wires fragColor to its source_ids[0]
- dag_catalog: "output" node (1 input, red)
- dag_compile: skips Output in node_<i> emission; final fragColor resolves from Output's connection
- dag_node_editor: no more Add button; drops "DAG_NODE_TYPE" payloads at mouse canvas position; Output cannot be deleted; Output has no output pin
- dag_palette (new fn): Functions window with grouped, draggable node cards
- main.cpp: "Functions" window added; ensure_dag_default seeds plasma + connected Output
2026-04-24 22:16:47 +02:00
egutierrez 42957d10f6 fix(shaders_lab): node drag was overwritten by SetNodePosition each frame
Previously SetNodePosition was called after EndNode every frame, which
reset any drag the user had done. Now the initial position is set once
per editor_uid (tracked in a static unordered_set), and the editor owns
the position afterwards. GetNodePosition at end-of-frame keeps step
state in sync for future persistence.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 22:04:07 +02:00
egutierrez 2b55a4823d feat(shaders_lab): visual node editor (imgui-node-editor) + multi-source
- cpp/vendor/imgui-node-editor: vendorized thedmd/imgui-node-editor v0.9.4
- cpp/functions/gfx/dag_node_editor: new visual pipeline editor replacing dag_panel
- DagStep: source_ids[4] + editor_pos + editor_uid (multi-input support)
- DagNodeDef: num_inputs explicit; circle reclassified as Op
- dag_compile: N inputs per node, topological ordering preserved
- main: use node editor; destroy on shutdown
- patch imgui_extra_math.inl: guard operator*(float, ImVec2) for imgui >= 18955

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 21:56:48 +02:00
egutierrez 8eebd1abce feat(shaders_lab): two simultaneous canvases (Code + DAG)
Canvas Code and Canvas DAG are now independent windows, each with its
own ShaderCanvas, FBO and compiled program. Both render every frame in
parallel. No more focus-based recompile — each source compiles when its
own content changes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 21:50:29 +02:00
egutierrez 3f622561ce feat(cpp/viz): static-plot primitive + tooltips + rotated labels + card compacta
Nuevo primitivo compartido:
- cpp/functions/viz/plot_static.h: header-only con flags ImPlotFlags /
  ImPlotAxisFlags agrupados (NoFrame|NoMenus|NoBoxSelect|NoMouseText +
  Lock|NoInitialFit|NoHighlight) para visualizacion estatica en
  dashboards. Lo usan todos los charts de viz/.

Charts refactorizados a v1.1 con parametro `height` explicito (rompe el
feedback loop con contenedores AutoResizeY que producia vibracion al
redimensionar) y ejes pineados con ImPlotCond_Always:
- bar_chart v1.2: tooltip al hover (label + valor) + auto-rotacion de
  labels a 45 cuando no caben horizontalmente (medidos con CalcTextSize
  vs ancho del plot). Los labels rotados se dibujan manualmente con
  ImDrawList::PrimQuadUV + ImFontBaked::FindGlyph (API ImGui 1.92+).
- pie_chart v1.1: tooltip por slice (detecta cual via atan2 desde centro
  en sentido CCW matematico, que es como ImPlot dibuja los slices desde
  angle0=90) con label + valor + porcentaje. Aspect 1:1 mantenido.
- line_plot, scatter_plot, histogram v1.1: ejes pineados con limites
  calculados de min/max + 5% headroom (histogram usa AutoFit por los
  bins dinamicos, con Lock para bloquear pan/zoom).

kpi_card v1.2: card mas compacta — altura 78px (antes 108), font scale
1.4x (antes 1.8x), padding sm (antes md). Apto para densidades altas
de KPIs en dashboards.

fullscreen_window v0.2: NoScrollbar|NoScrollWithMouse para eliminar el
scrollbar fugaz que aparecia cuando el contenido excedia por 1-2px la
ventana, reflow de ancho y vibracion visible al redimensionar.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 21:31:00 +02:00
egutierrez 6f269949f1 feat(shaders_lab): independent windows for Code, DAG, Controls, Canvas, GLSL
Remove Code/DAG toggle. Each panel lives in its own dockable window.
Active source (Code or DAG) is whichever window has focus; Canvas title
shows the current active source. Switching active source triggers an
immediate recompile so the canvas reflects the selected pipeline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 21:27:50 +02:00
egutierrez bdce314199 feat(shaders_lab): drag-and-drop to reorder DAG steps
ImGui native BeginDragDropSource/Target over each CollapsingHeader.
Drag source adjusted if ahead of target to keep final position correct.
Move Up/Down buttons kept for keyboard/touchpad fallback.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 21:21:58 +02:00
egutierrez e115c2e3fd feat(shaders_lab): DAG pipeline mode with node catalog
- cpp/functions/gfx/dag_types: DagStep, DagNodeDef, DagControl (header-only)
- cpp/functions/gfx/dag_catalog: 10 hardcoded nodes (4 gen, 3 op, 3 blend) ported from shader-dag-blends.jsx
- cpp/functions/gfx/dag_compile: pipeline → GLSL 330 core with fan-in via source_id
- cpp/functions/gfx/dag_uniforms: upload u_params[16] via glUniform4fv
- cpp/functions/gfx/dag_panel: ImGui pipeline editor (add/remove/reorder/controls)
- main.cpp: Code/DAG mode toggle, per-mode compile path and uniforms
- gl_loader: +glUniform4fv
- rebuild Windows .exe

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 21:15:21 +02:00
egutierrez 4610bb4a99 feat(shaders_lab): uniform annotations → auto-generated ImGui controls
- cpp/functions/gfx/uniform_parser: regex-based parser of @slider/@color/@toggle/@xy annotations (+ inline tests)
- cpp/functions/gfx/uniform_panel: ImGui widgets + value store + glUniform* apply
- shader_canvas: optional uniforms callback invoked per-frame
- gl_loader: +glUniform1i/3f/4f
- seed plasma: demo uniforms u_speed + u_color
- rebuild Windows .exe

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 21:02:35 +02:00
egutierrez b828fd6acc feat(cpp/viz): kpi_card v1.1 + bar_chart v1.1 — contenedor y altura fijas
kpi_card:
- v1.1: envuelve el contenido en BeginChild con surface bg + border +
  radius::md + padding::md (tokens). Replica Mantine Paper withBorder
  radius="md" p="md" usado en @fn_library/kpi_card.tsx.
- Ancho adaptativo via GetContentRegionAvail — requiere contenedor que
  propague ancho constrained (ImGui::BeginTable). dashboard_grid / BeginGroup
  no funcionan porque no constrainen ancho y la card desborda la celda.
- Linea de trend SIEMPRE visible: delta, sparkline, o em dash (text_dim)
  como placeholder, para que un grid de KPIs quede alineado vertical.
- Colores del delta via tokens (success/error) en vez de hardcoded ImVec4.

bar_chart:
- v1.1: altura explicita como parametro (default 200px). Sin esto, ImPlot
  con ImVec2(-1, 0) entra en feedback loop cuando esta dentro de un
  dashboard_panel (BeginChild con AutoResizeY): plot pide espacio -> padre
  se redimensiona -> plot recalcula. Efecto visual: las barras se deslizan
  los primeros frames.
- Ejes blindados: Lock + NoInitialFit + Cond_Always ademas de los flags
  previos. Y max pre-calculado con 15% de headroom.
- Sin inputs (NoInputs|NoFrame|NoBoxSelect|NoMouseText): estos charts son
  de resumen, no de exploracion.

Actualizados los .md correspondientes con el contrato visual + requisitos
de contenedor, para que cualquier dashboard que componga estos primitivos
obtenga el mismo look.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 20:59:51 +02:00
egutierrez 9b1ca41c4d feat(shaders_lab): add gl_loader + Windows cross-compile
- cpp/functions/gfx/gl_loader.{h,cpp,md}: mini loader para OpenGL 2.0+
  (Linux no-op via GL_GLEXT_PROTOTYPES, Windows wglGetProcAddress)
- Portar gl_shader/gl_framebuffer/fullscreen_quad/shader_canvas al loader
- CMakeLists: WIN32_EXECUTABLE para lanzar sin consola en Windows
- apps/shaders_lab/shaders_lab.exe: binario PE32+ precompilado

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 20:52:37 +02:00
egutierrez 3008b56e76 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
egutierrez e39445dd55 feat(cpp/core): design tokens + primitivos UI para dashboards ImGui
Trasladar principios del DESIGN_SYSTEM.md de @fn_library (Mantine/React)
al mundo C++/ImGui sin añadir deps externas:

  cpp/functions/core/
    tokens       — colors/spacing/radius/font_size como constexpr +
                   apply_dark_theme() al ImGuiStyle global. Dark + indigo
                   primary (Mantine-inspired).
    badge        — etiqueta inline 6 variantes (Default/Success/Warning/
                   Error/Info/Outline). <Badge> de @fn_library en C++.
    empty_state  — placeholder centrado para tablas/listas vacías.
    page_header  — header con title + subtitle + separator + hueco
                   para acciones (patrón begin/end).

Scope limitado (KISS) a fases 1-2 del plan: tokens + 3 primitivos.
No se duplica dashboard_panel con un "card" — el existente ya cumple
el rol. Fases 3-5 (charts ImPlot line/area, app_shell con navbar,
toast/alert) quedan fuera hasta que el dashboard crezca en alcance.

Resultado:
- 869 funciones (+4) en registry.db.
- Dashboard con header homogéneo y empty states en todas las tablas.
- Sin hardcode de ImVec4 disperso en views.cpp.

Diary + CHANGELOG actualizados.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 14:52:09 +02:00