Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is accessible from RNA and C code. The second is implemented with `GeometryComponent` and is only accessible in C++ code. The second is widely used, but only being accessible through the `GeometrySet` API makes it awkward to use, and even impossible for types that don't correspond directly to a geometry component like `CurvesGeometry`. This patch adds a new attribute API, designed to replace the `GeometryComponent` attribute API now, and to eventually replace or be the basis of the other one. The basic idea is that there is an `AttributeAccessor` class that allows code to interact with a set of attributes owned by some geometry. The accessor itself has no ownership. `AttributeAccessor` is a simple type that can be passed around by value. That makes it easy to return it from functions and to store it in containers. For const-correctness, there is also a `MutableAttributeAccessor` that allows changing individual and can add or remove attributes. Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer to the owner of the attribute data. The second is a pointer to a struct with function pointers, that is similar to a virtual function table. The functions know how to access attributes on the owner. The actual attribute access for geometries is still implemented with the `AttributeProvider` pattern, which makes it easy to support different sources of attributes on a geometry and simplifies dealing with built-in attributes. There are different ways to get an attribute accessor for a geometry: * `GeometryComponent.attributes()` * `CurvesGeometry.attributes()` * `bke::mesh_attributes(const Mesh &)` * `bke::pointcloud_attributes(const PointCloud &)` All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`. Differential Revision: https://developer.blender.org/D15280
This commit is contained in:
@@ -7,7 +7,6 @@
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
||||
#include "BKE_attribute_access.hh"
|
||||
#include "BKE_geometry_set.hh"
|
||||
#include "BKE_mesh.h"
|
||||
|
||||
@@ -322,11 +321,10 @@ static void calculate_polys(const CuboidConfig &config,
|
||||
|
||||
static void calculate_uvs(const CuboidConfig &config, Mesh *mesh, const bke::AttributeIDRef &uv_id)
|
||||
{
|
||||
MeshComponent mesh_component;
|
||||
mesh_component.replace(mesh, GeometryOwnershipType::Editable);
|
||||
bke::OutputAttribute_Typed<float2> uv_attribute =
|
||||
mesh_component.attribute_try_get_for_output_only<float2>(uv_id, ATTR_DOMAIN_CORNER);
|
||||
MutableSpan<float2> uvs = uv_attribute.as_span();
|
||||
bke::MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh);
|
||||
bke::SpanAttributeWriter<float2> uv_attribute =
|
||||
attributes.lookup_or_add_for_write_only_span<float2>(uv_id, ATTR_DOMAIN_CORNER);
|
||||
MutableSpan<float2> uvs = uv_attribute.span;
|
||||
|
||||
int loop_index = 0;
|
||||
|
||||
@@ -394,7 +392,7 @@ static void calculate_uvs(const CuboidConfig &config, Mesh *mesh, const bke::Att
|
||||
}
|
||||
}
|
||||
|
||||
uv_attribute.save();
|
||||
uv_attribute.finish();
|
||||
}
|
||||
|
||||
Mesh *create_cuboid_mesh(const float3 &size,
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
||||
#include "BKE_attribute_access.hh"
|
||||
#include "BKE_attribute.hh"
|
||||
#include "BKE_attribute_math.hh"
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_geometry_set.hh"
|
||||
@@ -44,14 +44,13 @@ static Curves *create_curve_from_vert_indices(const MeshComponent &mesh_componen
|
||||
curves.cyclic_for_write().fill(false);
|
||||
curves.cyclic_for_write().slice(cyclic_curves).fill(true);
|
||||
|
||||
Set<bke::AttributeIDRef> source_attribute_ids = mesh_component.attribute_ids();
|
||||
bke::MutableAttributeAccessor curves_attributes = curves.attributes_for_write();
|
||||
const bke::AttributeAccessor mesh_attributes = *mesh_component.attributes();
|
||||
|
||||
CurveComponent curves_component;
|
||||
curves_component.replace(curves_id, GeometryOwnershipType::Editable);
|
||||
Set<bke::AttributeIDRef> source_attribute_ids = mesh_attributes.all_ids();
|
||||
|
||||
for (const bke::AttributeIDRef &attribute_id : source_attribute_ids) {
|
||||
if (mesh_component.attribute_is_builtin(attribute_id) &&
|
||||
!curves_component.attribute_is_builtin(attribute_id)) {
|
||||
if (mesh_attributes.is_builtin(attribute_id) && !curves_attributes.is_builtin(attribute_id)) {
|
||||
/* Don't copy attributes that are built-in on meshes but not on curves. */
|
||||
continue;
|
||||
}
|
||||
@@ -60,8 +59,7 @@ static Curves *create_curve_from_vert_indices(const MeshComponent &mesh_componen
|
||||
continue;
|
||||
}
|
||||
|
||||
const GVArray mesh_attribute = mesh_component.attribute_try_get_for_read(attribute_id,
|
||||
ATTR_DOMAIN_POINT);
|
||||
const GVArray mesh_attribute = mesh_attributes.lookup(attribute_id, ATTR_DOMAIN_POINT);
|
||||
/* Some attributes might not exist if they were builtin attribute on domains that don't
|
||||
* have any elements, i.e. a face attribute on the output of the line primitive node. */
|
||||
if (!mesh_attribute) {
|
||||
@@ -71,10 +69,10 @@ static Curves *create_curve_from_vert_indices(const MeshComponent &mesh_componen
|
||||
/* Copy attribute based on the map for this curve. */
|
||||
attribute_math::convert_to_static_type(mesh_attribute.type(), [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
bke::OutputAttribute_Typed<T> attribute =
|
||||
curves_component.attribute_try_get_for_output_only<T>(attribute_id, ATTR_DOMAIN_POINT);
|
||||
copy_with_map<T>(mesh_attribute.typed<T>(), vert_indices, attribute.as_span());
|
||||
attribute.save();
|
||||
bke::SpanAttributeWriter<T> attribute =
|
||||
curves_attributes.lookup_or_add_for_write_only_span<T>(attribute_id, ATTR_DOMAIN_POINT);
|
||||
copy_with_map<T>(mesh_attribute.typed<T>(), vert_indices, attribute.span);
|
||||
attribute.finish();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -104,24 +104,24 @@ PointCloud *point_merge_by_distance(const PointCloudComponent &src_points,
|
||||
point_merge_counts[dst_index]++;
|
||||
}
|
||||
|
||||
Set<bke::AttributeIDRef> attributes = src_points.attribute_ids();
|
||||
const bke::AttributeAccessor src_attributes = *src_points.attributes();
|
||||
bke::MutableAttributeAccessor dst_attributes = *dst_points.attributes_for_write();
|
||||
Set<bke::AttributeIDRef> attributes = src_attributes.all_ids();
|
||||
|
||||
/* Transfer the ID attribute if it exists, using the ID of the first merged point. */
|
||||
if (attributes.contains("id")) {
|
||||
VArray<int> src = src_points.attribute_get_for_read<int>("id", ATTR_DOMAIN_POINT, 0);
|
||||
bke::OutputAttribute_Typed<int> dst = dst_points.attribute_try_get_for_output_only<int>(
|
||||
VArraySpan<int> src = src_attributes.lookup_or_default<int>("id", ATTR_DOMAIN_POINT, 0);
|
||||
bke::SpanAttributeWriter<int> dst = dst_attributes.lookup_or_add_for_write_only_span<int>(
|
||||
"id", ATTR_DOMAIN_POINT);
|
||||
Span<int> src_ids = src.get_internal_span();
|
||||
MutableSpan<int> dst_ids = dst.as_span();
|
||||
|
||||
threading::parallel_for(IndexRange(dst_size), 1024, [&](IndexRange range) {
|
||||
for (const int i_dst : range) {
|
||||
const IndexRange points(map_offsets[i_dst], map_offsets[i_dst + 1] - map_offsets[i_dst]);
|
||||
dst_ids[i_dst] = src_ids[points.first()];
|
||||
dst.span[i_dst] = src[points.first()];
|
||||
}
|
||||
});
|
||||
|
||||
dst.save();
|
||||
dst.finish();
|
||||
attributes.remove_contained("id");
|
||||
}
|
||||
|
||||
@@ -131,20 +131,19 @@ PointCloud *point_merge_by_distance(const PointCloudComponent &src_points,
|
||||
continue;
|
||||
}
|
||||
|
||||
bke::ReadAttributeLookup src_attribute = src_points.attribute_try_get_for_read(id);
|
||||
bke::GAttributeReader src_attribute = src_attributes.lookup(id);
|
||||
attribute_math::convert_to_static_type(src_attribute.varray.type(), [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
|
||||
bke::OutputAttribute_Typed<T> dst_attribute =
|
||||
dst_points.attribute_try_get_for_output_only<T>(id, ATTR_DOMAIN_POINT);
|
||||
Span<T> src = src_attribute.varray.get_internal_span().typed<T>();
|
||||
MutableSpan<T> dst = dst_attribute.as_span();
|
||||
bke::SpanAttributeWriter<T> dst_attribute =
|
||||
dst_attributes.lookup_or_add_for_write_only_span<T>(id, ATTR_DOMAIN_POINT);
|
||||
VArraySpan<T> src = src_attribute.varray.typed<T>();
|
||||
|
||||
threading::parallel_for(IndexRange(dst_size), 1024, [&](IndexRange range) {
|
||||
for (const int i_dst : range) {
|
||||
/* Create a separate mixer for every point to avoid allocating temporary buffers
|
||||
* in the mixer the size of the result point cloud and to improve memory locality. */
|
||||
attribute_math::DefaultMixer<T> mixer{dst.slice(i_dst, 1)};
|
||||
attribute_math::DefaultMixer<T> mixer{dst_attribute.span.slice(i_dst, 1)};
|
||||
|
||||
const IndexRange points(map_offsets[i_dst],
|
||||
map_offsets[i_dst + 1] - map_offsets[i_dst]);
|
||||
@@ -157,7 +156,7 @@ PointCloud *point_merge_by_distance(const PointCloudComponent &src_points,
|
||||
}
|
||||
});
|
||||
|
||||
dst_attribute.save();
|
||||
dst_attribute.finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -23,12 +23,13 @@
|
||||
namespace blender::geometry {
|
||||
|
||||
using blender::bke::AttributeIDRef;
|
||||
using blender::bke::AttributeKind;
|
||||
using blender::bke::AttributeMetaData;
|
||||
using blender::bke::custom_data_type_to_cpp_type;
|
||||
using blender::bke::CustomDataAttributes;
|
||||
using blender::bke::GSpanAttributeWriter;
|
||||
using blender::bke::object_get_evaluated_geometry_set;
|
||||
using blender::bke::OutputAttribute;
|
||||
using blender::bke::OutputAttribute_Typed;
|
||||
using blender::bke::ReadAttributeLookup;
|
||||
using blender::bke::SpanAttributeWriter;
|
||||
|
||||
/**
|
||||
* An ordered set of attribute ids. Attributes are ordered to avoid name lookups in many places.
|
||||
@@ -287,26 +288,27 @@ static void copy_generic_attributes_to_result(
|
||||
const AttributeFallbacksArray &attribute_fallbacks,
|
||||
const OrderedAttributes &ordered_attributes,
|
||||
const FunctionRef<IndexRange(eAttrDomain)> &range_fn,
|
||||
MutableSpan<GMutableSpan> dst_attributes)
|
||||
MutableSpan<GSpanAttributeWriter> dst_attribute_writers)
|
||||
{
|
||||
threading::parallel_for(dst_attributes.index_range(), 10, [&](const IndexRange attribute_range) {
|
||||
for (const int attribute_index : attribute_range) {
|
||||
const eAttrDomain domain = ordered_attributes.kinds[attribute_index].domain;
|
||||
const IndexRange element_slice = range_fn(domain);
|
||||
threading::parallel_for(
|
||||
dst_attribute_writers.index_range(), 10, [&](const IndexRange attribute_range) {
|
||||
for (const int attribute_index : attribute_range) {
|
||||
const eAttrDomain domain = ordered_attributes.kinds[attribute_index].domain;
|
||||
const IndexRange element_slice = range_fn(domain);
|
||||
|
||||
GMutableSpan dst_span = dst_attributes[attribute_index].slice(element_slice);
|
||||
if (src_attributes[attribute_index].has_value()) {
|
||||
threaded_copy(*src_attributes[attribute_index], dst_span);
|
||||
}
|
||||
else {
|
||||
const CPPType &cpp_type = dst_span.type();
|
||||
const void *fallback = attribute_fallbacks.array[attribute_index] == nullptr ?
|
||||
cpp_type.default_value() :
|
||||
attribute_fallbacks.array[attribute_index];
|
||||
threaded_fill({cpp_type, fallback}, dst_span);
|
||||
}
|
||||
}
|
||||
});
|
||||
GMutableSpan dst_span = dst_attribute_writers[attribute_index].span.slice(element_slice);
|
||||
if (src_attributes[attribute_index].has_value()) {
|
||||
threaded_copy(*src_attributes[attribute_index], dst_span);
|
||||
}
|
||||
else {
|
||||
const CPPType &cpp_type = dst_span.type();
|
||||
const void *fallback = attribute_fallbacks.array[attribute_index] == nullptr ?
|
||||
cpp_type.default_value() :
|
||||
attribute_fallbacks.array[attribute_index];
|
||||
threaded_fill({cpp_type, fallback}, dst_span);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void create_result_ids(const RealizeInstancesOptions &options,
|
||||
@@ -361,7 +363,7 @@ static Vector<std::pair<int, GSpan>> prepare_attribute_fallbacks(
|
||||
const OrderedAttributes &ordered_attributes)
|
||||
{
|
||||
Vector<std::pair<int, GSpan>> attributes_to_override;
|
||||
const CustomDataAttributes &attributes = instances_component.attributes();
|
||||
const CustomDataAttributes &attributes = instances_component.instance_attributes();
|
||||
attributes.foreach_attribute(
|
||||
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
|
||||
const int attribute_index = ordered_attributes.ids.index_of_try(attribute_id);
|
||||
@@ -447,7 +449,7 @@ static void gather_realize_tasks_for_instances(GatherTasksInfo &gather_info,
|
||||
|
||||
Span<int> stored_instance_ids;
|
||||
if (gather_info.create_id_attribute_on_any_component) {
|
||||
std::optional<GSpan> ids = instances_component.attributes().get_for_read("id");
|
||||
std::optional<GSpan> ids = instances_component.instance_attributes().get_for_read("id");
|
||||
if (ids.has_value()) {
|
||||
stored_instance_ids = ids->typed<int>();
|
||||
}
|
||||
@@ -646,34 +648,34 @@ static AllPointCloudsInfo preprocess_pointclouds(const GeometrySet &geometry_set
|
||||
pointcloud_info.pointcloud = pointcloud;
|
||||
|
||||
/* Access attributes. */
|
||||
PointCloudComponent component;
|
||||
component.replace(const_cast<PointCloud *>(pointcloud), GeometryOwnershipType::ReadOnly);
|
||||
bke::AttributeAccessor attributes = bke::pointcloud_attributes(*pointcloud);
|
||||
pointcloud_info.attributes.reinitialize(info.attributes.size());
|
||||
for (const int attribute_index : info.attributes.index_range()) {
|
||||
const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index];
|
||||
const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
|
||||
const eAttrDomain domain = info.attributes.kinds[attribute_index].domain;
|
||||
if (component.attribute_exists(attribute_id)) {
|
||||
GVArray attribute = component.attribute_get_for_read(attribute_id, domain, data_type);
|
||||
if (attributes.contains(attribute_id)) {
|
||||
GVArray attribute = attributes.lookup_or_default(attribute_id, domain, data_type);
|
||||
pointcloud_info.attributes[attribute_index].emplace(std::move(attribute));
|
||||
}
|
||||
}
|
||||
if (info.create_id_attribute) {
|
||||
ReadAttributeLookup ids_lookup = component.attribute_try_get_for_read("id");
|
||||
if (ids_lookup) {
|
||||
pointcloud_info.stored_ids = ids_lookup.varray.get_internal_span().typed<int>();
|
||||
bke::GAttributeReader ids_attribute = attributes.lookup("id");
|
||||
if (ids_attribute) {
|
||||
pointcloud_info.stored_ids = ids_attribute.varray.get_internal_span().typed<int>();
|
||||
}
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
static void execute_realize_pointcloud_task(const RealizeInstancesOptions &options,
|
||||
const RealizePointCloudTask &task,
|
||||
const OrderedAttributes &ordered_attributes,
|
||||
PointCloud &dst_pointcloud,
|
||||
MutableSpan<GMutableSpan> dst_attribute_spans,
|
||||
MutableSpan<int> all_dst_ids)
|
||||
static void execute_realize_pointcloud_task(
|
||||
const RealizeInstancesOptions &options,
|
||||
const RealizePointCloudTask &task,
|
||||
const OrderedAttributes &ordered_attributes,
|
||||
PointCloud &dst_pointcloud,
|
||||
MutableSpan<GSpanAttributeWriter> dst_attribute_writers,
|
||||
MutableSpan<int> all_dst_ids)
|
||||
{
|
||||
const PointCloudRealizeInfo &pointcloud_info = *task.pointcloud_info;
|
||||
const PointCloud &pointcloud = *pointcloud_info.pointcloud;
|
||||
@@ -699,7 +701,7 @@ static void execute_realize_pointcloud_task(const RealizeInstancesOptions &optio
|
||||
UNUSED_VARS_NDEBUG(domain);
|
||||
return point_slice;
|
||||
},
|
||||
dst_attribute_spans);
|
||||
dst_attribute_writers);
|
||||
}
|
||||
|
||||
static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &options,
|
||||
@@ -721,42 +723,43 @@ static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &opti
|
||||
PointCloudComponent &dst_component =
|
||||
r_realized_geometry.get_component_for_write<PointCloudComponent>();
|
||||
dst_component.replace(dst_pointcloud);
|
||||
bke::MutableAttributeAccessor dst_attributes = bke::pointcloud_attributes_for_write(
|
||||
*dst_pointcloud);
|
||||
|
||||
/* Prepare id attribute. */
|
||||
OutputAttribute_Typed<int> point_ids;
|
||||
MutableSpan<int> point_ids_span;
|
||||
SpanAttributeWriter<int> point_ids;
|
||||
if (all_pointclouds_info.create_id_attribute) {
|
||||
point_ids = dst_component.attribute_try_get_for_output_only<int>("id", ATTR_DOMAIN_POINT);
|
||||
point_ids_span = point_ids.as_span();
|
||||
point_ids = dst_attributes.lookup_or_add_for_write_only_span<int>("id", ATTR_DOMAIN_POINT);
|
||||
}
|
||||
|
||||
/* Prepare generic output attributes. */
|
||||
Vector<OutputAttribute> dst_attributes;
|
||||
Vector<GMutableSpan> dst_attribute_spans;
|
||||
Vector<GSpanAttributeWriter> dst_attribute_writers;
|
||||
for (const int attribute_index : ordered_attributes.index_range()) {
|
||||
const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
|
||||
const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
|
||||
OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
|
||||
attribute_id, ATTR_DOMAIN_POINT, data_type);
|
||||
dst_attribute_spans.append(dst_attribute.as_span());
|
||||
dst_attributes.append(std::move(dst_attribute));
|
||||
dst_attribute_writers.append(dst_attributes.lookup_or_add_for_write_only_span(
|
||||
attribute_id, ATTR_DOMAIN_POINT, data_type));
|
||||
}
|
||||
|
||||
/* Actually execute all tasks. */
|
||||
threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
|
||||
for (const int task_index : task_range) {
|
||||
const RealizePointCloudTask &task = tasks[task_index];
|
||||
execute_realize_pointcloud_task(
|
||||
options, task, ordered_attributes, *dst_pointcloud, dst_attribute_spans, point_ids_span);
|
||||
execute_realize_pointcloud_task(options,
|
||||
task,
|
||||
ordered_attributes,
|
||||
*dst_pointcloud,
|
||||
dst_attribute_writers,
|
||||
point_ids.span);
|
||||
}
|
||||
});
|
||||
|
||||
/* Save modified attributes. */
|
||||
for (OutputAttribute &dst_attribute : dst_attributes) {
|
||||
dst_attribute.save();
|
||||
/* Tag modified attributes. */
|
||||
for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) {
|
||||
dst_attribute.finish();
|
||||
}
|
||||
if (point_ids) {
|
||||
point_ids.save();
|
||||
point_ids.finish();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -837,22 +840,21 @@ static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set,
|
||||
}
|
||||
|
||||
/* Access attributes. */
|
||||
MeshComponent component;
|
||||
component.replace(const_cast<Mesh *>(mesh), GeometryOwnershipType::ReadOnly);
|
||||
bke::AttributeAccessor attributes = bke::mesh_attributes(*mesh);
|
||||
mesh_info.attributes.reinitialize(info.attributes.size());
|
||||
for (const int attribute_index : info.attributes.index_range()) {
|
||||
const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index];
|
||||
const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
|
||||
const eAttrDomain domain = info.attributes.kinds[attribute_index].domain;
|
||||
if (component.attribute_exists(attribute_id)) {
|
||||
GVArray attribute = component.attribute_get_for_read(attribute_id, domain, data_type);
|
||||
if (attributes.contains(attribute_id)) {
|
||||
GVArray attribute = attributes.lookup_or_default(attribute_id, domain, data_type);
|
||||
mesh_info.attributes[attribute_index].emplace(std::move(attribute));
|
||||
}
|
||||
}
|
||||
if (info.create_id_attribute) {
|
||||
ReadAttributeLookup ids_lookup = component.attribute_try_get_for_read("id");
|
||||
if (ids_lookup) {
|
||||
mesh_info.stored_vertex_ids = ids_lookup.varray.get_internal_span().typed<int>();
|
||||
bke::GAttributeReader ids_attribute = attributes.lookup("id");
|
||||
if (ids_attribute) {
|
||||
mesh_info.stored_vertex_ids = ids_attribute.varray.get_internal_span().typed<int>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -863,7 +865,7 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options,
|
||||
const RealizeMeshTask &task,
|
||||
const OrderedAttributes &ordered_attributes,
|
||||
Mesh &dst_mesh,
|
||||
MutableSpan<GMutableSpan> dst_attribute_spans,
|
||||
MutableSpan<GSpanAttributeWriter> dst_attribute_writers,
|
||||
MutableSpan<int> all_dst_vertex_ids)
|
||||
{
|
||||
const MeshRealizeInfo &mesh_info = *task.mesh_info;
|
||||
@@ -949,7 +951,7 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options,
|
||||
return IndexRange();
|
||||
}
|
||||
},
|
||||
dst_attribute_spans);
|
||||
dst_attribute_writers);
|
||||
}
|
||||
|
||||
static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
|
||||
@@ -973,6 +975,7 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
|
||||
Mesh *dst_mesh = BKE_mesh_new_nomain(tot_vertices, tot_edges, 0, tot_loops, tot_poly);
|
||||
MeshComponent &dst_component = r_realized_geometry.get_component_for_write<MeshComponent>();
|
||||
dst_component.replace(dst_mesh);
|
||||
bke::MutableAttributeAccessor dst_attributes = bke::mesh_attributes_for_write(*dst_mesh);
|
||||
|
||||
/* Copy settings from the first input geometry set with a mesh. */
|
||||
const RealizeMeshTask &first_task = tasks.first();
|
||||
@@ -986,24 +989,19 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
|
||||
}
|
||||
|
||||
/* Prepare id attribute. */
|
||||
OutputAttribute_Typed<int> vertex_ids;
|
||||
MutableSpan<int> vertex_ids_span;
|
||||
SpanAttributeWriter<int> vertex_ids;
|
||||
if (all_meshes_info.create_id_attribute) {
|
||||
vertex_ids = dst_component.attribute_try_get_for_output_only<int>("id", ATTR_DOMAIN_POINT);
|
||||
vertex_ids_span = vertex_ids.as_span();
|
||||
vertex_ids = dst_attributes.lookup_or_add_for_write_only_span<int>("id", ATTR_DOMAIN_POINT);
|
||||
}
|
||||
|
||||
/* Prepare generic output attributes. */
|
||||
Vector<OutputAttribute> dst_attributes;
|
||||
Vector<GMutableSpan> dst_attribute_spans;
|
||||
Vector<GSpanAttributeWriter> dst_attribute_writers;
|
||||
for (const int attribute_index : ordered_attributes.index_range()) {
|
||||
const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
|
||||
const eAttrDomain domain = ordered_attributes.kinds[attribute_index].domain;
|
||||
const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
|
||||
OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
|
||||
attribute_id, domain, data_type);
|
||||
dst_attribute_spans.append(dst_attribute.as_span());
|
||||
dst_attributes.append(std::move(dst_attribute));
|
||||
dst_attribute_writers.append(
|
||||
dst_attributes.lookup_or_add_for_write_only_span(attribute_id, domain, data_type));
|
||||
}
|
||||
|
||||
/* Actually execute all tasks. */
|
||||
@@ -1011,16 +1009,16 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
|
||||
for (const int task_index : task_range) {
|
||||
const RealizeMeshTask &task = tasks[task_index];
|
||||
execute_realize_mesh_task(
|
||||
options, task, ordered_attributes, *dst_mesh, dst_attribute_spans, vertex_ids_span);
|
||||
options, task, ordered_attributes, *dst_mesh, dst_attribute_writers, vertex_ids.span);
|
||||
}
|
||||
});
|
||||
|
||||
/* Save modified attributes. */
|
||||
for (OutputAttribute &dst_attribute : dst_attributes) {
|
||||
dst_attribute.save();
|
||||
/* Tag modified attributes. */
|
||||
for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) {
|
||||
dst_attribute.finish();
|
||||
}
|
||||
if (vertex_ids) {
|
||||
vertex_ids.save();
|
||||
vertex_ids.finish();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1088,49 +1086,43 @@ static AllCurvesInfo preprocess_curves(const GeometrySet &geometry_set,
|
||||
curve_info.curves = curves_id;
|
||||
|
||||
/* Access attributes. */
|
||||
CurveComponent component;
|
||||
component.replace(const_cast<Curves *>(curves_id), GeometryOwnershipType::ReadOnly);
|
||||
bke::AttributeAccessor attributes = curves.attributes();
|
||||
curve_info.attributes.reinitialize(info.attributes.size());
|
||||
for (const int attribute_index : info.attributes.index_range()) {
|
||||
const eAttrDomain domain = info.attributes.kinds[attribute_index].domain;
|
||||
const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index];
|
||||
const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
|
||||
if (component.attribute_exists(attribute_id)) {
|
||||
GVArray attribute = component.attribute_get_for_read(attribute_id, domain, data_type);
|
||||
if (attributes.contains(attribute_id)) {
|
||||
GVArray attribute = attributes.lookup_or_default(attribute_id, domain, data_type);
|
||||
curve_info.attributes[attribute_index].emplace(std::move(attribute));
|
||||
}
|
||||
}
|
||||
if (info.create_id_attribute) {
|
||||
ReadAttributeLookup ids_lookup = component.attribute_try_get_for_read("id");
|
||||
if (ids_lookup) {
|
||||
curve_info.stored_ids = ids_lookup.varray.get_internal_span().typed<int>();
|
||||
bke::GAttributeReader id_attribute = attributes.lookup("id");
|
||||
if (id_attribute) {
|
||||
curve_info.stored_ids = id_attribute.varray.get_internal_span().typed<int>();
|
||||
}
|
||||
}
|
||||
|
||||
/* Retrieve the radius attribute, if it exists. */
|
||||
if (component.attribute_exists("radius")) {
|
||||
curve_info.radius = component
|
||||
.attribute_get_for_read<float>("radius", ATTR_DOMAIN_POINT, 0.0f)
|
||||
.get_internal_span();
|
||||
if (attributes.contains("radius")) {
|
||||
curve_info.radius =
|
||||
attributes.lookup<float>("radius", ATTR_DOMAIN_POINT).get_internal_span();
|
||||
info.create_radius_attribute = true;
|
||||
}
|
||||
|
||||
/* Retrieve the resolution attribute, if it exists. */
|
||||
curve_info.resolution = curves.resolution();
|
||||
if (component.attribute_exists("resolution")) {
|
||||
if (attributes.contains("resolution")) {
|
||||
info.create_resolution_attribute = true;
|
||||
}
|
||||
|
||||
/* Retrieve handle position attributes, if they exist. */
|
||||
if (component.attribute_exists("handle_right")) {
|
||||
curve_info.handle_left = component
|
||||
.attribute_get_for_read<float3>(
|
||||
"handle_left", ATTR_DOMAIN_POINT, float3(0))
|
||||
.get_internal_span();
|
||||
curve_info.handle_right = component
|
||||
.attribute_get_for_read<float3>(
|
||||
"handle_right", ATTR_DOMAIN_POINT, float3(0))
|
||||
.get_internal_span();
|
||||
if (attributes.contains("handle_right")) {
|
||||
curve_info.handle_left =
|
||||
attributes.lookup<float3>("handle_left", ATTR_DOMAIN_POINT).get_internal_span();
|
||||
curve_info.handle_right =
|
||||
attributes.lookup<float3>("handle_right", ATTR_DOMAIN_POINT).get_internal_span();
|
||||
info.create_handle_postion_attributes = true;
|
||||
}
|
||||
}
|
||||
@@ -1142,7 +1134,7 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options,
|
||||
const RealizeCurveTask &task,
|
||||
const OrderedAttributes &ordered_attributes,
|
||||
bke::CurvesGeometry &dst_curves,
|
||||
MutableSpan<GMutableSpan> dst_attribute_spans,
|
||||
MutableSpan<GSpanAttributeWriter> dst_attribute_writers,
|
||||
MutableSpan<int> all_dst_ids,
|
||||
MutableSpan<float3> all_handle_left,
|
||||
MutableSpan<float3> all_handle_right,
|
||||
@@ -1220,7 +1212,7 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options,
|
||||
return IndexRange();
|
||||
}
|
||||
},
|
||||
dst_attribute_spans);
|
||||
dst_attribute_writers);
|
||||
}
|
||||
|
||||
static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
|
||||
@@ -1244,57 +1236,45 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
|
||||
dst_curves.offsets_for_write().last() = points_num;
|
||||
CurveComponent &dst_component = r_realized_geometry.get_component_for_write<CurveComponent>();
|
||||
dst_component.replace(dst_curves_id);
|
||||
bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
|
||||
|
||||
/* Prepare id attribute. */
|
||||
OutputAttribute_Typed<int> point_ids;
|
||||
MutableSpan<int> point_ids_span;
|
||||
SpanAttributeWriter<int> point_ids;
|
||||
if (all_curves_info.create_id_attribute) {
|
||||
point_ids = dst_component.attribute_try_get_for_output_only<int>("id", ATTR_DOMAIN_POINT);
|
||||
point_ids_span = point_ids.as_span();
|
||||
point_ids = dst_attributes.lookup_or_add_for_write_only_span<int>("id", ATTR_DOMAIN_POINT);
|
||||
}
|
||||
|
||||
/* Prepare generic output attributes. */
|
||||
Vector<OutputAttribute> dst_attributes;
|
||||
Vector<GMutableSpan> dst_attribute_spans;
|
||||
Vector<GSpanAttributeWriter> dst_attribute_writers;
|
||||
for (const int attribute_index : ordered_attributes.index_range()) {
|
||||
const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
|
||||
const eAttrDomain domain = ordered_attributes.kinds[attribute_index].domain;
|
||||
const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
|
||||
OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
|
||||
attribute_id, domain, data_type);
|
||||
dst_attribute_spans.append(dst_attribute.as_span());
|
||||
dst_attributes.append(std::move(dst_attribute));
|
||||
dst_attribute_writers.append(
|
||||
dst_attributes.lookup_or_add_for_write_only_span(attribute_id, domain, data_type));
|
||||
}
|
||||
|
||||
/* Prepare handle position attributes if necessary. */
|
||||
OutputAttribute_Typed<float3> handle_left;
|
||||
OutputAttribute_Typed<float3> handle_right;
|
||||
MutableSpan<float3> handle_left_span;
|
||||
MutableSpan<float3> handle_right_span;
|
||||
SpanAttributeWriter<float3> handle_left;
|
||||
SpanAttributeWriter<float3> handle_right;
|
||||
if (all_curves_info.create_handle_postion_attributes) {
|
||||
handle_left = dst_component.attribute_try_get_for_output_only<float3>("handle_left",
|
||||
ATTR_DOMAIN_POINT);
|
||||
handle_right = dst_component.attribute_try_get_for_output_only<float3>("handle_right",
|
||||
handle_left = dst_attributes.lookup_or_add_for_write_only_span<float3>("handle_left",
|
||||
ATTR_DOMAIN_POINT);
|
||||
handle_left_span = handle_left.as_span();
|
||||
handle_right_span = handle_right.as_span();
|
||||
handle_right = dst_attributes.lookup_or_add_for_write_only_span<float3>("handle_right",
|
||||
ATTR_DOMAIN_POINT);
|
||||
}
|
||||
|
||||
/* Prepare radius attribute if necessary. */
|
||||
OutputAttribute_Typed<float> radius;
|
||||
MutableSpan<float> radius_span;
|
||||
SpanAttributeWriter<float> radius;
|
||||
if (all_curves_info.create_radius_attribute) {
|
||||
radius = dst_component.attribute_try_get_for_output_only<float>("radius", ATTR_DOMAIN_POINT);
|
||||
radius_span = radius.as_span();
|
||||
radius = dst_attributes.lookup_or_add_for_write_only_span<float>("radius", ATTR_DOMAIN_POINT);
|
||||
}
|
||||
|
||||
/* Prepare resolution attribute if necessary. */
|
||||
OutputAttribute_Typed<int> resolution;
|
||||
MutableSpan<int> resolution_span;
|
||||
SpanAttributeWriter<int> resolution;
|
||||
if (all_curves_info.create_resolution_attribute) {
|
||||
resolution = dst_component.attribute_try_get_for_output_only<int>("resolution",
|
||||
ATTR_DOMAIN_CURVE);
|
||||
resolution_span = resolution.as_span();
|
||||
resolution = dst_attributes.lookup_or_add_for_write_only_span<int>("resolution",
|
||||
ATTR_DOMAIN_CURVE);
|
||||
}
|
||||
|
||||
/* Actually execute all tasks. */
|
||||
@@ -1306,31 +1286,31 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
|
||||
task,
|
||||
ordered_attributes,
|
||||
dst_curves,
|
||||
dst_attribute_spans,
|
||||
point_ids_span,
|
||||
handle_left_span,
|
||||
handle_right_span,
|
||||
radius_span,
|
||||
resolution_span);
|
||||
dst_attribute_writers,
|
||||
point_ids.span,
|
||||
handle_left.span,
|
||||
handle_right.span,
|
||||
radius.span,
|
||||
resolution.span);
|
||||
}
|
||||
});
|
||||
|
||||
/* Save modified attributes. */
|
||||
for (OutputAttribute &dst_attribute : dst_attributes) {
|
||||
dst_attribute.save();
|
||||
/* Tag modified attributes. */
|
||||
for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) {
|
||||
dst_attribute.finish();
|
||||
}
|
||||
if (point_ids) {
|
||||
point_ids.save();
|
||||
point_ids.finish();
|
||||
}
|
||||
if (radius) {
|
||||
radius.save();
|
||||
radius.finish();
|
||||
}
|
||||
if (resolution) {
|
||||
resolution.save();
|
||||
resolution.finish();
|
||||
}
|
||||
if (all_curves_info.create_handle_postion_attributes) {
|
||||
handle_left.save();
|
||||
handle_right.save();
|
||||
handle_left.finish();
|
||||
handle_right.finish();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1345,7 +1325,7 @@ static void remove_id_attribute_from_instances(GeometrySet &geometry_set)
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &sub_geometry) {
|
||||
if (sub_geometry.has<InstancesComponent>()) {
|
||||
InstancesComponent &component = sub_geometry.get_component_for_write<InstancesComponent>();
|
||||
component.attributes().remove("id");
|
||||
component.instance_attributes().remove("id");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -92,17 +92,18 @@ static void retrieve_attribute_spans(const Span<bke::AttributeIDRef> ids,
|
||||
CurveComponent &dst_component,
|
||||
Vector<GSpan> &src,
|
||||
Vector<GMutableSpan> &dst,
|
||||
Vector<bke::OutputAttribute> &dst_attributes)
|
||||
Vector<bke::GSpanAttributeWriter> &dst_attributes)
|
||||
{
|
||||
for (const int i : ids.index_range()) {
|
||||
GVArray src_attribute = src_component.attribute_try_get_for_read(ids[i], ATTR_DOMAIN_POINT);
|
||||
GVArray src_attribute = src_component.attributes()->lookup(ids[i], ATTR_DOMAIN_POINT);
|
||||
BLI_assert(src_attribute);
|
||||
src.append(src_attribute.get_internal_span());
|
||||
|
||||
const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(src_attribute.type());
|
||||
bke::OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
|
||||
ids[i], ATTR_DOMAIN_POINT, data_type);
|
||||
dst.append(dst_attribute.as_span());
|
||||
bke::GSpanAttributeWriter dst_attribute =
|
||||
dst_component.attributes_for_write()->lookup_or_add_for_write_only_span(
|
||||
ids[i], ATTR_DOMAIN_POINT, data_type);
|
||||
dst.append(dst_attribute.span);
|
||||
dst_attributes.append(std::move(dst_attribute));
|
||||
}
|
||||
}
|
||||
@@ -111,7 +112,7 @@ struct AttributesForInterpolation : NonCopyable, NonMovable {
|
||||
Vector<GSpan> src;
|
||||
Vector<GMutableSpan> dst;
|
||||
|
||||
Vector<bke::OutputAttribute> dst_attributes;
|
||||
Vector<bke::GSpanAttributeWriter> dst_attributes;
|
||||
|
||||
Vector<GSpan> src_no_interpolation;
|
||||
Vector<GMutableSpan> dst_no_interpolation;
|
||||
@@ -129,8 +130,8 @@ static void gather_point_attributes_to_interpolate(const CurveComponent &src_com
|
||||
|
||||
VectorSet<bke::AttributeIDRef> ids;
|
||||
VectorSet<bke::AttributeIDRef> ids_no_interpolation;
|
||||
src_component.attribute_foreach(
|
||||
[&](const bke::AttributeIDRef &id, const AttributeMetaData meta_data) {
|
||||
src_component.attributes()->for_all(
|
||||
[&](const bke::AttributeIDRef &id, const bke::AttributeMetaData meta_data) {
|
||||
if (meta_data.domain != ATTR_DOMAIN_POINT) {
|
||||
return true;
|
||||
}
|
||||
@@ -311,8 +312,8 @@ static Curves *resample_to_uniform(const CurveComponent &src_component,
|
||||
bke::curves::copy_point_data(
|
||||
src_curves, dst_curves, unselected_ranges, src_positions, dst_positions);
|
||||
|
||||
for (bke::OutputAttribute &attribute : attributes.dst_attributes) {
|
||||
attribute.save();
|
||||
for (bke::GSpanAttributeWriter &attribute : attributes.dst_attributes) {
|
||||
attribute.finish();
|
||||
}
|
||||
|
||||
return dst_curves_id;
|
||||
@@ -433,8 +434,8 @@ Curves *resample_to_evaluated(const CurveComponent &src_component,
|
||||
bke::curves::copy_point_data(
|
||||
src_curves, dst_curves, unselected_ranges, src_positions, dst_positions);
|
||||
|
||||
for (bke::OutputAttribute &attribute : attributes.dst_attributes) {
|
||||
attribute.save();
|
||||
for (bke::GSpanAttributeWriter &attribute : attributes.dst_attributes) {
|
||||
attribute.finish();
|
||||
}
|
||||
|
||||
return dst_curves_id;
|
||||
|
||||
@@ -290,32 +290,32 @@ struct GenericAttributes : NonCopyable, NonMovable {
|
||||
Vector<GSpan> src;
|
||||
Vector<GMutableSpan> dst;
|
||||
|
||||
Vector<bke::OutputAttribute> attributes;
|
||||
Vector<bke::GSpanAttributeWriter> attributes;
|
||||
};
|
||||
|
||||
static void retrieve_generic_point_attributes(const CurveComponent &src_component,
|
||||
CurveComponent &dst_component,
|
||||
static void retrieve_generic_point_attributes(const bke::AttributeAccessor &src_attributes,
|
||||
bke::MutableAttributeAccessor &dst_attributes,
|
||||
GenericAttributes &attributes)
|
||||
{
|
||||
src_component.attribute_foreach(
|
||||
[&](const bke::AttributeIDRef &id, const AttributeMetaData meta_data) {
|
||||
src_attributes.for_all(
|
||||
[&](const bke::AttributeIDRef &id, const bke::AttributeMetaData meta_data) {
|
||||
if (meta_data.domain != ATTR_DOMAIN_POINT) {
|
||||
/* Curve domain attributes are all copied directly to the result in one step. */
|
||||
return true;
|
||||
}
|
||||
if (src_component.attribute_is_builtin(id)) {
|
||||
if (src_attributes.is_builtin(id)) {
|
||||
if (!(id.is_named() && ELEM(id, "tilt", "radius"))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
GVArray src_attribute = src_component.attribute_try_get_for_read(id, ATTR_DOMAIN_POINT);
|
||||
GVArray src_attribute = src_attributes.lookup(id, ATTR_DOMAIN_POINT);
|
||||
BLI_assert(src_attribute);
|
||||
attributes.src.append(src_attribute.get_internal_span());
|
||||
|
||||
bke::OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
|
||||
bke::GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_span(
|
||||
id, ATTR_DOMAIN_POINT, meta_data.data_type);
|
||||
attributes.dst.append(dst_attribute.as_span());
|
||||
attributes.dst.append(dst_attribute.span);
|
||||
attributes.attributes.append(std::move(dst_attribute));
|
||||
|
||||
return true;
|
||||
@@ -367,8 +367,11 @@ static Curves *convert_curves_to_bezier(const CurveComponent &src_component,
|
||||
bke::curves::accumulate_counts_to_offsets(dst_offsets);
|
||||
dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
|
||||
|
||||
const bke::AttributeAccessor src_attributes = *src_component.attributes();
|
||||
bke::MutableAttributeAccessor dst_attributes = *dst_component.attributes_for_write();
|
||||
|
||||
GenericAttributes attributes;
|
||||
retrieve_generic_point_attributes(src_component, dst_component, attributes);
|
||||
retrieve_generic_point_attributes(src_attributes, dst_attributes, attributes);
|
||||
|
||||
MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
|
||||
MutableSpan<float3> dst_handles_l = dst_curves.handle_positions_left_for_write();
|
||||
@@ -494,8 +497,8 @@ static Curves *convert_curves_to_bezier(const CurveComponent &src_component,
|
||||
src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]);
|
||||
}
|
||||
|
||||
for (bke::OutputAttribute &attribute : attributes.attributes) {
|
||||
attribute.save();
|
||||
for (bke::GSpanAttributeWriter &attribute : attributes.attributes) {
|
||||
attribute.finish();
|
||||
}
|
||||
|
||||
return dst_curves_id;
|
||||
@@ -524,8 +527,11 @@ static Curves *convert_curves_to_nurbs(const CurveComponent &src_component,
|
||||
bke::curves::accumulate_counts_to_offsets(dst_offsets);
|
||||
dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
|
||||
|
||||
const bke::AttributeAccessor src_attributes = *src_component.attributes();
|
||||
bke::MutableAttributeAccessor dst_attributes = *dst_component.attributes_for_write();
|
||||
|
||||
GenericAttributes attributes;
|
||||
retrieve_generic_point_attributes(src_component, dst_component, attributes);
|
||||
retrieve_generic_point_attributes(src_attributes, dst_attributes, attributes);
|
||||
|
||||
MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
|
||||
|
||||
@@ -659,8 +665,8 @@ static Curves *convert_curves_to_nurbs(const CurveComponent &src_component,
|
||||
src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]);
|
||||
}
|
||||
|
||||
for (bke::OutputAttribute &attribute : attributes.attributes) {
|
||||
attribute.save();
|
||||
for (bke::GSpanAttributeWriter &attribute : attributes.attributes) {
|
||||
attribute.finish();
|
||||
}
|
||||
|
||||
return dst_curves_id;
|
||||
|
||||
@@ -79,16 +79,17 @@ static void calculate_result_offsets(const bke::CurvesGeometry &src_curves,
|
||||
struct AttributeTransferData {
|
||||
/* Expect that if an attribute exists, it is stored as a contiguous array internally anyway. */
|
||||
GVArraySpan src;
|
||||
bke::OutputAttribute dst;
|
||||
bke::GSpanAttributeWriter dst;
|
||||
};
|
||||
|
||||
static Vector<AttributeTransferData> retrieve_point_attributes(const CurveComponent &src_component,
|
||||
CurveComponent &dst_component,
|
||||
const Set<std::string> &skip = {})
|
||||
static Vector<AttributeTransferData> retrieve_point_attributes(
|
||||
const bke::AttributeAccessor &src_attributes,
|
||||
bke::MutableAttributeAccessor &dst_attributes,
|
||||
const Set<std::string> &skip = {})
|
||||
{
|
||||
Vector<AttributeTransferData> attributes;
|
||||
src_component.attribute_foreach(
|
||||
[&](const bke::AttributeIDRef &id, const AttributeMetaData meta_data) {
|
||||
src_attributes.for_all(
|
||||
[&](const bke::AttributeIDRef &id, const bke::AttributeMetaData meta_data) {
|
||||
if (meta_data.domain != ATTR_DOMAIN_POINT) {
|
||||
/* Curve domain attributes are all copied directly to the result in one step. */
|
||||
return true;
|
||||
@@ -97,9 +98,9 @@ static Vector<AttributeTransferData> retrieve_point_attributes(const CurveCompon
|
||||
return true;
|
||||
}
|
||||
|
||||
GVArray src = src_component.attribute_try_get_for_read(id, ATTR_DOMAIN_POINT);
|
||||
GVArray src = src_attributes.lookup(id, ATTR_DOMAIN_POINT);
|
||||
BLI_assert(src);
|
||||
bke::OutputAttribute dst = dst_component.attribute_try_get_for_output_only(
|
||||
bke::GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
|
||||
id, ATTR_DOMAIN_POINT, meta_data.data_type);
|
||||
BLI_assert(dst);
|
||||
attributes.append({std::move(src), std::move(dst)});
|
||||
@@ -384,28 +385,27 @@ Curves *subdivide_curves(const CurveComponent &src_component,
|
||||
|
||||
dst_curves.resize(dst_curves.offsets().last(), dst_curves.curves_num());
|
||||
|
||||
const bke::AttributeAccessor src_attributes = *src_component.attributes();
|
||||
bke::MutableAttributeAccessor dst_attributes = *dst_component.attributes_for_write();
|
||||
|
||||
auto subdivide_catmull_rom = [&](IndexMask selection) {
|
||||
for (auto &attribute : retrieve_point_attributes(src_component, dst_component)) {
|
||||
for (auto &attribute : retrieve_point_attributes(src_attributes, dst_attributes)) {
|
||||
subdivide_attribute_catmull_rom(src_curves,
|
||||
dst_curves,
|
||||
selection,
|
||||
point_offsets,
|
||||
cyclic,
|
||||
attribute.src,
|
||||
attribute.dst.as_span());
|
||||
attribute.dst.save();
|
||||
attribute.dst.span);
|
||||
attribute.dst.finish();
|
||||
}
|
||||
};
|
||||
|
||||
auto subdivide_poly = [&](IndexMask selection) {
|
||||
for (auto &attribute : retrieve_point_attributes(src_component, dst_component)) {
|
||||
subdivide_attribute_linear(src_curves,
|
||||
dst_curves,
|
||||
selection,
|
||||
point_offsets,
|
||||
attribute.src,
|
||||
attribute.dst.as_span());
|
||||
attribute.dst.save();
|
||||
for (auto &attribute : retrieve_point_attributes(src_attributes, dst_attributes)) {
|
||||
subdivide_attribute_linear(
|
||||
src_curves, dst_curves, selection, point_offsets, attribute.src, attribute.dst.span);
|
||||
attribute.dst.finish();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -443,20 +443,16 @@ Curves *subdivide_curves(const CurveComponent &src_component,
|
||||
}
|
||||
});
|
||||
|
||||
for (auto &attribute : retrieve_point_attributes(src_component,
|
||||
dst_component,
|
||||
for (auto &attribute : retrieve_point_attributes(src_attributes,
|
||||
dst_attributes,
|
||||
{"position",
|
||||
"handle_type_left",
|
||||
"handle_type_right",
|
||||
"handle_right",
|
||||
"handle_left"})) {
|
||||
subdivide_attribute_linear(src_curves,
|
||||
dst_curves,
|
||||
selection,
|
||||
point_offsets,
|
||||
attribute.src,
|
||||
attribute.dst.as_span());
|
||||
attribute.dst.save();
|
||||
subdivide_attribute_linear(
|
||||
src_curves, dst_curves, selection, point_offsets, attribute.src, attribute.dst.span);
|
||||
attribute.dst.finish();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -473,10 +469,10 @@ Curves *subdivide_curves(const CurveComponent &src_component,
|
||||
subdivide_nurbs);
|
||||
|
||||
if (!unselected_ranges.is_empty()) {
|
||||
for (auto &attribute : retrieve_point_attributes(src_component, dst_component)) {
|
||||
for (auto &attribute : retrieve_point_attributes(src_attributes, dst_attributes)) {
|
||||
bke::curves::copy_point_data(
|
||||
src_curves, dst_curves, unselected_ranges, attribute.src, attribute.dst.as_span());
|
||||
attribute.dst.save();
|
||||
src_curves, dst_curves, unselected_ranges, attribute.src, attribute.dst.span);
|
||||
attribute.dst.finish();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user