#include "attribute_storage.h"
namespace godot {
int attr_type_size(AttrType p_type) {
switch (p_type) {
case AttrType::Float: return 4;
case AttrType::Float2: return 8;
case AttrType::Float3: return 12;
case AttrType::Float4: return 16;
case AttrType::Int: return 4;
case AttrType::Int2: return 8;
case AttrType::Bool: return 1;
case AttrType::Color: return 16;
case AttrType::ColorByte: return 4;
case AttrType::Quaternion: return 16;
case AttrType::Float4x4: return 64;
}
return 0;
}
const char *attr_type_name(AttrType p_type) {
switch (p_type) {
case AttrType::Float: return "Float";
case AttrType::Float2: return "Float2";
case AttrType::Float3: return "Float3";
case AttrType::Float4: return "Float4";
case AttrType::Int: return "Int";
case AttrType::Int2: return "Int2";
case AttrType::Bool: return "Bool";
case AttrType::Color: return "Color";
case AttrType::ColorByte: return "ColorByte";
case AttrType::Quaternion: return "Quaternion";
case AttrType::Float4x4: return "Float4x4";
}
return "Unknown";
}
const char *attr_domain_name(AttrDomain p_domain) {
switch (p_domain) {
case AttrDomain::Point: return "Point";
case AttrDomain::Edge: return "Edge";
case AttrDomain::Face: return "Face";
case AttrDomain::Corner: return "Corner";
case AttrDomain::Curve: return "Curve";
case AttrDomain::Instance: return "Instance";
}
return "Unknown";
}
// AttributeArray
void AttributeArray::_bind_methods() {
}
void AttributeArray::resize(int32_t p_count) {
element_count = p_count;
data.resize(p_count * attr_type_size(type));
}
void AttributeArray::copy_element(int32_t p_from, const Ref<AttributeArray> &p_dst, int32_t p_to) const {
int elem_size = attr_type_size(type);
const uint8_t *src = data.ptr() + p_from * elem_size;
uint8_t *dst = p_dst->data.ptrw() + p_to * elem_size;
memcpy(dst, src, elem_size);
}
Ref<AttributeArray> AttributeArray::duplicate_array() const {
Ref<AttributeArray> dup;
dup.instantiate();
dup->name = name;
dup->type = type;
dup->domain = domain;
dup->element_count = element_count;
dup->data = data; // Godot PackedByteArray CoW
return dup;
}
// AttributeStorage
bool AttributeStorage::has(const StringName &p_name) const {
return attributes.has(p_name);
}
Ref<AttributeArray> AttributeStorage::get(const StringName &p_name) const {
if (attributes.has(p_name)) {
return attributes[p_name];
}
return Ref<AttributeArray>();
}
Ref<AttributeArray> AttributeStorage::get_for_read(const StringName &p_name) const {
return get(p_name);
}
Ref<AttributeArray> AttributeStorage::get_for_write(const StringName &p_name) {
if (!attributes.has(p_name)) {
return Ref<AttributeArray>();
}
Ref<AttributeArray> attr = attributes[p_name];
if (attr->get_reference_count() > 1) {
attr = attr->duplicate_array();
attributes[p_name] = attr;
}
return attr;
}
void AttributeStorage::set(const StringName &p_name, const Ref<AttributeArray> &p_attr) {
attributes[p_name] = p_attr;
}
void AttributeStorage::remove(const StringName &p_name) {
attributes.erase(p_name);
}
void AttributeStorage::clear() {
attributes.clear();
}
void AttributeStorage::propagate_from(const AttributeStorage &p_src) {
for (const KeyValue<StringName, Ref<AttributeArray>> &kv : p_src.attributes) {
if (!attributes.has(kv.key)) {
attributes[kv.key] = kv.value; // CoW reference
}
}
}
void AttributeStorage::remap_from(const AttributeStorage &p_src, const PackedInt32Array &p_index_map, int32_t p_new_count) {
for (const KeyValue<StringName, Ref<AttributeArray>> &kv : p_src.attributes) {
const Ref<AttributeArray> &src_attr = kv.value;
Ref<AttributeArray> dst_attr;
dst_attr.instantiate();
dst_attr->name = src_attr->name;
dst_attr->type = src_attr->type;
dst_attr->domain = src_attr->domain;
dst_attr->resize(p_new_count);
const int32_t *map = p_index_map.ptr();
for (int i = 0; i < p_index_map.size(); i++) {
if (map[i] >= 0) {
src_attr->copy_element(i, dst_attr, map[i]);
}
}
attributes[kv.key] = dst_attr;
}
}
} // namespace godot