# shaders_lab — proximos pasos: tipos de datos en las aristas del DAG

## Estado actual

Por cada arista del DAG circula **un solo tipo**: `vec4` (RGBA por pixel).
El DAG no es un grafo de pasadas de render — es una plantilla que se compila
a **un unico fragment shader GLSL 330 core** (ver `cpp/functions/gfx/dag_compile.cpp`).
Cada nodo se compila a `vec4 node_<i>(vec4 a, ..., vec2 uv)`. Las conexiones
del editor son llamadas a funcion dentro del mismo `main()`.

Datos accesibles dentro de cualquier nodo, **sin pasar por aristas**:
- `u_time`, `u_resolution`, `u_mouse` (preamble de `gl_shader`)
- `u_params[64]` (vec4 array global con todos los parametros del DAG)
- `u_preview_target` (int, para thumbnails per-nodo)
- `uv` (pasado explicitamente como ultimo argumento)

Tipos de nodo (`DagKind` en `cpp/functions/gfx/dag_types.h`):

| Kind   | num_inputs | Recibe                       | Produce                |
|--------|-----------:|------------------------------|------------------------|
| Gen    | 0          | `uv`, `u_params`             | `vec4` generado        |
| Op     | 1          | `vec4 a, vec2 uv`            | `vec4` transformado    |
| Blend  | 2          | `vec4 a, vec4 b, vec2 uv`    | `vec4` combinado       |
| Output | 1          | (sumidero)                   | `fragColor` directo    |

---

## Tier 0 — Pins tipados (otros tipos GLSL escalares/vectoriales)

Mismo modelo single-pass. Solo hay que **declarar tipo por pin** y ajustar
el fallback de input vacio en `dag_compile.cpp:75-89`.

| Tipo   | Para que                                        | Coste    |
|--------|--------------------------------------------------|----------|
| float  | mascaras, alpha, heightmaps, distance fields    | trivial  |
| vec2   | UVs deformadas, gradientes, flow fields         | trivial  |
| vec3   | normales, posiciones, color sin alpha           | trivial  |
| mat2/3 | warps, rotaciones, transforms 2D                | trivial  |

Desbloquea **Op de displacement**: nodo que toma `vec2` (offset) + `vec4`
(textura) y devuelve `vec4` muestreado con offset.

Cambios necesarios:
- `DagNodeDef` declara tipo por pin de entrada y por salida
- `dag_compile` genera `node_<i>` con esas firmas
- `dag_node_editor` pinta colores de pin distintos y rechaza conexiones incompatibles

---

## Tier 1 — Imagenes rasterizadas (texturas)

Sigue siendo single-pass. Anade un **Gen `image_load`** con `uniform sampler2D`
y emite `texture(u_img_<i>, uv)` como `vec4`. Lo mismo aplica a:

- **Video** → `sampler2D` re-subido cada frame
- **Webcam** → idem
- **Audio FFT** → `sampler1D` (espectro) o `sampler2D` con historial

Coste: **medio**. Hace falta gestor de texturas (slot binding, hot-reload,
resize). La primitiva `Framebuffer` ya existe (`gl_framebuffer.h`) y
`gl_shader` ya gestiona uniforms — solo falta el camino de carga PNG/JPG → GL.

---

## Tier 2 — Multi-pass (rompe el modelo de un solo shader)

**Salto arquitectonico**. Hay operaciones imposibles en un solo pase porque
cada nodo solo "ve" su propio pixel:

- Blur real con kernel grande (lee vecinos)
- Downsample / mipmap / piramides
- FFT, convoluciones, dilations
- Bloom, glow, SSAO
- Reaction-diffusion, fluidos, feedback (frame anterior)
- Cualquier filtro que requiera la imagen ya rasterizada

Una arista deja de ser `vec4` y pasa a ser **texture handle (FBO completo)**.
Cada nodo se compila a su propio fragment shader, renderiza a su FBO, y el
siguiente lo muestrea como `sampler2D`.

`dag_compile` cambia de naturaleza: pasa de "compilar a un main()" a
**planificar passes** (orden topologico, asignar FBOs con pool reusable,
ejecutar en orden).

**Modos coexisten**: cada nodo declara `mode: inline` (se inlinea como hoy)
o `mode: pass` (FBO propio). En cruces `pass→inline` se muestrea el FBO; en
`inline→inline` sigue siendo llamada a funcion. Mejor de los dos mundos.

Coste: **alto** pero la base ya esta (`Framebuffer`, `fullscreen_quad`).
Es trabajo de arquitectura, no de OpenGL.

---

## Tier 3 — SDF (Signed Distance Fields)

Sub-dominio aparte. Sigue siendo single-pass. **Mucho retorno por poco
codigo** — solo necesita pins de tipo `float` (Tier 0) + nuevos nodos.

- Aristas llevan `float` (distancia con signo)
- Gens: `sdf_sphere`, `sdf_box`, `sdf_torus`, `sdf_plane`
- Ops: `sdf_smooth_union`, `sdf_intersect`, `sdf_subtract`, `sdf_round`, `sdf_displace`
- Terminator: `sdf_raymarch` toma SDF + material → `vec4` (raymarching dentro del fragment)

Te da **3D real (esferas, mezclas organicas, fractales tipo Mandelbulb) sin
mallas, vertices ni camara fuera del shader**. Es el truco de la mitad de Shadertoy.

---

## Tier 4 — Geometria 3D real

Aqui ya **no es solo un fragment shader**. Necesita:

- Vertex buffers (`GL_ARRAY_BUFFER`) con posiciones, normales, UVs
- Vertex shader + fragment shader emparejados
- Depth buffer
- Matrices `model/view/projection`, camara
- Posiblemente indices, instancing, geometry/tess shaders

El DAG cambia de naturaleza: dos sub-grafos distintos.

1. **Grafo de geometria** (mallas, transforms, materiales, luces)
2. **Grafo de imagen** (post-process del render final)

Forma realista de integrarlo: un nodo "Render 3D Scene" (con mini-DAG
interno de mallas/camara/luces) **produce una textura** que entra en el
grafo 2D existente como cualquier otro `vec4`.

Coste: **muy alto**. Practicamente otra app dentro de la app.

---

## Tier 5 — Compute / particulas / simulaciones

Compute shaders (`GL_COMPUTE_SHADER`), SSBOs, transform feedback. Para
sistemas de particulas con miles/millones de elementos, simulaciones
fisicas, reaction-diffusion masivo, etc.

Coste muy alto, valor medio salvo que el objetivo del lab cambie.

---

## Recomendacion de orden

1. **Pins tipados** (Tier 0) — desbloquea displacement, mascaras, base para SDFs.
2. **Texturas** (Tier 1) — `image_load`, `video`, `webcam`, `audio_fft`.
3. **SDF + raymarch** (Tier 3) — maximo retorno por linea de codigo.
4. **Multi-pass** (Tier 2) — el salto arquitectonico. Permite blur real, bloom, feedback.
5. **Geometria 3D** (Tier 4) — solo si el caso de uso lo justifica; Tier 3 ya cubre mucho 3D estetico.

Tier 2 es el cruce de caminos: hasta ahi puedes ir extendiendo el modelo
actual; a partir de ahi toca redisenar `dag_compile` como planificador de passes.
