Blender V5.0
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_hide.hh"
28#include "sculpt_intern.hh"
29#include "sculpt_smooth.hh"
30#include "sculpt_undo.hh"
31
32#include "RNA_access.hh"
33#include "RNA_define.hh"
34
35#include "bmesh.hh"
36
38
47
49 const Span<bool> hide_vert,
50 const Span<float> mask,
51 const MutableSpan<float> new_mask)
52{
53 BLI_assert(verts.size() == new_mask.size());
54 if (hide_vert.is_empty()) {
55 return;
56 }
57
58 for (const int i : verts.index_range()) {
59 if (hide_vert[verts[i]]) {
60 new_mask[i] = mask[verts[i]];
61 }
62 }
63}
64
66 const float factor,
67 const float offset,
68 const MutableSpan<float> dst)
69{
70 for (const int i : src.index_range()) {
71 dst[i] = factor * src[i] + offset;
72 }
73}
74
76 const MutableSpan<float> dst)
77{
78 const float contrast = 0.1f;
79 const float delta = contrast * 0.5f;
80 const float gain = math::rcp(1.0f - contrast);
81 const float offset = gain * -delta;
82 multiply_add(src, gain, offset, dst);
83
85}
86
88 const MutableSpan<float> dst)
89{
90 const float contrast = -0.1f;
91 const float delta = contrast * 0.5f;
92 const float gain = 1.0f - contrast;
93 const float offset = gain * -delta;
94 multiply_add(src, gain, offset, dst);
95
97}
98
99BLI_NOINLINE static void sharpen_masks(const Span<float> old_masks,
100 const MutableSpan<float> new_mask)
101{
102 for (const int i : old_masks.index_range()) {
103 float val = new_mask[i];
104 float mask = old_masks[i];
105 val -= mask;
106 if (mask > 0.5f) {
107 mask += 0.05f;
108 }
109 else {
110 mask -= 0.05f;
111 }
112 mask += val / 2.0f;
113 new_mask[i] = mask;
114 }
115
116 mask::clamp_mask(new_mask);
117}
118
126
127static void apply_new_mask_mesh(const Depsgraph &depsgraph,
128 Object &object,
129 const IndexMask &node_mask,
130 const OffsetIndices<int> node_verts,
131 const Span<float> new_mask,
133{
134 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
136
137 Array<bool> node_changed(node_mask.min_array_size(), false);
138
139 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
140 const Span<int> verts = nodes[i].verts();
141 const Span<float> new_node_mask = new_mask.slice(node_verts[pos]);
143 return;
144 }
146 scatter_data_mesh(new_node_mask, verts, mask);
148 node_changed[i] = true;
149 });
150
151 IndexMaskMemory memory;
152 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
153}
154
156 const Span<int> corner_verts,
157 const GroupedSpan<int> vert_to_face,
158 const Span<bool> hide_poly,
159 const Span<bool> hide_vert,
160 const Span<float> mask,
161 const bke::pbvh::MeshNode &node,
162 FilterLocalData &tls,
163 MutableSpan<float> new_mask)
164{
165 const Span<int> verts = node.verts();
166
168 corner_verts,
169 vert_to_face,
170 hide_poly,
171 verts,
173 tls.neighbor_data);
174
175 tls.node_mask.resize(verts.size());
176 const MutableSpan<float> node_mask = tls.node_mask;
177 gather_data_mesh(mask, verts, node_mask);
178
179 smooth::neighbor_data_average_mesh(mask, neighbors, new_mask);
180 mask::mix_new_masks(new_mask, 0.5f, node_mask);
181 copy_old_hidden_mask_mesh(verts, hide_vert, mask, node_mask);
182 mask::clamp_mask(node_mask);
183 new_mask.copy_from(node_mask);
184}
185
187 const Span<int> corner_verts,
188 const GroupedSpan<int> vert_to_face,
189 const Span<bool> hide_poly,
190 const Span<bool> hide_vert,
191 const Span<float> mask,
192 const bke::pbvh::MeshNode &node,
193 FilterLocalData &tls,
194 MutableSpan<float> new_mask)
195{
196 const Span<int> verts = node.verts();
197
198 tls.node_mask.resize(verts.size());
199 const MutableSpan<float> node_mask = tls.node_mask;
200 gather_data_mesh(mask, verts, node_mask);
201
203 corner_verts,
204 vert_to_face,
205 hide_poly,
206 verts,
208 tls.neighbor_data);
209
210 smooth::neighbor_data_average_mesh(mask, neighbors, new_mask);
211
212 sharpen_masks(node_mask, new_mask);
213 copy_old_hidden_mask_mesh(verts, hide_vert, mask, new_mask);
214}
215
217 const Span<int> corner_verts,
218 const GroupedSpan<int> vert_to_face,
219 const Span<bool> hide_poly,
220 const Span<bool> hide_vert,
221 const Span<float> mask,
222 const bke::pbvh::MeshNode &node,
223 FilterLocalData &tls,
224 MutableSpan<float> new_mask)
225{
226 const Span<int> verts = node.verts();
227
229 corner_verts,
230 vert_to_face,
231 hide_poly,
232 verts,
234 tls.neighbor_data);
235
236 for (const int i : verts.index_range()) {
237 new_mask[i] = mask[verts[i]];
238 for (const int neighbor : neighbors[i]) {
239 new_mask[i] = std::max(mask[neighbor], new_mask[i]);
240 }
241 }
242 copy_old_hidden_mask_mesh(verts, hide_vert, mask, new_mask);
243}
244
246 const Span<int> corner_verts,
247 const GroupedSpan<int> vert_to_face,
248 const Span<bool> hide_poly,
249 const Span<bool> hide_vert,
250 const Span<float> mask,
251 const bke::pbvh::MeshNode &node,
252 FilterLocalData &tls,
253 MutableSpan<float> new_mask)
254{
255 const Span<int> verts = node.verts();
256
258 corner_verts,
259 vert_to_face,
260 hide_poly,
261 verts,
263 tls.neighbor_data);
264
265 for (const int i : verts.index_range()) {
266 new_mask[i] = mask[verts[i]];
267 for (const int neighbor : neighbors[i]) {
268 new_mask[i] = std::min(mask[neighbor], new_mask[i]);
269 }
270 }
271 copy_old_hidden_mask_mesh(verts, hide_vert, mask, new_mask);
272}
273
274static bool increase_contrast_mask_mesh(const Depsgraph &depsgraph,
275 const Object &object,
276 const Span<bool> hide_vert,
278 FilterLocalData &tls,
280{
281 const Span<int> verts = hide::node_visible_verts(node, hide_vert, tls.visible_verts);
282
283 const Span<float> node_mask = gather_data_mesh(mask.as_span(), verts, tls.node_mask);
284
285 tls.new_mask.resize(verts.size());
286 const MutableSpan<float> new_mask = tls.new_mask;
287 mask_increase_contrast(node_mask, new_mask);
288 copy_old_hidden_mask_mesh(verts, hide_vert, mask, new_mask);
289
290 if (node_mask == new_mask.as_span()) {
291 return false;
292 }
293
295 scatter_data_mesh(new_mask.as_span(), verts, mask);
297 return true;
298}
299
300static bool decrease_contrast_mask_mesh(const Depsgraph &depsgraph,
301 const Object &object,
302 const Span<bool> hide_vert,
304 FilterLocalData &tls,
306{
307 const Span<int> verts = hide::node_visible_verts(node, hide_vert, tls.visible_verts);
308
309 const Span<float> node_mask = gather_data_mesh(mask.as_span(), verts, tls.node_mask);
310
311 tls.new_mask.resize(verts.size());
312 const MutableSpan<float> new_mask = tls.new_mask;
313 mask_decrease_contrast(node_mask, new_mask);
314 copy_old_hidden_mask_mesh(verts, hide_vert, mask, new_mask);
315
316 if (node_mask == new_mask.as_span()) {
317 return false;
318 }
319
321 scatter_data_mesh(new_mask.as_span(), verts, mask);
323 return true;
324}
325
327 const Span<int> grids,
328 const MutableSpan<float> new_mask)
329{
330 const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
331 if (subdiv_ccg.grid_hidden.is_empty()) {
332 return;
333 }
334 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
335 const Span<float> masks = subdiv_ccg.masks;
336 for (const int i : grids.index_range()) {
337 const Span grid_masks = masks.slice(bke::ccg::grid_range(key, grids[i]));
338 MutableSpan grid_dst = new_mask.slice(bke::ccg::grid_range(key, i));
339 bits::foreach_1_index(grid_hidden[grids[i]],
340 [&](const int offset) { grid_dst[offset] = grid_masks[offset]; });
341 }
342}
343
344static void apply_new_mask_grids(const Depsgraph &depsgraph,
345 Object &object,
346 const IndexMask &node_mask,
347 const OffsetIndices<int> node_verts,
348 const Span<float> new_mask)
349{
350 SculptSession &ss = *object.sculpt;
351 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
353 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
354 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
355 MutableSpan<float> masks = subdiv_ccg.masks;
356
357 Array<bool> node_changed(node_mask.min_array_size(), false);
358
359 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
360 const Span<int> grids = nodes[i].grids();
361 const Span<float> new_node_mask = new_mask.slice(node_verts[pos]);
362 if (mask_equals_array_grids(masks, key, grids, new_node_mask)) {
363 return;
364 }
366 scatter_data_grids(subdiv_ccg, new_node_mask, grids, masks);
368 node_changed[i] = true;
369 });
370
371 IndexMaskMemory memory;
372 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
373
374 /* New mask values need propagation across grid boundaries. */
376}
377
378static void smooth_mask_grids(const SubdivCCG &subdiv_ccg,
379 const bke::pbvh::GridsNode &node,
380 FilterLocalData &tls,
381 MutableSpan<float> new_mask)
382{
383 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
384
385 const Span<int> grids = node.grids();
386 const int grid_verts_num = grids.size() * key.grid_area;
387
388 tls.node_mask.resize(grid_verts_num);
389 const MutableSpan<float> node_mask = tls.node_mask;
390 gather_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, node_mask);
391
392 smooth::average_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, new_mask);
393 mask::mix_new_masks(new_mask, 0.5f, node_mask);
394 copy_old_hidden_mask_grids(subdiv_ccg, grids, node_mask);
395 mask::clamp_mask(node_mask);
396 new_mask.copy_from(node_mask);
397}
398
399static void sharpen_mask_grids(const SubdivCCG &subdiv_ccg,
400 const bke::pbvh::GridsNode &node,
401 FilterLocalData &tls,
402 MutableSpan<float> new_mask)
403{
404 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
405
406 const Span<int> grids = node.grids();
407 const int grid_verts_num = grids.size() * key.grid_area;
408
409 tls.node_mask.resize(grid_verts_num);
410 const MutableSpan<float> node_mask = tls.node_mask;
411 gather_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, node_mask);
412
413 smooth::average_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, new_mask);
414
415 sharpen_masks(node_mask, new_mask);
416
417 copy_old_hidden_mask_grids(subdiv_ccg, grids, new_mask);
418}
419
420static void grow_mask_grids(const SubdivCCG &subdiv_ccg,
421 const bke::pbvh::GridsNode &node,
422 MutableSpan<float> new_mask)
423{
424 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
425 const Span<float> masks = subdiv_ccg.masks;
426
427 const Span<int> grids = node.grids();
428
429 for (const int i : grids.index_range()) {
430 const int grid = grids[i];
431 const Span grid_masks = masks.slice(bke::ccg::grid_range(key, grid));
432 MutableSpan grid_dst = new_mask.slice(bke::ccg::grid_range(key, i));
433
434 for (const short y : IndexRange(key.grid_size)) {
435 for (const short x : IndexRange(key.grid_size)) {
436 const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
437
438 SubdivCCGNeighbors neighbors;
439 SubdivCCGCoord coord{grid, x, y};
440 BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, coord, false, neighbors);
441
442 grid_dst[offset] = grid_masks[offset];
443 for (const SubdivCCGCoord neighbor : neighbors.coords) {
444 grid_dst[offset] = std::max(masks[neighbor.to_index(key)], grid_dst[offset]);
445 }
446 }
447 }
448 }
449
450 copy_old_hidden_mask_grids(subdiv_ccg, grids, new_mask);
451}
452
453static void shrink_mask_grids(const SubdivCCG &subdiv_ccg,
454 const bke::pbvh::GridsNode &node,
455 MutableSpan<float> new_mask)
456{
457 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
458 const Span<float> masks = subdiv_ccg.masks;
459
460 const Span<int> grids = node.grids();
461
462 for (const int i : grids.index_range()) {
463 const int grid = grids[i];
464 const Span grid_masks = masks.slice(bke::ccg::grid_range(key, grid));
465 MutableSpan grid_dst = new_mask.slice(bke::ccg::grid_range(key, i));
466
467 for (const short y : IndexRange(key.grid_size)) {
468 for (const short x : IndexRange(key.grid_size)) {
469 const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
470
471 SubdivCCGNeighbors neighbors;
472 SubdivCCGCoord coord{grid, x, y};
473 BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, coord, false, neighbors);
474
475 grid_dst[offset] = grid_masks[offset];
476 for (const SubdivCCGCoord neighbor : neighbors.coords) {
477 grid_dst[offset] = std::min(masks[neighbor.to_index(key)], grid_dst[offset]);
478 }
479 }
480 }
481 }
482
483 copy_old_hidden_mask_grids(subdiv_ccg, grids, new_mask);
484}
485
486static bool increase_contrast_mask_grids(const Depsgraph &depsgraph,
487 const Object &object,
489 FilterLocalData &tls)
490{
491 SculptSession &ss = *object.sculpt;
492 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
493 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
494
495 const Span<int> grids = node.grids();
496 const int grid_verts_num = grids.size() * key.grid_area;
497
498 tls.node_mask.resize(grid_verts_num);
499 const MutableSpan<float> node_mask = tls.node_mask;
500 gather_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, node_mask);
501
502 tls.new_mask.resize(grid_verts_num);
503 const MutableSpan<float> new_mask = tls.new_mask;
504 mask_increase_contrast(node_mask, new_mask);
505
506 copy_old_hidden_mask_grids(subdiv_ccg, grids, new_mask);
507
508 if (node_mask.as_span() == new_mask.as_span()) {
509 return false;
510 }
511
513 scatter_data_grids(subdiv_ccg, new_mask.as_span(), grids, subdiv_ccg.masks.as_mutable_span());
514 bke::pbvh::node_update_mask_grids(key, subdiv_ccg.masks, node);
515 return true;
516}
517
518static bool decrease_contrast_mask_grids(const Depsgraph &depsgraph,
519 const Object &object,
521 FilterLocalData &tls)
522{
523 SculptSession &ss = *object.sculpt;
524 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
525 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
526
527 const Span<int> grids = node.grids();
528 const int grid_verts_num = grids.size() * key.grid_area;
529
530 tls.node_mask.resize(grid_verts_num);
531 const MutableSpan<float> node_mask = tls.node_mask;
532 gather_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, node_mask);
533
534 tls.new_mask.resize(grid_verts_num);
535 const MutableSpan<float> new_mask = tls.new_mask;
536 mask_decrease_contrast(node_mask, new_mask);
537
538 copy_old_hidden_mask_grids(subdiv_ccg, grids, new_mask);
539
540 if (node_mask.as_span() == new_mask.as_span()) {
541 return false;
542 }
543
545 scatter_data_grids(subdiv_ccg, new_mask.as_span(), grids, subdiv_ccg.masks.as_mutable_span());
546 bke::pbvh::node_update_mask_grids(key, subdiv_ccg.masks, node);
547 return true;
548}
549
550BLI_NOINLINE static void copy_old_hidden_mask_bmesh(const int mask_offset,
551 const Set<BMVert *, 0> &verts,
552 const MutableSpan<float> new_mask)
553{
554 int i = 0;
555 for (const BMVert *vert : verts) {
557 new_mask[i] = BM_ELEM_CD_GET_FLOAT(vert, mask_offset);
558 }
559 i++;
560 }
561}
562
563static void apply_new_mask_bmesh(const Depsgraph &depsgraph,
564 Object &object,
565 const int mask_offset,
566 const IndexMask &node_mask,
567 const OffsetIndices<int> node_verts,
568 const Span<float> new_mask)
569{
570 SculptSession &ss = *object.sculpt;
571 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
573 BMesh &bm = *ss.bm;
574
575 Array<bool> node_changed(node_mask.min_array_size(), false);
576
577 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
579 const Span<float> new_node_mask = new_mask.slice(node_verts[pos]);
580 if (mask_equals_array_bmesh(mask_offset, verts, new_node_mask)) {
581 return;
582 }
584 scatter_mask_bmesh(new_node_mask, bm, verts);
586 node_changed[i] = true;
587 });
588
589 IndexMaskMemory memory;
590 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
591}
592
593static void smooth_mask_bmesh(const BMesh &bm,
594 const int mask_offset,
596 FilterLocalData &tls,
597 MutableSpan<float> new_mask)
598{
600
601 tls.node_mask.resize(verts.size());
602 const MutableSpan<float> node_mask = tls.node_mask;
603 gather_mask_bmesh(bm, verts, node_mask);
604
605 average_neighbor_mask_bmesh(mask_offset, verts, new_mask);
606 mask::mix_new_masks(new_mask, 0.5f, node_mask);
607 copy_old_hidden_mask_bmesh(mask_offset, verts, node_mask);
608 mask::clamp_mask(node_mask);
609 new_mask.copy_from(node_mask);
610}
611
612static void sharpen_mask_bmesh(const BMesh &bm,
613 const int mask_offset,
615 FilterLocalData &tls,
616 MutableSpan<float> new_mask)
617{
619
620 tls.node_mask.resize(verts.size());
621 const MutableSpan<float> node_mask = tls.node_mask;
622 gather_mask_bmesh(bm, verts, node_mask);
623
624 average_neighbor_mask_bmesh(mask_offset, verts, new_mask);
625
626 sharpen_masks(node_mask, new_mask);
627
628 copy_old_hidden_mask_bmesh(mask_offset, verts, new_mask);
629}
630
631static void grow_mask_bmesh(const int mask_offset,
633 MutableSpan<float> new_mask)
634{
636
637 BMeshNeighborVerts neighbors;
638 int i = 0;
639 for (BMVert *vert : verts) {
640 new_mask[i] = BM_ELEM_CD_GET_FLOAT(vert, mask_offset);
641 for (const BMVert *neighbor : vert_neighbors_get_bmesh(*vert, neighbors)) {
642 new_mask[i] = std::max(BM_ELEM_CD_GET_FLOAT(neighbor, mask_offset), new_mask[i]);
643 }
644 i++;
645 }
646
647 copy_old_hidden_mask_bmesh(mask_offset, verts, new_mask);
648}
649
650static void shrink_mask_bmesh(const int mask_offset,
652 MutableSpan<float> new_mask)
653{
655
656 BMeshNeighborVerts neighbors;
657 int i = 0;
658 for (BMVert *vert : verts) {
659 new_mask[i] = BM_ELEM_CD_GET_FLOAT(vert, mask_offset);
660 for (const BMVert *neighbor : vert_neighbors_get_bmesh(*vert, neighbors)) {
661 new_mask[i] = std::min(BM_ELEM_CD_GET_FLOAT(neighbor, mask_offset), new_mask[i]);
662 }
663 i++;
664 }
665
666 copy_old_hidden_mask_bmesh(mask_offset, verts, new_mask);
667}
668
669static bool increase_contrast_mask_bmesh(const Depsgraph &depsgraph,
670 Object &object,
671 const int mask_offset,
673 FilterLocalData &tls)
674{
675 SculptSession &ss = *object.sculpt;
676 BMesh &bm = *ss.bm;
677
679
680 tls.node_mask.resize(verts.size());
681 const MutableSpan<float> node_mask = tls.node_mask;
682 gather_mask_bmesh(bm, verts, node_mask);
683
684 tls.new_mask.resize(verts.size());
685 const MutableSpan<float> new_mask = tls.new_mask;
686 mask_increase_contrast(node_mask, new_mask);
687
688 copy_old_hidden_mask_bmesh(mask_offset, verts, new_mask);
689
690 if (node_mask.as_span() == new_mask.as_span()) {
691 return false;
692 }
693
695 scatter_mask_bmesh(new_mask.as_span(), bm, verts);
696 bke::pbvh::node_update_mask_bmesh(mask_offset, node);
697 return true;
698}
699
700static bool decrease_contrast_mask_bmesh(const Depsgraph &depsgraph,
701 Object &object,
702 const int mask_offset,
704 FilterLocalData &tls)
705{
706 SculptSession &ss = *object.sculpt;
707 BMesh &bm = *ss.bm;
708
710
711 tls.node_mask.resize(verts.size());
712 const MutableSpan<float> node_mask = tls.node_mask;
713 gather_mask_bmesh(bm, verts, node_mask);
714
715 tls.new_mask.resize(verts.size());
716 const MutableSpan<float> new_mask = tls.new_mask;
717 mask_decrease_contrast(node_mask, new_mask);
718
719 copy_old_hidden_mask_bmesh(mask_offset, verts, new_mask);
720
721 if (node_mask.as_span() == new_mask.as_span()) {
722 return false;
723 }
724
726 scatter_mask_bmesh(new_mask.as_span(), bm, verts);
727 bke::pbvh::node_update_mask_bmesh(mask_offset, node);
728 return true;
729}
730
732{
733 const Scene &scene = *CTX_data_scene(C);
736 const FilterType filter_type = FilterType(RNA_enum_get(op->ptr, "filter_type"));
737
738 const View3D *v3d = CTX_wm_view3d(C);
739 const Base *base = CTX_data_active_base(C);
740 if (!BKE_base_is_visible(v3d, base)) {
741 return OPERATOR_CANCELLED;
742 }
743
746
748
749 SculptSession &ss = *ob.sculpt;
751
752 IndexMaskMemory memory;
753 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
754 undo::push_begin(scene, ob, op);
755
756 int iterations = RNA_int_get(op->ptr, "iterations");
757
758 /* Auto iteration count calculates the number of iteration based on the vertices of the mesh to
759 * avoid adding an unnecessary amount of undo steps when using the operator from a shortcut.
760 * One iteration per 50000 vertices in the mesh should be fine in most cases.
761 * Maybe we want this to be configurable. */
762 if (RNA_boolean_get(op->ptr, "auto_iteration_count")) {
763 iterations = int(SCULPT_vertex_count_get(ob) / 50000.0f) + 1;
764 }
765
767 switch (pbvh.type()) {
770 Mesh &mesh = *static_cast<Mesh *>(ob.data);
771 const OffsetIndices<int> faces = mesh.faces();
772 const Span<int> corner_verts = mesh.corner_verts();
773 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
774 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
775 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
776 const VArraySpan hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
777 bke::SpanAttributeWriter mask = attributes.lookup_for_write_span<float>(".sculpt_mask");
778
779 Array<int> node_vert_offset_data;
781 nodes, node_mask, node_vert_offset_data);
782 Array<float> new_masks(node_offsets.total_size());
783
784 for ([[maybe_unused]] const int iteration : IndexRange(iterations)) {
785 switch (filter_type) {
786 case FilterType::Smooth: {
787 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
788 FilterLocalData &tls = all_tls.local();
790 corner_verts,
791 vert_to_face_map,
792 hide_poly,
793 hide_vert,
794 mask.span,
795 nodes[i],
796 tls,
797 new_masks.as_mutable_span().slice(node_offsets[pos]));
798 });
799 apply_new_mask_mesh(*depsgraph, ob, node_mask, node_offsets, new_masks, mask.span);
800 break;
801 }
802 case FilterType::Sharpen: {
803 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
804 FilterLocalData &tls = all_tls.local();
806 corner_verts,
807 vert_to_face_map,
808 hide_poly,
809 hide_vert,
810 mask.span,
811 nodes[i],
812 tls,
813 new_masks.as_mutable_span().slice(node_offsets[pos]));
814 });
815 apply_new_mask_mesh(*depsgraph, ob, node_mask, node_offsets, new_masks, mask.span);
816 break;
817 }
818 case FilterType::Grow: {
819 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
820 FilterLocalData &tls = all_tls.local();
822 corner_verts,
823 vert_to_face_map,
824 hide_poly,
825 hide_vert,
826 mask.span,
827 nodes[i],
828 tls,
829 new_masks.as_mutable_span().slice(node_offsets[pos]));
830 });
831 apply_new_mask_mesh(*depsgraph, ob, node_mask, node_offsets, new_masks, mask.span);
832 break;
833 }
834 case FilterType::Shrink: {
835 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
836 FilterLocalData &tls = all_tls.local();
838 corner_verts,
839 vert_to_face_map,
840 hide_poly,
841 hide_vert,
842 mask.span,
843 nodes[i],
844 tls,
845 new_masks.as_mutable_span().slice(node_offsets[pos]));
846 });
847 apply_new_mask_mesh(*depsgraph, ob, node_mask, node_offsets, new_masks, mask.span);
848 break;
849 }
851 Array<bool> node_changed(node_mask.min_array_size(), false);
852 node_mask.foreach_index(GrainSize(1), [&](const int i) {
853 FilterLocalData &tls = all_tls.local();
854 node_changed[i] = increase_contrast_mask_mesh(
855 *depsgraph, ob, hide_vert, nodes[i], tls, mask.span);
856 });
857 IndexMaskMemory memory;
858 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
859 break;
860 }
862 Array<bool> node_changed(node_mask.min_array_size(), false);
863 node_mask.foreach_index(GrainSize(1), [&](const int i) {
864 FilterLocalData &tls = all_tls.local();
865 node_changed[i] = decrease_contrast_mask_mesh(
866 *depsgraph, ob, hide_vert, nodes[i], tls, mask.span);
867 });
868 IndexMaskMemory memory;
869 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
870 break;
871 }
872 }
873 }
874 mask.finish();
875 break;
876 }
879 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
880
881 Array<int> node_vert_offset_data;
883 BKE_subdiv_ccg_key_top_level(subdiv_ccg), nodes, node_mask, node_vert_offset_data);
884 Array<float> new_masks(node_offsets.total_size());
885
886 for ([[maybe_unused]] const int iteration : IndexRange(iterations)) {
887 switch (filter_type) {
888 case FilterType::Smooth: {
889 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
890 FilterLocalData &tls = all_tls.local();
892 subdiv_ccg, nodes[i], tls, new_masks.as_mutable_span().slice(node_offsets[pos]));
893 });
894 apply_new_mask_grids(*depsgraph, ob, node_mask, node_offsets, new_masks);
895 break;
896 }
897 case FilterType::Sharpen: {
898 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
899 FilterLocalData &tls = all_tls.local();
901 subdiv_ccg, nodes[i], tls, new_masks.as_mutable_span().slice(node_offsets[pos]));
902 });
903 apply_new_mask_grids(*depsgraph, ob, node_mask, node_offsets, new_masks);
904 break;
905 }
906 case FilterType::Grow: {
907 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
909 subdiv_ccg, nodes[i], new_masks.as_mutable_span().slice(node_offsets[pos]));
910 });
911 apply_new_mask_grids(*depsgraph, ob, node_mask, node_offsets, new_masks);
912 break;
913 }
914 case FilterType::Shrink: {
915 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
917 subdiv_ccg, nodes[i], new_masks.as_mutable_span().slice(node_offsets[pos]));
918 });
919 apply_new_mask_grids(*depsgraph, ob, node_mask, node_offsets, new_masks);
920 break;
921 }
923 Array<bool> node_changed(node_mask.min_array_size(), false);
924 node_mask.foreach_index(GrainSize(1), [&](const int i) {
925 FilterLocalData &tls = all_tls.local();
926 node_changed[i] = increase_contrast_mask_grids(*depsgraph, ob, nodes[i], tls);
927 });
928 IndexMaskMemory memory;
929 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
930 break;
931 }
933 Array<bool> node_changed(node_mask.min_array_size(), false);
934 node_mask.foreach_index(GrainSize(1), [&](const int i) {
935 FilterLocalData &tls = all_tls.local();
936 node_changed[i] = decrease_contrast_mask_grids(*depsgraph, ob, nodes[i], tls);
937 });
938 IndexMaskMemory memory;
939 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
940 break;
941 }
942 }
943 }
944 break;
945 }
948 BMesh &bm = *ss.bm;
950 const int mask_offset = CustomData_get_offset_named(
951 &bm.vdata, CD_PROP_FLOAT, ".sculpt_mask");
952
953 Array<int> node_vert_offset_data;
955 nodes, node_mask, node_vert_offset_data);
956 Array<float> new_masks(node_offsets.total_size());
957
958 for ([[maybe_unused]] const int iteration : IndexRange(iterations)) {
959 switch (filter_type) {
960 case FilterType::Smooth: {
961 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
962 FilterLocalData &tls = all_tls.local();
964 mask_offset,
965 nodes[i],
966 tls,
967 new_masks.as_mutable_span().slice(node_offsets[pos]));
968 });
969 apply_new_mask_bmesh(*depsgraph, ob, mask_offset, node_mask, node_offsets, new_masks);
970 break;
971 }
972 case FilterType::Sharpen: {
973 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
974 FilterLocalData &tls = all_tls.local();
976 mask_offset,
977 nodes[i],
978 tls,
979 new_masks.as_mutable_span().slice(node_offsets[pos]));
980 });
981 apply_new_mask_bmesh(*depsgraph, ob, mask_offset, node_mask, node_offsets, new_masks);
982 break;
983 }
984 case FilterType::Grow: {
985 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
987 mask_offset, nodes[i], new_masks.as_mutable_span().slice(node_offsets[pos]));
988 });
989 apply_new_mask_bmesh(*depsgraph, ob, mask_offset, node_mask, node_offsets, new_masks);
990 break;
991 }
992 case FilterType::Shrink: {
993 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
995 mask_offset, nodes[i], new_masks.as_mutable_span().slice(node_offsets[pos]));
996 });
997 apply_new_mask_bmesh(*depsgraph, ob, mask_offset, node_mask, node_offsets, new_masks);
998 break;
999 }
1001 Array<bool> node_changed(node_mask.min_array_size(), false);
1002 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1003 FilterLocalData &tls = all_tls.local();
1004 node_changed[i] = increase_contrast_mask_bmesh(
1005 *depsgraph, ob, mask_offset, nodes[i], tls);
1006 });
1007 IndexMaskMemory memory;
1008 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
1009 break;
1010 }
1012 Array<bool> node_changed(node_mask.min_array_size(), false);
1013 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1014 FilterLocalData &tls = all_tls.local();
1015 node_changed[i] = decrease_contrast_mask_bmesh(
1016 *depsgraph, ob, mask_offset, nodes[i], tls);
1017 });
1018 IndexMaskMemory memory;
1019 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
1020 break;
1021 }
1022 }
1023 }
1024 break;
1025 }
1026 }
1027
1028 undo::push_end(ob);
1029
1032
1034
1035 return OPERATOR_FINISHED;
1036}
1037
1039{
1040 ot->name = "Mask Filter";
1041 ot->idname = "SCULPT_OT_mask_filter";
1042 ot->description = "Applies a filter to modify the current mask";
1043
1045 ot->poll = SCULPT_mode_poll;
1046
1047 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1048
1049 static EnumPropertyItem type_items[] = {
1050 {int(FilterType::Smooth), "SMOOTH", 0, "Smooth Mask", ""},
1051 {int(FilterType::Sharpen), "SHARPEN", 0, "Sharpen Mask", ""},
1052 {int(FilterType::Grow), "GROW", 0, "Grow Mask", ""},
1053 {int(FilterType::Shrink), "SHRINK", 0, "Shrink Mask", ""},
1054 {int(FilterType::ContrastIncrease), "CONTRAST_INCREASE", 0, "Increase Contrast", ""},
1055 {int(FilterType::ContrastDecrease), "CONTRAST_DECREASE", 0, "Decrease Contrast", ""},
1056 {0, nullptr, 0, nullptr, nullptr},
1057 };
1058
1059 RNA_def_enum(ot->srna,
1060 "filter_type",
1061 type_items,
1062 int(FilterType::Smooth),
1063 "Type",
1064 "Filter that is going to be applied to the mask");
1065 RNA_def_int(ot->srna,
1066 "iterations",
1067 1,
1068 1,
1069 100,
1070 "Iterations",
1071 "Number of times that the filter is going to be applied",
1072 1,
1073 100);
1075 ot->srna,
1076 "auto_iteration_count",
1077 true,
1078 "Auto Iteration Count",
1079 "Use an automatic number of iterations based on the number of vertices of the sculpt");
1080}
1081
1082} // 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:73
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:2513
void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph, Object *ob_orig, bool is_paint_tool)
Definition paint.cc:2797
void BKE_sculpt_mask_layers_ensure(Depsgraph *depsgraph, Main *bmain, Object *ob, MultiresModifierData *mmd)
Definition paint.cc:2806
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:243
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:248
void resize(const int64_t new_size)
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:248
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:669
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:3052
IndexMask all_leaf_nodes(const Tree &pbvh, IndexMaskMemory &memory)
Definition pbvh.cc:2628
void node_update_mask_bmesh(int mask_offset, BMeshNode &node)
Definition pbvh.cc:1479
void node_update_mask_mesh(Span< float > mask, MeshNode &node)
Definition pbvh.cc:1421
void node_update_mask_grids(const CCGKey &key, Span< float > masks, GridsNode &node)
Definition pbvh.cc:1449
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:95
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:6405
void vert_random_access_ensure(Object &object)
Definition sculpt.cc:141
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:7597
Vector< BMVert *, 64 > BMeshNeighborVerts
void flush_update_done(const bContext *C, Object &ob, const UpdateType update_type)
Definition sculpt.cc:5146
void scatter_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6435
OffsetIndices< int > create_node_vert_offsets(Span< bke::pbvh::MeshNode > nodes, const IndexMask &node_mask, Array< int > &node_data)
Definition sculpt.cc:7563
Span< BMVert * > vert_neighbors_get_bmesh(BMVert &vert, BMeshNeighborVerts &r_neighbors)
Definition sculpt.cc:387
void gather_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6395
void flush_update_step(const bContext *C, const UpdateType update_type)
Definition sculpt.cc:5098
void scatter_data_grids(const SubdivCCG &subdiv_ccg, Span< T > node_data, Span< int > grids, MutableSpan< T > dst)
Definition sculpt.cc:6445
OffsetIndices< int > create_node_vert_offsets_bmesh(Span< bke::pbvh::BMeshNode > nodes, const IndexMask &node_mask, Array< int > &node_data)
Definition sculpt.cc:7585
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:3677
int SCULPT_vertex_count_get(const Object &object)
Definition sculpt.cc:151
void SCULPT_tag_update_overlays(bContext *C)
Definition sculpt.cc:759
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:395
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:4237