graph_labels_draw pinta etiquetas de nodos sobre el FBO del graph_renderer
via ImDrawList. Politica configurable: always-on para selected/hovered/
pinned, top-N por size*(degree+1), culling por viewport AABB y
min_node_pixel_size. Cap duro = max_visible + |always_*|.
API:
- graph_labels_draw(graph, viewport_state, policy, cb, user)
- graph_labels_draw_at(...) — variante con rect explicito
- graph_labels_select(...) — helper puro testeable
- graph_compute_degrees(...) — O(E)
Splitting en dos TUs:
- graph_labels.cpp — funciones draw (depende de ImGui)
- graph_labels_select.cpp — helpers puros para tests sin ImGui
12 tests en test_graph_labels (culling, max_visible cap, min_pixel_size,
always_* gating por viewport, top-N por score, edge cases). Todos verdes.
Integrado en demos_graph con UI: toggle Labels, sliders Max visible /
Font / Min px, checkboxes Selected/Hovered/Pinned. Golden de
graph_viewport regenerado.
Cierra issue 0049j.
Layout force-directed en GPU usando 5 compute shaders 4.3 + spatial hash
grid 64x64. API simetrica con graph_force_layout (CPU) para que el consumer
pueda swappear sin cambios. atomicCompSwap loop para float-add portable.
- cpp/functions/viz/graph_force_layout_gpu.{h,cpp,md}: nuevo modulo
- cpp/functions/gfx/gl_loader: anade glDispatchCompute, glMemoryBarrier,
glBindBufferBase, glGetBufferSubData (Windows wgl)
- cpp/tests/test_graph_force_layout_gpu.cpp: smoke + pinned + CPU vs GPU.
Crea ventana GLFW oculta GL 4.3; SKIP si headless o sin compute.
- demos_graph: checkbox "GPU layout" para swappear CPU/GPU en runtime
- issue movido a dev/issues/completed/
graph_renderer 1.5.0:
- 6 shapes SDF (circle, square, diamond, hex, triangle, rounded square)
con dispatch en fragment shader y AA via fwidth.
- Atlas opcional de iconos Tabler bakeado por graph_icons; el shader
compone overlay desde un uniform vec4 u_icon_uvs[256]. Setter publico
graph_renderer_set_icon_atlas(r, tex, uv_table, count).
- Aristas direccionales: 6 vertices por arista (line + chevron de la
flecha) en una sola draw call; segmento principal acortado por el
radio del nodo target.
- Edge styles solid/dashed/dotted via descarte por arc_length en el
fragment shader; las lineas del chevron son siempre solidas.
graph_icons 1.0.0 (nuevo):
- Atlas RGBA8 512x512 = grid 16x16 (256 iconos max) bakeado con
stb_truetype desde tabler-icons.ttf.
- API: graph_icons_build/texture/region/uv_table/destroy. icon_id es
1-based; 0 reservado para "sin icono".
- Hook FN_GRAPH_ICONS_SKIP_GL=1 para tests sin contexto GL.
Demo demos_graph_styles en primitives_gallery: 6 EntityTypes (uno por
shape) con icono Tabler representativo + 3 RelationTypes (knows/uses/
owns) con flechas direccionales y los 3 estilos.
test_graph_icons: 6 casos cubriendo bake, regiones 1-indexed, uv_table
consistente, layout en grid 16x16, validacion de count fuera de rango,
y verificacion de alpha != 0 en las celdas tras bake.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Modo de captura que renderiza cada demo de la gallery en una ventana GLFW
invisible (GLFW_VISIBLE=GLFW_FALSE) y guarda PNG por demo via stb_image_write.
- capture.{h,cpp}: API gallery::run_capture(cfg, items) — warmup_frames,
glReadPixels(GL_RGBA), flip vertical, stbi_write_png.
- main.cpp: parsea --capture <dir> antes de fn::run_app y delega a capture.cpp.
- vendor: stb_image_write.h v1.16 (mismo commit que stb_image.h).
Funciona en WSL con LIBGL_ALWAYS_SOFTWARE=1 (Mesa/llvmpipe). Si el entorno
no tiene contexto GL, el binario sale con rc!=0 sin generar PNGs.
Issue 0048.
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
Adds three new demos to the Core section of primitives_gallery:
- demo_tween: dropdown of all 16 Ease modes + animated plot showing the
curve and a moving marker that traverses t=0..1 in a loop.
- demo_bezier_editor: live editor with reset + ease-out / ease-in-out
presets, current control points displayed, slider over t showing
bezier_eval(curve, t).
- demo_timeline: 2 tracks (hue, amp) with mixed eases, live progress bars
showing track_value_at(current_time) updating each frame.
Wires the three demos into k_demos[] in main.cpp and adds the new sources
(plus the three function .cpp files) to CMakeLists.txt.
Demo nuevo en demos_sql.cpp: abre registry.db en SQLITE_OPEN_READONLY
(resolviendo via FN_REGISTRY_ROOT o cwd ascendente), monta
fn::SqlWorkbenchState con readonly=true y query inicial sobre la tabla
functions. Wire-up: entry en k_demos[] tras process_runner; declaracion
en demos.h; sources sql_workbench.cpp + demos_sql.cpp + link
SQLite::SQLite3 en CMakeLists.txt.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- 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.
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).
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>
- 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>