Blender V4.5
paint_mask.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2012 by Nicholas Bishop. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8#include "paint_mask.hh"
9
10#include <cstdlib>
11
12#include "MEM_guardedalloc.h"
13
14#include "DNA_object_types.h"
15
16#include "BLI_array_utils.hh"
17#include "BLI_bit_span_ops.hh"
19#include "BLI_span.hh"
20#include "BLI_vector.hh"
21
22#include "BKE_attribute.hh"
23#include "BKE_brush.hh"
24#include "BKE_ccg.hh"
25#include "BKE_context.hh"
26#include "BKE_mesh.hh"
27#include "BKE_multires.hh"
28#include "BKE_paint.hh"
29#include "BKE_paint_bvh.hh"
30#include "BKE_subdiv_ccg.hh"
31#include "BKE_subsurf.hh"
32
33#include "RNA_access.hh"
34#include "RNA_define.hh"
35
36#include "WM_api.hh"
37#include "WM_types.hh"
38
39#include "ED_select_utils.hh"
40
41#include "bmesh.hh"
42
43#include "mesh_brush_common.hh"
44#include "paint_intern.hh"
45#include "sculpt_automask.hh"
46#include "sculpt_gesture.hh"
47#include "sculpt_hide.hh"
48#include "sculpt_intern.hh"
49#include "sculpt_undo.hh"
50
52
53/* -------------------------------------------------------------------- */
56
58{
59 const SculptSession &ss = *object.sculpt;
60 switch (bke::object::pbvh_get(object)->type()) {
62 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
63 const bke::AttributeAccessor attributes = mesh.attributes();
64 const VArray mask = *attributes.lookup_or_default<float>(
65 ".sculpt_mask", bke::AttrDomain::Point, 0.0f);
66 Array<float> result(mask.size());
67 mask.materialize(result);
68 return result;
69 }
71 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
72 if (subdiv_ccg.masks.is_empty()) {
73 return Array<float>(subdiv_ccg.positions.size(), 0.0f);
74 }
75 return subdiv_ccg.masks;
76 }
78 BMesh &bm = *ss.bm;
79 const int offset = CustomData_get_offset_named(&bm.vdata, CD_PROP_FLOAT, ".sculpt_mask");
80 Array<float> result(bm.totvert);
81 if (offset == -1) {
82 result.fill(0.0f);
83 }
84 else {
85 vert_random_access_ensure(const_cast<Object &>(object));
86 for (const int i : result.index_range()) {
88 }
89 }
90 return result;
91 }
92 }
94 return {};
95}
96
97void mix_new_masks(const Span<float> new_masks, const float factor, const MutableSpan<float> masks)
98{
99 BLI_assert(new_masks.size() == masks.size());
100
101 for (const int i : masks.index_range()) {
102 masks[i] += (new_masks[i] - masks[i]) * factor;
103 }
104}
105
106void mix_new_masks(const Span<float> new_masks,
107 const Span<float> factors,
108 const MutableSpan<float> masks)
109{
110 BLI_assert(new_masks.size() == factors.size());
111 BLI_assert(new_masks.size() == masks.size());
112
113 for (const int i : masks.index_range()) {
114 masks[i] += (new_masks[i] - masks[i]) * factors[i];
115 }
116}
117
119{
120 for (float &mask : masks) {
121 mask = std::clamp(mask, 0.0f, 1.0f);
122 }
123}
124
126{
127 for (float &mask : masks) {
128 mask = 1.0f - mask;
129 }
130}
131
133 const Set<BMVert *, 0> &verts,
134 const MutableSpan<float> r_mask)
135{
136 BLI_assert(verts.size() == r_mask.size());
137
138 /* TODO: Avoid overhead of accessing attributes for every bke::pbvh::Tree node. */
139 const int mask_offset = CustomData_get_offset_named(&bm.vdata, CD_PROP_FLOAT, ".sculpt_mask");
140 int i = 0;
141 for (const BMVert *vert : verts) {
142 r_mask[i] = (mask_offset == -1) ? 0.0f : BM_ELEM_CD_GET_FLOAT(vert, mask_offset);
143 i++;
144 }
145}
146
147void gather_mask_grids(const SubdivCCG &subdiv_ccg,
148 const Span<int> grids,
149 const MutableSpan<float> r_mask)
150{
151 if (!subdiv_ccg.masks.is_empty()) {
152 gather_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, r_mask);
153 }
154 else {
155 r_mask.fill(0.0f);
156 }
157}
158
159void scatter_mask_grids(const Span<float> mask, SubdivCCG &subdiv_ccg, const Span<int> grids)
160{
161 scatter_data_grids(subdiv_ccg, mask, grids, subdiv_ccg.masks.as_mutable_span());
162}
163
165{
166 BLI_assert(verts.size() == mask.size());
167
168 const int mask_offset = CustomData_get_offset_named(&bm.vdata, CD_PROP_FLOAT, ".sculpt_mask");
169 BLI_assert(mask_offset != -1);
170 int i = 0;
171 for (BMVert *vert : verts) {
172 BM_ELEM_CD_SET_FLOAT(vert, mask_offset, mask[i]);
173 i++;
174 }
175}
176
177static float average_masks(const int mask_offset, const Span<const BMVert *> verts)
178{
179 float sum = 0;
180 for (const BMVert *vert : verts) {
181 sum += BM_ELEM_CD_GET_FLOAT(vert, mask_offset);
182 }
183 return sum / float(verts.size());
184}
185
186void average_neighbor_mask_bmesh(const int mask_offset,
187 const Set<BMVert *, 0> &verts,
188 const MutableSpan<float> new_masks)
189{
190 BMeshNeighborVerts neighbors;
191 int i = 0;
192 for (BMVert *vert : verts) {
193 new_masks[i] = average_masks(mask_offset, vert_neighbors_get_bmesh(*vert, neighbors));
194 i++;
195 }
196}
197
198void update_mask_mesh(const Depsgraph &depsgraph,
199 Object &object,
200 const IndexMask &node_mask,
201 FunctionRef<void(MutableSpan<float>, Span<int>)> update_fn)
202{
203 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
205
206 Mesh &mesh = *static_cast<Mesh *>(object.data);
207 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
208 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
210 ".sculpt_mask", bke::AttrDomain::Point);
211 if (!mask) {
212 return;
213 }
214
215 struct LocalData {
216 Vector<int> visible_verts;
218 };
219
220 Array<bool> node_changed(node_mask.min_array_size(), false);
221
223 node_mask.foreach_index(GrainSize(1), [&](const int i) {
224 LocalData &tls = all_tls.local();
225 const Span<int> verts = hide::node_visible_verts(nodes[i], hide_vert, tls.visible_verts);
226 tls.mask.resize(verts.size());
227 gather_data_mesh(mask.span.as_span(), verts, tls.mask.as_mutable_span());
228 update_fn(tls.mask, verts);
230 return;
231 }
235 node_changed[i] = true;
236 });
237
238 IndexMaskMemory memory;
239 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
240
241 mask.finish();
242}
243
245 const CCGKey &key,
246 const Span<int> grids,
247 const Span<float> values)
248{
249 BLI_assert(grids.size() * key.grid_area == values.size());
250
251 const IndexRange range = grids.index_range();
252 return std::all_of(range.begin(), range.end(), [&](const int i) {
253 return masks.slice(bke::ccg::grid_range(key, grids[i])) ==
254 values.slice(bke::ccg::grid_range(key, i));
255 return true;
256 });
257}
258
259bool mask_equals_array_bmesh(const int mask_offset,
260 const Set<BMVert *, 0> &verts,
261 const Span<float> values)
262{
263 BLI_assert(verts.size() == values.size());
264
265 int i = 0;
266 for (const BMVert *vert : verts) {
267 if (BM_ELEM_CD_GET_FLOAT(vert, mask_offset) != values[i]) {
268 return false;
269 }
270 i++;
271 }
272 return true;
273}
274
276
277/* -------------------------------------------------------------------- */
281
282/* The gesture API doesn't write to this enum type,
283 * it writes to eSelectOp from ED_select_utils.hh.
284 * We must thus map the modes here to the desired
285 * eSelectOp modes.
286 *
287 * Fixes #102349.
288 */
294
295static const EnumPropertyItem mode_items[] = {
297 "VALUE",
298 0,
299 "Value",
300 "Set mask to the level specified by the 'value' property"},
302 "VALUE_INVERSE",
303 0,
304 "Value Inverted",
305 "Set mask to the level specified by the inverted 'value' property"},
306 {int(FloodFillMode::InverseMeshValue), "INVERT", 0, "Invert", "Invert the mask"},
307 {0}};
308
310 const Span<bool> hide_vert,
312{
313 if (hide_vert.is_empty()) {
314 return {};
315 }
316 const Span<int> verts = node.verts();
318 return verts;
319 }
320 indices.resize(verts.size());
321 const int *end = std::copy_if(verts.begin(), verts.end(), indices.begin(), [&](const int vert) {
322 return hide_vert[vert];
323 });
324 indices.resize(end - indices.begin());
325 return indices;
326}
327
328static bool try_remove_mask_mesh(const Depsgraph &depsgraph,
329 Object &object,
330 const IndexMask &node_mask)
331{
332 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
334 Mesh &mesh = *static_cast<Mesh *>(object.data);
335 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
336 const VArraySpan mask = *attributes.lookup<float>(".sculpt_mask", bke::AttrDomain::Point);
337 if (mask.is_empty()) {
338 return true;
339 }
340
341 /* If there are any hidden vertices that shouldn't be affected with a mask value set, the
342 * attribute cannot be removed. This could also be done by building an IndexMask in the full
343 * vertex domain. */
344 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
346 const bool hidden_masked_verts = threading::parallel_reduce(
347 node_mask.index_range(),
348 1,
349 false,
350 [&](const IndexRange range, bool value) {
351 if (value) {
352 return value;
353 }
354 Vector<int> &index_data = all_index_data.local();
355 node_mask.slice(range).foreach_index([&](const int i) {
356 if (value) {
357 return;
358 }
359 const Span<int> verts = get_hidden_verts(nodes[i], hide_vert, index_data);
360 if (std::any_of(verts.begin(), verts.end(), [&](int i) { return mask[i] > 0.0f; })) {
361 value = true;
362 return;
363 }
364 });
365 return value;
366 },
367 std::logical_or());
368 if (hidden_masked_verts) {
369 return false;
370 }
371
372 IndexMaskMemory memory;
373 const IndexMask changed_nodes = IndexMask::from_predicate(
374 node_mask, GrainSize(1), memory, [&](const int i) {
375 const Span<int> verts = nodes[i].verts();
376 return std::any_of(
377 verts.begin(), verts.end(), [&](const int i) { return mask[i] != 0.0f; });
378 });
379
380 undo::push_nodes(depsgraph, object, changed_nodes, undo::Type::Mask);
381 attributes.remove(".sculpt_mask");
382 changed_nodes.foreach_index([&](const int i) {
383 BKE_pbvh_node_fully_masked_set(nodes[i], false);
385 });
386 pbvh.tag_masks_changed(changed_nodes);
387 return true;
388}
389
390static void fill_mask_mesh(const Depsgraph &depsgraph,
391 Object &object,
392 const float value,
393 const IndexMask &node_mask)
394{
395 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
397
398 Mesh &mesh = *static_cast<Mesh *>(object.data);
399 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
400 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
401 if (value == 0.0f) {
402 if (try_remove_mask_mesh(depsgraph, object, node_mask)) {
403 return;
404 }
405 }
406
408 ".sculpt_mask", bke::AttrDomain::Point);
409
410 Array<bool> node_changed(node_mask.min_array_size(), false);
411
413 node_mask.foreach_index(GrainSize(1), [&](const int i) {
414 Vector<int> &index_data = all_index_data.local();
415 const Span<int> verts = hide::node_visible_verts(nodes[i], hide_vert, index_data);
416 if (std::all_of(verts.begin(), verts.end(), [&](int i) { return mask.span[i] == value; })) {
417 return;
418 }
420 mask.span.fill_indices(verts, value);
421 node_changed[i] = true;
422 });
423
424 IndexMaskMemory memory;
425 const IndexMask changed_nodes = IndexMask::from_bools(node_mask, node_changed, memory);
426 pbvh.tag_masks_changed(changed_nodes);
427
428 mask.finish();
429 changed_nodes.foreach_index([&](const int i) {
430 BKE_pbvh_node_fully_masked_set(nodes[i], value == 1.0f);
432 });
433}
434
435static void fill_mask_grids(Main &bmain,
436 const Scene &scene,
437 Depsgraph &depsgraph,
438 Object &object,
439 const float value,
440 const IndexMask &node_mask)
441{
442 SculptSession &ss = *object.sculpt;
443
444 if (value == 0.0f && ss.subdiv_ccg->masks.is_empty()) {
445 /* NOTE: Deleting the mask array would be possible here. */
446 return;
447 }
448
449 MultiresModifierData &mmd = *BKE_sculpt_multires_active(&scene, &object);
450 BKE_sculpt_mask_layers_ensure(&depsgraph, &bmain, &object, &mmd);
451
452 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
454 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
455 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
456
457 const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
458
459 Array<bool> node_changed(node_mask.min_array_size(), false);
460
461 MutableSpan<float> masks = subdiv_ccg.masks;
462 node_mask.foreach_index(GrainSize(1), [&](const int i) {
463 const Span<int> grid_indices = nodes[i].grids();
464 if (std::all_of(grid_indices.begin(), grid_indices.end(), [&](const int grid) {
465 const Span<float> grid_masks = masks.slice(bke::ccg::grid_range(key, grid));
466 return std::all_of(grid_masks.begin(), grid_masks.end(), [&](const float mask) {
467 return mask == value;
468 });
469 }))
470 {
471 return;
472 }
474
475 if (grid_hidden.is_empty()) {
476 for (const int grid : grid_indices) {
477 masks.slice(bke::ccg::grid_range(key, grid)).fill(value);
478 }
479 }
480 else {
481 for (const int grid : grid_indices) {
482 MutableSpan<float> grid_masks = masks.slice(bke::ccg::grid_range(key, grid));
483 bits::foreach_0_index(grid_hidden[grid], [&](const int i) { grid_masks[i] = value; });
484 }
485 }
486 node_changed[i] = true;
487 });
488
489 IndexMaskMemory memory;
490 const IndexMask changed_nodes = IndexMask::from_bools(node_changed, memory);
491 if (node_changed.is_empty()) {
492 return;
493 }
494 pbvh.tag_masks_changed(changed_nodes);
496 changed_nodes.foreach_index([&](const int i) {
497 BKE_pbvh_node_fully_masked_set(nodes[i], value == 1.0f);
499 });
500}
501
502static void fill_mask_bmesh(const Depsgraph &depsgraph,
503 Object &object,
504 const float value,
505 const IndexMask &node_mask)
506{
507 SculptSession &ss = *object.sculpt;
508 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
510
511 BMesh &bm = *ss.bm;
512 const int offset = CustomData_get_offset_named(&bm.vdata, CD_PROP_FLOAT, ".sculpt_mask");
513 if (value == 0.0f && offset == -1) {
514 return;
515 }
516 if (offset == -1) {
517 /* Mask is not dynamically added or removed for dynamic topology sculpting. */
519 return;
520 }
521
522 undo::push_nodes(depsgraph, object, node_mask, undo::Type::Mask);
523
524 Array<bool> node_changed(node_mask.min_array_size(), false);
525
526 node_mask.foreach_index(GrainSize(1), [&](const int i) {
527 bool changed = false;
529 if (!BM_elem_flag_test(vert, BM_ELEM_HIDDEN)) {
530 if (BM_ELEM_CD_GET_FLOAT(vert, offset) != value) {
531 BM_ELEM_CD_SET_FLOAT(vert, offset, value);
532 changed = true;
533 }
534 }
535 }
536 if (changed) {
537 node_changed[i] = true;
538 }
539 });
540 IndexMaskMemory memory;
541 const IndexMask changed_nodes = IndexMask::from_bools(node_changed, memory);
542 if (node_changed.is_empty()) {
543 return;
544 }
545 pbvh.tag_masks_changed(changed_nodes);
546 changed_nodes.foreach_index([&](const int i) {
547 BKE_pbvh_node_fully_masked_set(nodes[i], value == 1.0f);
549 });
550}
551
552static void fill_mask(
553 Main &bmain, const Scene &scene, Depsgraph &depsgraph, Object &object, const float value)
554{
555 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
556 IndexMaskMemory memory;
557 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
558 switch (pbvh.type()) {
560 fill_mask_mesh(depsgraph, object, value, node_mask);
561 break;
563 fill_mask_grids(bmain, scene, depsgraph, object, value, node_mask);
564 break;
566 fill_mask_bmesh(depsgraph, object, value, node_mask);
567 break;
568 }
569}
570
571static void invert_mask_grids(Main &bmain,
572 const Scene &scene,
573 Depsgraph &depsgraph,
574 Object &object,
575 const IndexMask &node_mask)
576{
577 SculptSession &ss = *object.sculpt;
578
579 MultiresModifierData &mmd = *BKE_sculpt_multires_active(&scene, &object);
580 BKE_sculpt_mask_layers_ensure(&depsgraph, &bmain, &object, &mmd);
581
582 undo::push_nodes(depsgraph, object, node_mask, undo::Type::Mask);
583
584 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
586 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
587 const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
588
589 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
590 MutableSpan<float> masks = subdiv_ccg.masks;
591 node_mask.foreach_index(GrainSize(1), [&](const int i) {
592 const Span<int> grid_indices = nodes[i].grids();
593 if (grid_hidden.is_empty()) {
594 for (const int grid : grid_indices) {
595 for (float &value : masks.slice(bke::ccg::grid_range(key, grid))) {
596 value = 1.0f - value;
597 }
598 }
599 }
600 else {
601 for (const int grid : grid_indices) {
602 MutableSpan<float> grid_masks = masks.slice(bke::ccg::grid_range(key, grid));
603 bits::foreach_0_index(grid_hidden[grid],
604 [&](const int i) { grid_masks[i] = 1.0f - grid_masks[i]; });
605 }
606 }
608 });
609 pbvh.tag_masks_changed(node_mask);
610
612}
613
614static void invert_mask_bmesh(const Depsgraph &depsgraph,
615 Object &object,
616 const IndexMask &node_mask)
617{
618 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
620 BMesh &bm = *object.sculpt->bm;
621 const int offset = CustomData_get_offset_named(&bm.vdata, CD_PROP_FLOAT, ".sculpt_mask");
622 if (offset == -1) {
624 return;
625 }
626
627 undo::push_nodes(depsgraph, object, node_mask, undo::Type::Mask);
628 node_mask.foreach_index(GrainSize(1), [&](const int i) {
630 if (!BM_elem_flag_test(vert, BM_ELEM_HIDDEN)) {
631 BM_ELEM_CD_SET_FLOAT(vert, offset, 1.0f - BM_ELEM_CD_GET_FLOAT(vert, offset));
632 }
633 }
635 });
636 pbvh.tag_masks_changed(node_mask);
637}
638
639static void invert_mask(Main &bmain, const Scene &scene, Depsgraph &depsgraph, Object &object)
640{
641 IndexMaskMemory memory;
642 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(*bke::object::pbvh_get(object), memory);
643 switch (bke::object::pbvh_get(object)->type()) {
646 depsgraph, object, node_mask, [&](MutableSpan<float> mask, const Span<int> verts) {
647 for (const int vert : verts) {
648 mask[vert] = 1.0f - mask[vert];
649 }
650 });
651 break;
653 invert_mask_grids(bmain, scene, depsgraph, object, node_mask);
654 break;
656 invert_mask_bmesh(depsgraph, object, node_mask);
657 break;
658 }
659}
660
662{
663 Main &bmain = *CTX_data_main(C);
664 const Scene &scene = *CTX_data_scene(C);
665 Object &object = *CTX_data_active_object(C);
667
668 const FloodFillMode mode = FloodFillMode(RNA_enum_get(op->ptr, "mode"));
669 const float value = RNA_float_get(op->ptr, "value");
670
672
673 undo::push_begin(scene, object, op);
674 switch (mode) {
676 fill_mask(bmain, scene, depsgraph, object, value);
677 break;
679 fill_mask(bmain, scene, depsgraph, object, 1.0f - value);
680 break;
682 invert_mask(bmain, scene, depsgraph, object);
683 break;
684 }
685
686 undo::push_end(object);
687
689
690 return OPERATOR_FINISHED;
691}
692
694{
695 /* Identifiers. */
696 ot->name = "Mask Flood Fill";
697 ot->idname = "PAINT_OT_mask_flood_fill";
698 ot->description = "Fill the whole mask with a given value, or invert its values";
699
700 /* API callbacks. */
701 ot->exec = mask_flood_fill_exec;
702 ot->poll = SCULPT_mode_poll;
703
704 ot->flag = OPTYPE_REGISTER;
705
706 /* RNA. */
707 RNA_def_enum(ot->srna, "mode", mode_items, int(FloodFillMode::Value), "Mode", nullptr);
709 ot->srna,
710 "value",
711 0.0f,
712 0.0f,
713 1.0f,
714 "Value",
715 "Mask level to use when mode is 'Value'; zero means no masking and one is fully masked",
716 0.0f,
717 1.0f);
718}
719
721
722/* -------------------------------------------------------------------- */
726
733
734static void gesture_begin(bContext &C, wmOperator &op, gesture::GestureData &gesture_data)
735{
736 const Scene &scene = *CTX_data_scene(&C);
739 undo::push_begin(scene, *gesture_data.vc.obact, &op);
740}
741
742static float mask_gesture_get_new_value(const float elem, FloodFillMode mode, float value)
743{
744 switch (mode) {
746 return value;
748 return 1.0f - value;
750 return 1.0f - elem;
751 }
753 return 0.0f;
754}
755
757{
758 const IndexMask &node_mask = gesture_data.node_mask;
759 const MaskOperation &op = *reinterpret_cast<const MaskOperation *>(gesture_data.operation);
760 Object &object = *gesture_data.vc.obact;
761 const Depsgraph &depsgraph = *gesture_data.vc.depsgraph;
762 switch (bke::object::pbvh_get(object)->type()) {
764 const Span<float3> positions = bke::pbvh::vert_positions_eval(depsgraph, object);
767 depsgraph, object, node_mask, [&](MutableSpan<float> node_mask, const Span<int> verts) {
768 for (const int i : verts.index_range()) {
769 const int vert = verts[i];
770 if (gesture::is_affected(gesture_data, positions[vert], normals[vert])) {
771 node_mask[i] = mask_gesture_get_new_value(node_mask[i], op.mode, op.value);
772 }
773 }
774 });
775 break;
776 }
778 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
780 SubdivCCG &subdiv_ccg = *gesture_data.ss->subdiv_ccg;
781 const Span<float3> positions = subdiv_ccg.positions;
782 const Span<float3> normals = subdiv_ccg.normals;
783 MutableSpan<float> masks = subdiv_ccg.masks;
784 const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
785 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
786
787 Array<bool> node_changed(node_mask.min_array_size(), false);
788
789 node_mask.foreach_index(GrainSize(1), [&](const int node_index) {
790 bke::pbvh::GridsNode &node = nodes[node_index];
791 bool any_changed = false;
792 for (const int grid : node.grids()) {
793 const int vert_start = grid * key.grid_area;
794 BKE_subdiv_ccg_foreach_visible_grid_vert(key, grid_hidden, grid, [&](const int i) {
795 const int vert = vert_start + i;
796 if (gesture::is_affected(gesture_data, positions[vert], normals[vert])) {
797 float &mask = masks[vert];
798 if (!any_changed) {
799 any_changed = true;
801 }
803 }
804 });
805 if (any_changed) {
806 bke::pbvh::node_update_mask_grids(key, masks, node);
807 node_changed[node_index] = true;
808 }
809 }
810 });
811
812 IndexMaskMemory memory;
813 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
814 break;
815 }
817 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
819 BMesh &bm = *gesture_data.ss->bm;
820 const int offset = CustomData_get_offset_named(&bm.vdata, CD_PROP_FLOAT, ".sculpt_mask");
821
822 Array<bool> node_changed(node_mask.min_array_size(), false);
823
824 node_mask.foreach_index(GrainSize(1), [&](const int i) {
825 bool any_changed = false;
827 if (gesture::is_affected(gesture_data, vert->co, vert->no)) {
828 const float old_mask = BM_ELEM_CD_GET_FLOAT(vert, offset);
829 if (!any_changed) {
830 any_changed = true;
832 }
833 const float new_mask = mask_gesture_get_new_value(old_mask, op.mode, op.value);
834 BM_ELEM_CD_SET_FLOAT(vert, offset, new_mask);
835 }
836 }
837 if (any_changed) {
839 node_changed[i] = true;
840 }
841 });
842
843 IndexMaskMemory memory;
844 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
845 break;
846 }
847 }
848}
849
850static void gesture_end(bContext &C, gesture::GestureData &gesture_data)
851{
853 Object &object = *gesture_data.vc.obact;
854 if (bke::object::pbvh_get(object)->type() == bke::pbvh::Type::Grids) {
856 }
857 undo::push_end(object);
858}
859
860static void init_operation(bContext &C, gesture::GestureData &gesture_data, wmOperator &op)
861{
862 gesture_data.operation = reinterpret_cast<gesture::Operation *>(
864
865 MaskOperation *mask_operation = (MaskOperation *)gesture_data.operation;
866
867 Object *object = gesture_data.vc.obact;
868 MultiresModifierData *mmd = BKE_sculpt_multires_active(gesture_data.vc.scene, object);
870 CTX_data_depsgraph_pointer(&C), CTX_data_main(&C), gesture_data.vc.obact, mmd);
871
872 mask_operation->op.begin = gesture_begin;
874 mask_operation->op.end = gesture_end;
875
876 mask_operation->mode = FloodFillMode(RNA_enum_get(op.ptr, "mode"));
877 mask_operation->value = RNA_float_get(op.ptr, "value");
878}
879
881{
882 RNA_def_enum(ot->srna, "mode", mode_items, int(FloodFillMode::Value), "Mode", nullptr);
884 ot->srna,
885 "value",
886 1.0f,
887 0.0f,
888 1.0f,
889 "Value",
890 "Mask level to use when mode is 'Value'; zero means no masking and one is fully masked",
891 0.0f,
892 1.0f);
893}
894
896{
897 std::unique_ptr<gesture::GestureData> gesture_data = gesture::init_from_box(C, op);
898 if (!gesture_data) {
899 return OPERATOR_CANCELLED;
900 }
901 init_operation(*C, *gesture_data, *op);
902 gesture::apply(*C, *gesture_data, *op);
903 return OPERATOR_FINISHED;
904}
905
907{
908 std::unique_ptr<gesture::GestureData> gesture_data = gesture::init_from_lasso(C, op);
909 if (!gesture_data) {
910 return OPERATOR_CANCELLED;
911 }
912 init_operation(*C, *gesture_data, *op);
913 gesture::apply(*C, *gesture_data, *op);
914 return OPERATOR_FINISHED;
915}
916
918{
919 std::unique_ptr<gesture::GestureData> gesture_data = gesture::init_from_line(C, op);
920 if (!gesture_data) {
921 return OPERATOR_CANCELLED;
922 }
923 init_operation(*C, *gesture_data, *op);
924 gesture::apply(*C, *gesture_data, *op);
925 return OPERATOR_FINISHED;
926}
927
929{
930 std::unique_ptr<gesture::GestureData> gesture_data = gesture::init_from_polyline(C, op);
931 if (!gesture_data) {
932 return OPERATOR_CANCELLED;
933 }
934 init_operation(*C, *gesture_data, *op);
935 gesture::apply(*C, *gesture_data, *op);
936 return OPERATOR_FINISHED;
937}
938
940{
941 ot->name = "Mask Lasso Gesture";
942 ot->idname = "PAINT_OT_mask_lasso_gesture";
943 ot->description = "Mask within a shape defined by the cursor";
944
945 ot->invoke = WM_gesture_lasso_invoke;
946 ot->modal = WM_gesture_lasso_modal;
947 ot->exec = gesture_lasso_exec;
948
950
952
955
957}
958
960{
961 ot->name = "Mask Box Gesture";
962 ot->idname = "PAINT_OT_mask_box_gesture";
963 ot->description = "Mask within a rectangle defined by the cursor";
964
965 ot->invoke = WM_gesture_box_invoke;
966 ot->modal = WM_gesture_box_modal;
967 ot->exec = gesture_box_exec;
968
970
971 ot->flag = OPTYPE_REGISTER;
972
975
977}
978
980{
981 ot->name = "Mask Line Gesture";
982 ot->idname = "PAINT_OT_mask_line_gesture";
983 ot->description = "Mask to one side of a line defined by the cursor";
984
987 ot->exec = gesture_line_exec;
988
990
991 ot->flag = OPTYPE_REGISTER;
992
995
997}
998
1000{
1001 ot->name = "Mask Polyline Gesture";
1002 ot->idname = "PAINT_OT_mask_polyline_gesture";
1003 ot->description = "Mask within a shape defined by the cursor";
1004
1007 ot->exec = gesture_polyline_exec;
1008
1010
1012
1015
1017}
1018
1020
1021} // namespace blender::ed::sculpt_paint::mask
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
int CustomData_get_offset_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
void multires_mark_as_modified(Depsgraph *depsgraph, Object *object, MultiresModifiedFlags flags)
Definition multires.cc:365
MultiresModifierData * BKE_sculpt_multires_active(const Scene *scene, Object *ob)
Definition paint.cc:2373
void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph, Object *ob_orig, bool is_paint_tool)
Definition paint.cc:2657
void BKE_sculpt_mask_layers_ensure(Depsgraph *depsgraph, Main *bmain, Object *ob, MultiresModifierData *mmd)
Definition paint.cc:2666
A BVH for high poly meshes.
bool BKE_pbvh_node_fully_hidden_get(const blender::bke::pbvh::Node &node)
Definition pbvh.cc:1539
void BKE_pbvh_node_fully_unmasked_set(blender::bke::pbvh::Node &node, int fully_masked)
Definition pbvh.cc:1563
void BKE_pbvh_node_fully_masked_set(blender::bke::pbvh::Node &node, int fully_masked)
Definition pbvh.cc:1545
const blender::Set< BMVert *, 0 > & BKE_pbvh_bmesh_node_unique_verts(blender::bke::pbvh::BMeshNode *node)
CCGKey BKE_subdiv_ccg_key_top_level(const SubdivCCG &subdiv_ccg)
void BKE_subdiv_ccg_foreach_visible_grid_vert(const CCGKey &key, const blender::BitGroupVector<> &grid_hidden, const int grid, const Fn &fn)
@ MULTIRES_COORDS_MODIFIED
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
@ CD_PROP_FLOAT
Object is a sort of wrapper for general info.
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ SEL_OP_ADD
@ SEL_OP_SUB
@ SEL_OP_XOR
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
@ OPTYPE_DEPENDS_ON_CURSOR
Definition WM_types.hh:218
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define BM_ELEM_CD_SET_FLOAT(ele, offset, f)
#define BM_ELEM_CD_GET_FLOAT(ele, offset)
@ BM_ELEM_HIDDEN
#define BM_elem_flag_test(ele, hflag)
BMesh * bm
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
BPy_StructRNA * depsgraph
static T sum(const btAlignedObjectArray< T > &items)
Span< T > as_span() const
Definition BLI_array.hh:232
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:237
bool is_empty() const
Definition BLI_array.hh:253
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
static IndexMask from_bools(Span< bool > bools, IndexMaskMemory &memory)
void resize(const int64_t new_size)
MutableSpan< T > as_mutable_span()
Span< T > as_span() const
bool is_empty() const
Definition BLI_array.hh:253
static IndexMask from_bools(Span< bool > bools, IndexMaskMemory &memory)
constexpr Iterator end() const
constexpr Iterator begin() const
constexpr int64_t size() const
Definition BLI_span.hh:493
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:573
constexpr void fill(const T &value) const
Definition BLI_span.hh:517
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr const T * end() const
Definition BLI_span.hh:224
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr const T * begin() const
Definition BLI_span.hh:220
constexpr bool is_empty() const
Definition BLI_span.hh:260
GAttributeReader lookup(const StringRef attribute_id) const
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const void *default_value=nullptr) const
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
Span< NodeT > nodes() const
void tag_masks_changed(const IndexMask &node_mask)
Definition pbvh.cc:593
IndexMask slice(IndexRange range) const
void foreach_index(Fn &&fn) const
static ushort indices[]
static float verts[][3]
static float normals[][3]
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
bool indexed_data_equal(const Span< T > all_values, const Span< int > indices, const Span< T > values)
void foreach_0_index(const BitSpanT &data, Fn &&fn)
IndexRange grid_range(const int grid_area, const int grid)
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:2912
IndexMask all_leaf_nodes(const Tree &pbvh, IndexMaskMemory &memory)
Definition pbvh.cc:2544
void node_update_mask_bmesh(int mask_offset, BMeshNode &node)
Definition pbvh.cc:1295
void node_update_mask_mesh(Span< float > mask, MeshNode &node)
Definition pbvh.cc:1237
void node_update_mask_grids(const CCGKey &key, Span< float > masks, GridsNode &node)
Definition pbvh.cc:1265
Span< float3 > vert_normals_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2435
Span< float3 > vert_positions_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2416
std::unique_ptr< GestureData > init_from_box(bContext *C, wmOperator *op)
void operator_properties(wmOperatorType *ot, ShapeType shapeType)
std::unique_ptr< GestureData > init_from_polyline(bContext *C, wmOperator *op)
std::unique_ptr< GestureData > init_from_line(bContext *C, const wmOperator *op)
void apply(bContext &C, GestureData &gesture_data, wmOperator &op)
std::unique_ptr< GestureData > init_from_lasso(bContext *C, wmOperator *op)
bool is_affected(const GestureData &gesture_data, const float3 &position, const float3 &normal)
Span< int > node_visible_verts(const bke::pbvh::MeshNode &node, const Span< bool > hide_vert, Vector< int > &indices)
bool mask_equals_array_bmesh(const int mask_offset, const Set< BMVert *, 0 > &verts, const Span< float > values)
void scatter_mask_grids(const Span< float > mask, SubdivCCG &subdiv_ccg, const Span< int > grids)
static void gesture_end(bContext &C, gesture::GestureData &gesture_data)
static float average_masks(const int mask_offset, const Span< const BMVert * > verts)
void PAINT_OT_mask_polyline_gesture(wmOperatorType *ot)
bool mask_equals_array_grids(const Span< float > masks, const CCGKey &key, const Span< int > grids, const Span< float > values)
void PAINT_OT_mask_line_gesture(wmOperatorType *ot)
void write_mask_mesh(const Depsgraph &depsgraph, Object &object, const IndexMask &node_mask, FunctionRef< void(MutableSpan< float >, Span< int >)> write_fn)
static wmOperatorStatus gesture_polyline_exec(bContext *C, wmOperator *op)
static const EnumPropertyItem mode_items[]
static wmOperatorStatus mask_flood_fill_exec(bContext *C, wmOperator *op)
static void fill_mask_grids(Main &bmain, const Scene &scene, Depsgraph &depsgraph, Object &object, const float value, const IndexMask &node_mask)
static void invert_mask_bmesh(const Depsgraph &depsgraph, Object &object, const IndexMask &node_mask)
void update_mask_mesh(const Depsgraph &depsgraph, Object &object, const IndexMask &node_mask, FunctionRef< void(MutableSpan< float >, Span< int >)> update_fn)
static void init_operation(bContext &C, gesture::GestureData &gesture_data, wmOperator &op)
static bool try_remove_mask_mesh(const Depsgraph &depsgraph, Object &object, const IndexMask &node_mask)
void scatter_mask_bmesh(const Span< float > mask, const BMesh &bm, const Set< BMVert *, 0 > &verts)
static void gesture_apply_for_symmetry_pass(bContext &, gesture::GestureData &gesture_data)
void gather_mask_bmesh(const BMesh &bm, const Set< BMVert *, 0 > &verts, const MutableSpan< float > r_mask)
void mix_new_masks(const Span< float > new_masks, const float factor, const MutableSpan< float > masks)
Definition paint_mask.cc:97
static void gesture_begin(bContext &C, wmOperator &op, gesture::GestureData &gesture_data)
static wmOperatorStatus gesture_lasso_exec(bContext *C, wmOperator *op)
Array< float > duplicate_mask(const Object &object)
Definition paint_mask.cc:57
static Span< int > get_hidden_verts(const bke::pbvh::MeshNode &node, const Span< bool > hide_vert, Vector< int > &indices)
static void fill_mask(Main &bmain, const Scene &scene, Depsgraph &depsgraph, Object &object, const float value)
void invert_mask(const MutableSpan< float > masks)
void gather_mask_grids(const SubdivCCG &subdiv_ccg, const Span< int > grids, const MutableSpan< float > r_mask)
static wmOperatorStatus gesture_line_exec(bContext *C, wmOperator *op)
static void fill_mask_bmesh(const Depsgraph &depsgraph, Object &object, const float value, const IndexMask &node_mask)
static float mask_gesture_get_new_value(const float elem, FloodFillMode mode, float value)
static void gesture_operator_properties(wmOperatorType *ot)
void PAINT_OT_mask_box_gesture(wmOperatorType *ot)
static void invert_mask_grids(Main &bmain, const Scene &scene, Depsgraph &depsgraph, Object &object, const IndexMask &node_mask)
void PAINT_OT_mask_lasso_gesture(wmOperatorType *ot)
static wmOperatorStatus gesture_box_exec(bContext *C, wmOperator *op)
void clamp_mask(const MutableSpan< float > masks)
void PAINT_OT_mask_flood_fill(wmOperatorType *ot)
void average_neighbor_mask_bmesh(const int mask_offset, const Set< BMVert *, 0 > &verts, const MutableSpan< float > new_masks)
static void fill_mask_mesh(const Depsgraph &depsgraph, Object &object, const float value, const IndexMask &node_mask)
void push_nodes(const Depsgraph &depsgraph, Object &object, const IndexMask &node_mask, const Type type)
void push_node(const Depsgraph &depsgraph, const Object &object, const bke::pbvh::Node *node, const Type type)
void push_begin(const Scene &scene, Object &ob, const wmOperator *op)
void gather_data_grids(const SubdivCCG &subdiv_ccg, Span< T > src, Span< int > grids, MutableSpan< T > node_data)
Definition sculpt.cc:6391
void vert_random_access_ensure(Object &object)
Definition sculpt.cc:142
Vector< BMVert *, 64 > BMeshNeighborVerts
void scatter_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6421
Span< BMVert * > vert_neighbors_get_bmesh(BMVert &vert, BMeshNeighborVerts &r_neighbors)
Definition sculpt.cc:388
void gather_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6381
void scatter_data_grids(const SubdivCCG &subdiv_ccg, Span< T > node_data, Span< int > grids, MutableSpan< T > dst)
Definition sculpt.cc:6431
Value parallel_reduce(IndexRange range, int64_t grain_size, const Value &identity, const Function &function, const Reduction &reduction)
Definition BLI_task.hh:151
float RNA_float_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
bool SCULPT_mode_poll_view3d(bContext *C)
Definition sculpt.cc:3666
bool SCULPT_mode_poll(bContext *C)
Definition sculpt.cc:3660
void SCULPT_tag_update_overlays(bContext *C)
Definition sculpt.cc:760
int grid_area
Definition BKE_ccg.hh:35
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:415
blender::Array< float > masks
blender::Array< blender::float3 > positions
Scene * scene
Definition ED_view3d.hh:73
Object * obact
Definition ED_view3d.hh:75
Depsgraph * depsgraph
Definition ED_view3d.hh:72
void(* end)(bContext &, GestureData &)
void(* begin)(bContext &, wmOperator &, GestureData &)
void(* apply_for_symmetry_pass)(bContext &, GestureData &)
struct PointerRNA * ptr
i
Definition text_draw.cc:230
@ WM_CURSOR_EDIT
Definition wm_cursors.hh:19
wmOperatorType * ot
Definition wm_files.cc:4226
wmOperatorStatus WM_gesture_polyline_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_lasso_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_straightline_active_side_invoke(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_polyline_invoke(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_straightline_oneshot_modal(bContext *C, wmOperator *op, const wmEvent *event)
void WM_operator_properties_gesture_straightline(wmOperatorType *ot, int cursor)
void WM_operator_properties_border(wmOperatorType *ot)
void WM_operator_properties_gesture_lasso(wmOperatorType *ot)
void WM_operator_properties_gesture_polyline(wmOperatorType *ot)