Blender V4.5
sculpt_filter_mask.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2020 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_array_utils.hh"
11#include "BLI_math_base.hh"
12
13#include "BKE_attribute.hh"
14#include "BKE_context.hh"
15#include "BKE_layer.hh"
16#include "BKE_mesh.hh"
17#include "BKE_paint.hh"
18#include "BKE_paint_bvh.hh"
19#include "BKE_subdiv_ccg.hh"
20
21#include "WM_api.hh"
22#include "WM_types.hh"
23
24#include "mesh_brush_common.hh"
25#include "paint_intern.hh"
26#include "paint_mask.hh"
27#include "sculpt_automask.hh"
28#include "sculpt_hide.hh"
29#include "sculpt_intern.hh"
30#include "sculpt_smooth.hh"
31#include "sculpt_undo.hh"
32
33#include "RNA_access.hh"
34#include "RNA_define.hh"
35
36#include "bmesh.hh"
37
39
48
50 const Span<bool> hide_vert,
51 const Span<float> mask,
52 const MutableSpan<float> new_mask)
53{
54 BLI_assert(verts.size() == new_mask.size());
55 if (hide_vert.is_empty()) {
56 return;
57 }
58
59 for (const int i : verts.index_range()) {
60 if (hide_vert[verts[i]]) {
61 new_mask[i] = mask[verts[i]];
62 }
63 }
64}
65
67 const float factor,
68 const float offset,
69 const MutableSpan<float> dst)
70{
71 for (const int i : src.index_range()) {
72 dst[i] = factor * src[i] + offset;
73 }
74}
75
77 const MutableSpan<float> dst)
78{
79 const float contrast = 0.1f;
80 const float delta = contrast * 0.5f;
81 const float gain = math::rcp(1.0f - contrast);
82 const float offset = gain * -delta;
83 multiply_add(src, gain, offset, dst);
84
86}
87
89 const MutableSpan<float> dst)
90{
91 const float contrast = -0.1f;
92 const float delta = contrast * 0.5f;
93 const float gain = 1.0f - contrast;
94 const float offset = gain * -delta;
95 multiply_add(src, gain, offset, dst);
96
98}
99
100BLI_NOINLINE static void sharpen_masks(const Span<float> old_masks,
101 const MutableSpan<float> new_mask)
102{
103 for (const int i : old_masks.index_range()) {
104 float val = new_mask[i];
105 float mask = old_masks[i];
106 val -= mask;
107 if (mask > 0.5f) {
108 mask += 0.05f;
109 }
110 else {
111 mask -= 0.05f;
112 }
113 mask += val / 2.0f;
114 new_mask[i] = mask;
115 }
116
117 mask::clamp_mask(new_mask);
118}
119
127
128static void apply_new_mask_mesh(const Depsgraph &depsgraph,
129 Object &object,
130 const IndexMask &node_mask,
131 const OffsetIndices<int> node_verts,
132 const Span<float> new_mask,
134{
135 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
137
138 Array<bool> node_changed(node_mask.min_array_size(), false);
139
140 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
141 const Span<int> verts = nodes[i].verts();
142 const Span<float> new_node_mask = new_mask.slice(node_verts[pos]);
144 return;
145 }
147 scatter_data_mesh(new_node_mask, verts, mask);
149 node_changed[i] = true;
150 });
151
152 IndexMaskMemory memory;
153 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
154}
155
157 const Span<int> corner_verts,
158 const GroupedSpan<int> vert_to_face,
159 const Span<bool> hide_poly,
160 const Span<bool> hide_vert,
161 const Span<float> mask,
162 const bke::pbvh::MeshNode &node,
163 FilterLocalData &tls,
164 MutableSpan<float> new_mask)
165{
166 const Span<int> verts = node.verts();
167
169 corner_verts,
170 vert_to_face,
171 hide_poly,
172 verts,
174 tls.neighbor_data);
175
176 tls.node_mask.resize(verts.size());
177 const MutableSpan<float> node_mask = tls.node_mask;
178 gather_data_mesh(mask, verts, node_mask);
179
180 smooth::neighbor_data_average_mesh(mask, neighbors, new_mask);
181 mask::mix_new_masks(new_mask, 0.5f, node_mask);
182 copy_old_hidden_mask_mesh(verts, hide_vert, mask, node_mask);
183 mask::clamp_mask(node_mask);
184 new_mask.copy_from(node_mask);
185}
186
188 const Span<int> corner_verts,
189 const GroupedSpan<int> vert_to_face,
190 const Span<bool> hide_poly,
191 const Span<bool> hide_vert,
192 const Span<float> mask,
193 const bke::pbvh::MeshNode &node,
194 FilterLocalData &tls,
195 MutableSpan<float> new_mask)
196{
197 const Span<int> verts = node.verts();
198
199 tls.node_mask.resize(verts.size());
200 const MutableSpan<float> node_mask = tls.node_mask;
201 gather_data_mesh(mask, verts, node_mask);
202
204 corner_verts,
205 vert_to_face,
206 hide_poly,
207 verts,
209 tls.neighbor_data);
210
211 smooth::neighbor_data_average_mesh(mask, neighbors, new_mask);
212
213 sharpen_masks(node_mask, new_mask);
214 copy_old_hidden_mask_mesh(verts, hide_vert, mask, new_mask);
215}
216
218 const Span<int> corner_verts,
219 const GroupedSpan<int> vert_to_face,
220 const Span<bool> hide_poly,
221 const Span<bool> hide_vert,
222 const Span<float> mask,
223 const bke::pbvh::MeshNode &node,
224 FilterLocalData &tls,
225 MutableSpan<float> new_mask)
226{
227 const Span<int> verts = node.verts();
228
230 corner_verts,
231 vert_to_face,
232 hide_poly,
233 verts,
235 tls.neighbor_data);
236
237 for (const int i : verts.index_range()) {
238 new_mask[i] = mask[verts[i]];
239 for (const int neighbor : neighbors[i]) {
240 new_mask[i] = std::max(mask[neighbor], new_mask[i]);
241 }
242 }
243 copy_old_hidden_mask_mesh(verts, hide_vert, mask, new_mask);
244}
245
247 const Span<int> corner_verts,
248 const GroupedSpan<int> vert_to_face,
249 const Span<bool> hide_poly,
250 const Span<bool> hide_vert,
251 const Span<float> mask,
252 const bke::pbvh::MeshNode &node,
253 FilterLocalData &tls,
254 MutableSpan<float> new_mask)
255{
256 const Span<int> verts = node.verts();
257
259 corner_verts,
260 vert_to_face,
261 hide_poly,
262 verts,
264 tls.neighbor_data);
265
266 for (const int i : verts.index_range()) {
267 new_mask[i] = mask[verts[i]];
268 for (const int neighbor : neighbors[i]) {
269 new_mask[i] = std::min(mask[neighbor], new_mask[i]);
270 }
271 }
272 copy_old_hidden_mask_mesh(verts, hide_vert, mask, new_mask);
273}
274
275static bool increase_contrast_mask_mesh(const Depsgraph &depsgraph,
276 const Object &object,
277 const Span<bool> hide_vert,
279 FilterLocalData &tls,
281{
282 const Span<int> verts = hide::node_visible_verts(node, hide_vert, tls.visible_verts);
283
284 const Span<float> node_mask = gather_data_mesh(mask.as_span(), verts, tls.node_mask);
285
286 tls.new_mask.resize(verts.size());
287 const MutableSpan<float> new_mask = tls.new_mask;
288 mask_increase_contrast(node_mask, new_mask);
289 copy_old_hidden_mask_mesh(verts, hide_vert, mask, new_mask);
290
291 if (node_mask == new_mask.as_span()) {
292 return false;
293 }
294
296 scatter_data_mesh(new_mask.as_span(), verts, mask);
298 return true;
299}
300
301static bool decrease_contrast_mask_mesh(const Depsgraph &depsgraph,
302 const Object &object,
303 const Span<bool> hide_vert,
305 FilterLocalData &tls,
307{
308 const Span<int> verts = hide::node_visible_verts(node, hide_vert, tls.visible_verts);
309
310 const Span<float> node_mask = gather_data_mesh(mask.as_span(), verts, tls.node_mask);
311
312 tls.new_mask.resize(verts.size());
313 const MutableSpan<float> new_mask = tls.new_mask;
314 mask_decrease_contrast(node_mask, new_mask);
315 copy_old_hidden_mask_mesh(verts, hide_vert, mask, new_mask);
316
317 if (node_mask == new_mask.as_span()) {
318 return false;
319 }
320
322 scatter_data_mesh(new_mask.as_span(), verts, mask);
324 return true;
325}
326
328 const Span<int> grids,
329 const MutableSpan<float> new_mask)
330{
331 const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
332 if (subdiv_ccg.grid_hidden.is_empty()) {
333 return;
334 }
335 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
336 const Span<float> masks = subdiv_ccg.masks;
337 for (const int i : grids.index_range()) {
338 const Span grid_masks = masks.slice(bke::ccg::grid_range(key, grids[i]));
339 MutableSpan grid_dst = new_mask.slice(bke::ccg::grid_range(key, i));
340 bits::foreach_1_index(grid_hidden[grids[i]],
341 [&](const int offset) { grid_dst[offset] = grid_masks[offset]; });
342 }
343}
344
345static void apply_new_mask_grids(const Depsgraph &depsgraph,
346 Object &object,
347 const IndexMask &node_mask,
348 const OffsetIndices<int> node_verts,
349 const Span<float> new_mask)
350{
351 SculptSession &ss = *object.sculpt;
352 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
354 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
355 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
356 MutableSpan<float> masks = subdiv_ccg.masks;
357
358 Array<bool> node_changed(node_mask.min_array_size(), false);
359
360 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
361 const Span<int> grids = nodes[i].grids();
362 const Span<float> new_node_mask = new_mask.slice(node_verts[pos]);
363 if (mask_equals_array_grids(masks, key, grids, new_node_mask)) {
364 return;
365 }
367 scatter_data_grids(subdiv_ccg, new_node_mask, grids, masks);
369 node_changed[i] = true;
370 });
371
372 IndexMaskMemory memory;
373 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
374
375 /* New mask values need propagation across grid boundaries. */
377}
378
379static void smooth_mask_grids(const SubdivCCG &subdiv_ccg,
380 const bke::pbvh::GridsNode &node,
381 FilterLocalData &tls,
382 MutableSpan<float> new_mask)
383{
384 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
385
386 const Span<int> grids = node.grids();
387 const int grid_verts_num = grids.size() * key.grid_area;
388
389 tls.node_mask.resize(grid_verts_num);
390 const MutableSpan<float> node_mask = tls.node_mask;
391 gather_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, node_mask);
392
393 smooth::average_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, new_mask);
394 mask::mix_new_masks(new_mask, 0.5f, node_mask);
395 copy_old_hidden_mask_grids(subdiv_ccg, grids, node_mask);
396 mask::clamp_mask(node_mask);
397 new_mask.copy_from(node_mask);
398}
399
400static void sharpen_mask_grids(const SubdivCCG &subdiv_ccg,
401 const bke::pbvh::GridsNode &node,
402 FilterLocalData &tls,
403 MutableSpan<float> new_mask)
404{
405 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
406
407 const Span<int> grids = node.grids();
408 const int grid_verts_num = grids.size() * key.grid_area;
409
410 tls.node_mask.resize(grid_verts_num);
411 const MutableSpan<float> node_mask = tls.node_mask;
412 gather_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, node_mask);
413
414 smooth::average_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, new_mask);
415
416 sharpen_masks(node_mask, new_mask);
417
418 copy_old_hidden_mask_grids(subdiv_ccg, grids, new_mask);
419}
420
421static void grow_mask_grids(const SubdivCCG &subdiv_ccg,
422 const bke::pbvh::GridsNode &node,
423 MutableSpan<float> new_mask)
424{
425 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
426 const Span<float> masks = subdiv_ccg.masks;
427
428 const Span<int> grids = node.grids();
429
430 for (const int i : grids.index_range()) {
431 const int grid = grids[i];
432 const Span grid_masks = masks.slice(bke::ccg::grid_range(key, grid));
433 MutableSpan grid_dst = new_mask.slice(bke::ccg::grid_range(key, i));
434
435 for (const short y : IndexRange(key.grid_size)) {
436 for (const short x : IndexRange(key.grid_size)) {
437 const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
438
439 SubdivCCGNeighbors neighbors;
440 SubdivCCGCoord coord{grid, x, y};
441 BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, coord, false, neighbors);
442
443 grid_dst[offset] = grid_masks[offset];
444 for (const SubdivCCGCoord neighbor : neighbors.coords) {
445 grid_dst[offset] = std::max(masks[neighbor.to_index(key)], grid_dst[offset]);
446 }
447 }
448 }
449 }
450
451 copy_old_hidden_mask_grids(subdiv_ccg, grids, new_mask);
452}
453
454static void shrink_mask_grids(const SubdivCCG &subdiv_ccg,
455 const bke::pbvh::GridsNode &node,
456 MutableSpan<float> new_mask)
457{
458 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
459 const Span<float> masks = subdiv_ccg.masks;
460
461 const Span<int> grids = node.grids();
462
463 for (const int i : grids.index_range()) {
464 const int grid = grids[i];
465 const Span grid_masks = masks.slice(bke::ccg::grid_range(key, grid));
466 MutableSpan grid_dst = new_mask.slice(bke::ccg::grid_range(key, i));
467
468 for (const short y : IndexRange(key.grid_size)) {
469 for (const short x : IndexRange(key.grid_size)) {
470 const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
471
472 SubdivCCGNeighbors neighbors;
473 SubdivCCGCoord coord{grid, x, y};
474 BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, coord, false, neighbors);
475
476 grid_dst[offset] = grid_masks[offset];
477 for (const SubdivCCGCoord neighbor : neighbors.coords) {
478 grid_dst[offset] = std::min(masks[neighbor.to_index(key)], grid_dst[offset]);
479 }
480 }
481 }
482 }
483
484 copy_old_hidden_mask_grids(subdiv_ccg, grids, new_mask);
485}
486
487static bool increase_contrast_mask_grids(const Depsgraph &depsgraph,
488 const Object &object,
490 FilterLocalData &tls)
491{
492 SculptSession &ss = *object.sculpt;
493 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
494 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
495
496 const Span<int> grids = node.grids();
497 const int grid_verts_num = grids.size() * key.grid_area;
498
499 tls.node_mask.resize(grid_verts_num);
500 const MutableSpan<float> node_mask = tls.node_mask;
501 gather_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, node_mask);
502
503 tls.new_mask.resize(grid_verts_num);
504 const MutableSpan<float> new_mask = tls.new_mask;
505 mask_increase_contrast(node_mask, new_mask);
506
507 copy_old_hidden_mask_grids(subdiv_ccg, grids, new_mask);
508
509 if (node_mask.as_span() == new_mask.as_span()) {
510 return false;
511 }
512
514 scatter_data_grids(subdiv_ccg, new_mask.as_span(), grids, subdiv_ccg.masks.as_mutable_span());
515 bke::pbvh::node_update_mask_grids(key, subdiv_ccg.masks, node);
516 return true;
517}
518
519static bool decrease_contrast_mask_grids(const Depsgraph &depsgraph,
520 const Object &object,
522 FilterLocalData &tls)
523{
524 SculptSession &ss = *object.sculpt;
525 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
526 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
527
528 const Span<int> grids = node.grids();
529 const int grid_verts_num = grids.size() * key.grid_area;
530
531 tls.node_mask.resize(grid_verts_num);
532 const MutableSpan<float> node_mask = tls.node_mask;
533 gather_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, node_mask);
534
535 tls.new_mask.resize(grid_verts_num);
536 const MutableSpan<float> new_mask = tls.new_mask;
537 mask_decrease_contrast(node_mask, new_mask);
538
539 copy_old_hidden_mask_grids(subdiv_ccg, grids, new_mask);
540
541 if (node_mask.as_span() == new_mask.as_span()) {
542 return false;
543 }
544
546 scatter_data_grids(subdiv_ccg, new_mask.as_span(), grids, subdiv_ccg.masks.as_mutable_span());
547 bke::pbvh::node_update_mask_grids(key, subdiv_ccg.masks, node);
548 return true;
549}
550
551BLI_NOINLINE static void copy_old_hidden_mask_bmesh(const int mask_offset,
552 const Set<BMVert *, 0> &verts,
553 const MutableSpan<float> new_mask)
554{
555 int i = 0;
556 for (const BMVert *vert : verts) {
558 new_mask[i] = BM_ELEM_CD_GET_FLOAT(vert, mask_offset);
559 }
560 i++;
561 }
562}
563
564static void apply_new_mask_bmesh(const Depsgraph &depsgraph,
565 Object &object,
566 const int mask_offset,
567 const IndexMask &node_mask,
568 const OffsetIndices<int> node_verts,
569 const Span<float> new_mask)
570{
571 SculptSession &ss = *object.sculpt;
572 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
574 BMesh &bm = *ss.bm;
575
576 Array<bool> node_changed(node_mask.min_array_size(), false);
577
578 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
580 const Span<float> new_node_mask = new_mask.slice(node_verts[pos]);
581 if (mask_equals_array_bmesh(mask_offset, verts, new_node_mask)) {
582 return;
583 }
585 scatter_mask_bmesh(new_node_mask, bm, verts);
587 node_changed[i] = true;
588 });
589
590 IndexMaskMemory memory;
591 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
592}
593
594static void smooth_mask_bmesh(const BMesh &bm,
595 const int mask_offset,
597 FilterLocalData &tls,
598 MutableSpan<float> new_mask)
599{
601
602 tls.node_mask.resize(verts.size());
603 const MutableSpan<float> node_mask = tls.node_mask;
604 gather_mask_bmesh(bm, verts, node_mask);
605
606 average_neighbor_mask_bmesh(mask_offset, verts, new_mask);
607 mask::mix_new_masks(new_mask, 0.5f, node_mask);
608 copy_old_hidden_mask_bmesh(mask_offset, verts, node_mask);
609 mask::clamp_mask(node_mask);
610 new_mask.copy_from(node_mask);
611}
612
613static void sharpen_mask_bmesh(const BMesh &bm,
614 const int mask_offset,
616 FilterLocalData &tls,
617 MutableSpan<float> new_mask)
618{
620
621 tls.node_mask.resize(verts.size());
622 const MutableSpan<float> node_mask = tls.node_mask;
623 gather_mask_bmesh(bm, verts, node_mask);
624
625 average_neighbor_mask_bmesh(mask_offset, verts, new_mask);
626
627 sharpen_masks(node_mask, new_mask);
628
629 copy_old_hidden_mask_bmesh(mask_offset, verts, new_mask);
630}
631
632static void grow_mask_bmesh(const int mask_offset,
634 MutableSpan<float> new_mask)
635{
637
638 BMeshNeighborVerts neighbors;
639 int i = 0;
640 for (BMVert *vert : verts) {
641 new_mask[i] = BM_ELEM_CD_GET_FLOAT(vert, mask_offset);
642 for (const BMVert *neighbor : vert_neighbors_get_bmesh(*vert, neighbors)) {
643 new_mask[i] = std::max(BM_ELEM_CD_GET_FLOAT(neighbor, mask_offset), new_mask[i]);
644 }
645 i++;
646 }
647
648 copy_old_hidden_mask_bmesh(mask_offset, verts, new_mask);
649}
650
651static void shrink_mask_bmesh(const int mask_offset,
653 MutableSpan<float> new_mask)
654{
656
657 BMeshNeighborVerts neighbors;
658 int i = 0;
659 for (BMVert *vert : verts) {
660 new_mask[i] = BM_ELEM_CD_GET_FLOAT(vert, mask_offset);
661 for (const BMVert *neighbor : vert_neighbors_get_bmesh(*vert, neighbors)) {
662 new_mask[i] = std::min(BM_ELEM_CD_GET_FLOAT(neighbor, mask_offset), new_mask[i]);
663 }
664 i++;
665 }
666
667 copy_old_hidden_mask_bmesh(mask_offset, verts, new_mask);
668}
669
670static bool increase_contrast_mask_bmesh(const Depsgraph &depsgraph,
671 Object &object,
672 const int mask_offset,
674 FilterLocalData &tls)
675{
676 SculptSession &ss = *object.sculpt;
677 BMesh &bm = *ss.bm;
678
680
681 tls.node_mask.resize(verts.size());
682 const MutableSpan<float> node_mask = tls.node_mask;
683 gather_mask_bmesh(bm, verts, node_mask);
684
685 tls.new_mask.resize(verts.size());
686 const MutableSpan<float> new_mask = tls.new_mask;
687 mask_increase_contrast(node_mask, new_mask);
688
689 copy_old_hidden_mask_bmesh(mask_offset, verts, new_mask);
690
691 if (node_mask.as_span() == new_mask.as_span()) {
692 return false;
693 }
694
696 scatter_mask_bmesh(new_mask.as_span(), bm, verts);
697 bke::pbvh::node_update_mask_bmesh(mask_offset, node);
698 return true;
699}
700
701static bool decrease_contrast_mask_bmesh(const Depsgraph &depsgraph,
702 Object &object,
703 const int mask_offset,
705 FilterLocalData &tls)
706{
707 SculptSession &ss = *object.sculpt;
708 BMesh &bm = *ss.bm;
709
711
712 tls.node_mask.resize(verts.size());
713 const MutableSpan<float> node_mask = tls.node_mask;
714 gather_mask_bmesh(bm, verts, node_mask);
715
716 tls.new_mask.resize(verts.size());
717 const MutableSpan<float> new_mask = tls.new_mask;
718 mask_decrease_contrast(node_mask, new_mask);
719
720 copy_old_hidden_mask_bmesh(mask_offset, verts, new_mask);
721
722 if (node_mask.as_span() == new_mask.as_span()) {
723 return false;
724 }
725
727 scatter_mask_bmesh(new_mask.as_span(), bm, verts);
728 bke::pbvh::node_update_mask_bmesh(mask_offset, node);
729 return true;
730}
731
733{
734 const Scene &scene = *CTX_data_scene(C);
737 const FilterType filter_type = FilterType(RNA_enum_get(op->ptr, "filter_type"));
738
739 const View3D *v3d = CTX_wm_view3d(C);
740 const Base *base = CTX_data_active_base(C);
741 if (!BKE_base_is_visible(v3d, base)) {
742 return OPERATOR_CANCELLED;
743 }
744
747
749
750 SculptSession &ss = *ob.sculpt;
752
753 IndexMaskMemory memory;
754 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
755 undo::push_begin(scene, ob, op);
756
757 int iterations = RNA_int_get(op->ptr, "iterations");
758
759 /* Auto iteration count calculates the number of iteration based on the vertices of the mesh to
760 * avoid adding an unnecessary amount of undo steps when using the operator from a shortcut.
761 * One iteration per 50000 vertices in the mesh should be fine in most cases.
762 * Maybe we want this to be configurable. */
763 if (RNA_boolean_get(op->ptr, "auto_iteration_count")) {
764 iterations = int(SCULPT_vertex_count_get(ob) / 50000.0f) + 1;
765 }
766
768 switch (pbvh.type()) {
771 Mesh &mesh = *static_cast<Mesh *>(ob.data);
772 const OffsetIndices<int> faces = mesh.faces();
773 const Span<int> corner_verts = mesh.corner_verts();
774 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
775 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
776 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
777 const VArraySpan hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
778 bke::SpanAttributeWriter mask = attributes.lookup_for_write_span<float>(".sculpt_mask");
779
780 Array<int> node_vert_offset_data;
782 nodes, node_mask, node_vert_offset_data);
783 Array<float> new_masks(node_offsets.total_size());
784
785 for ([[maybe_unused]] const int iteration : IndexRange(iterations)) {
786 switch (filter_type) {
787 case FilterType::Smooth: {
788 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
789 FilterLocalData &tls = all_tls.local();
791 corner_verts,
792 vert_to_face_map,
793 hide_poly,
794 hide_vert,
795 mask.span,
796 nodes[i],
797 tls,
798 new_masks.as_mutable_span().slice(node_offsets[pos]));
799 });
800 apply_new_mask_mesh(*depsgraph, ob, node_mask, node_offsets, new_masks, mask.span);
801 break;
802 }
803 case FilterType::Sharpen: {
804 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
805 FilterLocalData &tls = all_tls.local();
807 corner_verts,
808 vert_to_face_map,
809 hide_poly,
810 hide_vert,
811 mask.span,
812 nodes[i],
813 tls,
814 new_masks.as_mutable_span().slice(node_offsets[pos]));
815 });
816 apply_new_mask_mesh(*depsgraph, ob, node_mask, node_offsets, new_masks, mask.span);
817 break;
818 }
819 case FilterType::Grow: {
820 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
821 FilterLocalData &tls = all_tls.local();
823 corner_verts,
824 vert_to_face_map,
825 hide_poly,
826 hide_vert,
827 mask.span,
828 nodes[i],
829 tls,
830 new_masks.as_mutable_span().slice(node_offsets[pos]));
831 });
832 apply_new_mask_mesh(*depsgraph, ob, node_mask, node_offsets, new_masks, mask.span);
833 break;
834 }
835 case FilterType::Shrink: {
836 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
837 FilterLocalData &tls = all_tls.local();
839 corner_verts,
840 vert_to_face_map,
841 hide_poly,
842 hide_vert,
843 mask.span,
844 nodes[i],
845 tls,
846 new_masks.as_mutable_span().slice(node_offsets[pos]));
847 });
848 apply_new_mask_mesh(*depsgraph, ob, node_mask, node_offsets, new_masks, mask.span);
849 break;
850 }
852 Array<bool> node_changed(node_mask.min_array_size(), false);
853 node_mask.foreach_index(GrainSize(1), [&](const int i) {
854 FilterLocalData &tls = all_tls.local();
855 node_changed[i] = increase_contrast_mask_mesh(
856 *depsgraph, ob, hide_vert, nodes[i], tls, mask.span);
857 });
858 IndexMaskMemory memory;
859 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
860 break;
861 }
863 Array<bool> node_changed(node_mask.min_array_size(), false);
864 node_mask.foreach_index(GrainSize(1), [&](const int i) {
865 FilterLocalData &tls = all_tls.local();
866 node_changed[i] = decrease_contrast_mask_mesh(
867 *depsgraph, ob, hide_vert, nodes[i], tls, mask.span);
868 });
869 IndexMaskMemory memory;
870 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
871 break;
872 }
873 }
874 }
875 mask.finish();
876 break;
877 }
880 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
881
882 Array<int> node_vert_offset_data;
884 BKE_subdiv_ccg_key_top_level(subdiv_ccg), nodes, node_mask, node_vert_offset_data);
885 Array<float> new_masks(node_offsets.total_size());
886
887 for ([[maybe_unused]] const int iteration : IndexRange(iterations)) {
888 switch (filter_type) {
889 case FilterType::Smooth: {
890 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
891 FilterLocalData &tls = all_tls.local();
893 subdiv_ccg, nodes[i], tls, new_masks.as_mutable_span().slice(node_offsets[pos]));
894 });
895 apply_new_mask_grids(*depsgraph, ob, node_mask, node_offsets, new_masks);
896 break;
897 }
898 case FilterType::Sharpen: {
899 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
900 FilterLocalData &tls = all_tls.local();
902 subdiv_ccg, nodes[i], tls, new_masks.as_mutable_span().slice(node_offsets[pos]));
903 });
904 apply_new_mask_grids(*depsgraph, ob, node_mask, node_offsets, new_masks);
905 break;
906 }
907 case FilterType::Grow: {
908 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
910 subdiv_ccg, nodes[i], new_masks.as_mutable_span().slice(node_offsets[pos]));
911 });
912 apply_new_mask_grids(*depsgraph, ob, node_mask, node_offsets, new_masks);
913 break;
914 }
915 case FilterType::Shrink: {
916 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
918 subdiv_ccg, nodes[i], new_masks.as_mutable_span().slice(node_offsets[pos]));
919 });
920 apply_new_mask_grids(*depsgraph, ob, node_mask, node_offsets, new_masks);
921 break;
922 }
924 Array<bool> node_changed(node_mask.min_array_size(), false);
925 node_mask.foreach_index(GrainSize(1), [&](const int i) {
926 FilterLocalData &tls = all_tls.local();
927 node_changed[i] = increase_contrast_mask_grids(*depsgraph, ob, nodes[i], tls);
928 });
929 IndexMaskMemory memory;
930 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
931 break;
932 }
934 Array<bool> node_changed(node_mask.min_array_size(), false);
935 node_mask.foreach_index(GrainSize(1), [&](const int i) {
936 FilterLocalData &tls = all_tls.local();
937 node_changed[i] = decrease_contrast_mask_grids(*depsgraph, ob, nodes[i], tls);
938 });
939 IndexMaskMemory memory;
940 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
941 break;
942 }
943 }
944 }
945 break;
946 }
949 BMesh &bm = *ss.bm;
951 const int mask_offset = CustomData_get_offset_named(
952 &bm.vdata, CD_PROP_FLOAT, ".sculpt_mask");
953
954 Array<int> node_vert_offset_data;
956 nodes, node_mask, node_vert_offset_data);
957 Array<float> new_masks(node_offsets.total_size());
958
959 for ([[maybe_unused]] const int iteration : IndexRange(iterations)) {
960 switch (filter_type) {
961 case FilterType::Smooth: {
962 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
963 FilterLocalData &tls = all_tls.local();
965 mask_offset,
966 nodes[i],
967 tls,
968 new_masks.as_mutable_span().slice(node_offsets[pos]));
969 });
970 apply_new_mask_bmesh(*depsgraph, ob, mask_offset, node_mask, node_offsets, new_masks);
971 break;
972 }
973 case FilterType::Sharpen: {
974 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
975 FilterLocalData &tls = all_tls.local();
977 mask_offset,
978 nodes[i],
979 tls,
980 new_masks.as_mutable_span().slice(node_offsets[pos]));
981 });
982 apply_new_mask_bmesh(*depsgraph, ob, mask_offset, node_mask, node_offsets, new_masks);
983 break;
984 }
985 case FilterType::Grow: {
986 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
988 mask_offset, nodes[i], new_masks.as_mutable_span().slice(node_offsets[pos]));
989 });
990 apply_new_mask_bmesh(*depsgraph, ob, mask_offset, node_mask, node_offsets, new_masks);
991 break;
992 }
993 case FilterType::Shrink: {
994 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
996 mask_offset, nodes[i], new_masks.as_mutable_span().slice(node_offsets[pos]));
997 });
998 apply_new_mask_bmesh(*depsgraph, ob, mask_offset, node_mask, node_offsets, new_masks);
999 break;
1000 }
1002 Array<bool> node_changed(node_mask.min_array_size(), false);
1003 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1004 FilterLocalData &tls = all_tls.local();
1005 node_changed[i] = increase_contrast_mask_bmesh(
1006 *depsgraph, ob, mask_offset, nodes[i], tls);
1007 });
1008 IndexMaskMemory memory;
1009 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
1010 break;
1011 }
1013 Array<bool> node_changed(node_mask.min_array_size(), false);
1014 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1015 FilterLocalData &tls = all_tls.local();
1016 node_changed[i] = decrease_contrast_mask_bmesh(
1017 *depsgraph, ob, mask_offset, nodes[i], tls);
1018 });
1019 IndexMaskMemory memory;
1020 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
1021 break;
1022 }
1023 }
1024 }
1025 break;
1026 }
1027 }
1028
1029 undo::push_end(ob);
1030
1033
1035
1036 return OPERATOR_FINISHED;
1037}
1038
1040{
1041 ot->name = "Mask Filter";
1042 ot->idname = "SCULPT_OT_mask_filter";
1043 ot->description = "Applies a filter to modify the current mask";
1044
1046 ot->poll = SCULPT_mode_poll;
1047
1048 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1049
1050 static EnumPropertyItem type_items[] = {
1051 {int(FilterType::Smooth), "SMOOTH", 0, "Smooth Mask", ""},
1052 {int(FilterType::Sharpen), "SHARPEN", 0, "Sharpen Mask", ""},
1053 {int(FilterType::Grow), "GROW", 0, "Grow Mask", ""},
1054 {int(FilterType::Shrink), "SHRINK", 0, "Shrink Mask", ""},
1055 {int(FilterType::ContrastIncrease), "CONTRAST_INCREASE", 0, "Increase Contrast", ""},
1056 {int(FilterType::ContrastDecrease), "CONTRAST_DECREASE", 0, "Decrease Contrast", ""},
1057 {0, nullptr, 0, nullptr, nullptr},
1058 };
1059
1060 RNA_def_enum(ot->srna,
1061 "filter_type",
1062 type_items,
1063 int(FilterType::Smooth),
1064 "Type",
1065 "Filter that is going to be applied to the mask");
1066 RNA_def_int(ot->srna,
1067 "iterations",
1068 1,
1069 1,
1070 100,
1071 "Iterations",
1072 "Number of times that the filter is going to be applied",
1073 1,
1074 100);
1076 ot->srna,
1077 "auto_iteration_count",
1078 true,
1079 "Auto Iteration Count",
1080 "Use an automatic number of iterations based on the number of vertices of the sculpt");
1081}
1082
1083} // namespace blender::ed::sculpt_paint::mask
int CCG_grid_xy_to_index(const int grid_size, const int x, const int y)
Definition BKE_ccg.hh:77
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Base * CTX_data_active_base(const bContext *C)
Main * CTX_data_main(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
int CustomData_get_offset_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
bool BKE_base_is_visible(const View3D *v3d, const Base *base)
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.
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_average_grids(SubdivCCG &subdiv_ccg)
void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord, bool include_duplicates, SubdivCCGNeighbors &r_neighbors)
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_NOINLINE
@ CD_PROP_FLOAT
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
#define C
Definition RandGen.cpp:29
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define BM_ELEM_CD_GET_FLOAT(ele, offset)
@ BM_ELEM_HIDDEN
#define BM_elem_flag_test(ele, hflag)
BMesh * bm
BPy_StructRNA * depsgraph
Span< T > as_span() const
Definition BLI_array.hh:232
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:237
void resize(const int64_t new_size)
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:237
static IndexMask from_bools(Span< bool > bools, IndexMaskMemory &memory)
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 Span< T > as_span() const
Definition BLI_span.hh:661
constexpr void copy_from(Span< T > values) const
Definition BLI_span.hh:739
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool is_empty() const
Definition BLI_span.hh:260
GAttributeReader lookup(const StringRef attribute_id) const
GSpanAttributeWriter lookup_for_write_span(StringRef attribute_id)
Span< NodeT > nodes() const
void tag_masks_changed(const IndexMask &node_mask)
Definition pbvh.cc:593
void foreach_index(Fn &&fn) const
static float verts[][3]
uint pos
static char faces[256]
bool indexed_data_equal(const Span< T > all_values, const Span< int > indices, const Span< T > values)
void foreach_1_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< int > node_visible_verts(const bke::pbvh::MeshNode &node, const Span< bool > hide_vert, Vector< int > &indices)
static BLI_NOINLINE void copy_old_hidden_mask_mesh(const Span< int > verts, const Span< bool > hide_vert, const Span< float > mask, const MutableSpan< float > new_mask)
bool mask_equals_array_bmesh(const int mask_offset, const Set< BMVert *, 0 > &verts, const Span< float > values)
static BLI_NOINLINE void multiply_add(const Span< float > src, const float factor, const float offset, const MutableSpan< float > dst)
static void grow_mask_bmesh(const int mask_offset, bke::pbvh::BMeshNode &node, MutableSpan< float > new_mask)
void SCULPT_OT_mask_filter(wmOperatorType *ot)
static void smooth_mask_mesh(const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face, const Span< bool > hide_poly, const Span< bool > hide_vert, const Span< float > mask, const bke::pbvh::MeshNode &node, FilterLocalData &tls, MutableSpan< float > new_mask)
static void grow_mask_mesh(const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face, const Span< bool > hide_poly, const Span< bool > hide_vert, const Span< float > mask, const bke::pbvh::MeshNode &node, FilterLocalData &tls, MutableSpan< float > new_mask)
bool mask_equals_array_grids(const Span< float > masks, const CCGKey &key, const Span< int > grids, const Span< float > values)
static void shrink_mask_bmesh(const int mask_offset, bke::pbvh::BMeshNode &node, MutableSpan< float > new_mask)
static void sharpen_mask_bmesh(const BMesh &bm, const int mask_offset, bke::pbvh::BMeshNode &node, FilterLocalData &tls, MutableSpan< float > new_mask)
static bool increase_contrast_mask_grids(const Depsgraph &depsgraph, const Object &object, bke::pbvh::GridsNode &node, FilterLocalData &tls)
static bool decrease_contrast_mask_grids(const Depsgraph &depsgraph, const Object &object, bke::pbvh::GridsNode &node, FilterLocalData &tls)
static bool decrease_contrast_mask_bmesh(const Depsgraph &depsgraph, Object &object, const int mask_offset, bke::pbvh::BMeshNode &node, FilterLocalData &tls)
static void smooth_mask_grids(const SubdivCCG &subdiv_ccg, const bke::pbvh::GridsNode &node, FilterLocalData &tls, MutableSpan< float > new_mask)
static bool increase_contrast_mask_mesh(const Depsgraph &depsgraph, const Object &object, const Span< bool > hide_vert, bke::pbvh::MeshNode &node, FilterLocalData &tls, MutableSpan< float > mask)
static void sharpen_mask_mesh(const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face, const Span< bool > hide_poly, const Span< bool > hide_vert, const Span< float > mask, const bke::pbvh::MeshNode &node, FilterLocalData &tls, MutableSpan< float > new_mask)
static void apply_new_mask_grids(const Depsgraph &depsgraph, Object &object, const IndexMask &node_mask, const OffsetIndices< int > node_verts, const Span< float > new_mask)
static bool increase_contrast_mask_bmesh(const Depsgraph &depsgraph, Object &object, const int mask_offset, bke::pbvh::BMeshNode &node, FilterLocalData &tls)
static void shrink_mask_mesh(const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face, const Span< bool > hide_poly, const Span< bool > hide_vert, const Span< float > mask, const bke::pbvh::MeshNode &node, FilterLocalData &tls, MutableSpan< float > new_mask)
static BLI_NOINLINE void sharpen_masks(const Span< float > old_masks, const MutableSpan< float > new_mask)
void scatter_mask_bmesh(const Span< float > mask, const BMesh &bm, const Set< BMVert *, 0 > &verts)
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 smooth_mask_bmesh(const BMesh &bm, const int mask_offset, bke::pbvh::BMeshNode &node, FilterLocalData &tls, MutableSpan< float > new_mask)
static void shrink_mask_grids(const SubdivCCG &subdiv_ccg, const bke::pbvh::GridsNode &node, MutableSpan< float > new_mask)
static void apply_new_mask_mesh(const Depsgraph &depsgraph, Object &object, const IndexMask &node_mask, const OffsetIndices< int > node_verts, const Span< float > new_mask, MutableSpan< float > mask)
static wmOperatorStatus sculpt_mask_filter_exec(bContext *C, wmOperator *op)
static BLI_NOINLINE void mask_increase_contrast(const Span< float > src, const MutableSpan< float > dst)
static BLI_NOINLINE void mask_decrease_contrast(const Span< float > src, const MutableSpan< float > dst)
static void apply_new_mask_bmesh(const Depsgraph &depsgraph, Object &object, const int mask_offset, const IndexMask &node_mask, const OffsetIndices< int > node_verts, const Span< float > new_mask)
static void sharpen_mask_grids(const SubdivCCG &subdiv_ccg, const bke::pbvh::GridsNode &node, FilterLocalData &tls, MutableSpan< float > new_mask)
static void grow_mask_grids(const SubdivCCG &subdiv_ccg, const bke::pbvh::GridsNode &node, MutableSpan< float > new_mask)
static BLI_NOINLINE void copy_old_hidden_mask_bmesh(const int mask_offset, const Set< BMVert *, 0 > &verts, const MutableSpan< float > new_mask)
void clamp_mask(const MutableSpan< float > masks)
static bool decrease_contrast_mask_mesh(const Depsgraph &depsgraph, const Object &object, const Span< bool > hide_vert, bke::pbvh::MeshNode &node, FilterLocalData &tls, MutableSpan< float > mask)
void average_neighbor_mask_bmesh(const int mask_offset, const Set< BMVert *, 0 > &verts, const MutableSpan< float > new_masks)
static BLI_NOINLINE void copy_old_hidden_mask_grids(const SubdivCCG &subdiv_ccg, const Span< int > grids, const MutableSpan< float > new_mask)
void neighbor_data_average_mesh(const Span< T > src, const GroupedSpan< int > vert_neighbors, const MutableSpan< T > dst)
void average_data_grids(const SubdivCCG &subdiv_ccg, const Span< T > src, const Span< int > grids, const MutableSpan< T > dst)
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
GroupedSpan< int > calc_vert_neighbors(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face, Span< bool > hide_poly, Span< int > verts, Vector< int > &r_offset_data, Vector< int > &r_data)
Definition sculpt.cc:7607
Vector< BMVert *, 64 > BMeshNeighborVerts
void flush_update_done(const bContext *C, Object &ob, const UpdateType update_type)
Definition sculpt.cc:5131
void scatter_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6421
OffsetIndices< int > create_node_vert_offsets(Span< bke::pbvh::MeshNode > nodes, const IndexMask &node_mask, Array< int > &node_data)
Definition sculpt.cc:7573
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 flush_update_step(const bContext *C, const UpdateType update_type)
Definition sculpt.cc:5083
void scatter_data_grids(const SubdivCCG &subdiv_ccg, Span< T > node_data, Span< int > grids, MutableSpan< T > dst)
Definition sculpt.cc:6431
OffsetIndices< int > create_node_vert_offsets_bmesh(Span< bke::pbvh::BMeshNode > nodes, const IndexMask &node_mask, Array< int > &node_data)
Definition sculpt.cc:7595
T rcp(const T &a)
int RNA_int_get(PointerRNA *ptr, const char *name)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
bool SCULPT_mode_poll(bContext *C)
Definition sculpt.cc:3660
int SCULPT_vertex_count_get(const Object &object)
Definition sculpt.cc:152
void SCULPT_tag_update_overlays(bContext *C)
Definition sculpt.cc:760
int grid_size
Definition BKE_ccg.hh:33
int grid_area
Definition BKE_ccg.hh:35
struct SculptSession * sculpt
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:415
int to_index(const CCGKey &key) const
SubdivCCGNeighborCoords coords
blender::BitGroupVector grid_hidden
blender::Array< float > masks
struct PointerRNA * ptr
i
Definition text_draw.cc:230
wmOperatorType * ot
Definition wm_files.cc:4226