Changeset View
Changeset View
Standalone View
Standalone View
source/blender/geometry/intern/subdivide_curves.cc
| Show First 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | for (const int curve_i : selection.slice(range)) { | ||||
| bke::curves::accumulate_counts_to_offsets(point_offsets); | bke::curves::accumulate_counts_to_offsets(point_offsets); | ||||
| dst_curve_offsets[curve_i] = point_offsets.last(); | dst_curve_offsets[curve_i] = point_offsets.last(); | ||||
| } | } | ||||
| }); | }); | ||||
| bke::curves::accumulate_counts_to_offsets(dst_curve_offsets); | bke::curves::accumulate_counts_to_offsets(dst_curve_offsets); | ||||
| } | } | ||||
| struct AttributeTransferData { | |||||
| /* Expect that if an attribute exists, it is stored as a contiguous array internally anyway. */ | |||||
| GVArraySpan src; | |||||
| bke::GSpanAttributeWriter dst; | |||||
| }; | |||||
| static Vector<AttributeTransferData> retrieve_point_attributes( | |||||
| const bke::AttributeAccessor &src_attributes, | |||||
| bke::MutableAttributeAccessor &dst_attributes, | |||||
| const Set<std::string> &skip = {}) | |||||
| { | |||||
| Vector<AttributeTransferData> attributes; | |||||
| 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 (id.is_named() && skip.contains(id.name())) { | |||||
| return true; | |||||
| } | |||||
| GVArray src = src_attributes.lookup(id, ATTR_DOMAIN_POINT); | |||||
| BLI_assert(src); | |||||
| 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)}); | |||||
| return true; | |||||
| }); | |||||
| return attributes; | |||||
| } | |||||
| template<typename T> | template<typename T> | ||||
| static inline void linear_interpolation(const T &a, const T &b, MutableSpan<T> dst) | static inline void linear_interpolation(const T &a, const T &b, MutableSpan<T> dst) | ||||
| { | { | ||||
| dst.first() = a; | dst.first() = a; | ||||
| const float step = 1.0f / dst.size(); | const float step = 1.0f / dst.size(); | ||||
| for (const int i : dst.index_range().drop_front(1)) { | for (const int i : dst.index_range().drop_front(1)) { | ||||
| dst[i] = attribute_math::mix2(i * step, a, b); | dst[i] = attribute_math::mix2(i * step, a, b); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 259 Lines • ▼ Show 20 Lines | #endif | ||||
| const Span<int> point_offsets = dst_point_offsets.as_span(); | const Span<int> point_offsets = dst_point_offsets.as_span(); | ||||
| dst_curves.resize(dst_curves.offsets().last(), dst_curves.curves_num()); | dst_curves.resize(dst_curves.offsets().last(), dst_curves.curves_num()); | ||||
| const bke::AttributeAccessor src_attributes = src_curves.attributes(); | const bke::AttributeAccessor src_attributes = src_curves.attributes(); | ||||
| bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write(); | bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write(); | ||||
| auto subdivide_catmull_rom = [&](IndexMask selection) { | auto subdivide_catmull_rom = [&](IndexMask selection) { | ||||
| for (auto &attribute : retrieve_point_attributes(src_attributes, dst_attributes)) { | for (auto &attribute : bke::retrieve_attributes_for_transfer( | ||||
| src_attributes, dst_attributes, ATTR_DOMAIN_MASK_POINT)) { | |||||
| subdivide_attribute_catmull_rom(src_curves, | subdivide_attribute_catmull_rom(src_curves, | ||||
| dst_curves, | dst_curves, | ||||
| selection, | selection, | ||||
| point_offsets, | point_offsets, | ||||
| cyclic, | cyclic, | ||||
| attribute.src, | attribute.src, | ||||
| attribute.dst.span); | attribute.dst.span); | ||||
| attribute.dst.finish(); | attribute.dst.finish(); | ||||
| } | } | ||||
| }; | }; | ||||
| auto subdivide_poly = [&](IndexMask selection) { | auto subdivide_poly = [&](IndexMask selection) { | ||||
| for (auto &attribute : retrieve_point_attributes(src_attributes, dst_attributes)) { | for (auto &attribute : bke::retrieve_attributes_for_transfer( | ||||
| src_attributes, dst_attributes, ATTR_DOMAIN_MASK_POINT)) { | |||||
| subdivide_attribute_linear( | subdivide_attribute_linear( | ||||
| src_curves, dst_curves, selection, point_offsets, attribute.src, attribute.dst.span); | src_curves, dst_curves, selection, point_offsets, attribute.src, attribute.dst.span); | ||||
| attribute.dst.finish(); | attribute.dst.finish(); | ||||
| } | } | ||||
| }; | }; | ||||
| auto subdivide_bezier = [&](IndexMask selection) { | auto subdivide_bezier = [&](IndexMask selection) { | ||||
| const Span<float3> src_positions = src_curves.positions(); | const Span<float3> src_positions = src_curves.positions(); | ||||
| Show All 24 Lines | threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) { | ||||
| dst_positions.slice(dst_points), | dst_positions.slice(dst_points), | ||||
| dst_types_l.slice(dst_points), | dst_types_l.slice(dst_points), | ||||
| dst_types_r.slice(dst_points), | dst_types_r.slice(dst_points), | ||||
| dst_handles_l.slice(dst_points), | dst_handles_l.slice(dst_points), | ||||
| dst_handles_r.slice(dst_points)); | dst_handles_r.slice(dst_points)); | ||||
| } | } | ||||
| }); | }); | ||||
| for (auto &attribute : retrieve_point_attributes(src_attributes, | for (auto &attribute : bke::retrieve_attributes_for_transfer(src_attributes, | ||||
| dst_attributes, | dst_attributes, | ||||
| ATTR_DOMAIN_MASK_POINT, | |||||
| {"position", | {"position", | ||||
| "handle_type_left", | "handle_type_left", | ||||
| "handle_type_right", | "handle_type_right", | ||||
| "handle_right", | "handle_right", | ||||
| "handle_left"})) { | "handle_left"})) { | ||||
| subdivide_attribute_linear( | subdivide_attribute_linear( | ||||
| src_curves, dst_curves, selection, point_offsets, attribute.src, attribute.dst.span); | src_curves, dst_curves, selection, point_offsets, attribute.src, attribute.dst.span); | ||||
| attribute.dst.finish(); | attribute.dst.finish(); | ||||
| } | } | ||||
| }; | }; | ||||
| /* NURBS curves are just treated as poly curves. NURBS subdivision that maintains | /* NURBS curves are just treated as poly curves. NURBS subdivision that maintains | ||||
| * their shape may be possible, but probably wouldn't work with the "cuts" input. */ | * their shape may be possible, but probably wouldn't work with the "cuts" input. */ | ||||
| auto subdivide_nurbs = subdivide_poly; | auto subdivide_nurbs = subdivide_poly; | ||||
| bke::curves::foreach_curve_by_type(src_curves.curve_types(), | bke::curves::foreach_curve_by_type(src_curves.curve_types(), | ||||
| src_curves.curve_type_counts(), | src_curves.curve_type_counts(), | ||||
| selection, | selection, | ||||
| subdivide_catmull_rom, | subdivide_catmull_rom, | ||||
| subdivide_poly, | subdivide_poly, | ||||
| subdivide_bezier, | subdivide_bezier, | ||||
| subdivide_nurbs); | subdivide_nurbs); | ||||
| if (!unselected_ranges.is_empty()) { | if (!unselected_ranges.is_empty()) { | ||||
| for (auto &attribute : retrieve_point_attributes(src_attributes, dst_attributes)) { | for (auto &attribute : bke::retrieve_attributes_for_transfer( | ||||
| src_attributes, dst_attributes, ATTR_DOMAIN_MASK_POINT)) { | |||||
| bke::curves::copy_point_data( | bke::curves::copy_point_data( | ||||
| src_curves, dst_curves, unselected_ranges, attribute.src, attribute.dst.span); | src_curves, dst_curves, unselected_ranges, attribute.src, attribute.dst.span); | ||||
| attribute.dst.finish(); | attribute.dst.finish(); | ||||
| } | } | ||||
| } | } | ||||
| return dst_curves; | return dst_curves; | ||||
| } | } | ||||
| } // namespace blender::geometry | } // namespace blender::geometry | ||||