Blender V5.0
grease_pencil_paint_common.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BKE_brush.hh"
6#include "BKE_colortools.hh"
7#include "BKE_context.hh"
8#include "BKE_crazyspace.hh"
9#include "BKE_curves.hh"
10#include "BKE_grease_pencil.hh"
11#include "BKE_paint.hh"
12
13#include "BLI_array_utils.hh"
14#include "BLI_index_mask.hh"
15#include "BLI_math_vector.hh"
16#include "BLI_task.hh"
17
19
20#include "DNA_brush_types.h"
21#include "DNA_screen_types.h"
22#include "DNA_view3d_types.h"
23
24#include "ED_grease_pencil.hh"
25#include "ED_view3d.hh"
26
28
30
32{
33 using namespace blender::bke::greasepencil;
34
35 const Scene &scene = *CTX_data_scene(&C);
36 Object &ob_orig = *CTX_data_active_object(&C);
37 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob_orig.data);
38
39 /* Apply to all editable drawings. */
41}
42
44 const bContext &C)
45{
46 using namespace blender::bke::greasepencil;
47
48 const Scene &scene = *CTX_data_scene(&C);
50 Object &ob_orig = *CTX_data_active_object(&C);
51 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob_orig.data);
52
53 const bool active_layer_masking = (ts.gp_sculpt.flag &
55
56 if (active_layer_masking) {
57 /* Apply only to the drawing at the current frame of the active layer. */
58 if (!grease_pencil.has_active_layer()) {
59 return {};
60 }
61 const Layer &active_layer = *grease_pencil.get_active_layer();
63 scene, grease_pencil, active_layer);
64 }
65
66 /* Apply to all editable drawings. */
68}
69
71{
72 if (brush.gpencil_settings == nullptr) {
74 }
75 BLI_assert(brush.gpencil_settings != nullptr);
76 BKE_curvemapping_init(brush.curve_distance_falloff);
77 BKE_curvemapping_init(brush.gpencil_settings->curve_strength);
78 BKE_curvemapping_init(brush.gpencil_settings->curve_sensitivity);
79 BKE_curvemapping_init(brush.gpencil_settings->curve_jitter);
80 BKE_curvemapping_init(brush.gpencil_settings->curve_rand_pressure);
81 BKE_curvemapping_init(brush.gpencil_settings->curve_rand_strength);
82 BKE_curvemapping_init(brush.gpencil_settings->curve_rand_uv);
83 BKE_curvemapping_init(brush.curve_rand_hue);
84 BKE_curvemapping_init(brush.curve_rand_saturation);
85 BKE_curvemapping_init(brush.curve_rand_value);
86}
87
88float brush_radius(const Paint &paint, const Brush &brush, const float pressure = 1.0f)
89{
90 float radius = BKE_brush_radius_get(&paint, &brush);
92 radius *= BKE_curvemapping_evaluateF(brush.gpencil_settings->curve_sensitivity, 0, pressure);
93 }
94 return radius;
95}
96
98 const Brush &brush,
99 const float2 &co,
100 const InputSample &sample,
101 const float multi_frame_falloff)
102{
103 const float radius = brush_radius(paint, brush, sample.pressure);
104 /* Basic strength factor from brush settings. */
105 const float brush_pressure = BKE_brush_use_alpha_pressure(&brush) ? sample.pressure : 1.0f;
106 const float influence_base = BKE_brush_alpha_get(&paint, &brush) * brush_pressure *
107 multi_frame_falloff;
108
109 /* Distance falloff. */
110 const float distance = math::distance(sample.mouse_position, co);
111 /* Apply Brush curve. */
112 const float brush_falloff = BKE_brush_curve_strength(&brush, distance, radius);
113
114 return influence_base * brush_falloff;
115}
116
118{
119 int j = verts.size() - 1;
120 bool isect = false;
121 float distance = FLT_MAX;
122 for (int i = 0; i < verts.size(); i++) {
123 /* Based on implementation of #isect_point_poly_v2. */
124 if (((verts[i].y > pt.y) != (verts[j].y > pt.y)) &&
125 (pt.x <
126 (verts[j].x - verts[i].x) * (pt.y - verts[i].y) / (verts[j].y - verts[i].y) + verts[i].x))
127 {
128 isect = !isect;
129 }
131 j = i;
132 }
133 return isect ? 0.0f : distance;
134}
135
137 const Brush &brush,
138 const Span<float2> fill_positions,
139 const InputSample &sample,
140 const float multi_frame_falloff)
141{
142 const float radius = brush_radius(paint, brush, sample.pressure);
143 /* Basic strength factor from brush settings. */
144 const float brush_pressure = BKE_brush_use_alpha_pressure(&brush) ? sample.pressure : 1.0f;
145 const float influence_base = BKE_brush_alpha_get(&paint, &brush) * brush_pressure *
146 multi_frame_falloff;
147
148 /* Distance falloff. */
149 const float distance = closest_distance_to_surface_2d(sample.mouse_position, fill_positions);
150 /* Apply Brush curve. */
151 const float brush_falloff = BKE_brush_curve_strength(&brush, distance, radius);
152
153 return influence_base * brush_falloff;
154}
155
157 const Brush &brush,
158 const float2 &mouse_position,
159 const float pressure,
160 const float multi_frame_falloff,
161 const IndexMask &selection,
162 const Span<float2> view_positions,
163 Vector<float> &influences,
164 IndexMaskMemory &memory)
165{
166 if (selection.is_empty()) {
167 return {};
168 }
169
170 const float radius = brush_radius(paint, brush, pressure);
171 const float radius_squared = radius * radius;
172 const float brush_pressure = BKE_brush_use_alpha_pressure(&brush) ? pressure : 1.0f;
173 const float influence_base = BKE_brush_alpha_get(&paint, &brush) * brush_pressure *
174 multi_frame_falloff;
175 const int2 mval_i = int2(math::round(mouse_position));
176
177 Array<float> all_influences(selection.min_array_size());
178 const IndexMask influence_mask = IndexMask::from_predicate(
179 selection, GrainSize(4096), memory, [&](const int point) {
180 /* Distance falloff. */
181 const float distance_squared = math::distance_squared(int2(view_positions[point]), mval_i);
182 if (distance_squared > radius_squared) {
183 all_influences[point] = 0.0f;
184 return false;
185 }
186 /* Apply Brush curve. */
187 const float brush_falloff = BKE_brush_curve_strength(
188 &brush, math::sqrt(distance_squared), radius);
189 all_influences[point] = influence_base * brush_falloff;
190 return all_influences[point] > 0.0f;
191 });
192 influences.resize(influence_mask.size());
193 array_utils::gather(all_influences.as_span(), influence_mask, influences.as_mutable_span());
194
195 return influence_mask;
196}
197
198bool brush_using_vertex_color(const GpPaint *gp_paint, const Brush *brush)
199{
200 const int brush_draw_mode = brush->gpencil_settings->brush_draw_mode;
201 const bool brush_use_pinned_mode = (brush_draw_mode != GP_BRUSH_MODE_ACTIVE);
202 if (brush_use_pinned_mode) {
203 return (brush_draw_mode == GP_BRUSH_MODE_VERTEXCOLOR);
204 }
205 return (gp_paint->mode == GPPAINT_FLAG_USE_VERTEXCOLOR);
206}
207
208bool is_brush_inverted(const Brush &brush, const BrushStrokeMode stroke_mode)
209{
210 /* The basic setting is the brush's setting. During runtime, the user can hold down the Ctrl key
211 * to invert the basic behavior. */
212 return bool(brush.flag & BRUSH_DIR_IN) ^ (stroke_mode == BrushStrokeMode::BRUSH_STROKE_INVERT);
213}
214
216 const Object &object,
217 const bke::greasepencil::Layer &layer)
218{
219 const float4x4 view_to_world = float4x4(params.rv3d.viewinv);
220 const float4x4 layer_to_world = layer.to_world_space(object);
221 const float4x4 world_to_layer = math::invert(layer_to_world);
222
223 auto screen_to_world = [=](const float3 &world_pos, const float2 &screen_delta) {
224 const float zfac = ED_view3d_calc_zfac(&params.rv3d, world_pos);
225 float3 world_delta;
226 ED_view3d_win_to_delta(&params.region, screen_delta, zfac, world_delta);
227 return world_delta;
228 };
229
230 float3 world_normal;
231 switch (params.toolsettings.gp_sculpt.lock_axis) {
232 case GP_LOCKAXIS_VIEW: {
233 world_normal = view_to_world.z_axis();
234 break;
235 }
236 case GP_LOCKAXIS_X: {
237 world_normal = layer_to_world.x_axis();
238 break;
239 }
240 case GP_LOCKAXIS_Y: {
241 world_normal = layer_to_world.y_axis();
242 break;
243 }
244 case GP_LOCKAXIS_Z: {
245 world_normal = layer_to_world.z_axis();
246 break;
247 }
248 case GP_LOCKAXIS_CURSOR: {
249 world_normal = params.scene.cursor.matrix<float3x3>().z_axis();
250 break;
251 }
252 default: {
254 return [](const float3 &, const float2 &) { return float3(); };
255 }
256 }
257
258 return [=](const float3 &position, const float2 &screen_delta) {
259 const float3 world_pos = math::transform_point(layer_to_world, position);
260 const float3 world_delta = screen_to_world(world_pos, screen_delta);
261 const float3 layer_delta = math::transform_direction(
262 world_to_layer, world_delta - world_normal * math::dot(world_delta, world_normal));
263 return position + layer_delta;
264 };
265}
266
268 const bke::crazyspace::GeometryDeformation &deformation,
269 const int index,
270 const float2 &screen_delta)
271{
272 const float3 old_position_eval = deformation.positions[index];
273 const float3 new_position_eval = projection_fn(old_position_eval, screen_delta);
274 const float3 translation_eval = new_position_eval - old_position_eval;
275 const float3 translation_orig = deformation.translation_from_deformed_to_original(
276 index, translation_eval);
277 return translation_orig;
278}
279
281 const Scene &scene,
282 Depsgraph &depsgraph,
285 Object &object,
286 const int layer_index,
287 const int frame_number,
288 const float multi_frame_falloff,
290{
292 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
293
294 const bke::greasepencil::Layer &layer = grease_pencil.layer(layer_index);
295 return {*scene.toolsettings,
296 region,
297 rv3d,
298 scene,
299 object,
300 ob_eval,
301 layer,
305 drawing};
306}
307
309 const bool use_selection_masking,
310 IndexMaskMemory &memory)
311{
312 return use_selection_masking ? ed::greasepencil::retrieve_editable_and_selected_points(
313 params.ob_orig, params.drawing, params.layer_index, memory) :
315 params.ob_orig, params.drawing, params.layer_index, memory);
316}
317
319 const bool use_selection_masking,
320 IndexMaskMemory &memory)
321{
323 params.ob_orig, params.drawing, params.layer_index, memory) :
325 params.ob_orig, params.drawing, params.layer_index, memory);
326}
327
329 const bool use_selection_masking,
330 IndexMaskMemory &memory)
331{
333 params.ob_orig, params.drawing, params.layer_index, memory) :
334 params.drawing.strokes().curves_range();
335}
336
343
345 const IndexMask &selection)
346{
348
349 Array<float2> view_positions(deformation.positions.size());
350
351 /* Compute screen space positions. */
352 const float4x4 transform = params.layer.to_world_space(params.ob_eval);
353 selection.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
355 &params.region,
356 math::transform_point(transform, deformation.positions[point_i]),
357 view_positions[point_i],
359 if (result != V3D_PROJ_RET_OK) {
360 view_positions[point_i] = float2(0);
361 }
362 });
363
364 return view_positions;
365}
366
368 const IndexMask &selection)
369{
370 const RegionView3D *rv3d = static_cast<RegionView3D *>(params.region.regiondata);
372
373 const VArray<float> radii = params.drawing.radii();
374 Array<float> view_radii(radii.size());
375 /* Compute screen space radii. */
376 const float4x4 transform = params.layer.to_world_space(params.ob_eval);
377 selection.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
378 const float pixel_size = ED_view3d_pixel_size(
379 rv3d, math::transform_point(transform, deformation.positions[point_i]));
380 view_radii[point_i] = radii[point_i] / pixel_size;
381 });
382
383 return view_radii;
384}
385
387{
388 return brush.gpencil_settings != nullptr &&
389 ELEM(brush.gpencil_settings->vertex_mode, GPPAINT_MODE_STROKE, GPPAINT_MODE_BOTH);
390}
391
393{
394 return brush.gpencil_settings != nullptr &&
395 ELEM(brush.gpencil_settings->vertex_mode, GPPAINT_MODE_FILL, GPPAINT_MODE_BOTH);
396}
397
402
404{
405 return input_sample.mouse_position - this->prev_mouse_position;
406}
407
409 const bContext &C,
410 FunctionRef<bool(const GreasePencilStrokeParams &params, const IndexMask &point_mask)> fn)
411 const
412{
413 using namespace blender::bke::greasepencil;
414
415 const Scene &scene = *CTX_data_scene(&C);
416 Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(&C);
417 ARegion &region = *CTX_wm_region(&C);
419 Object &object = *CTX_data_active_object(&C);
420 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
421
422 std::atomic<bool> changed = false;
424 for (const int64_t i : drawings.index_range()) {
425 const MutableDrawingInfo &info = drawings[i];
426 const AutoMaskingInfo &auto_mask_info = this->auto_masking_info_per_drawing[i];
428 scene,
429 depsgraph,
430 region,
431 rv3d,
432 object,
433 info.layer_index,
434 info.frame_number,
436 info.drawing);
437
438 if (fn(params, auto_mask_info.point_mask)) {
439 changed = true;
440 }
441 }
442
443 if (changed) {
444 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
445 WM_event_add_notifier(&C, NC_GEOM | ND_DATA, &grease_pencil);
446 }
447}
448
450 const bContext &C,
451 FunctionRef<bool(const GreasePencilStrokeParams &params,
452 const IndexMask &point_mask,
453 const DeltaProjectionFunc &projection_fn)> fn) const
454{
455 using namespace blender::bke::greasepencil;
456
457 const Scene &scene = *CTX_data_scene(&C);
458 Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(&C);
459 ARegion &region = *CTX_wm_region(&C);
461 Object &object = *CTX_data_active_object(&C);
462 Object &object_eval = *DEG_get_evaluated(&depsgraph, &object);
463 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
464
465 std::atomic<bool> changed = false;
467 threading::parallel_for_each(drawings.index_range(), [&](const int i) {
468 const MutableDrawingInfo &info = drawings[i];
469 const Layer &layer = grease_pencil.layer(info.layer_index);
470 const AutoMaskingInfo &auto_mask_info = this->auto_masking_info_per_drawing[i];
471 const GreasePencilStrokeParams params = GreasePencilStrokeParams::from_context(
472 scene,
473 depsgraph,
474 region,
475 rv3d,
476 object,
477 info.layer_index,
478 info.frame_number,
479 info.multi_frame_falloff,
480 info.drawing);
481
482 const DeltaProjectionFunc projection_fn = get_screen_projection_fn(params, object_eval, layer);
483 if (fn(params, auto_mask_info.point_mask, projection_fn)) {
484 changed = true;
485 }
486 });
487
488 if (changed) {
489 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
490 WM_event_add_notifier(&C, NC_GEOM | ND_DATA, &grease_pencil);
491 }
492}
493
495 const bContext &C, FunctionRef<bool(const GreasePencilStrokeParams &params)> fn) const
496{
497 using namespace blender::bke::greasepencil;
498
499 const Scene &scene = *CTX_data_scene(&C);
500 Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(&C);
501 ARegion &region = *CTX_wm_region(&C);
503 Object &object = *CTX_data_active_object(&C);
504 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
505
506 bool changed = false;
508 for (const int64_t i : drawings.index_range()) {
509 const MutableDrawingInfo &info = drawings[i];
511 scene,
512 depsgraph,
513 region,
514 rv3d,
515 object,
516 info.layer_index,
517 info.frame_number,
519 info.drawing);
520 if (fn(params)) {
521 changed = true;
522 }
523 }
524
525 if (changed) {
526 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
527 WM_event_add_notifier(&C, NC_GEOM | ND_DATA, &grease_pencil);
528 }
529}
530
532 const bContext &C,
534 const DeltaProjectionFunc &projection_fn)> fn) const
535{
536 using namespace blender::bke::greasepencil;
537
538 const Scene &scene = *CTX_data_scene(&C);
539 Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(&C);
540 ARegion &region = *CTX_wm_region(&C);
542 Object &object = *CTX_data_active_object(&C);
543 Object &object_eval = *DEG_get_evaluated(&depsgraph, &object);
544 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
545
546 bool changed = false;
548 for (const int64_t i : drawings.index_range()) {
549 const MutableDrawingInfo &info = drawings[i];
550 const Layer &layer = grease_pencil.layer(info.layer_index);
552 scene,
553 depsgraph,
554 region,
555 rv3d,
556 object,
557 info.layer_index,
558 info.frame_number,
560 info.drawing);
561
562 const DeltaProjectionFunc projection_fn = get_screen_projection_fn(params, object_eval, layer);
563 if (fn(params, projection_fn)) {
564 changed = true;
565 }
566 }
567
568 if (changed) {
569 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
570 WM_event_add_notifier(&C, NC_GEOM | ND_DATA, &grease_pencil);
571 }
572}
573
575 const bContext &C,
576 const GrainSize grain_size,
577 FunctionRef<bool(const GreasePencilStrokeParams &params)> fn) const
578{
579 using namespace blender::bke::greasepencil;
580
581 const Scene &scene = *CTX_data_scene(&C);
582 Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(&C);
583 ARegion &region = *CTX_wm_region(&C);
585 Object &object = *CTX_data_active_object(&C);
586 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
587
588 std::atomic<bool> changed = false;
590 threading::parallel_for(drawings.index_range(), grain_size.value, [&](const IndexRange range) {
591 for (const int64_t i : range) {
592 const MutableDrawingInfo &info = drawings[i];
593 GreasePencilStrokeParams params = GreasePencilStrokeParams::from_context(
594 scene,
595 depsgraph,
596 region,
597 rv3d,
598 object,
599 info.layer_index,
600 info.frame_number,
601 info.multi_frame_falloff,
602 info.drawing);
603 if (fn(params)) {
604 changed = true;
605 }
606 }
607 });
608
609 if (changed) {
610 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
611 WM_event_add_notifier(&C, NC_GEOM | ND_DATA, &grease_pencil);
612 }
613}
614
616 const InputSample &start_sample)
617{
620
622
623 this->start_mouse_position = start_sample.mouse_position;
624 this->prev_mouse_position = start_sample.mouse_position;
625}
626
628 const InputSample &start_sample)
629{
630 const Scene &scene = *CTX_data_scene(&C);
631 ARegion &region = *CTX_wm_region(&C);
633 Object &object = *CTX_data_active_object(&C);
634 Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(&C);
635
636 const eGP_Sculpt_SelectMaskFlag sculpt_selection_flag = eGP_Sculpt_SelectMaskFlag(
638 const bool use_sculpt_selection_masking = (sculpt_selection_flag &
642
643 const eGP_Sculpt_SettingsFlag sculpt_settings_flag = eGP_Sculpt_SettingsFlag(
645 const bool use_auto_mask_stroke = (sculpt_settings_flag & GP_SCULPT_SETT_FLAG_AUTOMASK_STROKE);
646 const bool use_auto_mask_layer = (sculpt_settings_flag &
648 const bool use_auto_mask_material = (sculpt_settings_flag &
650 const bool use_auto_mask_active_material = (sculpt_settings_flag &
652
653 const float stroke_distance_threshold = 20.0f;
654 const int2 mval_i = int2(math::round(start_sample.mouse_position));
655 const int active_material_index = math::max(object.actcol - 1, 0);
656
658 this->auto_masking_info_per_drawing.reinitialize(drawings.size());
659
660 VectorSet<int> masked_layer_indices;
661 VectorSet<int> masked_material_indices;
662 for (const int drawing_i : drawings.index_range()) {
663 const MutableDrawingInfo &drawing_info = drawings[drawing_i];
664 AutoMaskingInfo &automask_info = this->auto_masking_info_per_drawing[drawing_i];
666 scene,
667 depsgraph,
668 region,
669 rv3d,
670 object,
671 drawing_info.layer_index,
672 drawing_info.frame_number,
673 drawing_info.multi_frame_falloff,
674 drawing_info.drawing);
676 params, use_sculpt_selection_masking, automask_info.memory);
677 if (automask_info.point_mask.is_empty()) {
678 continue;
679 }
680
681 const bke::CurvesGeometry &curves = drawing_info.drawing.strokes();
682 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
683 const bke::AttributeAccessor attributes = curves.attributes();
684
685 if (use_auto_mask_active_material) {
686 IndexMaskMemory memory;
687 const VArraySpan<int> materials = *attributes.lookup_or_default<int>(
688 "material_index", bke::AttrDomain::Point, 0);
689 const IndexMask active_material_mask = IndexMask::from_predicate(
690 curves.points_range(), GrainSize(4096), memory, [&](const int64_t point_i) {
691 return active_material_index == materials[point_i];
692 });
694 automask_info.point_mask, active_material_mask, automask_info.memory);
695 if (automask_info.point_mask.is_empty()) {
696 continue;
697 }
698 }
699
700 if (use_auto_mask_layer || use_auto_mask_stroke || use_auto_mask_material) {
701 Array<float2> view_positions = calculate_view_positions(params, automask_info.point_mask);
702
703 IndexMaskMemory memory;
704 const IndexMask stroke_selection = curve_mask_for_stroke_operation(
705 params, use_sculpt_selection_masking, memory);
706 const IndexMask strokes_under_brush = IndexMask::from_predicate(
707 stroke_selection, GrainSize(512), memory, [&](const int curve_i) {
708 for (const int point_i : points_by_curve[curve_i]) {
709 const float distance = math::distance(mval_i, int2(view_positions[point_i]));
710 if (distance <= stroke_distance_threshold) {
711 return true;
712 }
713 }
714 return false;
715 });
716
717 if (use_auto_mask_layer && !strokes_under_brush.is_empty()) {
718 masked_layer_indices.add(drawing_info.layer_index);
719 }
720
721 if (use_auto_mask_stroke) {
723 automask_info.point_mask,
724 IndexMask::from_ranges(curves.points_by_curve(), strokes_under_brush, memory),
725 automask_info.memory);
726 }
727
728 if (use_auto_mask_material) {
729 const VArraySpan<int> material_indices = *attributes.lookup_or_default<int>(
730 "material_index", bke::AttrDomain::Curve, 0);
731 strokes_under_brush.foreach_index(
732 [&](const int curve_i) { masked_material_indices.add(material_indices[curve_i]); });
733 }
734 }
735 }
736
737 /* When we mask by the initial strokes under the cursor, the other masking options don't affect
738 * the resulting mask. So we can skip the second loop. */
739 if (use_auto_mask_stroke) {
740 return;
741 }
742
743 threading::parallel_for_each(drawings.index_range(), [&](const int drawing_i) {
744 const MutableDrawingInfo &drawing_info = drawings[drawing_i];
745 AutoMaskingInfo &automask_info = this->auto_masking_info_per_drawing[drawing_i];
746
747 if (use_auto_mask_layer && !masked_layer_indices.contains(drawing_info.layer_index)) {
748 automask_info.point_mask = {};
749 return;
750 }
751
752 if (use_auto_mask_material) {
753 const bke::CurvesGeometry &curves = drawing_info.drawing.strokes();
754 const VArraySpan<int> material_indices = *curves.attributes().lookup_or_default<int>(
755 "material_index", bke::AttrDomain::Curve, 0);
756 IndexMaskMemory memory;
757 const IndexMask masked_curves = IndexMask::from_predicate(
758 curves.curves_range(), GrainSize(1024), memory, [&](const int curve_i) {
759 return masked_material_indices.contains(material_indices[curve_i]);
760 });
761
762 automask_info.point_mask = IndexMask::from_intersection(
763 automask_info.point_mask,
764 IndexMask::from_ranges(curves.points_by_curve(), masked_curves, memory),
765 automask_info.memory);
766 }
767 });
768}
769
771{
772 this->prev_mouse_position = extension_sample.mouse_position;
773}
774
775} // namespace blender::ed::sculpt_paint::greasepencil
bool BKE_brush_use_alpha_pressure(const Brush *brush)
Definition brush.cc:1290
float BKE_brush_alpha_get(const Paint *paint, const Brush *brush)
Definition brush.cc:1357
float BKE_brush_curve_strength(eBrushCurvePreset preset, const CurveMapping *cumap, float distance, float brush_radius)
Definition brush.cc:1577
bool BKE_brush_use_size_pressure(const Brush *brush)
Definition brush.cc:1285
float BKE_brush_radius_get(const Paint *paint, const Brush *brush)
Definition brush.cc:1272
void BKE_brush_init_gpencil_settings(Brush *brush)
Definition brush.cc:648
float BKE_curvemapping_evaluateF(const CurveMapping *cumap, int cur, float value)
void BKE_curvemapping_init(CurveMapping *cumap)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
ToolSettings * CTX_data_tool_settings(const bContext *C)
RegionView3D * CTX_wm_region_view3d(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
Low-level operations for curves.
Low-level operations for grease pencil.
Paint * BKE_paint_get_active_from_context(const bContext *C)
Definition paint.cc:476
Brush * BKE_paint_brush(Paint *paint)
Definition paint.cc:645
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define ELEM(...)
void DEG_id_tag_update(ID *id, unsigned int flags)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
@ GP_BRUSH_MODE_VERTEXCOLOR
@ GP_BRUSH_MODE_ACTIVE
@ BRUSH_DIR_IN
@ GPPAINT_MODE_STROKE
@ GPPAINT_MODE_FILL
@ GPPAINT_MODE_BOTH
@ GPPAINT_FLAG_USE_VERTEXCOLOR
eGP_Sculpt_SettingsFlag
@ GP_SCULPT_SETT_FLAG_AUTOMASK_LAYER_ACTIVE
@ GP_SCULPT_SETT_FLAG_AUTOMASK_STROKE
@ GP_SCULPT_SETT_FLAG_AUTOMASK_MATERIAL_STROKE
@ GP_SCULPT_SETT_FLAG_AUTOMASK_MATERIAL_ACTIVE
@ GP_SCULPT_SETT_FLAG_AUTOMASK_LAYER_STROKE
@ GP_LOCKAXIS_X
@ GP_LOCKAXIS_VIEW
@ GP_LOCKAXIS_Y
@ GP_LOCKAXIS_Z
@ GP_LOCKAXIS_CURSOR
eGP_Sculpt_SelectMaskFlag
@ GP_SCULPT_MASK_SELECTMODE_POINT
@ GP_SCULPT_MASK_SELECTMODE_STROKE
@ GP_SCULPT_MASK_SELECTMODE_SEGMENT
void ED_view3d_win_to_delta(const ARegion *region, const float xy_delta[2], float zfac, float r_out[3], bool precise=false)
@ V3D_PROJ_TEST_NOP
Definition ED_view3d.hh:279
float ED_view3d_pixel_size(const RegionView3D *rv3d, const float co[3])
eV3DProjStatus
Definition ED_view3d.hh:255
@ V3D_PROJ_RET_OK
Definition ED_view3d.hh:256
float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3])
eV3DProjStatus ED_view3d_project_float_global(const ARegion *region, const float co[3], float r_co[2], eV3DProjTest flag)
#define C
Definition RandGen.cpp:29
#define NC_GEOM
Definition WM_types.hh:393
#define ND_DATA
Definition WM_types.hh:509
BPy_StructRNA * depsgraph
long long int int64_t
IndexRange index_range() const
Span< T > as_span() const
Definition BLI_array.hh:243
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
static IndexMask from_ranges(OffsetIndices< T > offsets, const IndexMask &mask, IndexMaskMemory &memory)
static IndexMask from_intersection(const IndexMask &mask_a, const IndexMask &mask_b, IndexMaskMemory &memory)
bool add(const Key &key)
bool contains(const Key &key) const
int64_t size() const
IndexRange index_range() const
void resize(const int64_t new_size)
MutableSpan< T > as_mutable_span()
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, AttrType data_type, const void *default_value=nullptr) const
const bke::CurvesGeometry & strokes() const
float4x4 to_world_space(const Object &object) const
void foreach_editable_drawing_with_automask(const bContext &C, FunctionRef< bool(const GreasePencilStrokeParams &params, const IndexMask &points)> fn) const
void init_auto_masking(const bContext &C, const InputSample &start_sample)
void foreach_editable_drawing(const bContext &C, FunctionRef< bool(const GreasePencilStrokeParams &params, const DeltaProjectionFunc &projection_fn)> fn) const
void foreach_index(Fn &&fn) const
static float verts[][3]
float distance(VecOp< float, D >, VecOp< float, D >) RET
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void gather(const GVArray &src, const IndexMask &indices, GMutableSpan dst, int64_t grain_size=4096)
GeometryDeformation get_evaluated_grease_pencil_drawing_deformation(const Object *ob_eval, const Object &ob_orig, const bke::greasepencil::Drawing &drawing_orig)
IndexMask retrieve_editable_and_selected_strokes(Object &object, const bke::greasepencil::Drawing &drawing, int layer_index, IndexMaskMemory &memory)
IndexMask retrieve_editable_points(Object &object, const bke::greasepencil::Drawing &drawing, int layer_index, IndexMaskMemory &memory)
IndexMask retrieve_editable_and_selected_fill_strokes(Object &object, const bke::greasepencil::Drawing &drawing, int layer_index, IndexMaskMemory &memory)
IndexMask retrieve_editable_and_selected_points(Object &object, const bke::greasepencil::Drawing &drawing, int layer_index, IndexMaskMemory &memory)
Vector< MutableDrawingInfo > retrieve_editable_drawings_from_layer_with_falloff(const Scene &scene, GreasePencil &grease_pencil, const blender::bke::greasepencil::Layer &layer)
Vector< MutableDrawingInfo > retrieve_editable_drawings_with_falloff(const Scene &scene, GreasePencil &grease_pencil)
IndexMask retrieve_editable_strokes(Object &object, const bke::greasepencil::Drawing &drawing, int layer_index, IndexMaskMemory &memory)
IndexMask curve_mask_for_stroke_operation(const GreasePencilStrokeParams &params, bool use_selection_masking, IndexMaskMemory &memory)
Vector< ed::greasepencil::MutableDrawingInfo > get_drawings_for_stroke_operation(const bContext &C)
bool is_brush_inverted(const Brush &brush, BrushStrokeMode stroke_mode)
float closest_distance_to_surface_2d(const float2 pt, const Span< float2 > verts)
IndexMask fill_mask_for_stroke_operation(const GreasePencilStrokeParams &params, bool use_selection_masking, IndexMaskMemory &memory)
Array< float > calculate_view_radii(const GreasePencilStrokeParams &params, const IndexMask &selection)
IndexMask point_mask_for_stroke_operation(const GreasePencilStrokeParams &params, bool use_selection_masking, IndexMaskMemory &memory)
IndexMask brush_point_influence_mask(const Paint &paint, const Brush &brush, const float2 &mouse_position, float pressure, float multi_frame_falloff, const IndexMask &selection, Span< float2 > view_positions, Vector< float > &influences, IndexMaskMemory &memory)
float brush_point_influence(const Paint &paint, const Brush &brush, const float2 &co, const InputSample &sample, float multi_frame_falloff)
Array< float2 > calculate_view_positions(const GreasePencilStrokeParams &params, const IndexMask &selection)
bool brush_using_vertex_color(const GpPaint *gp_paint, const Brush *brush)
Vector< ed::greasepencil::MutableDrawingInfo > get_drawings_with_masking_for_stroke_operation(const bContext &C)
float brush_fill_influence(const Paint &paint, const Brush &brush, Span< float2 > fill_positions, const InputSample &sample, float multi_frame_falloff)
bke::crazyspace::GeometryDeformation get_drawing_deformation(const GreasePencilStrokeParams &params)
DeltaProjectionFunc get_screen_projection_fn(const GreasePencilStrokeParams &params, const Object &object, const bke::greasepencil::Layer &layer)
float3 compute_orig_delta(const DeltaProjectionFunc &projection_fn, const bke::crazyspace::GeometryDeformation &deformation, int index, const float2 &screen_delta)
float brush_radius(const Paint &paint, const Brush &brush, float pressure)
std::function< float3(const float3 position, const float2 &screen_delta)> DeltaProjectionFunc
T sqrt(const T &a)
T distance(const T &a, const T &b)
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
T min(const T &a, const T &b)
CartesianBasis invert(const CartesianBasis &basis)
T distance_squared(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
T max(const T &a, const T &b)
VecBase< T, 3 > transform_direction(const MatBase< T, 3, 3 > &mat, const VecBase< T, 3 > &direction)
T round(const T &a)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
void parallel_for_each(Range &&range, const Function &function)
Definition BLI_task.hh:56
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
MatBase< float, 4, 4 > float4x4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
MatBase< float, 3, 3 > float3x3
VecBase< float, 3 > float3
BrushStrokeMode
@ BRUSH_STROKE_INVERT
#define FLT_MAX
Definition stdcycles.h:14
struct ToolSettings * toolsettings
char gpencil_selectmode_sculpt
struct GP_Sculpt_Settings gp_sculpt
float3 translation_from_deformed_to_original(const int position_i, const float3 &translation) const
static GreasePencilStrokeParams from_context(const Scene &scene, Depsgraph &depsgraph, ARegion &region, RegionView3D &rv3d, Object &object, int layer_index, int frame_number, float multi_frame_falloff, bke::greasepencil::Drawing &drawing)
i
Definition text_draw.cc:230
void WM_event_add_notifier(const bContext *C, uint type, void *reference)