Fix: Grease Pencil: Pen Tool does not work with multiple layers

The problem was that `threading::parallel_for` will return a range containing multiple elements even though the grain size is `1`.

Pull Request: https://projects.blender.org/blender/blender/pulls/144826
This commit is contained in:
Casey Bianco-Davis
2025-08-19 22:54:28 +02:00
committed by Thamsanqa Dreem
parent 2443f8bf08
commit 56ccaddc6c

View File

@@ -1160,40 +1160,64 @@ static wmOperatorStatus grease_pencil_pen_invoke(bContext *C, wmOperator *op, co
ptd.closest_element = pen_find_closest_element(ptd, ptd.mouse_co);
threading::parallel_for(ptd.drawings.index_range(), 1, [&](const IndexRange drawing_range) {
const int drawing_index = drawing_range.first();
const MutableDrawingInfo &info = ptd.drawings[drawing_index];
bke::CurvesGeometry &curves = info.drawing.strokes_for_write();
for (const int drawing_index : drawing_range) {
const MutableDrawingInfo &info = ptd.drawings[drawing_index];
bke::CurvesGeometry &curves = info.drawing.strokes_for_write();
if (curves.is_empty()) {
return;
}
if (ptd.closest_element.element_mode == ElementMode::Edge) {
add_single.store(false, std::memory_order_relaxed);
if (ptd.insert_point) {
ptd.insert_point_to_curve(curves);
info.drawing.tag_topology_changed();
changed.store(true, std::memory_order_relaxed);
if (curves.is_empty()) {
continue;
}
return;
}
if (ptd.closest_element.element_mode == ElementMode::None) {
if (ptd.extrude_point) {
const bke::greasepencil::Layer &layer = ptd.grease_pencil->layer(info.layer_index);
const float4x4 layer_to_object = layer.local_transform();
IndexMaskMemory memory;
const IndexMask editable_curves = ed::greasepencil::retrieve_editable_strokes(
*ptd.vc.obact, info.drawing, info.layer_index, memory);
const bke::CurvesGeometry &src = info.drawing.strokes();
if (std::optional<bke::CurvesGeometry> result = ptd.extrude_curves(
src, layer_to_object, editable_curves))
{
curves = std::move(*result);
if (ptd.closest_element.element_mode == ElementMode::Edge) {
add_single.store(false, std::memory_order_relaxed);
if (ptd.insert_point) {
ptd.insert_point_to_curve(curves);
info.drawing.tag_topology_changed();
changed.store(true, std::memory_order_relaxed);
}
else {
continue;
}
if (ptd.closest_element.element_mode == ElementMode::None) {
if (ptd.extrude_point) {
const bke::greasepencil::Layer &layer = ptd.grease_pencil->layer(info.layer_index);
const float4x4 layer_to_object = layer.local_transform();
IndexMaskMemory memory;
const IndexMask editable_curves = ed::greasepencil::retrieve_editable_strokes(
*ptd.vc.obact, info.drawing, info.layer_index, memory);
const bke::CurvesGeometry &src = info.drawing.strokes();
if (std::optional<bke::CurvesGeometry> result = ptd.extrude_curves(
src, layer_to_object, editable_curves))
{
curves = std::move(*result);
}
else {
for (const StringRef selection_attribute_name :
ed::curves::get_curves_selection_attribute_names(curves))
{
bke::GSpanAttributeWriter selection_writer = ed::curves::ensure_selection_attribute(
curves, bke::AttrDomain::Point, bke::AttrType::Bool, selection_attribute_name);
ed::curves::fill_selection_false(selection_writer.span);
selection_writer.finish();
}
continue;
}
add_single.store(false, std::memory_order_relaxed);
point_added.store(true, std::memory_order_relaxed);
info.drawing.tag_topology_changed();
changed.store(true, std::memory_order_relaxed);
continue;
}
continue;
}
if (drawing_index != ptd.closest_element.drawing_index) {
if (event->val != KM_DBL_CLICK && !ptd.delete_point) {
for (const StringRef selection_attribute_name :
ed::curves::get_curves_selection_attribute_names(curves))
{
@@ -1202,65 +1226,42 @@ static wmOperatorStatus grease_pencil_pen_invoke(bContext *C, wmOperator *op, co
ed::curves::fill_selection_false(selection_writer.span);
selection_writer.finish();
}
return;
}
add_single.store(false, std::memory_order_relaxed);
point_added.store(true, std::memory_order_relaxed);
continue;
}
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
const IndexRange points = points_by_curve[ptd.closest_element.curve_index];
if (event->val == KM_DBL_CLICK && ptd.cycle_handle_type) {
const int8_t handle_type = curves.handle_types_right()[ptd.closest_element.point_index];
/* Cycle to the next type. */
const int8_t new_handle_type = (handle_type + 1) % CURVE_HANDLE_TYPES_NUM;
curves.handle_types_left_for_write()[ptd.closest_element.point_index] = new_handle_type;
curves.handle_types_right_for_write()[ptd.closest_element.point_index] = new_handle_type;
curves.calculate_bezier_auto_handles();
info.drawing.tag_topology_changed();
changed.store(true, std::memory_order_relaxed);
return;
add_single.store(false, std::memory_order_relaxed);
}
return;
}
if (drawing_index != ptd.closest_element.drawing_index) {
if (event->val != KM_DBL_CLICK && !ptd.delete_point) {
for (const StringRef selection_attribute_name :
ed::curves::get_curves_selection_attribute_names(curves))
{
bke::GSpanAttributeWriter selection_writer = ed::curves::ensure_selection_attribute(
curves, bke::AttrDomain::Point, bke::AttrType::Bool, selection_attribute_name);
ed::curves::fill_selection_false(selection_writer.span);
selection_writer.finish();
}
if (ptd.delete_point) {
curves.remove_points(IndexRange::from_single(ptd.closest_element.point_index), {});
add_single.store(false, std::memory_order_relaxed);
point_removed.store(true, std::memory_order_relaxed);
info.drawing.tag_topology_changed();
continue;
}
return;
const bool clear_selection = event->val != KM_DBL_CLICK && !ptd.delete_point;
if (ptd.close_curve_and_select(curves, points, clear_selection)) {
info.drawing.tag_topology_changed();
add_single.store(false, std::memory_order_relaxed);
}
changed.store(true, std::memory_order_relaxed);
}
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
const IndexRange points = points_by_curve[ptd.closest_element.curve_index];
if (event->val == KM_DBL_CLICK && ptd.cycle_handle_type) {
const int8_t handle_type = curves.handle_types_right()[ptd.closest_element.point_index];
/* Cycle to the next type. */
const int8_t new_handle_type = (handle_type + 1) % CURVE_HANDLE_TYPES_NUM;
curves.handle_types_left_for_write()[ptd.closest_element.point_index] = new_handle_type;
curves.handle_types_right_for_write()[ptd.closest_element.point_index] = new_handle_type;
curves.calculate_bezier_auto_handles();
info.drawing.tag_topology_changed();
add_single.store(false, std::memory_order_relaxed);
}
if (ptd.delete_point) {
curves.remove_points(IndexRange::from_single(ptd.closest_element.point_index), {});
add_single.store(false, std::memory_order_relaxed);
point_removed.store(true, std::memory_order_relaxed);
info.drawing.tag_topology_changed();
return;
}
const bool clear_selection = event->val != KM_DBL_CLICK && !ptd.delete_point;
if (ptd.close_curve_and_select(curves, points, clear_selection)) {
info.drawing.tag_topology_changed();
add_single.store(false, std::memory_order_relaxed);
}
changed.store(true, std::memory_order_relaxed);
});
if (add_single) {