feat(viz): renderer shapes/iconos/flechas/edge-styles (issue 0049f)

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>
This commit is contained in:
2026-04-29 23:01:49 +02:00
parent 34a3addc56
commit c967c2edfd
14 changed files with 1180 additions and 174 deletions
+10 -3
View File
@@ -3,13 +3,13 @@ name: graph_renderer
kind: function
lang: cpp
domain: viz
version: "1.4.0"
version: "1.5.0"
purity: impure
signature: "GraphRenderer* graph_renderer_create(int width, int height, const GraphRendererConfig& config)"
description: "Renderer GPU de grafos con instanced rendering a FBO, compatible con ImGui::Image para visualizacion de grafos grandes"
tags: [graph, renderer, opengl, gpu, instanced, fbo, visualization, frustum-cull, rgba8, vertex-pulling, tbo]
tags: [graph, renderer, opengl, gpu, instanced, fbo, visualization, frustum-cull, rgba8, vertex-pulling, tbo, sdf, icons, arrows, edge-styles]
uses_functions: ["gl_loader_cpp_gfx"]
uses_types: ["GraphData_cpp_viz"]
uses_types: ["GraphData_cpp_viz", "EntityType_cpp_viz", "RelationType_cpp_viz"]
returns: []
returns_optional: false
error_type: "error_go_core"
@@ -88,6 +88,13 @@ ndc = (screen / viewport) * 2 - 1
## Notas
- **v1.5** (2026-04-29, issue 0049f): renderer extendido con shapes SDF, atlas de iconos, flechas direccionales y estilos de arista. API publica gana `graph_renderer_set_icon_atlas(r, tex, uv_table, count)`. Cambios internos:
1. **6 shapes SDF en el fragment shader**: circle, square, diamond, hex (regular), triangle (equilatero), rounded_square. `pick_sdf(shape)` despacha por valor (1..6). El AA usa `fwidth(d)` para mantener calidad a cualquier zoom; el outline se compone con un `smoothstep` extra del SDF.
2. **Icon atlas opcional**: el shader compone un overlay con el icono Tabler bakeado por `graph_icons_build`. Las UVs (4 floats por icono) viven en un `uniform vec4 u_icon_uvs[256]` — solo se sube el icon_id (16 bits) por instancia. La textura se bindea al texture unit 1.
3. **Aristas direccionales**: cada arista pasa de 2 a 6 vertices (`glDrawArraysInstanced(GL_LINES, 0, 6, edges)`). Los 4 vertices extra dibujan un chevron (2 lineas) en la cabeza si `flags & EF_DIRECTED`; el segmento principal se acorta 5 px para que la flecha no se incruste en el target.
4. **Edge styles**: `style_flags` (32 bits) combina `flags` (low 8) y `style` (next 8). Fragment shader descarta segun `arc_length` interpolado: dashed (mod 8 > 4) y dotted (mod 4 > 1). Las lineas del chevron son siempre solidas.
5. **NodeInstance**: 16 → 24 bytes (anade `shape_icon` packeado + 4 bytes pad). EdgeStatic: 16 → 20 bytes (anade `style_flags`). Bandwidth de aristas sigue subiendo solo en cambios de grafo (vertex pulling intacto).
- **v1.4** (2026-04-29, issue 0049e): adapta el renderer al modelo extendido de `GraphData`. Lee `n.flags & NF_VISIBLE` para skipear nodos invisibles, resuelve color via `n.color_override``EntityType` → fallback indexado por `type_id`. Aristas: skip si `!(EF_VISIBLE)` o si los endpoints no son visibles, color via `RelationType`. Shapes/iconos/dashed-style siguen como circulo solido — el dispatch real llega en 0049f.
- **v1.3** (2026-04-29, issue 0049d): aristas via vertex pulling. API publica intacta.
- El buffer de aristas pasa a ser estatico (`source_idx, target_idx, color, flags` × E, 16 bytes/arista) y solo se reupload cuando el grafo cambia (detectado por `(edges_ptr, edge_count)` — heuristica suficiente mientras `GraphData` no tenga `revision`). Para 100k aristas: 1.6 MB iniciales vs 4.8 MB/frame del esquema anterior — el upload baja a cero en regimen estable.