Files
fn_registry/dev/issues/completed/0049f-graph-renderer-symbols.md

167 lines
6.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: "0049f"
title: "Renderer extendido: shapes SDF, icon atlas, flechas, edge styles"
status: completado
type: feature
domain: []
scope: multi-app
priority: alta
depends: []
blocks: []
related: []
created: 2026-05-17
updated: 2026-05-17
tags: []
---
# 0049f — Renderer extendido: shapes SDF, icon atlas, flechas, edge styles
## Metadata
| Campo | Valor |
|-------|-------|
| **ID** | 0049f |
| **Estado** | pendiente |
| **Prioridad** | alta |
| **Tipo** | feature — parte de [#0049](0049-osint-graph-viewer.md) |
## Dependencias
**Bloqueada por:** [0049e](0049e-graph-types-extended.md) (necesita `shape`, `icon_id`, `flags.directed`, `style`).
---
## Objetivo
Extender el fragment shader del renderer con una libreria de SDF (circulo, cuadrado, diamante, hex, triangulo, rounded square), un atlas de iconos Tabler renderizado a textura, flechas direccionales en aristas, y estilos solid/dashed/dotted. Una sola draw call para todos los nodos, una para todas las aristas.
## Contexto
Maltego/OSINT requiere distinguir entidades de un vistazo: Person ≠ Email ≠ Domain. Color solo no escala — necesitamos forma + icono. El stack ya tiene Tabler como font (`cpp/functions/core/icons_tabler.h`); aqui lo bakeamos a una textura para que cada nodo pueda llevar un icono dentro.
## Arquitectura
```
cpp/functions/viz/
├── graph_renderer.{h,cpp} # MOD: shaders extendidos + uniform sampler de iconos
├── graph_renderer.md # MOD: bump version
├── graph_icons.{h,cpp} # NEW: builder del atlas
├── graph_icons.md # NEW
└── (fragment shader incluye sdf_*.glsl inline)
cpp/tests/
└── test_graph_icons.cpp # NEW
```
### API `graph_icons`
```cpp
struct IconAtlas;
struct IconRegion {
uint16_t id; // = posicion en el array al construir
float u0, v0, u1, v1; // UVs en la textura
};
// Construye una textura 512x512 RGBA con `count` iconos Tabler renderizados a 32px.
// Codepoints son los valores `TI_*` del header.
IconAtlas* graph_icons_build(const uint16_t* codepoints, int count, int icon_px = 32);
unsigned int graph_icons_texture(const IconAtlas*); // GL texture id
const IconRegion* graph_icons_region(const IconAtlas*, uint16_t icon_id);
void graph_icons_destroy(IconAtlas*);
```
### Shaders extendidos
Vertex shader de nodos ya pasa `type_id`, `shape`, `icon_id` por instance. Fragment shader compone:
```glsl
float sdf_circle (vec2 uv) { return length(uv - 0.5) - 0.5; }
float sdf_square (vec2 uv) { vec2 d = abs(uv - 0.5) - 0.5; return max(d.x, d.y); }
float sdf_diamond(vec2 uv) { vec2 d = abs(uv - 0.5); return d.x + d.y - 0.5; }
float sdf_hex (vec2 uv) { ... }
float sdf_triangle(vec2 uv){ ... }
float sdf_rrect (vec2 uv) { vec2 d = abs(uv - 0.5) - 0.5 + r; return length(max(d,0.0)) - r; }
float pick_sdf(uint shape, vec2 uv) {
switch (shape) {
case 0u: return sdf_circle(uv);
case 1u: return sdf_square(uv);
case 2u: return sdf_diamond(uv);
...
}
}
void main() {
float d = pick_sdf(v_shape, v_uv);
float aa = fwidth(d);
float a = 1.0 - smoothstep(0.0, aa, d);
if (a < 0.001) discard;
vec3 col = v_color.rgb;
if (v_icon_id != 0u) {
// UV del icono dentro del atlas: (uv - 0.5) * scale + region_center
vec2 atlas_uv = mix(vec2(v_icon_u0, v_icon_v0), vec2(v_icon_u1, v_icon_v1), v_uv);
vec4 ic = texture(u_icon_atlas, atlas_uv);
col = mix(col, vec3(1.0), ic.a * 0.85);
}
frag_color = vec4(col, a * v_color.a);
}
```
### Aristas direccionales con flecha
Cada arista pasa de 2 vertices (line) a 4 vertices: 2 para el segmento + 2 para el triangulo de la flecha (solo si `flags & EF_DIRECTED`). Indices 0-1 = linea, 2-3 = triangulo apuntando al target. Vertex shader calcula la flecha en world coords usando direccion target-source y tamaño constante en pixels.
### Edge styles
Fragment shader de aristas recibe `arc_length` (interpolado linealmente entre source y target en pixels). Para `style=DASHED`: `if (mod(arc_length, 8.0) > 4.0) discard;`. Para `DOTTED`: similar con periodo y duty diferentes.
## Tareas
### Fase 1 — `graph_icons`
- [ ] **1.1** Crear `graph_icons.{h,cpp,md}`. Implementar `_build` usando `stb_truetype` (o ImGui font baker) para rasterizar codepoints Tabler a una bitmap 512×512.
- [ ] **1.2** Layout simple: grid 16×16 a 32px por celda → 256 iconos por atlas.
- [ ] **1.3** Subir como GL texture RGBA8 con linear filtering.
- [ ] **1.4** Tests: build de 10 iconos conocidos; verificar que la textura tiene contenido en las regiones esperadas.
### Fase 2 — Shaders SDF
- [ ] **2.1** Implementar las 6 funciones SDF en GLSL.
- [ ] **2.2** `pick_sdf` con switch por `shape_id`.
- [ ] **2.3** Pasar `shape`, `icon_id`, `icon_u0/v0/u1/v1` por instance. Layout actualizado.
- [ ] **2.4** Compose icon overlay en fragment.
### Fase 3 — Aristas direccionales + estilos
- [ ] **3.1** Cambiar `glDrawArrays(GL_LINES, ...)` por geometry expansion en CPU/shader: 4 vertices por arista, los 2 ultimos solo se usan si `EF_DIRECTED`.
- [ ] **3.2** Vertex shader calcula posicion de la flecha (10 px constante en pantalla).
- [ ] **3.3** Fragment shader recibe `arc_length` y descarta segun `style`.
### Fase 4 — Demo
- [ ] **4.1** Crear `cpp/apps/primitives_gallery/demos_graph_styles.cpp`: grafo pequeño (~30 nodos) con 6 EntityTypes (uno por shape), 3 RelationTypes (solid/dashed/dotted), aristas direccionales mezcladas. Iconos Tabler representativos: `TI_USER`, `TI_MAIL`, `TI_GLOBE`, `TI_PHONE`, `TI_BUILDING`, `TI_DATABASE`.
- [ ] **4.2** Anadirlo a `demos.h` y al menu de la galeria.
- [ ] **4.3** Visual golden generado.
### Fase 5 — Cleanup
- [ ] Bump version `graph_renderer` 1.2.0 → 1.3.0; `graph_icons` 1.0.0.
- [ ] `fn index`.
- [ ] Commit `feat(viz): renderer shapes/iconos/flechas/edge-styles`.
## Criterio de done
- [ ] `demos_graph_styles` muestra todas las shapes + iconos + flechas + estilos visualmente correctos.
- [ ] Sigue siendo 1 draw call por nodos y 1 por aristas.
- [ ] Test golden estable.
- [ ] Tests `test_graph_icons` verdes.
## Riesgos
| Riesgo | Mitigacion |
|---|---|
| `switch` en GLSL ramifica → menos eficiente | Acceptable a estas escalas; se puede unfold luego con `#define` por tipo si hace falta |
| Atlas baker mete artifacts en bordes | Padding 2px entre celdas |
| Flechas ocupan area visible del nodo target | Acortar el segmento de linea por el radio del nodo target en vertex shader |
| Codepoints Tabler con caracteres compuestos | Usar solo los basicos del header `icons_tabler.h` (ya validados) |