OverviewFilesCommitsIssuesDocsReleasesPeers

proc-nodes / src / core / attribute_storage.h

109 lines · c ref:
#ifndef PROC_NODES_ATTRIBUTE_STORAGE_H
#define PROC_NODES_ATTRIBUTE_STORAGE_H

#include <godot_cpp/classes/ref.hpp>
#include <godot_cpp/classes/ref_counted.hpp>
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/templates/hash_map.hpp>
#include <godot_cpp/variant/packed_byte_array.hpp>
#include <godot_cpp/variant/string_name.hpp>

namespace godot {

// Attribute data types
enum class AttrType : uint8_t {
	Float,
	Float2,
	Float3,
	Float4,
	Int,
	Int2,
	Bool,
	Color,       // RGBA float (4 floats)
	ColorByte,   // RGBA uint8 (4 bytes)
	Quaternion,  // 4 floats
	Float4x4,    // 16 floats
};

// Attribute domain — which element owns the data
enum class AttrDomain : uint8_t {
	Point,     // Per-vertex / per-control-point
	Edge,      // Per-edge (mesh only)
	Face,      // Per-face (mesh only)
	Corner,    // Per-loop / per-face-corner (mesh only)
	Curve,     // Per-curve (curves only)
	Instance,  // Per-instance (instances only)
};

int attr_type_size(AttrType p_type);
const char *attr_type_name(AttrType p_type);
const char *attr_domain_name(AttrDomain p_domain);

// A single named attribute array
class AttributeArray : public RefCounted {
	GDCLASS(AttributeArray, RefCounted);

protected:
	static void _bind_methods();

public:
	StringName name;
	AttrType type = AttrType::Float;
	AttrDomain domain = AttrDomain::Point;
	PackedByteArray data;
	int32_t element_count = 0;

	void resize(int32_t p_count);
	int32_t size() const { return element_count; }
	int32_t byte_size() const { return element_count * attr_type_size(type); }

	// Typed access (caller must ensure correct type)
	template <typename T>
	const T *data_ptr() const {
		return reinterpret_cast<const T *>(data.ptr());
	}

	template <typename T>
	T *data_ptrw() {
		return reinterpret_cast<T *>(data.ptrw());
	}

	// Copy a single element from src to dst index
	void copy_element(int32_t p_from, const Ref<AttributeArray> &p_dst, int32_t p_to) const;

	Ref<AttributeArray> duplicate_array() const;

	AttributeArray() = default;
};

// Collection of named attributes for a domain
class AttributeStorage {
public:
	HashMap<StringName, Ref<AttributeArray>> attributes;

	bool has(const StringName &p_name) const;
	Ref<AttributeArray> get(const StringName &p_name) const;

	// Get for reading (returns const ref, no copy)
	Ref<AttributeArray> get_for_read(const StringName &p_name) const;

	// Get for writing (copies if shared)
	Ref<AttributeArray> get_for_write(const StringName &p_name);

	void set(const StringName &p_name, const Ref<AttributeArray> &p_attr);
	void remove(const StringName &p_name);
	void clear();

	int size() const { return attributes.size(); }

	// Propagate all attributes from src (CoW, no deep copy)
	void propagate_from(const AttributeStorage &p_src);

	// Remap attributes using index map (for topology changes)
	void remap_from(const AttributeStorage &p_src, const PackedInt32Array &p_index_map, int32_t p_new_count);
};

} // namespace godot

#endif // PROC_NODES_ATTRIBUTE_STORAGE_H