OverviewFilesCommitsIssuesDocsReleasesPeers

proc-nodes / src / core / proc_geometry.cpp

162 lines · cpp ref:
#include "proc_geometry.h"

namespace godot {

void ProcGeometry::_bind_methods() {
	ClassDB::bind_method(D_METHOD("get_mesh"), &ProcGeometry::get_mesh);
	ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &ProcGeometry::set_mesh);
	ClassDB::bind_method(D_METHOD("get_curves"), &ProcGeometry::get_curves);
	ClassDB::bind_method(D_METHOD("set_curves", "curves"), &ProcGeometry::set_curves);
	ClassDB::bind_method(D_METHOD("get_pointcloud"), &ProcGeometry::get_pointcloud);
	ClassDB::bind_method(D_METHOD("set_pointcloud", "pointcloud"), &ProcGeometry::set_pointcloud);
	ClassDB::bind_method(D_METHOD("get_instances"), &ProcGeometry::get_instances);
	ClassDB::bind_method(D_METHOD("set_instances", "instances"), &ProcGeometry::set_instances);
	ClassDB::bind_method(D_METHOD("get_volume"), &ProcGeometry::get_volume);
	ClassDB::bind_method(D_METHOD("set_volume", "volume"), &ProcGeometry::set_volume);
	ClassDB::bind_method(D_METHOD("is_empty"), &ProcGeometry::is_empty);
	ClassDB::bind_method(D_METHOD("duplicate_geometry"), &ProcGeometry::duplicate_geometry);

	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "ProcMesh"), "set_mesh", "get_mesh");
	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curves", PROPERTY_HINT_RESOURCE_TYPE, "ProcCurves"), "set_curves", "get_curves");
	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "pointcloud", PROPERTY_HINT_RESOURCE_TYPE, "ProcPointCloud"), "set_pointcloud", "get_pointcloud");
	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "instances", PROPERTY_HINT_RESOURCE_TYPE, "ProcInstances"), "set_instances", "get_instances");
	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "volume", PROPERTY_HINT_RESOURCE_TYPE, "ProcVolume"), "set_volume", "get_volume");
}

bool ProcGeometry::is_empty() const {
	return mesh.is_null() && curves.is_null() && pointcloud.is_null() && instances.is_null() && volume.is_null();
}

int ProcGeometry::domain_size(AttrDomain p_domain) const {
	int total = 0;
	if (mesh.is_valid()) {
		total += mesh->domain_size(p_domain);
	}
	if (curves.is_valid()) {
		total += curves->domain_size(p_domain);
	}
	if (pointcloud.is_valid()) {
		total += pointcloud->domain_size(p_domain);
	}
	if (instances.is_valid()) {
		total += instances->domain_size(p_domain);
	}
	return total;
}

Ref<ProcMesh> ProcGeometry::ensure_mesh() {
	if (mesh.is_null()) {
		mesh.instantiate();
	}
	return mesh;
}

Ref<ProcCurves> ProcGeometry::ensure_curves() {
	if (curves.is_null()) {
		curves.instantiate();
	}
	return curves;
}

Ref<ProcPointCloud> ProcGeometry::ensure_pointcloud() {
	if (pointcloud.is_null()) {
		pointcloud.instantiate();
	}
	return pointcloud;
}

Ref<ProcInstances> ProcGeometry::ensure_instances() {
	if (instances.is_null()) {
		instances.instantiate();
	}
	return instances;
}

Ref<ProcVolume> ProcGeometry::ensure_volume() {
	if (volume.is_null()) {
		volume.instantiate();
	}
	return volume;
}

Ref<ProcGeometry> ProcGeometry::duplicate_geometry() const {
	Ref<ProcGeometry> dup;
	dup.instantiate();
	if (mesh.is_valid()) {
		dup->mesh = mesh->duplicate_mesh();
	}
	if (curves.is_valid()) {
		dup->curves = curves->duplicate_curves();
	}
	if (pointcloud.is_valid()) {
		dup->pointcloud = pointcloud->duplicate_pointcloud();
	}
	if (instances.is_valid()) {
		dup->instances = instances->duplicate_instances();
	}
	if (volume.is_valid()) {
		dup->volume = volume->duplicate_volume();
	}
	return dup;
}

void ProcGeometry::join(const Ref<ProcGeometry> &p_other) {
	if (p_other.is_null()) {
		return;
	}

	// Join meshes
	if (p_other->mesh.is_valid() && p_other->mesh->vertex_count() > 0) {
		Ref<ProcMesh> m = ensure_mesh();
		int base_vertex = m->positions.size();
		int base_index = m->indices.size();

		m->positions.append_array(p_other->mesh->positions);
		m->normals.append_array(p_other->mesh->normals);
		m->uvs.append_array(p_other->mesh->uvs);
		m->colors.append_array(p_other->mesh->colors);

		// Offset indices
		PackedInt32Array other_indices = p_other->mesh->indices;
		int32_t *ow = other_indices.ptrw();
		for (int i = 0; i < other_indices.size(); i++) {
			ow[i] += base_vertex;
		}
		m->indices.append_array(other_indices);

		// Propagate attributes
		m->point_attrs.propagate_from(p_other->mesh->point_attrs);
	}

	// Join instances
	if (p_other->instances.is_valid() && p_other->instances->instance_count() > 0) {
		Ref<ProcInstances> inst = ensure_instances();
		int base_ref = inst->references.size();

		// Add references
		for (int i = 0; i < p_other->instances->references.size(); i++) {
			inst->references.push_back(p_other->instances->references[i]);
		}

		// Add instances with offset reference indices
		for (int i = 0; i < p_other->instances->instance_count(); i++) {
			inst->transforms.push_back(p_other->instances->transforms[i]);
		}
		PackedInt32Array other_refs = p_other->instances->reference_indices;
		int32_t *rw = other_refs.ptrw();
		for (int i = 0; i < other_refs.size(); i++) {
			rw[i] += base_ref;
		}
		inst->reference_indices.append_array(other_refs);
	}

	// Join point clouds
	if (p_other->pointcloud.is_valid() && p_other->pointcloud->point_count() > 0) {
		Ref<ProcPointCloud> pc = ensure_pointcloud();
		pc->positions.append_array(p_other->pointcloud->positions);
		pc->radii.append_array(p_other->pointcloud->radii);
	}
}

} // namespace godot