diff options
author | Kévin Dietrich <kevin.dietrich@mailoo.org> | 2022-03-13 20:05:40 +0300 |
---|---|---|
committer | Kévin Dietrich <kevin.dietrich@mailoo.org> | 2022-03-13 20:05:40 +0300 |
commit | 5a0efc9c8b5ad991109c97d52d476d8c071a78ac (patch) | |
tree | e5c8290bc613ef8eea923d0983cb51512c4b1ce7 /source/blender/blenkernel/intern/curves_geometry.cc | |
parent | 1ca7821b15f3883121552495436142814c73fbb7 (diff) | |
parent | 91dbc28363e5450f241eb9696aaca29075c01d20 (diff) |
Merge branch 'master' into temp-abc-features
Diffstat (limited to 'source/blender/blenkernel/intern/curves_geometry.cc')
-rw-r--r-- | source/blender/blenkernel/intern/curves_geometry.cc | 253 |
1 files changed, 232 insertions, 21 deletions
diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index 3eea579230a..dd91e788e5a 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -84,6 +84,42 @@ CurvesGeometry &CurvesGeometry::operator=(const CurvesGeometry &other) return *this; } +/* The source should be empty, but in a valid state so that using it further will work. */ +static void move_curves_geometry(CurvesGeometry &dst, CurvesGeometry &src) +{ + dst.point_size = src.point_size; + std::swap(dst.point_data, src.point_data); + CustomData_free(&src.point_data, src.point_size); + src.point_size = 0; + + dst.curve_size = src.curve_size; + std::swap(dst.curve_data, dst.curve_data); + CustomData_free(&src.curve_data, src.curve_size); + src.curve_size = 0; + + std::swap(dst.curve_offsets, src.curve_offsets); + MEM_SAFE_FREE(src.curve_offsets); + + std::swap(dst.runtime, src.runtime); + + src.update_customdata_pointers(); + dst.update_customdata_pointers(); +} + +CurvesGeometry::CurvesGeometry(CurvesGeometry &&other) + : CurvesGeometry(other.point_size, other.curve_size) +{ + move_curves_geometry(*this, other); +} + +CurvesGeometry &CurvesGeometry::operator=(CurvesGeometry &&other) +{ + if (this != &other) { + move_curves_geometry(*this, other); + } + return *this; +} + CurvesGeometry::~CurvesGeometry() { CustomData_free(&this->point_data, this->point_size); @@ -124,29 +160,83 @@ int CurvesGeometry::evaluated_points_size() const IndexRange CurvesGeometry::range_for_curve(const int index) const { + BLI_assert(this->curve_size > 0); + BLI_assert(this->curve_offsets != nullptr); const int offset = this->curve_offsets[index]; const int offset_next = this->curve_offsets[index + 1]; return {offset, offset_next - offset}; } -VArray<int8_t> CurvesGeometry::curve_types() const +IndexRange CurvesGeometry::range_for_curves(const IndexRange curves) const +{ + BLI_assert(this->curve_size > 0); + BLI_assert(this->curve_offsets != nullptr); + 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) { - if (const int8_t *data = (const int8_t *)CustomData_get_layer_named( - &this->curve_data, CD_PROP_INT8, ATTR_CURVE_TYPE.c_str())) { - return VArray<int8_t>::ForSpan({data, this->curve_size}); + return domain == ATTR_DOMAIN_POINT ? curves.points_size() : curves.curves_size(); +} + +static CustomData &domain_custom_data(CurvesGeometry &curves, const AttributeDomain domain) +{ + return domain == ATTR_DOMAIN_POINT ? curves.point_data : curves.curve_data; +} + +static const CustomData &domain_custom_data(const CurvesGeometry &curves, + const AttributeDomain domain) +{ + return domain == ATTR_DOMAIN_POINT ? curves.point_data : curves.curve_data; +} + +template<typename T> +static VArray<T> get_varray_attribute(const CurvesGeometry &curves, + const AttributeDomain domain, + const StringRefNull name, + const T default_value) +{ + const int size = domain_size(curves, domain); + const CustomDataType type = cpp_type_to_custom_data_type(CPPType::get<T>()); + const CustomData &custom_data = domain_custom_data(curves, domain); + + const T *data = (const T *)CustomData_get_layer_named(&custom_data, type, name.c_str()); + if (data != nullptr) { + return VArray<T>::ForSpan(Span<T>(data, size)); + } + return VArray<T>::ForSingle(default_value, size); +} + +template<typename T> +static MutableSpan<T> get_mutable_attribute(CurvesGeometry &curves, + const AttributeDomain domain, + const StringRefNull name) +{ + const int size = domain_size(curves, domain); + const CustomDataType type = cpp_type_to_custom_data_type(CPPType::get<T>()); + CustomData &custom_data = domain_custom_data(curves, domain); + + T *data = (T *)CustomData_duplicate_referenced_layer_named( + &custom_data, type, name.c_str(), size); + if (data != nullptr) { + return {data, size}; } - return VArray<int8_t>::ForSingle(CURVE_TYPE_CATMULL_ROM, this->curve_size); + data = (T *)CustomData_add_layer_named( + &custom_data, type, CD_CALLOC, nullptr, size, name.c_str()); + return {data, size}; +} + +VArray<int8_t> CurvesGeometry::curve_types() const +{ + return get_varray_attribute<int8_t>( + *this, ATTR_DOMAIN_CURVE, ATTR_CURVE_TYPE, CURVE_TYPE_CATMULL_ROM); } MutableSpan<int8_t> CurvesGeometry::curve_types() { - int8_t *data = (int8_t *)CustomData_add_layer_named(&this->curve_data, - CD_PROP_INT8, - CD_CALLOC, - nullptr, - this->curve_size, - ATTR_CURVE_TYPE.c_str()); - return {data, this->curve_size}; + return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_CURVE_TYPE); } MutableSpan<float3> CurvesGeometry::positions() @@ -171,19 +261,12 @@ Span<int> CurvesGeometry::offsets() const VArray<bool> CurvesGeometry::cyclic() const { - const bool *data = (const bool *)CustomData_get_layer_named( - &this->curve_data, CD_PROP_INT8, ATTR_CURVE_TYPE.c_str()); - if (data != nullptr) { - return VArray<bool>::ForSpan(Span(data, this->curve_size)); - } - return VArray<bool>::ForSingle(false, this->curve_size); + return get_varray_attribute<bool>(*this, ATTR_DOMAIN_CURVE, ATTR_CYCLIC, false); } MutableSpan<bool> CurvesGeometry::cyclic() { - bool *data = (bool *)CustomData_add_layer_named( - &this->curve_data, CD_PROP_BOOL, CD_CALLOC, nullptr, this->curve_size, ATTR_CYCLIC.c_str()); - return {data, this->curve_size}; + return get_mutable_attribute<bool>(*this, ATTR_DOMAIN_CURVE, ATTR_CYCLIC); } void CurvesGeometry::resize(const int point_size, const int curve_size) @@ -269,6 +352,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); +} + /** \} */ /* -------------------------------------------------------------------- */ |