e828af3ac1
- DagKind::Output (new enum): terminal sink; compiler wires fragColor to its source_ids[0] - dag_catalog: "output" node (1 input, red) - dag_compile: skips Output in node_<i> emission; final fragColor resolves from Output's connection - dag_node_editor: no more Add button; drops "DAG_NODE_TYPE" payloads at mouse canvas position; Output cannot be deleted; Output has no output pin - dag_palette (new fn): Functions window with grouped, draggable node cards - main.cpp: "Functions" window added; ensure_dag_default seeds plasma + connected Output
109 lines
3.5 KiB
C++
109 lines
3.5 KiB
C++
#include "gfx/dag_compile.h"
|
|
#include "gfx/dag_catalog.h"
|
|
#include <algorithm>
|
|
#include <sstream>
|
|
|
|
namespace fn::gfx {
|
|
|
|
static constexpr int MAX_NODES = 16;
|
|
|
|
std::string compile_dag_to_glsl(const std::vector<DagStep>& pipeline) {
|
|
const int n = static_cast<int>(std::min(pipeline.size(), static_cast<size_t>(MAX_NODES)));
|
|
std::ostringstream out;
|
|
|
|
out << "uniform vec4 u_params[16];\n\n";
|
|
|
|
if (n == 0) {
|
|
out << "void main() {\n";
|
|
out << " vec2 uv = gl_FragCoord.xy / u_resolution;\n";
|
|
out << " (void)uv;\n";
|
|
out << " fragColor = vec4(0.04, 0.04, 0.06, 1.0);\n";
|
|
out << "}\n";
|
|
return out.str();
|
|
}
|
|
|
|
// Emit per-node functions (skip Output: it's a sink, no body)
|
|
for (int i = 0; i < n; ++i) {
|
|
const DagStep& step = pipeline[static_cast<size_t>(i)];
|
|
const DagNodeDef* def = dag_find(step.name);
|
|
if (!def) continue;
|
|
if (def->kind == DagKind::Output) continue;
|
|
|
|
int ni = def->num_inputs;
|
|
out << "vec4 node_" << i << "(";
|
|
if (ni >= 1) out << "vec4 a";
|
|
if (ni >= 2) out << ", vec4 b";
|
|
if (ni >= 3) out << ", vec4 c";
|
|
if (ni >= 4) out << ", vec4 d";
|
|
if (ni > 0) out << ", ";
|
|
out << "vec2 uv) {\n";
|
|
out << def->body_glsl(i) << "\n";
|
|
out << "}\n\n";
|
|
}
|
|
|
|
out << "void main() {\n";
|
|
out << " vec2 uv = gl_FragCoord.xy / u_resolution;\n";
|
|
|
|
int last_valid_out = -1;
|
|
int output_idx = -1;
|
|
|
|
for (int i = 0; i < n; ++i) {
|
|
const DagStep& step = pipeline[static_cast<size_t>(i)];
|
|
const DagNodeDef* def = dag_find(step.name);
|
|
if (!def) continue;
|
|
if (def->kind == DagKind::Output) { output_idx = i; continue; }
|
|
|
|
int ni = def->num_inputs;
|
|
|
|
auto resolve = [&](int k) -> std::string {
|
|
const std::string& sid = step.source_ids[static_cast<size_t>(k)];
|
|
if (!sid.empty()) {
|
|
for (int j = 0; j < i; ++j) {
|
|
if (pipeline[static_cast<size_t>(j)].id == sid) {
|
|
const DagNodeDef* jdef = dag_find(pipeline[static_cast<size_t>(j)].name);
|
|
if (jdef && jdef->kind == DagKind::Output) continue; // Output has no out_j
|
|
return "out_" + std::to_string(j);
|
|
}
|
|
}
|
|
}
|
|
if (last_valid_out < 0) return "vec4(0.0, 0.0, 0.0, 1.0)";
|
|
return "out_" + std::to_string(last_valid_out);
|
|
};
|
|
|
|
out << " vec4 out_" << i << " = node_" << i << "(";
|
|
for (int k = 0; k < ni; ++k) {
|
|
if (k > 0) out << ", ";
|
|
out << resolve(k);
|
|
}
|
|
if (ni > 0) out << ", ";
|
|
out << "uv);\n";
|
|
|
|
last_valid_out = i;
|
|
}
|
|
|
|
// Resolve fragColor: if there's an Output node with a connection, use that; else fallback.
|
|
auto seed = [&]() { out << " fragColor = vec4(0.04, 0.04, 0.06, 1.0);\n"; };
|
|
|
|
if (output_idx >= 0) {
|
|
const std::string& sid = pipeline[static_cast<size_t>(output_idx)].source_ids[0];
|
|
int src = -1;
|
|
if (!sid.empty()) {
|
|
for (int j = 0; j < output_idx; ++j) {
|
|
if (pipeline[static_cast<size_t>(j)].id == sid) { src = j; break; }
|
|
}
|
|
}
|
|
if (src >= 0) out << " fragColor = out_" << src << ";\n";
|
|
else seed();
|
|
} else if (last_valid_out >= 0) {
|
|
out << " fragColor = out_" << last_valid_out << ";\n";
|
|
} else {
|
|
seed();
|
|
}
|
|
|
|
out << "}\n";
|
|
|
|
return out.str();
|
|
}
|
|
|
|
} // namespace fn::gfx
|