feat(shaders_lab): per-node preview thumbnails + double-rclick delete node
- DagStep: preview_open flag (default false). - dag_compile: emit `uniform int u_preview_target` and a series of early-return branches at the start of fragColor selection. -1 (default) falls through to the real Output-driven fragColor. - dag_node_previews (new fn): per-node FBO keyed by editor_uid, lazy created. Renders each node with preview_open=true to its FBO by setting u_preview_target = step index. Texture exposed via dag_preview_texture(uid) for ImGui::Image. - dag_node_editor: small toggle button "[+] preview"/"[-] preview" in each non-Output node; when open, ImGui::Image(96x64, V-flipped). - dag_node_editor: double right-click on hovered node deletes it (Output is protected). - main.cpp: dag_previews_render after Canvas DAG; dag_previews_destroy on shutdown. Single GL program drives both the canvas and all thumbnails — moving sliders never recompiles, only the topology change does. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#include "gfx/dag_node_editor.h"
|
||||
#include "gfx/dag_catalog.h"
|
||||
#include "gfx/dag_node_previews.h"
|
||||
#include "imgui.h"
|
||||
#include "imgui_node_editor.h"
|
||||
#include <algorithm>
|
||||
@@ -304,6 +305,25 @@ bool dag_node_editor(std::vector<DagStep>& pipeline) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Per-node preview thumbnail (off by default).
|
||||
if (def->kind != DagKind::Output) {
|
||||
char btn_lbl[64];
|
||||
std::snprintf(btn_lbl, sizeof(btn_lbl), "%s preview##pv%u",
|
||||
step.preview_open ? "[-]" : "[+]", step.editor_uid);
|
||||
if (ImGui::SmallButton(btn_lbl)) {
|
||||
step.preview_open = !step.preview_open;
|
||||
}
|
||||
if (step.preview_open) {
|
||||
unsigned tex = dag_preview_texture(step.editor_uid);
|
||||
if (tex != 0) {
|
||||
ImGui::Image(static_cast<ImTextureID>(static_cast<intptr_t>(tex)),
|
||||
ImVec2(96, 64), ImVec2(0, 1), ImVec2(1, 0));
|
||||
} else {
|
||||
ImGui::Dummy(ImVec2(96, 64));
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::PopID();
|
||||
ImGui::EndGroup();
|
||||
|
||||
@@ -360,6 +380,28 @@ bool dag_node_editor(std::vector<DagStep>& pipeline) {
|
||||
ed::Resume();
|
||||
}
|
||||
|
||||
// ── Double right-click on a node deletes it (Output is protected) ──────
|
||||
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Right)) {
|
||||
ed::NodeId hovered = ed::GetHoveredNode();
|
||||
uint32_t uid = static_cast<uint32_t>(hovered.Get());
|
||||
if (uid != 0) {
|
||||
int idx = find_by_uid(pipeline, uid);
|
||||
if (idx >= 0) {
|
||||
const DagNodeDef* d = dag_find(pipeline[static_cast<size_t>(idx)].name);
|
||||
if (d && d->kind != DagKind::Output) {
|
||||
const std::string del_id = pipeline[static_cast<size_t>(idx)].id;
|
||||
for (auto& s : pipeline) {
|
||||
for (auto& sid : s.source_ids) {
|
||||
if (sid == del_id) sid.clear();
|
||||
}
|
||||
}
|
||||
pipeline.erase(pipeline.begin() + idx);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Right-click on a pin clears all connections of that pin ────────────
|
||||
{
|
||||
ed::Suspend();
|
||||
|
||||
Reference in New Issue
Block a user