/* SPDX-FileCopyrightText: 2024 Blender Authors * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "GEO_extract_elements.hh" #include "BLI_index_mask.hh" #include "BKE_attribute.hh" #include "BKE_curves.hh" #include "BKE_geometry_set.hh" #include "BKE_grease_pencil.hh" #include "BKE_instances.hh" #include "BKE_mesh.hh" #include "BKE_pointcloud.hh" namespace blender::geometry { using bke::AttrDomain; struct PropagationAttribute { StringRef name; eCustomDataType cd_type; AttrDomain domain; GVArray data; }; Array extract_mesh_vertices(const Mesh &mesh, const IndexMask &mask, const bke::AttributeFilter &attribute_filter) { BLI_assert(mask.min_array_size() <= mesh.verts_num); Array elements(mask.size(), nullptr); const bke::AttributeAccessor src_attributes = mesh.attributes(); Vector propagation_attributes; src_attributes.foreach_attribute([&](const bke::AttributeIter &iter) { if (iter.data_type == CD_PROP_STRING) { return; } if (attribute_filter.allow_skip(iter.name)) { return; } const bke::GAttributeReader src_attribute = iter.get(AttrDomain::Point); propagation_attributes.append({iter.name, iter.data_type, AttrDomain::Point, *src_attribute}); }); mask.foreach_index(GrainSize(32), [&](const int vert_i, const int element_i) { Mesh *element = BKE_mesh_new_nomain(1, 0, 0, 0); BKE_mesh_copy_parameters_for_eval(element, &mesh); bke::MutableAttributeAccessor element_attributes = element->attributes_for_write(); for (const PropagationAttribute &src_attribute : propagation_attributes) { bke::GSpanAttributeWriter dst = element_attributes.lookup_or_add_for_write_only_span( src_attribute.name, AttrDomain::Point, src_attribute.cd_type); if (!dst) { continue; } src_attribute.data.get(vert_i, dst.span[0]); dst.finish(); } elements[element_i] = element; }); return elements; } Array extract_mesh_edges(const Mesh &mesh, const IndexMask &mask, const bke::AttributeFilter &attribute_filter) { BLI_assert(mask.min_array_size() <= mesh.edges_num); Array elements(mask.size(), nullptr); const Span src_edges = mesh.edges(); const bke::AttributeAccessor src_attributes = mesh.attributes(); Vector propagation_attributes; src_attributes.foreach_attribute([&](const bke::AttributeIter &iter) { if (iter.data_type == CD_PROP_STRING) { return; } if (iter.name == ".edge_verts") { return; } if (attribute_filter.allow_skip(iter.name)) { return; } const bke::GAttributeReader src_attribute = iter.get(); if (ELEM(src_attribute.domain, AttrDomain::Point, AttrDomain::Edge)) { propagation_attributes.append( {iter.name, iter.data_type, src_attribute.domain, *src_attribute}); } else if (src_attribute.domain == AttrDomain::Corner) { if (GVArray adapted_attribute = src_attributes.adapt_domain( *src_attribute, src_attribute.domain, AttrDomain::Point)) { propagation_attributes.append( {iter.name, iter.data_type, AttrDomain::Point, adapted_attribute}); } } else if (src_attribute.domain == AttrDomain::Face) { if (GVArray adapted_attribute = src_attributes.adapt_domain( *src_attribute, src_attribute.domain, AttrDomain::Edge)) { propagation_attributes.append( {iter.name, iter.data_type, AttrDomain::Edge, adapted_attribute}); } } }); mask.foreach_index(GrainSize(32), [&](const int edge_i, const int element_i) { Mesh *element = BKE_mesh_new_nomain(2, 1, 0, 0); BKE_mesh_copy_parameters_for_eval(element, &mesh); MutableSpan element_edges = element->edges_for_write(); element_edges[0] = {0, 1}; const int2 &src_edge = src_edges[edge_i]; bke::MutableAttributeAccessor element_attributes = element->attributes_for_write(); for (const PropagationAttribute &src_attribute : propagation_attributes) { bke::GSpanAttributeWriter dst = element_attributes.lookup_or_add_for_write_only_span( src_attribute.name, src_attribute.domain, src_attribute.cd_type); if (!dst) { continue; } if (src_attribute.domain == AttrDomain::Point) { src_attribute.data.get(src_edge[0], dst.span[0]); src_attribute.data.get(src_edge[1], dst.span[1]); } else { src_attribute.data.get(edge_i, dst.span[0]); } dst.finish(); } elements[element_i] = element; }); return elements; } Array extract_mesh_faces(const Mesh &mesh, const IndexMask &mask, const bke::AttributeFilter &attribute_filter) { BLI_assert(mask.min_array_size() <= mesh.faces_num); Array elements(mask.size(), nullptr); const Span src_corner_verts = mesh.corner_verts(); const Span src_corner_edges = mesh.corner_edges(); const OffsetIndices src_faces = mesh.faces(); const bke::AttributeAccessor src_attributes = mesh.attributes(); Vector propagation_attributes; src_attributes.foreach_attribute([&](const bke::AttributeIter &iter) { if (iter.data_type == CD_PROP_STRING) { return; } if (ELEM(iter.name, ".edge_verts", ".corner_edge", ".corner_vert")) { return; } if (attribute_filter.allow_skip(iter.name)) { return; } const bke::GAttributeReader src_attribute = iter.get(); if (!src_attribute) { return; } propagation_attributes.append( {iter.name, iter.data_type, src_attribute.domain, *src_attribute}); }); mask.foreach_index(GrainSize(32), [&](const int face_i, const int element_i) { const IndexRange src_face = src_faces[face_i]; const int verts_num = src_face.size(); Mesh *element = BKE_mesh_new_nomain(verts_num, verts_num, 1, verts_num); BKE_mesh_copy_parameters_for_eval(element, &mesh); MutableSpan element_edges = element->edges_for_write(); MutableSpan element_corner_verts = element->corner_verts_for_write(); MutableSpan element_corner_edges = element->corner_edges_for_write(); MutableSpan element_face_offsets = element->face_offsets_for_write(); for (const int i : IndexRange(verts_num)) { element_edges[i] = {i, i + 1}; element_corner_verts[i] = i; element_corner_edges[i] = i; } element_edges.last()[1] = 0; element_face_offsets[0] = 0; element_face_offsets[1] = verts_num; bke::MutableAttributeAccessor element_attributes = element->attributes_for_write(); for (const PropagationAttribute &src_attribute : propagation_attributes) { bke::GSpanAttributeWriter dst = element_attributes.lookup_or_add_for_write_only_span( src_attribute.name, src_attribute.domain, src_attribute.cd_type); if (!dst) { continue; } switch (src_attribute.domain) { case AttrDomain::Point: { for (const int i : IndexRange(verts_num)) { const int src_corner_i = src_face[i]; const int src_vert_i = src_corner_verts[src_corner_i]; src_attribute.data.get(src_vert_i, dst.span[i]); } break; } case AttrDomain::Edge: { for (const int i : IndexRange(verts_num)) { const int src_corner_i = src_face[i]; const int src_edge_i = src_corner_edges[src_corner_i]; src_attribute.data.get(src_edge_i, dst.span[i]); } break; } case AttrDomain::Corner: { src_attribute.data.materialize_compressed(src_face, dst.span.data()); break; } case AttrDomain::Face: { src_attribute.data.get(face_i, dst.span[0]); break; } default: BLI_assert_unreachable(); break; } dst.finish(); } elements[element_i] = element; }); return elements; } Array extract_pointcloud_points(const PointCloud &pointcloud, const IndexMask &mask, const bke::AttributeFilter &attribute_filter) { BLI_assert(mask.min_array_size() <= pointcloud.totpoint); Array elements(mask.size(), nullptr); const bke::AttributeAccessor src_attributes = pointcloud.attributes(); mask.foreach_index(GrainSize(32), [&](const int point_i, const int element_i) { PointCloud *element = BKE_pointcloud_new_nomain(1); element->totcol = pointcloud.totcol; element->mat = static_cast(MEM_dupallocN(pointcloud.mat)); bke::gather_attributes(src_attributes, AttrDomain::Point, AttrDomain::Point, attribute_filter, Span{point_i}, element->attributes_for_write()); elements[element_i] = element; }); return elements; } Array extract_curves_points(const Curves &curves, const IndexMask &mask, const bke::AttributeFilter &attribute_filter) { BLI_assert(mask.min_array_size() <= curves.geometry.point_num); Array elements(mask.size(), nullptr); const bke::CurvesGeometry &src_curves = curves.geometry.wrap(); const bke::AttributeAccessor src_attributes = src_curves.attributes(); const Array point_to_curve_map = src_curves.point_to_curve_map(); mask.foreach_index(GrainSize(32), [&](const int point_i, const int element_i) { const int curve_i = point_to_curve_map[point_i]; /* Actual curve type is propagated below. */ Curves *element = bke::curves_new_nomain_single(1, CURVE_TYPE_POLY); bke::curves_copy_parameters(curves, *element); bke::MutableAttributeAccessor element_attributes = element->geometry.wrap().attributes_for_write(); bke::gather_attributes(src_attributes, AttrDomain::Point, AttrDomain::Point, attribute_filter, Span{point_i}, element_attributes); bke::gather_attributes(src_attributes, AttrDomain::Curve, AttrDomain::Curve, attribute_filter, Span{curve_i}, element_attributes); elements[element_i] = element; }); return elements; } Array extract_curves(const Curves &curves, const IndexMask &mask, const bke::AttributeFilter &attribute_filter) { BLI_assert(mask.min_array_size() <= curves.geometry.curve_num); Array elements(mask.size(), nullptr); const bke::CurvesGeometry &src_curves = curves.geometry.wrap(); const bke::AttributeAccessor src_attributes = src_curves.attributes(); const OffsetIndices src_points_by_curve = src_curves.points_by_curve(); mask.foreach_index(GrainSize(32), [&](const int curve_i, const int element_i) { const IndexRange src_points = src_points_by_curve[curve_i]; const int points_num = src_points.size(); Curves *element = bke::curves_new_nomain_single(points_num, CURVE_TYPE_POLY); bke::MutableAttributeAccessor element_attributes = element->geometry.wrap().attributes_for_write(); bke::curves_copy_parameters(curves, *element); bke::gather_attributes(src_attributes, AttrDomain::Point, AttrDomain::Point, attribute_filter, src_points, element_attributes); bke::gather_attributes(src_attributes, AttrDomain::Curve, AttrDomain::Curve, attribute_filter, Span{curve_i}, element_attributes); element->geometry.wrap().update_curve_types(); elements[element_i] = element; }); return elements; } Array extract_instances(const bke::Instances &instances, const IndexMask &mask, const bke::AttributeFilter &attribute_filter) { using bke::Instances; BLI_assert(mask.min_array_size() <= instances.instances_num()); Array elements(mask.size(), nullptr); const bke::AttributeAccessor src_attributes = instances.attributes(); const Span src_references = instances.references(); const Span src_reference_handles = instances.reference_handles(); const Span src_transforms = instances.transforms(); mask.foreach_index(GrainSize(32), [&](const int instance_i, const int element_i) { const int old_handle = src_reference_handles[instance_i]; const bke::InstanceReference &old_reference = src_references[old_handle]; const float4x4 &old_transform = src_transforms[instance_i]; Instances *element = new Instances(); const int new_handle = element->add_new_reference(old_reference); element->add_instance(new_handle, old_transform); bke::gather_attributes(src_attributes, AttrDomain::Instance, AttrDomain::Instance, bke::attribute_filter_with_skip_ref( attribute_filter, {".reference_index", "instance_transform"}), Span{instance_i}, element->attributes_for_write()); elements[element_i] = element; }); return elements; } Array extract_greasepencil_layers(const GreasePencil &grease_pencil, const IndexMask &mask, const bke::AttributeFilter &attribute_filter) { using namespace bke::greasepencil; BLI_assert(mask.min_array_size() <= grease_pencil.layers().size()); Array elements(mask.size(), nullptr); const bke::AttributeAccessor src_attributes = grease_pencil.attributes(); const Span src_layers = grease_pencil.layers(); mask.foreach_index(GrainSize(32), [&](const int layer_i, const int element_i) { GreasePencil *element = BKE_grease_pencil_new_nomain(); element->material_array = static_cast( MEM_dupallocN(grease_pencil.material_array)); element->material_array_num = grease_pencil.material_array_num; const Layer &src_layer = *src_layers[layer_i]; const Drawing *src_drawing = grease_pencil.get_eval_drawing(src_layer); if (src_drawing) { Layer &new_layer = element->add_layer(src_layer.name()); Drawing &drawing = *element->insert_frame(new_layer, element->runtime->eval_frame); drawing.strokes_for_write() = src_drawing->strokes(); bke::gather_attributes(src_attributes, AttrDomain::Layer, AttrDomain::Layer, attribute_filter, Span{layer_i}, element->attributes_for_write()); } elements[element_i] = element; }); return elements; } Array extract_greasepencil_layer_points( const GreasePencil &grease_pencil, int layer_i, const IndexMask &mask, const bke::AttributeFilter &attribute_filter) { using namespace bke::greasepencil; const Layer &src_layer = grease_pencil.layer(layer_i); const Drawing &src_drawing = *grease_pencil.get_eval_drawing(src_layer); const bke::CurvesGeometry &src_curves = src_drawing.strokes(); const bke::AttributeAccessor src_layer_attributes = grease_pencil.attributes(); const bke::AttributeAccessor src_curves_attributes = src_curves.attributes(); const Array point_to_curve_map = src_curves.point_to_curve_map(); Array elements(mask.size(), nullptr); mask.foreach_index(GrainSize(32), [&](const int point_i, const int element_i) { const int curve_i = point_to_curve_map[point_i]; GreasePencil *element = BKE_grease_pencil_new_nomain(); element->material_array = static_cast( MEM_dupallocN(grease_pencil.material_array)); element->material_array_num = grease_pencil.material_array_num; Layer &new_layer = element->add_layer(src_layer.name()); Drawing &drawing = *element->insert_frame(new_layer, element->runtime->eval_frame); bke::CurvesGeometry &new_curves = drawing.strokes_for_write(); new_curves.resize(1, 1); new_curves.offsets_for_write().last() = 1; bke::gather_attributes(src_curves_attributes, AttrDomain::Point, AttrDomain::Point, attribute_filter, Span{point_i}, new_curves.attributes_for_write()); bke::gather_attributes(src_curves_attributes, AttrDomain::Curve, AttrDomain::Curve, attribute_filter, Span{curve_i}, new_curves.attributes_for_write()); bke::gather_attributes(src_layer_attributes, AttrDomain::Layer, AttrDomain::Layer, attribute_filter, Span{layer_i}, element->attributes_for_write()); new_curves.update_curve_types(); elements[element_i] = element; }); return elements; } Array extract_greasepencil_layer_curves( const GreasePencil &grease_pencil, const int layer_i, const IndexMask &mask, const bke::AttributeFilter &attribute_filter) { using namespace bke::greasepencil; const Layer &src_layer = grease_pencil.layer(layer_i); const Drawing &src_drawing = *grease_pencil.get_eval_drawing(src_layer); const bke::CurvesGeometry &src_curves = src_drawing.strokes(); const bke::AttributeAccessor src_layer_attributes = grease_pencil.attributes(); const bke::AttributeAccessor src_curves_attributes = src_curves.attributes(); const OffsetIndices src_points_by_curve = src_curves.points_by_curve(); Array elements(mask.size(), nullptr); mask.foreach_index(GrainSize(32), [&](const int curve_i, const int element_i) { const IndexRange src_points = src_points_by_curve[curve_i]; const int points_num = src_points.size(); GreasePencil *element = BKE_grease_pencil_new_nomain(); element->material_array = static_cast( MEM_dupallocN(grease_pencil.material_array)); element->material_array_num = grease_pencil.material_array_num; Layer &new_layer = element->add_layer(src_layer.name()); Drawing &drawing = *element->insert_frame(new_layer, element->runtime->eval_frame); bke::CurvesGeometry &new_curves = drawing.strokes_for_write(); new_curves.resize(points_num, 1); bke::gather_attributes(src_curves_attributes, AttrDomain::Point, AttrDomain::Point, attribute_filter, src_points, new_curves.attributes_for_write()); bke::gather_attributes(src_curves_attributes, AttrDomain::Curve, AttrDomain::Curve, attribute_filter, Span{curve_i}, new_curves.attributes_for_write()); bke::gather_attributes(src_layer_attributes, AttrDomain::Layer, AttrDomain::Layer, attribute_filter, Span{layer_i}, element->attributes_for_write()); new_curves.update_curve_types(); elements[element_i] = element; }); return elements; } } // namespace blender::geometry