OverviewFilesCommitsIssuesDocsReleasesPeers

proc-nodes / src / nodes / selection_nodes.h

176 lines · c ref:
#ifndef PROC_NODES_SELECTION_NODES_H
#define PROC_NODES_SELECTION_NODES_H

#include "../graph/proc_node.h"

namespace godot {

// Delete Geometry — remove elements where selection is true
class DeleteGeometryNode : public ProcNode {
	GDCLASS(DeleteGeometryNode, ProcNode);

protected:
	static void _bind_methods();

	int delete_domain = 0; // 0=Point, 2=Face

public:
	StringName get_node_type() const override { return "DeleteGeometry"; }
	String get_node_title() const override { return "Delete Geometry"; }
	String get_node_category() const override { return "Geometry"; }

	void set_delete_domain(int p_domain) { delete_domain = p_domain; }
	int get_delete_domain() const { return delete_domain; }

	void execute(ProcEvalContext &p_ctx, int p_node_idx) override;

	DeleteGeometryNode();
};

// Bounding Box — outputs min/max corners of geometry
class BoundingBoxNode : public ProcNode {
	GDCLASS(BoundingBoxNode, ProcNode);

protected:
	static void _bind_methods();

public:
	StringName get_node_type() const override { return "BoundingBox"; }
	String get_node_title() const override { return "Bounding Box"; }
	String get_node_category() const override { return "Geometry"; }

	void execute(ProcEvalContext &p_ctx, int p_node_idx) override;

	BoundingBoxNode();
};

// Separate Components — split geometry into mesh/curves/pointcloud/instances
class SeparateComponentsNode : public ProcNode {
	GDCLASS(SeparateComponentsNode, ProcNode);

protected:
	static void _bind_methods();

public:
	StringName get_node_type() const override { return "SeparateComponents"; }
	String get_node_title() const override { return "Separate Components"; }
	String get_node_category() const override { return "Geometry"; }

	void execute(ProcEvalContext &p_ctx, int p_node_idx) override;

	SeparateComponentsNode();
};

// Switch — select between two inputs based on boolean
// Switch — Blender's is TYPED. `input_type` picks what flows through it, and
// only GEOMETRY makes it a geometry switch; every other setting makes it a
// field function selecting per element.
//
// This declared its False/True sockets as Geometry unconditionally, so a Float
// switch -- the ordinary way to gate a displacement -- read its value through a
// geometry socket and delivered nothing. It was the last dead link in the
// bridged mountain: every parameter arrived, every node ran, and the offset
// this fed into Set Position was zero.
// Separate Geometry — Blender's: a geometry and a selection in, the SELECTED
// half and the INVERTED half out. It was mapped onto SeparateComponents, which
// splits a geometry by COMPONENT TYPE (mesh, curve, point cloud, instances) and
// is a different node with a different shape -- one input against two, four
// outputs against two.
class SeparateGeometryNode : public ProcNode {
	GDCLASS(SeparateGeometryNode, ProcNode);

	int domain = 0; // 0 Point, 2 Face -- as DeleteGeometry's

protected:
	static void _bind_methods();

public:
	StringName get_node_type() const override { return "SeparateGeometry"; }
	String get_node_title() const override { return "Separate Geometry"; }
	String get_node_category() const override { return "Geometry"; }

	void set_domain(int p_d) { domain = p_d; }
	int get_domain() const { return domain; }

	void execute(ProcEvalContext &p_ctx, int p_node_idx) override;

	SeparateGeometryNode();
};

class SwitchNode : public ProcNode {
	GDCLASS(SwitchNode, ProcNode);

	SocketType input_type = SocketType::Geometry;

protected:
	static void _bind_methods();

public:
	StringName get_node_type() const override { return "Switch"; }
	String get_node_title() const override { return "Switch"; }
	String get_node_category() const override { return "Utility"; }

	void set_input_type(int p_type);
	int get_input_type_prop() const { return (int)input_type; }

	// ⛔ GEOMETRY SWITCHING IS NOT A VALUE, so only the value forms emit. A
	// geometry Switch picks a BRANCH of the graph, which a per-vertex shader
	// cannot express, and claiming GPU support for it would make
	// compile_to_function refuse the whole graph.
	//
	// Why this matters beyond the density path: a batch is built backwards over
	// the value cone feeding Set Position, and it stops at the first node that
	// cannot emit. Measured on the bridged mountain --
	//
	//     GPU batch REFUSED: node 31 (CombineXYZ) socket 2 is connected from
	//     outside the batch and has no push-constant slot
	//
	// -- because CombineXYZ's Z came from this node. One missing compile_glsl
	// put Set Position on the CPU for 2.58M vertices: 17.8 s an evaluation.
	bool supports_gpu() const override { return input_type != SocketType::Geometry; }
	String compile_glsl(const GlslEmitContext &p_ctx, int p_node_idx) const override;

	void execute(ProcEvalContext &p_ctx, int p_node_idx) override;

	SwitchNode();
};

// Random Value — per-element random float
// Random Value — Blender's, which is FOUR data types and one of them has a
// DIFFERENT SOCKET SET: BOOLEAN drops Min and Max for a single Probability, so
// ID and Seed move from sockets 2 and 3 to 1 and 2.
class RandomValueNode : public ProcNode {
	GDCLASS(RandomValueNode, ProcNode);

protected:
	static void _bind_methods();

	int data_type = 10; // Blender's CD_PROP_* code; FLOAT is its default

public:
	StringName get_node_type() const override { return "RandomValue"; }
	String get_node_title() const override { return "Random Value"; }
	String get_node_category() const override { return "Utility"; }
	// ON since 2026-09-05. This node's history is the reason the rest of the
	// list was audited: supports_gpu() used to return true with NO
	// compile_glsl override at all, so the GPU path emitted none of its
	// arithmetic and said nothing. It is true again now because there is
	// something behind it -- calls into blender_hash.inc, the same text
	// execute() runs.
	bool supports_gpu() const override { return true; }
	String compile_glsl(const GlslEmitContext &p_ctx, int p_node_idx) const override;
	String compile_glsl_prelude(int p_node_idx) const override;

	// Rebuilds the socket LIST, not just its types.
	void set_data_type(int p_type);
	int get_data_type() const { return data_type; }

	void execute(ProcEvalContext &p_ctx, int p_node_idx) override;

	RandomValueNode();
};

} // namespace godot

#endif // PROC_NODES_SELECTION_NODES_H