OverviewFilesCommitsIssuesDocsReleasesPeers

proc-nodes / src / nodes / zone_nodes.cpp

319 lines · cpp ref:
#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