Curves: Mask function for end points

This essentially replaces the `ed::curves::select_ends` function by using a new masking function (`ed::curves::end_points`) and manipulating the selection attribute directly in the operators.

Pull Request: https://projects.blender.org/blender/blender/pulls/109293
This commit is contained in:
Falk David
2023-06-26 11:21:16 +02:00
committed by Falk David
parent 4a80d0b6d5
commit 32be07845f
6 changed files with 93 additions and 38 deletions

View File

@@ -26,6 +26,7 @@ set(SRC
intern/curves_add.cc
intern/curves_data.cc
intern/curves_edit.cc
intern/curves_masks.cc
intern/curves_ops.cc
intern/curves_selection.cc
intern/curves_undo.cc

View File

@@ -0,0 +1,35 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup edcurves
*/
#include "BKE_curves.hh"
#include "ED_curves.h"
namespace blender::ed::curves {
IndexMask end_points(const bke::CurvesGeometry &curves,
const int amount_start,
const int amount_end,
const bool inverted,
IndexMaskMemory &memory)
{
const OffsetIndices points_by_curve = curves.points_by_curve();
Array<bool> end_points(curves.points_num(), inverted ? false : true);
threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange range) {
for (const int curve_i : range) {
end_points.as_mutable_span()
.slice(points_by_curve[curve_i].drop_front(amount_start).drop_back(amount_end))
.fill(inverted ? true : false);
}
});
return IndexMask::from_bools(end_points, memory);
}
} // namespace blender::ed::curves

View File

@@ -948,7 +948,25 @@ static int select_ends_exec(bContext *C, wmOperator *op)
for (Curves *curves_id : unique_curves) {
CurvesGeometry &curves = curves_id->geometry.wrap();
select_ends(curves, amount_start, amount_end);
IndexMaskMemory memory;
const IndexMask inverted_end_points_mask = end_points(
curves, amount_start, amount_end, true, memory);
const bool was_anything_selected = has_anything_selected(curves);
bke::GSpanAttributeWriter selection = ensure_selection_attribute(
curves, ATTR_DOMAIN_POINT, CD_PROP_BOOL);
if (!was_anything_selected) {
fill_selection_true(selection.span);
}
if (selection.span.type().is<bool>()) {
index_mask::masked_fill(selection.span.typed<bool>(), false, inverted_end_points_mask);
}
if (selection.span.type().is<float>()) {
index_mask::masked_fill(selection.span.typed<float>(), 0.0f, inverted_end_points_mask);
}
selection.finish();
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
* attribute for now. */

View File

@@ -227,34 +227,6 @@ void select_all(bke::CurvesGeometry &curves, const eAttrDomain selection_domain,
}
}
void select_ends(bke::CurvesGeometry &curves, int amount_start, int amount_end)
{
const bool was_anything_selected = has_anything_selected(curves);
const OffsetIndices points_by_curve = curves.points_by_curve();
bke::GSpanAttributeWriter selection = ensure_selection_attribute(
curves, ATTR_DOMAIN_POINT, CD_PROP_BOOL);
if (!was_anything_selected) {
fill_selection_true(selection.span);
}
selection.span.type().to_static_type_tag<bool, float>([&](auto type_tag) {
using T = typename decltype(type_tag)::type;
if constexpr (std::is_void_v<T>) {
BLI_assert_unreachable();
}
else {
MutableSpan<T> selection_typed = selection.span.typed<T>();
threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange range) {
for (const int curve_i : range) {
selection_typed
.slice(points_by_curve[curve_i].drop_front(amount_start).drop_back(amount_end))
.fill(T(0));
}
});
}
});
selection.finish();
}
void select_linked(bke::CurvesGeometry &curves)
{
const OffsetIndices points_by_curve = curves.points_by_curve();

View File

@@ -243,7 +243,26 @@ static int select_ends_exec(bContext *C, wmOperator *op)
grease_pencil.foreach_editable_drawing(
scene->r.cfra, [&](int /*drawing_index*/, GreasePencilDrawing &drawing) {
blender::ed::curves::select_ends(drawing.geometry.wrap(), amount_start, amount_end);
bke::CurvesGeometry &curves = drawing.geometry.wrap();
IndexMaskMemory memory;
const IndexMask inverted_end_points_mask = ed::curves::end_points(
curves, amount_start, amount_end, true, memory);
const bool was_anything_selected = ed::curves::has_anything_selected(curves);
bke::GSpanAttributeWriter selection = ed::curves::ensure_selection_attribute(
curves, ATTR_DOMAIN_POINT, CD_PROP_BOOL);
if (!was_anything_selected) {
ed::curves::fill_selection_true(selection.span);
}
if (selection.span.type().is<bool>()) {
index_mask::masked_fill(selection.span.typed<bool>(), false, inverted_end_points_mask);
}
if (selection.span.type().is<float>()) {
index_mask::masked_fill(selection.span.typed<float>(), 0.0f, inverted_end_points_mask);
}
selection.finish();
});
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic

View File

@@ -89,6 +89,24 @@ bool curves_poll(bContext *C);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Mask Functions
* \{ */
/**
* Return a mask of all the end points in the curves.
* \param amount_start: The amount of points to mask from the front.
* \param amount_end: The amount of points to mask from the back.
* \param inverted: Invert the resulting mask.
*/
IndexMask end_points(const bke::CurvesGeometry &curves,
int amount_start,
int amount_end,
bool inverted,
IndexMaskMemory &memory);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Selection
*
@@ -147,14 +165,6 @@ void apply_selection_operation_at_index(GMutableSpan selection, int index, eSele
*/
void select_all(bke::CurvesGeometry &curves, eAttrDomain selection_domain, int action);
/**
* Select the ends (front or back) of all the curves.
*
* \param amount_start: The amount of points to select from the front.
* \param amount_end: The amount of points to select from the back.
*/
void select_ends(bke::CurvesGeometry &curves, int amount_start, int amount_end);
/**
* Select the points of all curves that have at least one point selected.
*/