diff options
author | Jacques Lucke <jacques@blender.org> | 2022-03-10 20:06:43 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2022-03-10 20:06:43 +0300 |
commit | 3f91e7d7792ed5315e8b0c80de4355f064db4a6d (patch) | |
tree | 304d896d716fb04283e0562ec41ece17d7246532 | |
parent | 22a341d9d8d3d337f79df228ab2e4e0726f81430 (diff) |
Curves: actually delete curves with Delete brush
Previously, the position was just set to zero as part of the prototype.
Differential Revision: https://developer.blender.org/D14291
-rw-r--r-- | source/blender/blenkernel/BKE_curves.hh | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/curves_geometry.cc | 135 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/curves_sculpt_ops.cc | 11 |
3 files changed, 141 insertions, 8 deletions
diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh index f3d9090d16b..6cab9c8ff90 100644 --- a/source/blender/blenkernel/BKE_curves.hh +++ b/source/blender/blenkernel/BKE_curves.hh @@ -95,6 +95,7 @@ class CurvesGeometry : public ::CurvesGeometry { * Access a range of indices of point data for a specific curve. */ IndexRange range_for_curve(int index) const; + IndexRange range_for_curves(IndexRange curves) const; /** The type (#CurveType) of each curve, or potentially a single if all are the same type. */ VArray<int8_t> curve_types() const; @@ -147,6 +148,8 @@ class CurvesGeometry : public ::CurvesGeometry { void update_customdata_pointers(); + void remove_curves(IndexMask curves_to_delete); + /* -------------------------------------------------------------------- * Attributes. */ diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index 0ae5654546b..afa0e6e452d 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -129,6 +129,13 @@ IndexRange CurvesGeometry::range_for_curve(const int index) const return {offset, offset_next - offset}; } +IndexRange CurvesGeometry::range_for_curves(const IndexRange curves) const +{ + const int offset = this->curve_offsets[curves.start()]; + const int offset_next = this->curve_offsets[curves.one_after_last()]; + return {offset, offset_next - offset}; +} + static int domain_size(const CurvesGeometry &curves, const AttributeDomain domain) { return domain == ATTR_DOMAIN_POINT ? curves.points_size() : curves.curves_size(); @@ -305,6 +312,134 @@ void CurvesGeometry::update_customdata_pointers() &this->point_data, CD_PROP_INT8, ATTR_CURVE_TYPE.c_str()); } +static void *ensure_customdata_layer(CustomData &custom_data, + const StringRefNull name, + const CustomDataType data_type, + const int tot_elements) +{ + for (const int other_layer_i : IndexRange(custom_data.totlayer)) { + CustomDataLayer &new_layer = custom_data.layers[other_layer_i]; + if (name == StringRef(new_layer.name)) { + return new_layer.data; + } + } + return CustomData_add_layer_named( + &custom_data, data_type, CD_DEFAULT, nullptr, tot_elements, name.c_str()); +} + +static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves, + const IndexMask curves_to_delete) +{ + const Span<int> old_offsets = curves.offsets(); + const Vector<IndexRange> old_curve_ranges = curves_to_delete.extract_ranges_invert( + curves.curves_range(), nullptr); + Vector<IndexRange> new_curve_ranges; + Vector<IndexRange> old_point_ranges; + Vector<IndexRange> new_point_ranges; + int new_tot_points = 0; + int new_tot_curves = 0; + for (const IndexRange &curve_range : old_curve_ranges) { + new_curve_ranges.append(IndexRange(new_tot_curves, curve_range.size())); + new_tot_curves += curve_range.size(); + + const IndexRange old_point_range = curves.range_for_curves(curve_range); + old_point_ranges.append(old_point_range); + new_point_ranges.append(IndexRange(new_tot_points, old_point_range.size())); + new_tot_points += old_point_range.size(); + } + + CurvesGeometry new_curves{new_tot_points, new_tot_curves}; + + threading::parallel_invoke( + /* Initialize curve offsets. */ + [&]() { + MutableSpan<int> new_offsets = new_curves.offsets(); + new_offsets.last() = new_tot_points; + threading::parallel_for( + old_curve_ranges.index_range(), 128, [&](const IndexRange ranges_range) { + for (const int range_i : ranges_range) { + const IndexRange old_curve_range = old_curve_ranges[range_i]; + const IndexRange new_curve_range = new_curve_ranges[range_i]; + const IndexRange old_point_range = old_point_ranges[range_i]; + const IndexRange new_point_range = new_point_ranges[range_i]; + const int offset_shift = new_point_range.start() - old_point_range.start(); + const int curves_in_range = old_curve_range.size(); + threading::parallel_for( + IndexRange(curves_in_range), 512, [&](const IndexRange range) { + for (const int i : range) { + const int old_curve_i = old_curve_range[i]; + const int new_curve_i = new_curve_range[i]; + const int old_offset = old_offsets[old_curve_i]; + const int new_offset = old_offset + offset_shift; + new_offsets[new_curve_i] = new_offset; + } + }); + } + }); + }, + /* Copy over point attributes. */ + [&]() { + const CustomData &old_point_data = curves.point_data; + CustomData &new_point_data = new_curves.point_data; + for (const int layer_i : IndexRange(old_point_data.totlayer)) { + const CustomDataLayer &old_layer = old_point_data.layers[layer_i]; + const CustomDataType data_type = static_cast<CustomDataType>(old_layer.type); + const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type); + + const void *src_buffer = old_layer.data; + void *dst_buffer = ensure_customdata_layer( + new_point_data, old_layer.name, data_type, new_tot_points); + + threading::parallel_for( + old_curve_ranges.index_range(), 128, [&](const IndexRange ranges_range) { + for (const int range_i : ranges_range) { + const IndexRange old_point_range = old_point_ranges[range_i]; + const IndexRange new_point_range = new_point_ranges[range_i]; + + type.copy_construct_n( + POINTER_OFFSET(src_buffer, type.size() * old_point_range.start()), + POINTER_OFFSET(dst_buffer, type.size() * new_point_range.start()), + old_point_range.size()); + } + }); + } + }, + /* Copy over curve attributes. */ + [&]() { + const CustomData &old_curve_data = curves.curve_data; + CustomData &new_curve_data = new_curves.curve_data; + for (const int layer_i : IndexRange(old_curve_data.totlayer)) { + const CustomDataLayer &old_layer = old_curve_data.layers[layer_i]; + const CustomDataType data_type = static_cast<CustomDataType>(old_layer.type); + const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type); + + const void *src_buffer = old_layer.data; + void *dst_buffer = ensure_customdata_layer( + new_curve_data, old_layer.name, data_type, new_tot_points); + + threading::parallel_for( + old_curve_ranges.index_range(), 128, [&](const IndexRange ranges_range) { + for (const int range_i : ranges_range) { + const IndexRange old_curve_range = old_curve_ranges[range_i]; + const IndexRange new_curve_range = new_curve_ranges[range_i]; + + type.copy_construct_n( + POINTER_OFFSET(src_buffer, type.size() * old_curve_range.start()), + POINTER_OFFSET(dst_buffer, type.size() * new_curve_range.start()), + old_curve_range.size()); + } + }); + } + }); + + return new_curves; +} + +void CurvesGeometry::remove_curves(const IndexMask curves_to_delete) +{ + *this = copy_with_removed_curves(*this, curves_to_delete); +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc index 1411f30bffd..47bf7a28352 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc @@ -7,6 +7,7 @@ #include "BKE_bvhutils.h" #include "BKE_context.h" #include "BKE_curves.hh" +#include "BKE_geometry_set.hh" #include "BKE_lib_id.h" #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" @@ -67,6 +68,7 @@ bool CURVES_SCULPT_mode_poll_view3d(bContext *C) namespace blender::ed::sculpt_paint { using blender::bke::CurvesGeometry; +using blender::fn::CPPType; /* -------------------------------------------------------------------- */ /** \name * SCULPT_CURVES_OT_brush_stroke @@ -134,14 +136,7 @@ class DeleteOperation : public CurvesSculptStrokeOperation { return false; }); - /* Just reset positions instead of actually removing the curves. This is just a prototype. */ - threading::parallel_for(curves_to_remove.index_range(), 512, [&](const IndexRange range) { - for (const int curve_i : curves_to_remove.slice(range)) { - for (const int point_i : curves.range_for_curve(curve_i)) { - positions[point_i] = {0.0f, 0.0f, 0.0f}; - } - } - }); + curves.remove_curves(curves_to_remove); curves.tag_positions_changed(); DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY); |