Grease Pencil: Sculpt Mode Auto-Masking option

This implements all the auto masking options in sculpt mode.

* Stroke: Only affects strokes that are initially under the cursor.
* Layer: Only affect strokes in the same layer as the initial strokes under the cursor.
* Material: Only affect strokes with the same material as the initial strokes under the cursor.
* Active Layer: Only affect strokes in the active layer.
* Active Material: Only affect strokes that use the active material.

The `Active Layer` toggle in the toolbar has been moved to this panel.

Resolves #130022.

Pull Request: https://projects.blender.org/blender/blender/pulls/132986
This commit is contained in:
Falk David
2025-01-24 10:20:03 +01:00
committed by Falk David
parent b8db212d95
commit 1eb39a8689
18 changed files with 499 additions and 301 deletions

View File

@@ -4077,6 +4077,10 @@ def km_grease_pencil_sculpt_mode(params):
# Active layer
op_menu("GREASE_PENCIL_MT_layer_active", {"type": 'Y', "value": 'PRESS'}),
# Auto-masking menu.
op_menu_pie("VIEW3D_MT_grease_pencil_sculpt_automasking_pie", {
"type": 'A', "value": 'PRESS', "shift": True, "alt": True}),
*_template_paint_radial_control("gpencil_sculpt_paint"),
*_template_asset_shelf_popup("VIEW3D_AST_brush_gpencil_sculpt", params.spacebar_action),
*_template_items_context_panel("VIEW3D_PT_greasepencil_sculpt_context_menu", params.context_menu_event),

View File

@@ -435,8 +435,6 @@ class _draw_tool_settings_context_mode:
# Brush falloff
layout.popover("VIEW3D_PT_tools_brush_falloff")
# Active layer only switch
layout.prop(brush.gpencil_settings, "use_active_layer_only")
return True
@staticmethod
@@ -954,6 +952,12 @@ class VIEW3D_HT_header(Header):
panel="VIEW3D_PT_grease_pencil_guide",
text="Guides",
)
if object_mode == 'SCULPT_GREASE_PENCIL':
layout.popover(
panel="VIEW3D_PT_grease_pencil_sculpt_automasking",
text="",
icon=VIEW3D_HT_header._grease_pencil_sculpt_automasking_icon(tool_settings.gpencil_sculpt),
)
elif object_mode == 'SCULPT':
# If the active tool supports it, show the canvas selector popover.

View File

@@ -47,7 +47,9 @@ class GreasePencilStrokeOperation : public PaintModeData {
namespace greasepencil {
/* Get list of drawings the tool should be operating on. */
Vector<ed::greasepencil::MutableDrawingInfo> get_drawings_for_painting(const bContext &C);
Vector<ed::greasepencil::MutableDrawingInfo> get_drawings_for_stroke_operation(const bContext &C);
Vector<ed::greasepencil::MutableDrawingInfo> get_drawings_with_masking_for_stroke_operation(
const bContext &C);
/* Get the brush radius accounting for pen pressure. */
float brush_radius(const Scene &scene, const Brush &brush, float pressure);
@@ -118,15 +120,15 @@ struct GreasePencilStrokeParams {
};
/* Point index mask for a drawing based on selection tool settings. */
IndexMask point_selection_mask(const GreasePencilStrokeParams &params,
const bool use_masking,
IndexMaskMemory &memory);
IndexMask stroke_selection_mask(const GreasePencilStrokeParams &params,
const bool use_masking,
IndexMaskMemory &memory);
IndexMask fill_selection_mask(const GreasePencilStrokeParams &params,
const bool use_masking,
IndexMaskMemory &memory);
IndexMask point_mask_for_stroke_operation(const GreasePencilStrokeParams &params,
bool use_selection_masking,
IndexMaskMemory &memory);
IndexMask curve_mask_for_stroke_operation(const GreasePencilStrokeParams &params,
bool use_selection_masking,
IndexMaskMemory &memory);
IndexMask fill_mask_for_stroke_operation(const GreasePencilStrokeParams &params,
bool use_selection_masking,
IndexMaskMemory &memory);
bke::crazyspace::GeometryDeformation get_drawing_deformation(
const GreasePencilStrokeParams &params);
@@ -170,6 +172,13 @@ class GreasePencilStrokeOperationCommon : public GreasePencilStrokeOperation {
/** Previous mouse position for computing the direction. */
float2 prev_mouse_position;
/* When auto-masking is used, this contains the index mask of the elements that are affected. */
struct AutoMaskingInfo {
IndexMask point_mask;
IndexMaskMemory memory;
};
Array<AutoMaskingInfo> auto_masking_info_per_drawing;
GreasePencilStrokeOperationCommon() {}
GreasePencilStrokeOperationCommon(const BrushStrokeMode stroke_mode) : stroke_mode(stroke_mode)
{
@@ -179,18 +188,25 @@ class GreasePencilStrokeOperationCommon : public GreasePencilStrokeOperation {
float2 mouse_delta(const InputSample &input_sample) const;
void init_stroke(const bContext &C, const InputSample &start_sample);
void init_auto_masking(const bContext &C, const InputSample &start_sample);
void stroke_extended(const InputSample &extension_sample);
void foreach_editable_drawing_with_automask(
const bContext &C,
FunctionRef<bool(const GreasePencilStrokeParams &params, const IndexMask &points)> fn) const;
void foreach_editable_drawing_with_automask(
const bContext &C,
FunctionRef<bool(const GreasePencilStrokeParams &params,
const IndexMask &points,
const DeltaProjectionFunc &projection_fn)> fn) const;
/** Used in vertex paint mode. */
void foreach_editable_drawing(
const bContext &C, FunctionRef<bool(const GreasePencilStrokeParams &params)> fn) const;
void foreach_editable_drawing(
const bContext &C,
GrainSize grain_size,
FunctionRef<bool(const GreasePencilStrokeParams &params)> fn) const;
void foreach_editable_drawing(
const bContext &C,
FunctionRef<bool(const GreasePencilStrokeParams &params,
const DeltaProjectionFunc &projection_fn)> fn) const;
};
/* Operations */

View File

@@ -28,19 +28,32 @@
namespace blender::ed::sculpt_paint::greasepencil {
Vector<ed::greasepencil::MutableDrawingInfo> get_drawings_for_painting(const bContext &C)
Vector<ed::greasepencil::MutableDrawingInfo> get_drawings_for_stroke_operation(const bContext &C)
{
using namespace blender::bke::greasepencil;
const Scene &scene = *CTX_data_scene(&C);
Object &ob_orig = *CTX_data_active_object(&C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob_orig.data);
Paint &paint = *BKE_paint_get_active_from_context(&C);
const Brush &brush = *BKE_paint_brush(&paint);
const bool active_layer_only = ((brush.gpencil_settings->flag & GP_BRUSH_ACTIVE_LAYER_ONLY) !=
0);
if (active_layer_only) {
/* Apply to all editable drawings. */
return ed::greasepencil::retrieve_editable_drawings_with_falloff(scene, grease_pencil);
}
Vector<ed::greasepencil::MutableDrawingInfo> get_drawings_with_masking_for_stroke_operation(
const bContext &C)
{
using namespace blender::bke::greasepencil;
const Scene &scene = *CTX_data_scene(&C);
const ToolSettings &ts = *CTX_data_tool_settings(&C);
Object &ob_orig = *CTX_data_active_object(&C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob_orig.data);
const bool active_layer_masking = (ts.gp_sculpt.flag &
GP_SCULPT_SETT_FLAG_AUTOMASK_LAYER_ACTIVE) != 0;
if (active_layer_masking) {
/* Apply only to the drawing at the current frame of the active layer. */
if (!grease_pencil.has_active_layer()) {
return {};
@@ -293,35 +306,33 @@ GreasePencilStrokeParams GreasePencilStrokeParams::from_context(
drawing};
}
IndexMask point_selection_mask(const GreasePencilStrokeParams &params,
const bool use_masking,
IndexMaskMemory &memory)
IndexMask point_mask_for_stroke_operation(const GreasePencilStrokeParams &params,
const bool use_selection_masking,
IndexMaskMemory &memory)
{
return use_masking ? ed::greasepencil::retrieve_editable_and_selected_points(
params.ob_orig, params.drawing, params.layer_index, memory) :
ed::greasepencil::retrieve_editable_points(
params.ob_orig, params.drawing, params.layer_index, memory);
return use_selection_masking ? ed::greasepencil::retrieve_editable_and_selected_points(
params.ob_orig, params.drawing, params.layer_index, memory) :
ed::greasepencil::retrieve_editable_points(
params.ob_orig, params.drawing, params.layer_index, memory);
}
IndexMask stroke_selection_mask(const GreasePencilStrokeParams &params,
const bool use_masking,
IndexMaskMemory &memory)
IndexMask curve_mask_for_stroke_operation(const GreasePencilStrokeParams &params,
const bool use_selection_masking,
IndexMaskMemory &memory)
{
return use_masking ? ed::greasepencil::retrieve_editable_and_selected_strokes(
params.ob_orig, params.drawing, params.layer_index, memory) :
ed::greasepencil::retrieve_editable_strokes(
params.ob_orig, params.drawing, params.layer_index, memory);
return use_selection_masking ? ed::greasepencil::retrieve_editable_and_selected_strokes(
params.ob_orig, params.drawing, params.layer_index, memory) :
ed::greasepencil::retrieve_editable_strokes(
params.ob_orig, params.drawing, params.layer_index, memory);
}
IndexMask fill_selection_mask(const GreasePencilStrokeParams &params,
const bool use_masking,
IndexMaskMemory &memory)
IndexMask fill_mask_for_stroke_operation(const GreasePencilStrokeParams &params,
const bool use_selection_masking,
IndexMaskMemory &memory)
{
return use_masking ? ed::greasepencil::retrieve_editable_and_selected_fill_strokes(
params.ob_orig, params.drawing, params.layer_index, memory) :
params.drawing.strokes().curves_range();
return use_selection_masking ? ed::greasepencil::retrieve_editable_and_selected_fill_strokes(
params.ob_orig, params.drawing, params.layer_index, memory) :
params.drawing.strokes().curves_range();
}
bke::crazyspace::GeometryDeformation get_drawing_deformation(
@@ -395,6 +406,92 @@ float2 GreasePencilStrokeOperationCommon::mouse_delta(const InputSample &input_s
return input_sample.mouse_position - this->prev_mouse_position;
}
void GreasePencilStrokeOperationCommon::foreach_editable_drawing_with_automask(
const bContext &C,
FunctionRef<bool(const GreasePencilStrokeParams &params, const IndexMask &point_mask)> fn)
const
{
using namespace blender::bke::greasepencil;
const Scene &scene = *CTX_data_scene(&C);
Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(&C);
ARegion &region = *CTX_wm_region(&C);
RegionView3D &rv3d = *CTX_wm_region_view3d(&C);
Object &object = *CTX_data_active_object(&C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
std::atomic<bool> changed = false;
const Vector<MutableDrawingInfo> drawings = get_drawings_with_masking_for_stroke_operation(C);
for (const int64_t i : drawings.index_range()) {
const MutableDrawingInfo &info = drawings[i];
const AutoMaskingInfo &auto_mask_info = this->auto_masking_info_per_drawing[i];
GreasePencilStrokeParams params = GreasePencilStrokeParams::from_context(
scene,
depsgraph,
region,
rv3d,
object,
info.layer_index,
info.frame_number,
info.multi_frame_falloff,
info.drawing);
if (fn(params, auto_mask_info.point_mask)) {
changed = true;
}
}
if (changed) {
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(&C, NC_GEOM | ND_DATA, &grease_pencil);
}
}
void GreasePencilStrokeOperationCommon::foreach_editable_drawing_with_automask(
const bContext &C,
FunctionRef<bool(const GreasePencilStrokeParams &params,
const IndexMask &point_mask,
const DeltaProjectionFunc &projection_fn)> fn) const
{
using namespace blender::bke::greasepencil;
const Scene &scene = *CTX_data_scene(&C);
Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(&C);
ARegion &region = *CTX_wm_region(&C);
RegionView3D &rv3d = *CTX_wm_region_view3d(&C);
Object &object = *CTX_data_active_object(&C);
Object &object_eval = *DEG_get_evaluated_object(&depsgraph, &object);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
std::atomic<bool> changed = false;
const Vector<MutableDrawingInfo> drawings = get_drawings_with_masking_for_stroke_operation(C);
threading::parallel_for_each(drawings.index_range(), [&](const int i) {
const MutableDrawingInfo &info = drawings[i];
const Layer &layer = grease_pencil.layer(info.layer_index);
const AutoMaskingInfo &auto_mask_info = this->auto_masking_info_per_drawing[i];
const GreasePencilStrokeParams params = GreasePencilStrokeParams::from_context(
scene,
depsgraph,
region,
rv3d,
object,
info.layer_index,
info.frame_number,
info.multi_frame_falloff,
info.drawing);
const DeltaProjectionFunc projection_fn = get_screen_projection_fn(params, object_eval, layer);
if (fn(params, auto_mask_info.point_mask, projection_fn)) {
changed = true;
}
});
if (changed) {
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(&C, NC_GEOM | ND_DATA, &grease_pencil);
}
}
void GreasePencilStrokeOperationCommon::foreach_editable_drawing(
const bContext &C, FunctionRef<bool(const GreasePencilStrokeParams &params)> fn) const
{
@@ -407,8 +504,8 @@ void GreasePencilStrokeOperationCommon::foreach_editable_drawing(
Object &object = *CTX_data_active_object(&C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
std::atomic<bool> changed = false;
const Vector<MutableDrawingInfo> drawings = get_drawings_for_painting(C);
bool changed = false;
const Vector<MutableDrawingInfo> drawings = get_drawings_for_stroke_operation(C);
for (const int64_t i : drawings.index_range()) {
const MutableDrawingInfo &info = drawings[i];
GreasePencilStrokeParams params = GreasePencilStrokeParams::from_context(
@@ -447,7 +544,7 @@ void GreasePencilStrokeOperationCommon::foreach_editable_drawing(
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
std::atomic<bool> changed = false;
const Vector<MutableDrawingInfo> drawings = get_drawings_for_painting(C);
const Vector<MutableDrawingInfo> drawings = get_drawings_for_stroke_operation(C);
threading::parallel_for(drawings.index_range(), grain_size.value, [&](const IndexRange range) {
for (const int64_t i : range) {
const MutableDrawingInfo &info = drawings[i];
@@ -473,48 +570,6 @@ void GreasePencilStrokeOperationCommon::foreach_editable_drawing(
}
}
void GreasePencilStrokeOperationCommon::foreach_editable_drawing(
const bContext &C,
FunctionRef<bool(const GreasePencilStrokeParams &params,
const DeltaProjectionFunc &projection_fn)> fn) const
{
using namespace blender::bke::greasepencil;
const Scene &scene = *CTX_data_scene(&C);
Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(&C);
ARegion &region = *CTX_wm_region(&C);
RegionView3D &rv3d = *CTX_wm_region_view3d(&C);
Object &object = *CTX_data_active_object(&C);
Object &object_eval = *DEG_get_evaluated_object(&depsgraph, &object);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
std::atomic<bool> changed = false;
const Vector<MutableDrawingInfo> drawings = get_drawings_for_painting(C);
threading::parallel_for_each(drawings, [&](const MutableDrawingInfo &info) {
const Layer &layer = grease_pencil.layer(info.layer_index);
const GreasePencilStrokeParams params = GreasePencilStrokeParams::from_context(
scene,
depsgraph,
region,
rv3d,
object,
info.layer_index,
info.frame_number,
info.multi_frame_falloff,
info.drawing);
const DeltaProjectionFunc projection_fn = get_screen_projection_fn(params, object_eval, layer);
if (fn(params, projection_fn)) {
changed = true;
}
});
if (changed) {
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(&C, NC_GEOM | ND_DATA, &grease_pencil);
}
}
void GreasePencilStrokeOperationCommon::init_stroke(const bContext &C,
const InputSample &start_sample)
{
@@ -527,6 +582,150 @@ void GreasePencilStrokeOperationCommon::init_stroke(const bContext &C,
this->prev_mouse_position = start_sample.mouse_position;
}
void GreasePencilStrokeOperationCommon::init_auto_masking(const bContext &C,
const InputSample &start_sample)
{
const Scene &scene = *CTX_data_scene(&C);
ARegion &region = *CTX_wm_region(&C);
RegionView3D &rv3d = *CTX_wm_region_view3d(&C);
Object &object = *CTX_data_active_object(&C);
Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(&C);
Paint &paint = *BKE_paint_get_active_from_context(&C);
const Brush &brush = *BKE_paint_brush(&paint);
const eGP_Sculpt_SelectMaskFlag sculpt_selection_flag = eGP_Sculpt_SelectMaskFlag(
scene.toolsettings->gpencil_selectmode_sculpt);
const bool use_sculpt_selection_masking = (sculpt_selection_flag &
(GP_SCULPT_MASK_SELECTMODE_POINT |
GP_SCULPT_MASK_SELECTMODE_STROKE |
GP_SCULPT_MASK_SELECTMODE_SEGMENT)) != 0;
const eGP_Sculpt_SettingsFlag sculpt_settings_flag = eGP_Sculpt_SettingsFlag(
scene.toolsettings->gp_sculpt.flag);
const bool use_auto_mask_stroke = (sculpt_settings_flag & GP_SCULPT_SETT_FLAG_AUTOMASK_STROKE);
const bool use_auto_mask_layer = (sculpt_settings_flag &
GP_SCULPT_SETT_FLAG_AUTOMASK_LAYER_STROKE);
const bool use_auto_mask_material = (sculpt_settings_flag &
GP_SCULPT_SETT_FLAG_AUTOMASK_MATERIAL_STROKE);
const bool use_auto_mask_active_material = (sculpt_settings_flag &
GP_SCULPT_SETT_FLAG_AUTOMASK_MATERIAL_ACTIVE);
const float radius = brush_radius(scene, brush);
const int2 mval_i = int2(math::round(start_sample.mouse_position));
const int active_material_index = math::max(object.actcol - 1, 0);
const Vector<MutableDrawingInfo> drawings = get_drawings_with_masking_for_stroke_operation(C);
this->auto_masking_info_per_drawing.reinitialize(drawings.size());
VectorSet<int> masked_layer_indices;
VectorSet<int> masked_material_indices;
for (const int drawing_i : drawings.index_range()) {
const MutableDrawingInfo &drawing_info = drawings[drawing_i];
AutoMaskingInfo &automask_info = this->auto_masking_info_per_drawing[drawing_i];
GreasePencilStrokeParams params = GreasePencilStrokeParams::from_context(
scene,
depsgraph,
region,
rv3d,
object,
drawing_info.layer_index,
drawing_info.frame_number,
drawing_info.multi_frame_falloff,
drawing_info.drawing);
automask_info.point_mask = point_mask_for_stroke_operation(
params, use_sculpt_selection_masking, automask_info.memory);
if (automask_info.point_mask.is_empty()) {
continue;
}
const bke::CurvesGeometry &curves = drawing_info.drawing.strokes();
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
const bke::AttributeAccessor attributes = curves.attributes();
if (use_auto_mask_active_material) {
IndexMaskMemory memory;
const VArraySpan<int> materials = *attributes.lookup_or_default<int>(
"material_index", bke::AttrDomain::Point, 0);
const IndexMask active_material_mask = IndexMask::from_predicate(
curves.points_range(), GrainSize(4096), memory, [&](const int64_t point_i) {
return active_material_index == materials[point_i];
});
automask_info.point_mask = IndexMask::from_intersection(
automask_info.point_mask, active_material_mask, automask_info.memory);
if (automask_info.point_mask.is_empty()) {
continue;
}
}
if (use_auto_mask_layer || use_auto_mask_stroke || use_auto_mask_material) {
Array<float2> view_positions = calculate_view_positions(params, automask_info.point_mask);
IndexMaskMemory memory;
const IndexMask stroke_selection = curve_mask_for_stroke_operation(
params, use_sculpt_selection_masking, memory);
const IndexMask strokes_under_brush = IndexMask::from_predicate(
stroke_selection, GrainSize(512), memory, [&](const int curve_i) {
for (const int point_i : points_by_curve[curve_i]) {
const float distance = math::distance(mval_i, int2(view_positions[point_i]));
if (distance <= radius) {
return true;
}
}
return false;
});
if (use_auto_mask_layer && !strokes_under_brush.is_empty()) {
masked_layer_indices.add(drawing_info.layer_index);
}
if (use_auto_mask_stroke) {
automask_info.point_mask = IndexMask::from_intersection(
automask_info.point_mask,
IndexMask::from_ranges(curves.points_by_curve(), strokes_under_brush, memory),
automask_info.memory);
}
if (use_auto_mask_material) {
const VArraySpan<int> material_indices = *attributes.lookup<int>("material_index",
bke::AttrDomain::Curve);
strokes_under_brush.foreach_index(
[&](const int curve_i) { masked_material_indices.add(material_indices[curve_i]); });
}
}
}
/* When we mask by the initial strokes under the cursor, the other masking options don't affect
* the resulting mask. So we can skip the second loop. */
if (use_auto_mask_stroke) {
return;
}
threading::parallel_for_each(drawings.index_range(), [&](const int drawing_i) {
const MutableDrawingInfo &drawing_info = drawings[drawing_i];
AutoMaskingInfo &automask_info = this->auto_masking_info_per_drawing[drawing_i];
if (use_auto_mask_layer && !masked_layer_indices.contains(drawing_info.layer_index)) {
automask_info.point_mask = {};
return;
}
if (use_auto_mask_material) {
const bke::CurvesGeometry &curves = drawing_info.drawing.strokes();
const VArraySpan<int> material_indices = *curves.attributes().lookup<int>("material_index");
IndexMaskMemory memory;
const IndexMask masked_curves = IndexMask::from_predicate(
curves.curves_range(), GrainSize(1024), memory, [&](const int curve_i) {
return masked_material_indices.contains(material_indices[curve_i]);
});
automask_info.point_mask = IndexMask::from_intersection(
automask_info.point_mask,
IndexMask::from_ranges(curves.points_by_curve(), masked_curves, memory),
automask_info.memory);
}
});
}
void GreasePencilStrokeOperationCommon::stroke_extended(const InputSample &extension_sample)
{
this->prev_mouse_position = extension_sample.mouse_position;

View File

@@ -47,8 +47,11 @@ void CloneOperation::on_stroke_begin(const bContext &C, const InputSample &start
* - Continuous: Create multiple copies during the stroke (disabled)
*
* Here we only have the GPv2 behavior that actually works for now. */
this->foreach_editable_drawing(
C, [&](const GreasePencilStrokeParams &params, const DeltaProjectionFunc &projection_fn) {
this->foreach_editable_drawing_with_automask(
C,
[&](const GreasePencilStrokeParams &params,
const IndexMask & /*point_mask*/,
const DeltaProjectionFunc &projection_fn) {
/* Only insert on the active layer. */
if (&params.layer != grease_pencil.get_active_layer()) {
return false;

View File

@@ -127,17 +127,16 @@ void GrabOperation::on_stroke_begin(const bContext &C, const InputSample &start_
Object &ob_eval = *DEG_get_evaluated_object(&depsgraph, &ob_orig);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob_orig.data);
const bool is_masking = GPENCIL_ANY_SCULPT_MASK(
eGP_Sculpt_SelectMaskFlag(scene.toolsettings->gpencil_selectmode_sculpt));
init_brush(brush);
init_auto_masking(C, start_sample);
this->prev_mouse_position = start_sample.mouse_position;
const Vector<MutableDrawingInfo> drawings = get_drawings_for_painting(C);
const Vector<MutableDrawingInfo> drawings = get_drawings_with_masking_for_stroke_operation(C);
this->drawing_data.reinitialize(drawings.size());
threading::parallel_for_each(drawings.index_range(), [&](const int i) {
const MutableDrawingInfo &info = drawings[i];
const AutoMaskingInfo &auto_mask_info = this->auto_masking_info_per_drawing[i];
BLI_assert(info.layer_index >= 0);
PointWeights &data = this->drawing_data[i];
@@ -155,10 +154,8 @@ void GrabOperation::on_stroke_begin(const bContext &C, const InputSample &start_
info.frame_number,
info.multi_frame_falloff,
info.drawing};
IndexMaskMemory selection_memory;
IndexMask selection = point_selection_mask(params, is_masking, selection_memory);
Array<float2> view_positions = calculate_view_positions(params, selection);
Array<float2> view_positions = calculate_view_positions(params, auto_mask_info.point_mask);
/* Cache points under brush influence. */
Vector<float> weights;
@@ -167,7 +164,7 @@ void GrabOperation::on_stroke_begin(const bContext &C, const InputSample &start_
start_sample.mouse_position,
1.0f,
info.multi_frame_falloff,
selection,
auto_mask_info.point_mask,
view_positions,
weights,
data.memory);

View File

@@ -33,6 +33,7 @@ class PinchOperation : public GreasePencilStrokeOperationCommon {
void PinchOperation::on_stroke_begin(const bContext &C, const InputSample &start_sample)
{
this->init_stroke(C, start_sample);
this->init_auto_masking(C, start_sample);
}
void PinchOperation::on_stroke_extended(const bContext &C, const InputSample &extension_sample)
@@ -41,25 +42,20 @@ void PinchOperation::on_stroke_extended(const bContext &C, const InputSample &ex
Paint &paint = *BKE_paint_get_active_from_context(&C);
const Brush &brush = *BKE_paint_brush(&paint);
const bool invert = this->is_inverted(brush);
const bool is_masking = GPENCIL_ANY_SCULPT_MASK(
eGP_Sculpt_SelectMaskFlag(scene.toolsettings->gpencil_selectmode_sculpt));
this->foreach_editable_drawing(
C, [&](const GreasePencilStrokeParams &params, const DeltaProjectionFunc &projection_fn) {
IndexMaskMemory selection_memory;
const IndexMask selection = point_selection_mask(params, is_masking, selection_memory);
if (selection.is_empty()) {
return false;
}
this->foreach_editable_drawing_with_automask(
C,
[&](const GreasePencilStrokeParams &params,
const IndexMask &point_mask,
const DeltaProjectionFunc &projection_fn) {
bke::crazyspace::GeometryDeformation deformation = get_drawing_deformation(params);
Array<float2> view_positions = calculate_view_positions(params, selection);
Array<float2> view_positions = calculate_view_positions(params, point_mask);
bke::CurvesGeometry &curves = params.drawing.strokes_for_write();
MutableSpan<float3> positions = curves.positions_for_write();
const float2 target = extension_sample.mouse_position;
selection.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
point_mask.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
const float2 &co = view_positions[point_i];
const float influence = brush_point_influence(
scene, brush, co, extension_sample, params.multi_frame_falloff);

View File

@@ -33,6 +33,7 @@ class PushOperation : public GreasePencilStrokeOperationCommon {
void PushOperation::on_stroke_begin(const bContext &C, const InputSample &start_sample)
{
this->init_stroke(C, start_sample);
this->init_auto_masking(C, start_sample);
}
void PushOperation::on_stroke_extended(const bContext &C, const InputSample &extension_sample)
@@ -41,25 +42,19 @@ void PushOperation::on_stroke_extended(const bContext &C, const InputSample &ext
Paint &paint = *BKE_paint_get_active_from_context(&C);
const Brush &brush = *BKE_paint_brush(&paint);
const bool is_masking = GPENCIL_ANY_SCULPT_MASK(
eGP_Sculpt_SelectMaskFlag(scene.toolsettings->gpencil_selectmode_sculpt));
this->foreach_editable_drawing(
C, [&](const GreasePencilStrokeParams &params, const DeltaProjectionFunc &projection_fn) {
IndexMaskMemory selection_memory;
const IndexMask selection = point_selection_mask(params, is_masking, selection_memory);
if (selection.is_empty()) {
return false;
}
this->foreach_editable_drawing_with_automask(
C,
[&](const GreasePencilStrokeParams &params,
const IndexMask &point_mask,
const DeltaProjectionFunc &projection_fn) {
bke::crazyspace::GeometryDeformation deformation = get_drawing_deformation(params);
Array<float2> view_positions = calculate_view_positions(params, selection);
Array<float2> view_positions = calculate_view_positions(params, point_mask);
bke::CurvesGeometry &curves = params.drawing.strokes_for_write();
MutableSpan<float3> positions = curves.positions_for_write();
const float2 mouse_delta = this->mouse_delta(extension_sample);
selection.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
point_mask.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
const float2 &co = view_positions[point_i];
const float influence = brush_point_influence(
scene, brush, co, extension_sample, params.multi_frame_falloff);

View File

@@ -53,6 +53,7 @@ uint32_t RandomizeOperation::unique_seed() const
void RandomizeOperation::on_stroke_begin(const bContext &C, const InputSample &start_sample)
{
this->init_stroke(C, start_sample);
this->init_auto_masking(C, start_sample);
}
void RandomizeOperation::on_stroke_extended(const bContext &C, const InputSample &extension_sample)
@@ -62,21 +63,15 @@ void RandomizeOperation::on_stroke_extended(const bContext &C, const InputSample
const Brush &brush = *BKE_paint_brush(&paint);
const int sculpt_mode_flag = brush.gpencil_settings->sculpt_mode_flag;
const bool is_masking = GPENCIL_ANY_SCULPT_MASK(
eGP_Sculpt_SelectMaskFlag(scene.toolsettings->gpencil_selectmode_sculpt));
this->foreach_editable_drawing(
C, [&](const GreasePencilStrokeParams &params, const DeltaProjectionFunc &projection_fn) {
this->foreach_editable_drawing_with_automask(
C,
[&](const GreasePencilStrokeParams &params,
const IndexMask &point_mask,
const DeltaProjectionFunc &projection_fn) {
const uint32_t seed = this->unique_seed();
IndexMaskMemory selection_memory;
const IndexMask selection = point_selection_mask(params, is_masking, selection_memory);
if (selection.is_empty()) {
return false;
}
bke::crazyspace::GeometryDeformation deformation = get_drawing_deformation(params);
Array<float2> view_positions = calculate_view_positions(params, selection);
Array<float2> view_positions = calculate_view_positions(params, point_mask);
bke::CurvesGeometry &curves = params.drawing.strokes_for_write();
bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
@@ -88,7 +83,7 @@ void RandomizeOperation::on_stroke_extended(const bContext &C, const InputSample
const float2 forward = math::normalize(this->mouse_delta(extension_sample));
const float2 sideways = float2(-forward.y, forward.x);
selection.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
point_mask.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
const float2 &co = view_positions[point_i];
const float influence = brush_point_influence(
scene, brush, co, extension_sample, params.multi_frame_falloff);
@@ -105,7 +100,7 @@ void RandomizeOperation::on_stroke_extended(const bContext &C, const InputSample
}
if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_STRENGTH) {
MutableSpan<float> opacities = params.drawing.opacities_for_write();
selection.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
point_mask.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
const float2 &co = view_positions[point_i];
const float influence = brush_point_influence(
scene, brush, co, extension_sample, params.multi_frame_falloff);
@@ -119,7 +114,7 @@ void RandomizeOperation::on_stroke_extended(const bContext &C, const InputSample
}
if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_THICKNESS) {
const MutableSpan<float> radii = params.drawing.radii_for_write();
selection.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
point_mask.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
const float2 &co = view_positions[point_i];
const float influence = brush_point_influence(
scene, brush, co, extension_sample, params.multi_frame_falloff);
@@ -135,7 +130,7 @@ void RandomizeOperation::on_stroke_extended(const bContext &C, const InputSample
if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_UV) {
bke::SpanAttributeWriter<float> rotations =
attributes.lookup_or_add_for_write_span<float>("rotation", bke::AttrDomain::Point);
selection.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
point_mask.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
const float2 &co = view_positions[point_i];
const float influence = brush_point_influence(
scene, brush, co, extension_sample, params.multi_frame_falloff);

View File

@@ -57,6 +57,7 @@ void SmoothOperation::on_stroke_begin(const bContext &C, const InputSample &star
else {
this->init_stroke(C, start_sample);
}
this->init_auto_masking(C, start_sample);
}
void SmoothOperation::on_stroke_extended(const bContext &C, const InputSample &extension_sample)
@@ -74,91 +75,86 @@ void SmoothOperation::on_stroke_extended(const bContext &C, const InputSample &e
}();
const int sculpt_mode_flag = brush.gpencil_settings->sculpt_mode_flag;
const bool is_masking = GPENCIL_ANY_SCULPT_MASK(
eGP_Sculpt_SelectMaskFlag(scene.toolsettings->gpencil_selectmode_sculpt));
this->foreach_editable_drawing_with_automask(
C, [&](const GreasePencilStrokeParams &params, const IndexMask &point_mask) {
Array<float2> view_positions = calculate_view_positions(params, point_mask);
bke::CurvesGeometry &curves = params.drawing.strokes_for_write();
bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
const OffsetIndices points_by_curve = curves.points_by_curve();
const VArray<bool> cyclic = curves.cyclic();
const int iterations = 2;
this->foreach_editable_drawing(C, [&](const GreasePencilStrokeParams &params) {
IndexMaskMemory selection_memory;
const IndexMask selection = point_selection_mask(params, is_masking, selection_memory);
if (selection.is_empty()) {
return false;
}
const VArray<float> influences = VArray<float>::ForFunc(
view_positions.size(), [&](const int64_t point_) {
return brush_point_influence(scene,
brush,
view_positions[point_],
extension_sample,
params.multi_frame_falloff);
});
Array<bool> selection_array(curves.points_num());
point_mask.to_bools(selection_array);
const VArray<bool> selection_varray = VArray<bool>::ForSpan(selection_array);
Array<float2> view_positions = calculate_view_positions(params, selection);
bke::CurvesGeometry &curves = params.drawing.strokes_for_write();
bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
const OffsetIndices points_by_curve = curves.points_by_curve();
const VArray<bool> cyclic = curves.cyclic();
const int iterations = 2;
const VArray<float> influences = VArray<float>::ForFunc(
view_positions.size(), [&](const int64_t point_) {
return brush_point_influence(
scene, brush, view_positions[point_], extension_sample, params.multi_frame_falloff);
});
Array<bool> selection_array(curves.points_num());
selection.to_bools(selection_array);
const VArray<bool> selection_varray = VArray<bool>::ForSpan(selection_array);
bool changed = false;
if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_POSITION) {
MutableSpan<float3> positions = curves.positions_for_write();
geometry::smooth_curve_attribute(curves.curves_range(),
points_by_curve,
selection_varray,
cyclic,
iterations,
influences,
false,
false,
positions);
params.drawing.tag_positions_changed();
changed = true;
}
if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_STRENGTH) {
MutableSpan<float> opacities = params.drawing.opacities_for_write();
geometry::smooth_curve_attribute(curves.curves_range(),
points_by_curve,
selection_varray,
cyclic,
iterations,
influences,
true,
false,
opacities);
changed = true;
}
if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_THICKNESS) {
const MutableSpan<float> radii = params.drawing.radii_for_write();
geometry::smooth_curve_attribute(curves.curves_range(),
points_by_curve,
selection_varray,
cyclic,
iterations,
influences,
true,
false,
radii);
curves.tag_radii_changed();
changed = true;
}
if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_UV) {
bke::SpanAttributeWriter<float> rotations = attributes.lookup_or_add_for_write_span<float>(
"rotation", bke::AttrDomain::Point);
geometry::smooth_curve_attribute(curves.curves_range(),
points_by_curve,
selection_varray,
cyclic,
iterations,
influences,
true,
false,
rotations.span);
rotations.finish();
changed = true;
}
return changed;
});
bool changed = false;
if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_POSITION) {
MutableSpan<float3> positions = curves.positions_for_write();
geometry::smooth_curve_attribute(curves.curves_range(),
points_by_curve,
selection_varray,
cyclic,
iterations,
influences,
false,
false,
positions);
params.drawing.tag_positions_changed();
changed = true;
}
if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_STRENGTH) {
MutableSpan<float> opacities = params.drawing.opacities_for_write();
geometry::smooth_curve_attribute(curves.curves_range(),
points_by_curve,
selection_varray,
cyclic,
iterations,
influences,
true,
false,
opacities);
changed = true;
}
if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_THICKNESS) {
const MutableSpan<float> radii = params.drawing.radii_for_write();
geometry::smooth_curve_attribute(curves.curves_range(),
points_by_curve,
selection_varray,
cyclic,
iterations,
influences,
true,
false,
radii);
curves.tag_radii_changed();
changed = true;
}
if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_UV) {
bke::SpanAttributeWriter<float> rotations =
attributes.lookup_or_add_for_write_span<float>("rotation", bke::AttrDomain::Point);
geometry::smooth_curve_attribute(curves.curves_range(),
points_by_curve,
selection_varray,
cyclic,
iterations,
influences,
true,
false,
rotations.span);
rotations.finish();
changed = true;
}
return changed;
});
this->stroke_extended(extension_sample);
}

View File

@@ -34,6 +34,7 @@ class StrengthOperation : public GreasePencilStrokeOperationCommon {
void StrengthOperation::on_stroke_begin(const bContext &C, const InputSample &start_sample)
{
this->init_stroke(C, start_sample);
this->init_auto_masking(C, start_sample);
}
void StrengthOperation::on_stroke_extended(const bContext &C, const InputSample &extension_sample)
@@ -43,30 +44,22 @@ void StrengthOperation::on_stroke_extended(const bContext &C, const InputSample
const Brush &brush = *BKE_paint_brush(&paint);
const bool invert = this->is_inverted(brush);
const bool is_masking = GPENCIL_ANY_SCULPT_MASK(
eGP_Sculpt_SelectMaskFlag(scene.toolsettings->gpencil_selectmode_sculpt));
this->foreach_editable_drawing_with_automask(
C, [&](const GreasePencilStrokeParams &params, const IndexMask &point_mask) {
Array<float2> view_positions = calculate_view_positions(params, point_mask);
MutableSpan<float> opacities = params.drawing.opacities_for_write();
this->foreach_editable_drawing(C, [&](const GreasePencilStrokeParams &params) {
IndexMaskMemory selection_memory;
const IndexMask selection = point_selection_mask(params, is_masking, selection_memory);
if (selection.is_empty()) {
return false;
}
point_mask.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
float &opacity = opacities[point_i];
const float influence = brush_point_influence(
scene, brush, view_positions[point_i], extension_sample, params.multi_frame_falloff);
/* Brush influence mapped to opacity by a factor of 0.125. */
const float delta_opacity = (invert ? -influence : influence) * 0.125f;
opacity = std::clamp(opacity + delta_opacity, 0.0f, 1.0f);
});
Array<float2> view_positions = calculate_view_positions(params, selection);
MutableSpan<float> opacities = params.drawing.opacities_for_write();
selection.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
float &opacity = opacities[point_i];
const float influence = brush_point_influence(
scene, brush, view_positions[point_i], extension_sample, params.multi_frame_falloff);
/* Brush influence mapped to opacity by a factor of 0.125. */
const float delta_opacity = (invert ? -influence : influence) * 0.125f;
opacity = std::clamp(opacity + delta_opacity, 0.0f, 1.0f);
});
return true;
});
return true;
});
this->stroke_extended(extension_sample);
}

View File

@@ -34,6 +34,7 @@ class ThicknessOperation : public GreasePencilStrokeOperationCommon {
void ThicknessOperation::on_stroke_begin(const bContext &C, const InputSample &start_sample)
{
this->init_stroke(C, start_sample);
this->init_auto_masking(C, start_sample);
}
void ThicknessOperation::on_stroke_extended(const bContext &C, const InputSample &extension_sample)
@@ -43,33 +44,25 @@ void ThicknessOperation::on_stroke_extended(const bContext &C, const InputSample
const Brush &brush = *BKE_paint_brush(&paint);
const bool invert = this->is_inverted(brush);
const bool is_masking = GPENCIL_ANY_SCULPT_MASK(
eGP_Sculpt_SelectMaskFlag(scene.toolsettings->gpencil_selectmode_sculpt));
this->foreach_editable_drawing_with_automask(
C, [&](const GreasePencilStrokeParams &params, const IndexMask &point_mask) {
Array<float2> view_positions = calculate_view_positions(params, point_mask);
bke::CurvesGeometry &curves = params.drawing.strokes_for_write();
BLI_assert(view_positions.size() == curves.points_num());
MutableSpan<float> radii = params.drawing.radii_for_write();
this->foreach_editable_drawing(C, [&](const GreasePencilStrokeParams &params) {
IndexMaskMemory selection_memory;
const IndexMask selection = point_selection_mask(params, is_masking, selection_memory);
if (selection.is_empty()) {
return false;
}
point_mask.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
float &radius = radii[point_i];
const float influence = brush_point_influence(
scene, brush, view_positions[point_i], extension_sample, params.multi_frame_falloff);
/* Factor 1/1000 is used to map arbitrary influence value to a sensible radius. */
const float delta_radius = (invert ? -influence : influence) * 0.001f;
radius = std::max(radius + delta_radius, 0.0f);
});
Array<float2> view_positions = calculate_view_positions(params, selection);
bke::CurvesGeometry &curves = params.drawing.strokes_for_write();
BLI_assert(view_positions.size() == curves.points_num());
MutableSpan<float> radii = params.drawing.radii_for_write();
selection.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
float &radius = radii[point_i];
const float influence = brush_point_influence(
scene, brush, view_positions[point_i], extension_sample, params.multi_frame_falloff);
/* Factor 1/1000 is used to map arbitrary influence value to a sensible radius. */
const float delta_radius = (invert ? -influence : influence) * 0.001f;
radius = std::max(radius + delta_radius, 0.0f);
});
curves.tag_radii_changed();
return true;
});
curves.tag_radii_changed();
return true;
});
this->stroke_extended(extension_sample);
}

View File

@@ -42,6 +42,7 @@ static float2 rotate_by_angle(const float2 &vec, const float angle)
void TwistOperation::on_stroke_begin(const bContext &C, const InputSample &start_sample)
{
this->init_stroke(C, start_sample);
this->init_auto_masking(C, start_sample);
}
void TwistOperation::on_stroke_extended(const bContext &C, const InputSample &extension_sample)
@@ -51,25 +52,19 @@ void TwistOperation::on_stroke_extended(const bContext &C, const InputSample &ex
const Brush &brush = *BKE_paint_brush(&paint);
const bool invert = this->is_inverted(brush);
const bool is_masking = GPENCIL_ANY_SCULPT_MASK(
eGP_Sculpt_SelectMaskFlag(scene.toolsettings->gpencil_selectmode_sculpt));
this->foreach_editable_drawing(
C, [&](const GreasePencilStrokeParams &params, const DeltaProjectionFunc &projection_fn) {
IndexMaskMemory selection_memory;
const IndexMask selection = point_selection_mask(params, is_masking, selection_memory);
if (selection.is_empty()) {
return false;
}
this->foreach_editable_drawing_with_automask(
C,
[&](const GreasePencilStrokeParams &params,
const IndexMask &point_mask,
const DeltaProjectionFunc &projection_fn) {
bke::crazyspace::GeometryDeformation deformation = get_drawing_deformation(params);
Array<float2> view_positions = calculate_view_positions(params, selection);
Array<float2> view_positions = calculate_view_positions(params, point_mask);
bke::CurvesGeometry &curves = params.drawing.strokes_for_write();
MutableSpan<float3> positions = curves.positions_for_write();
const float2 mouse_pos = extension_sample.mouse_position;
selection.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
point_mask.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
const float2 &co = view_positions[point_i];
const float influence = brush_point_influence(
scene, brush, co, extension_sample, params.multi_frame_falloff);

View File

@@ -38,7 +38,7 @@ void VertexAverageOperation::on_stroke_extended(const bContext &C,
const float radius = brush_radius(scene, brush, extension_sample.pressure);
const float radius_squared = radius * radius;
const bool is_masking = GPENCIL_ANY_VERTEX_MASK(
const bool use_selection_masking = GPENCIL_ANY_VERTEX_MASK(
eGP_vertex_SelectMaskFlag(scene.toolsettings->gpencil_selectmode_vertex));
const bool do_points = do_vertex_color_points(brush);
@@ -49,7 +49,8 @@ void VertexAverageOperation::on_stroke_extended(const bContext &C,
int color_count = 0;
this->foreach_editable_drawing(C, [&](const GreasePencilStrokeParams &params) {
IndexMaskMemory memory;
const IndexMask point_selection = point_selection_mask(params, is_masking, memory);
const IndexMask point_selection = point_mask_for_stroke_operation(
params, use_selection_masking, memory);
if (!point_selection.is_empty() && do_points) {
const Array<float2> view_positions = calculate_view_positions(params, point_selection);
const VArray<ColorGeometry4f> vertex_colors = params.drawing.vertex_colors();
@@ -64,7 +65,8 @@ void VertexAverageOperation::on_stroke_extended(const bContext &C,
}
});
}
const IndexMask fill_selection = fill_selection_mask(params, is_masking, memory);
const IndexMask fill_selection = fill_mask_for_stroke_operation(
params, use_selection_masking, memory);
if (!fill_selection.is_empty() && do_fill) {
const OffsetIndices<int> points_by_curve = params.drawing.strokes().points_by_curve();
const Array<float2> view_positions = calculate_view_positions(params, point_selection);
@@ -94,7 +96,8 @@ void VertexAverageOperation::on_stroke_extended(const bContext &C,
this->foreach_editable_drawing(C, GrainSize(1), [&](const GreasePencilStrokeParams &params) {
IndexMaskMemory memory;
const IndexMask point_selection = point_selection_mask(params, is_masking, memory);
const IndexMask point_selection = point_mask_for_stroke_operation(
params, use_selection_masking, memory);
if (!point_selection.is_empty() && do_points) {
const Array<float2> view_positions = calculate_view_positions(params, point_selection);
MutableSpan<ColorGeometry4f> vertex_colors = params.drawing.vertex_colors_for_write();
@@ -108,7 +111,8 @@ void VertexAverageOperation::on_stroke_extended(const bContext &C,
});
}
const IndexMask fill_selection = fill_selection_mask(params, is_masking, memory);
const IndexMask fill_selection = fill_mask_for_stroke_operation(
params, use_selection_masking, memory);
if (!fill_selection.is_empty() && do_fill) {
const OffsetIndices<int> points_by_curve = params.drawing.strokes().points_by_curve();
const Array<float2> view_positions = calculate_view_positions(params, point_selection);

View File

@@ -38,16 +38,18 @@ void VertexBlurOperation::on_stroke_extended(const bContext &C,
const float radius = brush_radius(scene, brush, extension_sample.pressure);
const float radius_squared = radius * radius;
const bool is_masking = GPENCIL_ANY_VERTEX_MASK(
const bool use_selection_masking = GPENCIL_ANY_VERTEX_MASK(
eGP_vertex_SelectMaskFlag(scene.toolsettings->gpencil_selectmode_vertex));
this->foreach_editable_drawing(C, GrainSize(1), [&](const GreasePencilStrokeParams &params) {
IndexMaskMemory memory;
const IndexMask stroke_selection = stroke_selection_mask(params, is_masking, memory);
const IndexMask stroke_selection = curve_mask_for_stroke_operation(
params, use_selection_masking, memory);
if (stroke_selection.is_empty()) {
return false;
}
const IndexMask point_selection = point_selection_mask(params, is_masking, memory);
const IndexMask point_selection = point_mask_for_stroke_operation(
params, use_selection_masking, memory);
const Array<float2> view_positions = calculate_view_positions(params, point_selection);
const OffsetIndices<int> points_by_curve = params.drawing.strokes().points_by_curve();
MutableSpan<ColorGeometry4f> vertex_colors = params.drawing.vertex_colors_for_write();

View File

@@ -39,7 +39,7 @@ void VertexPaintOperation::on_stroke_extended(const bContext &C,
const Brush &brush = *BKE_paint_brush(&paint);
const bool invert = this->is_inverted(brush);
const bool is_masking = GPENCIL_ANY_VERTEX_MASK(
const bool use_selection_masking = GPENCIL_ANY_VERTEX_MASK(
eGP_vertex_SelectMaskFlag(scene.toolsettings->gpencil_selectmode_vertex));
const bool do_points = do_vertex_color_points(brush);
@@ -51,7 +51,8 @@ void VertexPaintOperation::on_stroke_extended(const bContext &C,
this->foreach_editable_drawing(C, GrainSize(1), [&](const GreasePencilStrokeParams &params) {
IndexMaskMemory memory;
const IndexMask point_selection = point_selection_mask(params, is_masking, memory);
const IndexMask point_selection = point_mask_for_stroke_operation(
params, use_selection_masking, memory);
if (!point_selection.is_empty() && do_points) {
Array<float2> view_positions = calculate_view_positions(params, point_selection);
MutableSpan<ColorGeometry4f> vertex_colors = params.drawing.vertex_colors_for_write();
@@ -79,7 +80,8 @@ void VertexPaintOperation::on_stroke_extended(const bContext &C,
}
}
const IndexMask fill_selection = fill_selection_mask(params, is_masking, memory);
const IndexMask fill_selection = fill_mask_for_stroke_operation(
params, use_selection_masking, memory);
if (!fill_selection.is_empty() && do_fill) {
const OffsetIndices<int> points_by_curve = params.drawing.strokes().points_by_curve();
Array<float2> view_positions = calculate_view_positions(params, point_selection);

View File

@@ -36,7 +36,7 @@ void VertexReplaceOperation::on_stroke_extended(const bContext &C,
Paint &paint = *BKE_paint_get_active_from_context(&C);
const Brush &brush = *BKE_paint_brush(&paint);
const bool is_masking = GPENCIL_ANY_VERTEX_MASK(
const bool use_selection_masking = GPENCIL_ANY_VERTEX_MASK(
eGP_vertex_SelectMaskFlag(scene.toolsettings->gpencil_selectmode_vertex));
const bool do_points = do_vertex_color_points(brush);
@@ -48,7 +48,8 @@ void VertexReplaceOperation::on_stroke_extended(const bContext &C,
this->foreach_editable_drawing(C, GrainSize(1), [&](const GreasePencilStrokeParams &params) {
IndexMaskMemory memory;
const IndexMask point_selection = point_selection_mask(params, is_masking, memory);
const IndexMask point_selection = point_mask_for_stroke_operation(
params, use_selection_masking, memory);
if (!point_selection.is_empty() && do_points) {
Array<float2> view_positions = calculate_view_positions(params, point_selection);
MutableSpan<ColorGeometry4f> vertex_colors = params.drawing.vertex_colors_for_write();
@@ -61,7 +62,8 @@ void VertexReplaceOperation::on_stroke_extended(const bContext &C,
});
}
const IndexMask fill_selection = fill_selection_mask(params, is_masking, memory);
const IndexMask fill_selection = fill_mask_for_stroke_operation(
params, use_selection_masking, memory);
if (!fill_selection.is_empty() && do_fill) {
const OffsetIndices<int> points_by_curve = params.drawing.strokes().points_by_curve();
Array<float2> view_positions = calculate_view_positions(params, point_selection);

View File

@@ -71,7 +71,7 @@ void VertexSmearOperation::init_color_grid(const bContext &C, const float2 start
const Scene &scene = *CTX_data_scene(&C);
Paint &paint = *BKE_paint_get_active_from_context(&C);
const Brush &brush = *BKE_paint_brush(&paint);
const bool is_masking = GPENCIL_ANY_VERTEX_MASK(
const bool use_selection_masking = GPENCIL_ANY_VERTEX_MASK(
eGP_vertex_SelectMaskFlag(scene.toolsettings->gpencil_selectmode_vertex));
const float radius = brush_radius(scene, brush, 1.0f);
@@ -89,7 +89,8 @@ void VertexSmearOperation::init_color_grid(const bContext &C, const float2 start
/* Initialize grid values. */
this->foreach_editable_drawing(C, [&](const GreasePencilStrokeParams &params) {
IndexMaskMemory memory;
const IndexMask point_selection = point_selection_mask(params, is_masking, memory);
const IndexMask point_selection = point_mask_for_stroke_operation(
params, use_selection_masking, memory);
if (point_selection.is_empty()) {
return false;
}
@@ -154,12 +155,13 @@ void VertexSmearOperation::on_stroke_extended(const bContext &C,
const Brush &brush = *BKE_paint_brush(&paint);
const float radius = brush_radius(scene, brush, extension_sample.pressure);
const bool is_masking = GPENCIL_ANY_VERTEX_MASK(
const bool use_selection_masking = GPENCIL_ANY_VERTEX_MASK(
eGP_vertex_SelectMaskFlag(scene.toolsettings->gpencil_selectmode_vertex));
this->foreach_editable_drawing(C, GrainSize(1), [&](const GreasePencilStrokeParams &params) {
IndexMaskMemory memory;
const IndexMask point_selection = point_selection_mask(params, is_masking, memory);
const IndexMask point_selection = point_mask_for_stroke_operation(
params, use_selection_masking, memory);
if (point_selection.is_empty()) {
return false;
}