--- name: dag_node_editor kind: function lang: cpp domain: gfx version: "1.0.0" purity: impure signature: "bool dag_node_editor(std::vector& pipeline)" description: "Renderiza el node editor visual (imgui-node-editor) para el DAG de shaders. Modifica el pipeline in-place: añade/borra nodos, gestiona aristas (source_ids). Devuelve true si la topologia cambio." tags: [dag, imgui, node-editor, shader, visual, pipeline, gfx] uses_functions: ["dag_catalog_cpp_gfx", "dag_node_previews_cpp_gfx"] uses_types: [] returns: [] returns_optional: false error_type: "error_go_core" imports: ["imgui_node_editor.h", "gfx/dag_catalog.h", "gfx/dag_types.h"] tested: false tests: [] test_file_path: "" file_path: "cpp/functions/gfx/dag_node_editor.cpp" params: - name: pipeline desc: "vector de DagStep que representa el pipeline actual; modificado in-place" output: "true si la topologia cambio (nodos o aristas añadidos/quitados); false en caso contrario" notes: "consumido por cpp/apps/shaders_lab/main.cpp" --- ## Notas Sustituye a `dag_panel` como UI del pipeline. Usa `ax::NodeEditor` (thedmd/imgui-node-editor v0.9.4) con contexto singleton estático. Codificacion de IDs: - Node id = `editor_uid` del step - Output pin = `(uid << 8) | 0` - Input pin = `(uid << 8) | (slot + 1)` - Link id = `(from_uid << 20) | (to_uid << 8) | slot` Aplica topological sort (Kahn) tras cada cambio de topologia. Rechaza ciclos en `BeginCreate`. Multi-source: cada nodo declara `num_inputs` (0-4). Los slots de `source_ids[]` se mapean a los inputs del shader GLSL (`a`, `b`, `c`, `d`). ## Dependencia Requiere `imgui_node_editor` static library linkeada (`cpp/vendor/imgui-node-editor`). ## Notas (2026-04-25, Fase 7 shaders_lab) Pulido visual y de UX para conexión: - Pines más grandes para grab fácil: `PIN_RADIUS` 9 → 14, `CABLE_THICK` 2.5 → 3.5, `CONTROL_WIDTH` 150 → 220, `COL_GAP` 8 → 14. - Espaciado inicial entre nodos auto-colocados subido a 320 px. - Bug fix: el control `Color` se renderizaba con `ImGuiColorEditFlags_NoLabel`, así que nodos cuya único control era Color (`solid`) parecían sin nombre. Ahora se imprime `TextUnformatted(label) + SameLine` antes del swatch. Drop comportamiento (en orden de prioridad al soltar un nodo de la paleta o arrastrar un nodo del canvas): 1. **Drop sobre cable** (`dist_point_to_segment` < 18 px en canvas-space): splice. Solo aplica a nodos con `num_inputs >= 1` y kind != Output. 2. **Drop sobre nodo del mismo `DagKind`**: replace. Conserva `id`, `editor_uid`, `editor_pos_x/y`, `source_ids[]`, `preview_open`. Limpia slots de input que sobran si el nuevo def tiene menos `num_inputs`. 3. **Drop en vacío**: add. Inserción antes del `Output` para que el sink se quede al final. Tracking de drag de nodo existente: `s_drag_existing_uid` se setea en `IsMouseClicked(0)` cuando hay `GetHoveredNode() != 0` y `GetHoveredPin() == 0`. Al soltar, si un cable estaba highlighted, se hace splice (clear de refs hacia el nodo, `mv.source_ids[0] = src.id`, `dst.source_ids[slot] = mv.id`). Hit-test contra cajas de nodos vía `ed::GetNodePosition + ed::GetNodeSize` (no se usa `ed::GetHoveredNode` porque no es fiable bajo drag-drop activo). Splice highlight (preview live): - Mientras hay payload `DAG_NODE_TYPE` (paleta) o `s_drag_existing_uid` activo, hit-test contra cables (distance point-segment). - El cable candidato se pinta con `SPLICE_COLOR = (1.00, 0.82, 0.18, 1)` y `CABLE_THICK + 2` en `ed::Link()`. - **Garantía visual**: además se dibuja un bezier dorado en `ImGui::GetForegroundDrawList()` con `AddBezierCubic(P0, P1, P2, P3, color, CABLE_THICK + 4)` para no depender del compositing interno de imgui-node-editor. - Sin gates `IsMouseDown` / `window_hovered` (silenciaban el highlight). El payload o `s_drag_existing_uid` ya implican drag activo. Constantes públicas vivas (en el .cpp, no exportadas): - `PIN_RADIUS = 14`, `CABLE_THICK = 3.5`, `CONTROL_WIDTH = 220`, `COL_GAP = 14`. - `PIN_COLOR = (0.78, 0.78, 0.82, 1)`, `PIN_BORDER = (0.20, 0.20, 0.22, 1)`, `SPLICE_COLOR = (1.00, 0.82, 0.18, 1)`.