#include "zone_nodes.h"
#include "../graph/graph_executor.h"
namespace godot {
// --- RepeatZoneInputNode ---
void RepeatZoneInputNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_zone_id", "id"), &RepeatZoneInputNode::set_zone_id);
ClassDB::bind_method(D_METHOD("get_zone_id"), &RepeatZoneInputNode::get_zone_id);
ADD_PROPERTY(PropertyInfo(Variant::INT, "zone_id"), "set_zone_id", "get_zone_id");
ClassDB::bind_method(D_METHOD("set_item_names", "n"), &RepeatZoneInputNode::set_item_names);
ClassDB::bind_method(D_METHOD("get_item_names"), &RepeatZoneInputNode::get_item_names);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "item_names"),
"set_item_names", "get_item_names");
ClassDB::bind_method(D_METHOD("set_item_types", "t"), &RepeatZoneInputNode::set_item_types);
ClassDB::bind_method(D_METHOD("get_item_types"), &RepeatZoneInputNode::get_item_types);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "item_types"),
"set_item_types", "get_item_types");
}
void RepeatZoneInputNode::_rebuild_sockets() {
input_defs.clear();
output_defs.clear();
// Blender: Iterations, then one input per state item; Iteration, then one
// output per item. The output was named "Index"; Blender says "Iteration".
input_defs.push_back({ "Iterations", SocketType::Int, 1 });
output_defs.push_back({ "Iteration", SocketType::Int, Variant() });
const int n = item_names.size();
for (int i = 0; i < n; i++) {
Variant zero;
const int cd = (i < item_types.size()) ? item_types[i] : -1;
const SocketType st = socket_type_from_cd_prop(cd, zero);
const StringName nm = StringName(item_names[i]);
input_defs.push_back({ nm, st, zero });
output_defs.push_back({ nm, st, Variant() });
}
}
RepeatZoneInputNode::RepeatZoneInputNode() {
// One GEOMETRY item, which is the list Blender starts a zone with.
item_names.push_back("Geometry");
item_types.push_back(-1);
_rebuild_sockets();
}
void RepeatZoneInputNode::execute(ProcEvalContext &p_ctx, int p_node_idx) {
// Passthrough: just forward inputs to outputs
// The actual zone looping is handled by _execute_repeat_zone
p_ctx.write_int(p_node_idx, 0, 0);
Ref<ProcGeometry> geo = p_ctx.read_geometry(p_node_idx, 1);
p_ctx.write_geometry(p_node_idx, 1, geo);
}
// --- RepeatZoneOutputNode ---
void RepeatZoneOutputNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_zone_id", "id"), &RepeatZoneOutputNode::set_zone_id);
ClassDB::bind_method(D_METHOD("get_zone_id"), &RepeatZoneOutputNode::get_zone_id);
ADD_PROPERTY(PropertyInfo(Variant::INT, "zone_id"), "set_zone_id", "get_zone_id");
ClassDB::bind_method(D_METHOD("set_item_names", "n"), &RepeatZoneOutputNode::set_item_names);
ClassDB::bind_method(D_METHOD("get_item_names"), &RepeatZoneOutputNode::get_item_names);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "item_names"),
"set_item_names", "get_item_names");
ClassDB::bind_method(D_METHOD("set_item_types", "t"), &RepeatZoneOutputNode::set_item_types);
ClassDB::bind_method(D_METHOD("get_item_types"), &RepeatZoneOutputNode::get_item_types);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "item_types"),
"set_item_types", "get_item_types");
}
void RepeatZoneOutputNode::_rebuild_sockets() {
input_defs.clear();
output_defs.clear();
// Blender: one input and one output per state item, nothing fixed.
const int n = item_names.size();
for (int i = 0; i < n; i++) {
Variant zero;
const int cd = (i < item_types.size()) ? item_types[i] : -1;
const SocketType st = socket_type_from_cd_prop(cd, zero);
const StringName nm = StringName(item_names[i]);
input_defs.push_back({ nm, st, zero });
output_defs.push_back({ nm, st, Variant() });
}
}
RepeatZoneOutputNode::RepeatZoneOutputNode() {
// One GEOMETRY item, which is the list Blender starts a zone with.
item_names.push_back("Geometry");
item_types.push_back(-1);
_rebuild_sockets();
}
void RepeatZoneOutputNode::execute(ProcEvalContext &p_ctx, int p_node_idx) {
// Passthrough
Ref<ProcGeometry> geo = p_ctx.read_geometry(p_node_idx, 0);
p_ctx.write_geometry(p_node_idx, 0, geo);
}
// --- ForeachZoneInputNode ---
void ForeachZoneInputNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_zone_id", "id"), &ForeachZoneInputNode::set_zone_id);
ClassDB::bind_method(D_METHOD("get_zone_id"), &ForeachZoneInputNode::get_zone_id);
ADD_PROPERTY(PropertyInfo(Variant::INT, "zone_id"), "set_zone_id", "get_zone_id");
ClassDB::bind_method(D_METHOD("set_input_item_names", "v"), &ForeachZoneInputNode::set_input_item_names);
ClassDB::bind_method(D_METHOD("get_input_item_names"), &ForeachZoneInputNode::get_input_item_names);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "input_item_names"), "set_input_item_names", "get_input_item_names");
ClassDB::bind_method(D_METHOD("set_input_item_types", "v"), &ForeachZoneInputNode::set_input_item_types);
ClassDB::bind_method(D_METHOD("get_input_item_types"), &ForeachZoneInputNode::get_input_item_types);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "input_item_types"), "set_input_item_types", "get_input_item_types");
}
void ForeachZoneInputNode::_rebuild_sockets() {
input_defs.clear();
output_defs.clear();
// Blender: Geometry, Selection, then one input per input_item.
// SELECTION WAS MISSING ENTIRELY.
input_defs.push_back({ "Geometry", SocketType::Geometry, Variant() });
input_defs.push_back({ "Selection", SocketType::Bool, true });
// Blender: Index, Element, then one output per input_item. Ours put
// "Position" at index 1, which is where ELEMENT is -- so a graph wiring the
// element landed on a Vector socket.
output_defs.push_back({ "Index", SocketType::Int, Variant() });
output_defs.push_back({ "Element", SocketType::Geometry, Variant() });
const int n = input_item_names.size();
for (int i = 0; i < n; i++) {
Variant zero;
const int cd = (i < input_item_types.size()) ? input_item_types[i] : 10;
const SocketType st = socket_type_from_cd_prop(cd, zero);
const StringName nm = StringName(input_item_names[i]);
input_defs.push_back({ nm, st, zero });
output_defs.push_back({ nm, st, Variant() });
}
}
ForeachZoneInputNode::ForeachZoneInputNode() {
_rebuild_sockets();
}
void ForeachZoneInputNode::execute(ProcEvalContext &p_ctx, int p_node_idx) {
// Passthrough — actual logic in executor
p_ctx.write_int(p_node_idx, 0, 0);
p_ctx.write_vector(p_node_idx, 1, Vector3());
p_ctx.write_geometry(p_node_idx, 2, Ref<ProcGeometry>());
}
// --- ForeachZoneOutputNode ---
void ForeachZoneOutputNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_zone_id", "id"), &ForeachZoneOutputNode::set_zone_id);
ClassDB::bind_method(D_METHOD("get_zone_id"), &ForeachZoneOutputNode::get_zone_id);
ADD_PROPERTY(PropertyInfo(Variant::INT, "zone_id"), "set_zone_id", "get_zone_id");
ClassDB::bind_method(D_METHOD("set_main_item_names", "v"), &ForeachZoneOutputNode::set_main_item_names);
ClassDB::bind_method(D_METHOD("get_main_item_names"), &ForeachZoneOutputNode::get_main_item_names);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "main_item_names"), "set_main_item_names", "get_main_item_names");
ClassDB::bind_method(D_METHOD("set_main_item_types", "v"), &ForeachZoneOutputNode::set_main_item_types);
ClassDB::bind_method(D_METHOD("get_main_item_types"), &ForeachZoneOutputNode::get_main_item_types);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "main_item_types"), "set_main_item_types", "get_main_item_types");
ClassDB::bind_method(D_METHOD("set_generation_item_names", "v"), &ForeachZoneOutputNode::set_generation_item_names);
ClassDB::bind_method(D_METHOD("get_generation_item_names"), &ForeachZoneOutputNode::get_generation_item_names);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "generation_item_names"), "set_generation_item_names", "get_generation_item_names");
ClassDB::bind_method(D_METHOD("set_generation_item_types", "v"), &ForeachZoneOutputNode::set_generation_item_types);
ClassDB::bind_method(D_METHOD("get_generation_item_types"), &ForeachZoneOutputNode::get_generation_item_types);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "generation_item_types"), "set_generation_item_types", "get_generation_item_types");
}
void ForeachZoneOutputNode::_rebuild_sockets() {
input_defs.clear();
output_defs.clear();
// Blender: inputs are main_items then generation_items; outputs are the
// MAIN GEOMETRY first, then main_items, then generation_items. Ours was a
// single Geometry in and out, so with any main item present every
// generation link was displaced.
for (int i = 0; i < main_item_names.size(); i++) {
Variant zero;
const int cd = (i < main_item_types.size()) ? main_item_types[i] : 10;
const SocketType st = socket_type_from_cd_prop(cd, zero);
input_defs.push_back({ StringName(main_item_names[i]), st, zero });
}
for (int i = 0; i < generation_item_names.size(); i++) {
Variant zero;
const int cd = (i < generation_item_types.size()) ? generation_item_types[i] : -1;
const SocketType st = socket_type_from_cd_prop(cd, zero);
input_defs.push_back({ StringName(generation_item_names[i]), st, zero });
}
output_defs.push_back({ "Geometry", SocketType::Geometry, Variant() });
for (int i = 0; i < main_item_names.size(); i++) {
Variant zero;
const int cd = (i < main_item_types.size()) ? main_item_types[i] : 10;
const SocketType st = socket_type_from_cd_prop(cd, zero);
output_defs.push_back({ StringName(main_item_names[i]), st, Variant() });
}
for (int i = 0; i < generation_item_names.size(); i++) {
Variant zero;
const int cd = (i < generation_item_types.size()) ? generation_item_types[i] : -1;
const SocketType st = socket_type_from_cd_prop(cd, zero);
output_defs.push_back({ StringName(generation_item_names[i]), st, Variant() });
}
}
ForeachZoneOutputNode::ForeachZoneOutputNode() {
// Blender seeds generation_items with one Geometry item.
generation_item_names.push_back("Geometry");
generation_item_types.push_back(-1);
_rebuild_sockets();
}
void ForeachZoneOutputNode::execute(ProcEvalContext &p_ctx, int p_node_idx) {
// Passthrough
Ref<ProcGeometry> geo = p_ctx.read_geometry(p_node_idx, 0);
p_ctx.write_geometry(p_node_idx, 0, geo);
}
// --- SimulationZoneInputNode ---
void SimulationZoneInputNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_zone_id", "id"), &SimulationZoneInputNode::set_zone_id);
ClassDB::bind_method(D_METHOD("get_zone_id"), &SimulationZoneInputNode::get_zone_id);
ADD_PROPERTY(PropertyInfo(Variant::INT, "zone_id"), "set_zone_id", "get_zone_id");
ClassDB::bind_method(D_METHOD("set_item_names", "n"), &SimulationZoneInputNode::set_item_names);
ClassDB::bind_method(D_METHOD("get_item_names"), &SimulationZoneInputNode::get_item_names);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "item_names"),
"set_item_names", "get_item_names");
ClassDB::bind_method(D_METHOD("set_item_types", "t"), &SimulationZoneInputNode::set_item_types);
ClassDB::bind_method(D_METHOD("get_item_types"), &SimulationZoneInputNode::get_item_types);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "item_types"),
"set_item_types", "get_item_types");
}
void SimulationZoneInputNode::_rebuild_sockets() {
input_defs.clear();
output_defs.clear();
// Blender: one input per state item; Delta Time, then one output per item.
output_defs.push_back({ "Delta Time", SocketType::Float, Variant() });
const int n = item_names.size();
for (int i = 0; i < n; i++) {
Variant zero;
const int cd = (i < item_types.size()) ? item_types[i] : -1;
const SocketType st = socket_type_from_cd_prop(cd, zero);
const StringName nm = StringName(item_names[i]);
input_defs.push_back({ nm, st, zero });
output_defs.push_back({ nm, st, Variant() });
}
}
SimulationZoneInputNode::SimulationZoneInputNode() {
// One GEOMETRY item, which is the list Blender starts a zone with.
item_names.push_back("Geometry");
item_types.push_back(-1);
_rebuild_sockets();
}
void SimulationZoneInputNode::execute(ProcEvalContext &p_ctx, int p_node_idx) {
// Passthrough: write defaults. Actual zone logic is in _execute_simulation_zone.
p_ctx.write_float(p_node_idx, 0, 0.016f);
Ref<ProcGeometry> geo = p_ctx.read_geometry(p_node_idx, 0);
p_ctx.write_geometry(p_node_idx, 1, geo);
}
// --- SimulationZoneOutputNode ---
void SimulationZoneOutputNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_zone_id", "id"), &SimulationZoneOutputNode::set_zone_id);
ClassDB::bind_method(D_METHOD("get_zone_id"), &SimulationZoneOutputNode::get_zone_id);
ADD_PROPERTY(PropertyInfo(Variant::INT, "zone_id"), "set_zone_id", "get_zone_id");
ClassDB::bind_method(D_METHOD("set_item_names", "n"), &SimulationZoneOutputNode::set_item_names);
ClassDB::bind_method(D_METHOD("get_item_names"), &SimulationZoneOutputNode::get_item_names);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "item_names"),
"set_item_names", "get_item_names");
ClassDB::bind_method(D_METHOD("set_item_types", "t"), &SimulationZoneOutputNode::set_item_types);
ClassDB::bind_method(D_METHOD("get_item_types"), &SimulationZoneOutputNode::get_item_types);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "item_types"),
"set_item_types", "get_item_types");
}
void SimulationZoneOutputNode::_rebuild_sockets() {
input_defs.clear();
output_defs.clear();
// BLENDER HAS A `Skip` INPUT FIRST, which ours lacked entirely -- so our
// first state item sat on it and a graph wiring Skip drove the state.
input_defs.push_back({ "Skip", SocketType::Bool, false });
const int n = item_names.size();
for (int i = 0; i < n; i++) {
Variant zero;
const int cd = (i < item_types.size()) ? item_types[i] : -1;
const SocketType st = socket_type_from_cd_prop(cd, zero);
const StringName nm = StringName(item_names[i]);
input_defs.push_back({ nm, st, zero });
output_defs.push_back({ nm, st, Variant() });
}
}
SimulationZoneOutputNode::SimulationZoneOutputNode() {
// One GEOMETRY item, which is the list Blender starts a zone with.
item_names.push_back("Geometry");
item_types.push_back(-1);
_rebuild_sockets();
}
void SimulationZoneOutputNode::execute(ProcEvalContext &p_ctx, int p_node_idx) {
// Passthrough
Ref<ProcGeometry> geo = p_ctx.read_geometry(p_node_idx, 0);
p_ctx.write_geometry(p_node_idx, 0, geo);
}
} // namespace godot