#ifndef PROC_NODES_INPUT_NODES_H
#define PROC_NODES_INPUT_NODES_H
#include "../graph/proc_node.h"
namespace godot {
// Group Input — the graph's INTERFACE: the caller's geometry, and every
// parameter the graph exposes.
//
// A Blender geometry tree is only half of what evaluates; the modifier instance
// holds the other half. Subdivide level, cone power, peak height -- each is a
// link from a Group Input output socket, and its VALUE lives on the modifier.
// This node used to declare exactly ONE output, Geometry, no matter what the
// graph said, so every parameter link addressed a socket that did not exist and
// the whole value chain was inert while the geometry chain flowed.
//
// `interface` is a bound property, so a graph saved as a resource keeps its
// parameters, the same way input_defaults does for ordinary nodes.
class GroupInputNode : public ProcNode {
GDCLASS(GroupInputNode, ProcNode);
Array interface_spec;
protected:
static void _bind_methods();
public:
StringName get_node_type() const override { return "GroupInput"; }
String get_node_title() const override { return "Group Input"; }
String get_node_category() const override { return "Input"; }
// [{ name: String, type: int (SocketType), value: Variant }, ...].
// An empty spec leaves the single Geometry output a bare graph expects.
void set_interface(const Array &p_spec);
Array get_interface() const { return interface_spec; }
// ⛔ TRANSPARENT USED TO MEAN "EMITS NOTHING", and that is what broke.
//
// gpu_transparent() was written when Group Input had ONE output, the
// Geometry the caller hands in -- which the emitted shader carries
// implicitly as `pos`, so emitting nothing for the node was right. Since
// the node started carrying the modifier's exposed PARAMETERS on its other
// outputs, a transparent Group Input means every one of those is a variable
// the shader references and nothing declares:
//
// error: 'n0_s19' : undeclared identifier (x16, the bridged
// error: 'n0_s6' : undeclared identifier voronoi mountain)
//
// compile_to_glsl_function skips transparent nodes outright, so the density
// shader for EVERY bridged Blender graph with a group interface -- which is
// every real modifier graph, since that is how a knob is exposed -- failed
// to compile. The refusal machinery could not see it: each node reported GPU
// support and emitted real GLSL, and the missing text was the node that had
// been excused from emitting.
//
// Reading the value from output_defs is what execute() does, so the two
// paths take the same number from the same place rather than agreeing by
// coincidence.
// STILL TRANSPARENT, because the BATCH path's runs are built from
// non-transparent nodes and putting Group Input into them moved the
// boundaries: gpu_batch_gate went red with SetPosition reported 'cpu'.
// Transparent now means "may emit nothing", not "emits nothing" --
// compile_to_glsl_function includes these and accepts an empty result from
// them, which is how Group Input can declare its parameters for the density
// shader without joining a batch.
bool gpu_transparent() const override { return true; }
bool supports_gpu() const override { return true; }
String compile_glsl(const GlslEmitContext &p_ctx, int p_node_idx) const override;
void execute(ProcEvalContext &p_ctx, int p_node_idx) override;
GroupInputNode();
};
// Group Output — configurable inputs, marks graph output
class GroupOutputNode : public ProcNode {
GDCLASS(GroupOutputNode, ProcNode);
protected:
static void _bind_methods();
public:
StringName get_node_type() const override { return "GroupOutput"; }
String get_node_title() const override { return "Group Output"; }
String get_node_category() const override { return "Input"; }
// The graph's OUTPUT INTERFACE. Blender's tree says what it produces
// through its output sockets, and this node carries them. It used to be
// built with one fixed Geometry input whatever the tree declared -- the
// mirror of the Group Input bug #62 found -- so a tree returning a float
// had nowhere to put it, and the GLSL emitter could not be told what the
// graph's result was.
void set_interface(const Array &p_spec);
bool gpu_transparent() const override { return true; }
void execute(ProcEvalContext &p_ctx, int p_node_idx) override;
GroupOutputNode();
};
// Value — outputs a single float
class ValueNode : public ProcNode {
GDCLASS(ValueNode, ProcNode);
protected:
static void _bind_methods();
float value = 0.0f;
public:
StringName get_node_type() const override { return "Value"; }
String get_node_title() const override { return "Value"; }
String get_node_category() const override { return "Input"; }
bool supports_gpu() const override { return true; }
// A CONSTANT THAT EMITTED NOTHING. These five claimed GPU support with no
// compile_glsl at all, so the emitter skipped them silently and any node
// reading one referenced a variable that was never declared -- measured on a
// bridged graph whose Group Output returned `n2_s0` with nothing assigning
// it. Their value is a node PROPERTY rather than a socket, which is why it
// cannot come from the context's input resolution.
String compile_glsl(const GlslEmitContext &p_ctx, int p_node_idx) const override;
void set_value(float p_val) { value = p_val; }
float get_value() const { return value; }
void execute(ProcEvalContext &p_ctx, int p_node_idx) override;
ValueNode();
};
// Vector — outputs a Vector3
class VectorNode : public ProcNode {
GDCLASS(VectorNode, ProcNode);
protected:
static void _bind_methods();
Vector3 value;
public:
StringName get_node_type() const override { return "Vector"; }
String get_node_title() const override { return "Vector"; }
String get_node_category() const override { return "Input"; }
bool supports_gpu() const override { return true; }
// A CONSTANT THAT EMITTED NOTHING. These five claimed GPU support with no
// compile_glsl at all, so the emitter skipped them silently and any node
// reading one referenced a variable that was never declared -- measured on a
// bridged graph whose Group Output returned `n2_s0` with nothing assigning
// it. Their value is a node PROPERTY rather than a socket, which is why it
// cannot come from the context's input resolution.
String compile_glsl(const GlslEmitContext &p_ctx, int p_node_idx) const override;
void set_value(const Vector3 &p_val) { value = p_val; }
Vector3 get_value() const { return value; }
void execute(ProcEvalContext &p_ctx, int p_node_idx) override;
VectorNode();
};
// Integer — outputs a single integer
class IntegerNode : public ProcNode {
GDCLASS(IntegerNode, ProcNode);
protected:
static void _bind_methods();
int value = 0;
public:
StringName get_node_type() const override { return "Integer"; }
String get_node_title() const override { return "Integer"; }
String get_node_category() const override { return "Input"; }
bool supports_gpu() const override { return true; }
// A CONSTANT THAT EMITTED NOTHING. These five claimed GPU support with no
// compile_glsl at all, so the emitter skipped them silently and any node
// reading one referenced a variable that was never declared -- measured on a
// bridged graph whose Group Output returned `n2_s0` with nothing assigning
// it. Their value is a node PROPERTY rather than a socket, which is why it
// cannot come from the context's input resolution.
String compile_glsl(const GlslEmitContext &p_ctx, int p_node_idx) const override;
void set_value(int p_val) { value = p_val; }
int get_value() const { return value; }
void execute(ProcEvalContext &p_ctx, int p_node_idx) override;
IntegerNode();
};
// Boolean — outputs a single boolean
class BooleanNode : public ProcNode {
GDCLASS(BooleanNode, ProcNode);
protected:
static void _bind_methods();
bool value = false;
public:
StringName get_node_type() const override { return "Boolean"; }
String get_node_title() const override { return "Boolean"; }
String get_node_category() const override { return "Input"; }
bool supports_gpu() const override { return true; }
// A CONSTANT THAT EMITTED NOTHING. These five claimed GPU support with no
// compile_glsl at all, so the emitter skipped them silently and any node
// reading one referenced a variable that was never declared -- measured on a
// bridged graph whose Group Output returned `n2_s0` with nothing assigning
// it. Their value is a node PROPERTY rather than a socket, which is why it
// cannot come from the context's input resolution.
String compile_glsl(const GlslEmitContext &p_ctx, int p_node_idx) const override;
void set_value(bool p_val) { value = p_val; }
bool get_value() const { return value; }
void execute(ProcEvalContext &p_ctx, int p_node_idx) override;
BooleanNode();
};
// Color — outputs a single Color
class ColorNode : public ProcNode {
GDCLASS(ColorNode, ProcNode);
protected:
static void _bind_methods();
Color value = Color(1, 1, 1, 1);
public:
StringName get_node_type() const override { return "Color"; }
String get_node_title() const override { return "Color"; }
String get_node_category() const override { return "Input"; }
bool supports_gpu() const override { return true; }
// A CONSTANT THAT EMITTED NOTHING. These five claimed GPU support with no
// compile_glsl at all, so the emitter skipped them silently and any node
// reading one referenced a variable that was never declared -- measured on a
// bridged graph whose Group Output returned `n2_s0` with nothing assigning
// it. Their value is a node PROPERTY rather than a socket, which is why it
// cannot come from the context's input resolution.
String compile_glsl(const GlslEmitContext &p_ctx, int p_node_idx) const override;
void set_value(const Color &p_val) { value = p_val; }
Color get_value() const { return value; }
void execute(ProcEvalContext &p_ctx, int p_node_idx) override;
ColorNode();
};
// String — outputs a single String
class StringNode : public ProcNode {
GDCLASS(StringNode, ProcNode);
protected:
static void _bind_methods();
String value;
public:
StringName get_node_type() const override { return "String"; }
String get_node_title() const override { return "String"; }
String get_node_category() const override { return "Input"; }
void set_value(const String &p_val) { value = p_val; }
String get_value() const { return value; }
void execute(ProcEvalContext &p_ctx, int p_node_idx) override;
StringNode();
};
// ObjectInfo — provides object metadata (placeholder)
class ObjectInfoNode : public ProcNode {
GDCLASS(ObjectInfoNode, ProcNode);
protected:
static void _bind_methods();
public:
StringName get_node_type() const override { return "ObjectInfo"; }
String get_node_title() const override { return "Object Info"; }
String get_node_category() const override { return "Input"; }
void execute(ProcEvalContext &p_ctx, int p_node_idx) override;
ObjectInfoNode();
};
} // namespace godot
#endif // PROC_NODES_INPUT_NODES_H