OverviewFilesCommitsIssuesDocsReleasesPeers

proc-nodes / src / core / proc_curves.h

76 lines · c ref:
#ifndef PROC_NODES_PROC_CURVES_H
#define PROC_NODES_PROC_CURVES_H

#include "attribute_storage.h"
#include "offset_indices.h"
#include <godot_cpp/classes/ref_counted.hpp>
#include <godot_cpp/variant/packed_float32_array.hpp>
#include <godot_cpp/variant/packed_int32_array.hpp>
#include <godot_cpp/variant/packed_vector3_array.hpp>

namespace godot {

enum class CurveType : int32_t {
	Poly = 0,
	CatmullRom = 1,
	Bezier = 2,
};

class ProcCurves : public RefCounted {
	GDCLASS(ProcCurves, RefCounted);

protected:
	static void _bind_methods();

public:
	// All control points, contiguous (grouped by curve via curve_offsets)
	PackedVector3Array positions;
	PackedFloat32Array radii;
	PackedFloat32Array tilts;
	PackedInt32Array curve_offsets; // OffsetIndices raw data
	PackedInt32Array curve_types;   // Per-curve CurveType
	// PER-CURVE CYCLIC FLAG. Blender's Curve Circle is a closed loop of
	// `resolution` points; without this the only way to spell that was to
	// repeat the first point, which is one point more than Blender for the same
	// resolution and leaves a seam where the duplicate sits. Absent or 0 means
	// open, so every curve that existed before behaves as it did.
	PackedInt32Array curve_cyclic;

	AttributeStorage point_attrs;
	AttributeStorage curve_attrs;

	int point_count() const { return positions.size(); }
	int curve_count() const;
	int domain_size(AttrDomain p_domain) const;

	OffsetIndices get_offset_indices() const { return OffsetIndices(curve_offsets); }

	Ref<ProcCurves> duplicate_curves() const;

	// Evaluate position at parameter t (0..1) on curve index p_curve
	Vector3 evaluate_position(int p_curve, float p_t) const;
	Vector3 evaluate_position_cyclic(int p_curve, float p_t) const;

	// Sample a curve at `count` points spaced evenly BY ARC LENGTH, both ends
	// included. Blender resamples by length, not by parameter, and the two
	// agree only when every segment is the same length -- which is why a line
	// and a regular circle matched while a bezier did not.
	PackedVector3Array sample_uniform(int p_curve, int p_count) const;

	bool is_cyclic(int p_curve) const {
		return p_curve >= 0 && p_curve < curve_cyclic.size() && curve_cyclic[p_curve] != 0;
	}

	// Evaluate tangent at parameter t (0..1) on curve index p_curve
	Vector3 evaluate_tangent(int p_curve, float p_t) const;

	// Get total arc length of a curve (approximated by summing segment lengths)
	float approximate_length(int p_curve, int p_samples = 32) const;

	ProcCurves() = default;
};

} // namespace godot

#endif // PROC_NODES_PROC_CURVES_H