OverviewFilesCommitsIssuesDocsReleasesPeers

proc-nodes / src / core / attribute_storage.cpp

149 lines · cpp ref:
#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