#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