Blender V4.3
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
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_pbvh_api.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
40enum class FilterType {
41 Smooth = 0,
42 Sharpen = 1,
43 Grow = 2,
44 Shrink = 3,
47};
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
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]);
142 if (array_utils::indexed_data_equal<float>(mask, verts, new_mask)) {
143 return;
144 }
145 undo::push_node(depsgraph, object, &nodes[i], undo::Type::Mask);
146 scatter_data_mesh(new_node_mask, verts, mask);
147 bke::pbvh::node_update_mask_mesh(mask, nodes[i]);
148 node_changed[i] = true;
149 });
150
151 IndexMaskMemory memory;
152 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
153}
154
155static void smooth_mask_mesh(const OffsetIndices<int> faces,
156 const Span<int> corner_verts,
157 const GroupedSpan<int> vert_to_face_map,
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
167 tls.vert_neighbors.resize(verts.size());
168 const MutableSpan<Vector<int>> neighbors = tls.vert_neighbors;
169 calc_vert_neighbors(faces, corner_verts, vert_to_face_map, hide_poly, verts, neighbors);
170
171 smooth::neighbor_data_average_mesh(mask, neighbors, new_mask);
172 copy_old_hidden_mask_mesh(verts, hide_vert, mask, new_mask);
173}
174
175static void sharpen_mask_mesh(const OffsetIndices<int> faces,
176 const Span<int> corner_verts,
177 const GroupedSpan<int> vert_to_face_map,
178 const Span<bool> hide_poly,
179 const Span<bool> hide_vert,
180 const Span<float> mask,
181 const bke::pbvh::MeshNode &node,
182 FilterLocalData &tls,
183 MutableSpan<float> new_mask)
184{
185 const Span<int> verts = node.verts();
186
187 tls.node_mask.resize(verts.size());
188 const MutableSpan<float> node_mask = tls.node_mask;
189 gather_data_mesh(mask, verts, node_mask);
190
191 tls.vert_neighbors.resize(verts.size());
192 const MutableSpan<Vector<int>> neighbors = tls.vert_neighbors;
193 calc_vert_neighbors(faces, corner_verts, vert_to_face_map, hide_poly, verts, neighbors);
194
195 smooth::neighbor_data_average_mesh(mask, neighbors, new_mask);
196
197 sharpen_masks(node_mask, new_mask);
198 copy_old_hidden_mask_mesh(verts, hide_vert, mask, new_mask);
199}
200
201static void grow_mask_mesh(const OffsetIndices<int> faces,
202 const Span<int> corner_verts,
203 const GroupedSpan<int> vert_to_face_map,
204 const Span<bool> hide_poly,
205 const Span<bool> hide_vert,
206 const Span<float> mask,
207 const bke::pbvh::MeshNode &node,
208 FilterLocalData &tls,
209 MutableSpan<float> new_mask)
210{
211 const Span<int> verts = node.verts();
212
213 tls.vert_neighbors.resize(verts.size());
214 const MutableSpan<Vector<int>> neighbors = tls.vert_neighbors;
215 calc_vert_neighbors(faces, corner_verts, vert_to_face_map, hide_poly, verts, neighbors);
216
217 for (const int i : verts.index_range()) {
218 new_mask[i] = mask[verts[i]];
219 for (const int neighbor : neighbors[i]) {
220 new_mask[i] = std::max(mask[neighbor], new_mask[i]);
221 }
222 }
223 copy_old_hidden_mask_mesh(verts, hide_vert, mask, new_mask);
224}
225
226static void shrink_mask_mesh(const OffsetIndices<int> faces,
227 const Span<int> corner_verts,
228 const GroupedSpan<int> vert_to_face_map,
229 const Span<bool> hide_poly,
230 const Span<bool> hide_vert,
231 const Span<float> mask,
232 const bke::pbvh::MeshNode &node,
233 FilterLocalData &tls,
234 MutableSpan<float> new_mask)
235{
236 const Span<int> verts = node.verts();
237
238 tls.vert_neighbors.resize(verts.size());
239 const MutableSpan<Vector<int>> neighbors = tls.vert_neighbors;
240 calc_vert_neighbors(faces, corner_verts, vert_to_face_map, hide_poly, verts, neighbors);
241
242 for (const int i : verts.index_range()) {
243 new_mask[i] = mask[verts[i]];
244 for (const int neighbor : neighbors[i]) {
245 new_mask[i] = std::min(mask[neighbor], new_mask[i]);
246 }
247 }
248 copy_old_hidden_mask_mesh(verts, hide_vert, mask, new_mask);
249}
250
251static bool increase_contrast_mask_mesh(const Depsgraph &depsgraph,
252 const Object &object,
253 const Span<bool> hide_vert,
255 FilterLocalData &tls,
257{
258 const Span<int> verts = hide::node_visible_verts(node, hide_vert, tls.visible_verts);
259
260 const Span<float> node_mask = gather_data_mesh(mask.as_span(), verts, tls.node_mask);
261
262 tls.new_mask.resize(verts.size());
263 const MutableSpan<float> new_mask = tls.new_mask;
264 mask_increase_contrast(node_mask, new_mask);
265 copy_old_hidden_mask_mesh(verts, hide_vert, mask, new_mask);
266
267 if (node_mask == new_mask.as_span()) {
268 return false;
269 }
270
272 scatter_data_mesh(new_mask.as_span(), verts, mask);
274 return true;
275}
276
277static bool decrease_contrast_mask_mesh(const Depsgraph &depsgraph,
278 const Object &object,
279 const Span<bool> hide_vert,
281 FilterLocalData &tls,
283{
284 const Span<int> verts = hide::node_visible_verts(node, hide_vert, tls.visible_verts);
285
286 const Span<float> node_mask = gather_data_mesh(mask.as_span(), verts, tls.node_mask);
287
288 tls.new_mask.resize(verts.size());
289 const MutableSpan<float> new_mask = tls.new_mask;
290 mask_decrease_contrast(node_mask, new_mask);
291 copy_old_hidden_mask_mesh(verts, hide_vert, mask, new_mask);
292
293 if (node_mask == new_mask.as_span()) {
294 return false;
295 }
296
298 scatter_data_mesh(new_mask.as_span(), verts, mask);
300 return true;
301}
302
304 const Span<int> grids,
305 const MutableSpan<float> new_mask)
306{
307 const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
308 if (subdiv_ccg.grid_hidden.is_empty()) {
309 return;
310 }
311 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
312 const Span<float> masks = subdiv_ccg.masks;
313 for (const int i : grids.index_range()) {
314 const Span grid_masks = masks.slice(bke::ccg::grid_range(key, grids[i]));
315 MutableSpan grid_dst = new_mask.slice(bke::ccg::grid_range(key, i));
316 bits::foreach_1_index(grid_hidden[grids[i]],
317 [&](const int offset) { grid_dst[offset] = grid_masks[offset]; });
318 }
319}
320
321static void apply_new_mask_grids(const Depsgraph &depsgraph,
322 Object &object,
323 const IndexMask &node_mask,
324 const OffsetIndices<int> node_verts,
325 const Span<float> new_mask)
326{
327 SculptSession &ss = *object.sculpt;
328 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
330 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
331 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
332 MutableSpan<float> masks = subdiv_ccg.masks;
333
334 Array<bool> node_changed(node_mask.min_array_size(), false);
335
336 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
337 const Span<int> grids = nodes[i].grids();
338 const Span<float> new_node_mask = new_mask.slice(node_verts[pos]);
339 if (mask_equals_array_grids(masks, key, grids, new_node_mask)) {
340 return;
341 }
342 undo::push_node(depsgraph, object, &nodes[i], undo::Type::Mask);
343 scatter_data_grids(subdiv_ccg, new_node_mask, grids, masks);
344 bke::pbvh::node_update_mask_grids(key, masks, nodes[i]);
345 node_changed[i] = true;
346 });
347
348 IndexMaskMemory memory;
349 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
350
351 /* New mask values need propagation across grid boundaries. */
353}
354
355static void smooth_mask_grids(const SubdivCCG &subdiv_ccg,
356 const bke::pbvh::GridsNode &node,
357 MutableSpan<float> new_mask)
358{
359 const Span<int> grids = node.grids();
360 smooth::average_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, new_mask);
361 copy_old_hidden_mask_grids(subdiv_ccg, grids, new_mask);
362}
363
364static void sharpen_mask_grids(const SubdivCCG &subdiv_ccg,
365 const bke::pbvh::GridsNode &node,
366 FilterLocalData &tls,
367 MutableSpan<float> new_mask)
368{
369 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
370
371 const Span<int> grids = node.grids();
372 const int grid_verts_num = grids.size() * key.grid_area;
373
374 tls.node_mask.resize(grid_verts_num);
375 const MutableSpan<float> node_mask = tls.node_mask;
376 gather_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, node_mask);
377
378 smooth::average_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, new_mask);
379
380 sharpen_masks(node_mask, new_mask);
381
382 copy_old_hidden_mask_grids(subdiv_ccg, grids, new_mask);
383}
384
385static void grow_mask_grids(const SubdivCCG &subdiv_ccg,
386 const bke::pbvh::GridsNode &node,
387 MutableSpan<float> new_mask)
388{
389 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
390 const Span<float> masks = subdiv_ccg.masks;
391
392 const Span<int> grids = node.grids();
393
394 for (const int i : grids.index_range()) {
395 const int grid = grids[i];
396 const Span grid_masks = masks.slice(bke::ccg::grid_range(key, grid));
397 MutableSpan grid_dst = new_mask.slice(bke::ccg::grid_range(key, i));
398
399 for (const short y : IndexRange(key.grid_size)) {
400 for (const short x : IndexRange(key.grid_size)) {
401 const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
402
403 SubdivCCGNeighbors neighbors;
404 SubdivCCGCoord coord{grid, x, y};
405 BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, coord, false, neighbors);
406
407 grid_dst[offset] = grid_masks[offset];
408 for (const SubdivCCGCoord neighbor : neighbors.coords) {
409 grid_dst[offset] = std::max(masks[neighbor.to_index(key)], grid_dst[offset]);
410 }
411 }
412 }
413 }
414
415 copy_old_hidden_mask_grids(subdiv_ccg, grids, new_mask);
416}
417
418static void shrink_mask_grids(const SubdivCCG &subdiv_ccg,
419 const bke::pbvh::GridsNode &node,
420 MutableSpan<float> new_mask)
421{
422 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
423 const Span<float> masks = subdiv_ccg.masks;
424
425 const Span<int> grids = node.grids();
426
427 for (const int i : grids.index_range()) {
428 const int grid = grids[i];
429 const Span grid_masks = masks.slice(bke::ccg::grid_range(key, grid));
430 MutableSpan grid_dst = new_mask.slice(bke::ccg::grid_range(key, i));
431
432 for (const short y : IndexRange(key.grid_size)) {
433 for (const short x : IndexRange(key.grid_size)) {
434 const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
435
436 SubdivCCGNeighbors neighbors;
437 SubdivCCGCoord coord{grid, x, y};
438 BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, coord, false, neighbors);
439
440 grid_dst[offset] = grid_masks[offset];
441 for (const SubdivCCGCoord neighbor : neighbors.coords) {
442 grid_dst[offset] = std::min(masks[neighbor.to_index(key)], grid_dst[offset]);
443 }
444 }
445 }
446 }
447
448 copy_old_hidden_mask_grids(subdiv_ccg, grids, new_mask);
449}
450
451static bool increase_contrast_mask_grids(const Depsgraph &depsgraph,
452 const Object &object,
454 FilterLocalData &tls)
455{
456 SculptSession &ss = *object.sculpt;
457 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
458 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
459
460 const Span<int> grids = node.grids();
461 const int grid_verts_num = grids.size() * key.grid_area;
462
463 tls.node_mask.resize(grid_verts_num);
464 const MutableSpan<float> node_mask = tls.node_mask;
465 gather_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, node_mask);
466
467 tls.new_mask.resize(grid_verts_num);
468 const MutableSpan<float> new_mask = tls.new_mask;
469 mask_increase_contrast(node_mask, new_mask);
470
471 copy_old_hidden_mask_grids(subdiv_ccg, grids, new_mask);
472
473 if (node_mask.as_span() == new_mask.as_span()) {
474 return false;
475 }
476
478 scatter_data_grids(subdiv_ccg, new_mask.as_span(), grids, subdiv_ccg.masks.as_mutable_span());
479 bke::pbvh::node_update_mask_grids(key, subdiv_ccg.masks, node);
480 return true;
481}
482
483static bool decrease_contrast_mask_grids(const Depsgraph &depsgraph,
484 const Object &object,
486 FilterLocalData &tls)
487{
488 SculptSession &ss = *object.sculpt;
489 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
490 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
491
492 const Span<int> grids = node.grids();
493 const int grid_verts_num = grids.size() * key.grid_area;
494
495 tls.node_mask.resize(grid_verts_num);
496 const MutableSpan<float> node_mask = tls.node_mask;
497 gather_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, node_mask);
498
499 tls.new_mask.resize(grid_verts_num);
500 const MutableSpan<float> new_mask = tls.new_mask;
501 mask_decrease_contrast(node_mask, new_mask);
502
503 copy_old_hidden_mask_grids(subdiv_ccg, grids, new_mask);
504
505 if (node_mask.as_span() == new_mask.as_span()) {
506 return false;
507 }
508
510 scatter_data_grids(subdiv_ccg, new_mask.as_span(), grids, subdiv_ccg.masks.as_mutable_span());
511 bke::pbvh::node_update_mask_grids(key, subdiv_ccg.masks, node);
512 return true;
513}
514
515BLI_NOINLINE static void copy_old_hidden_mask_bmesh(const int mask_offset,
516 const Set<BMVert *, 0> &verts,
517 const MutableSpan<float> new_mask)
518{
519 int i = 0;
520 for (const BMVert *vert : verts) {
522 new_mask[i] = BM_ELEM_CD_GET_FLOAT(vert, mask_offset);
523 }
524 i++;
525 }
526}
527
528static void apply_new_mask_bmesh(const Depsgraph &depsgraph,
529 Object &object,
530 const int mask_offset,
531 const IndexMask &node_mask,
532 const OffsetIndices<int> node_verts,
533 const Span<float> new_mask)
534{
535 SculptSession &ss = *object.sculpt;
536 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
538 BMesh &bm = *ss.bm;
539
540 Array<bool> node_changed(node_mask.min_array_size(), false);
541
542 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
544 const Span<float> new_node_mask = new_mask.slice(node_verts[pos]);
545 if (mask_equals_array_bmesh(mask_offset, verts, new_node_mask)) {
546 return;
547 }
548 undo::push_node(depsgraph, object, &nodes[i], undo::Type::Mask);
549 scatter_mask_bmesh(new_node_mask, bm, verts);
550 bke::pbvh::node_update_mask_bmesh(mask_offset, nodes[i]);
551 node_changed[i] = true;
552 });
553
554 IndexMaskMemory memory;
555 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
556}
557
558static void smooth_mask_bmesh(const int mask_offset,
560 MutableSpan<float> new_mask)
561{
563 average_neighbor_mask_bmesh(mask_offset, verts, new_mask);
564 copy_old_hidden_mask_bmesh(mask_offset, verts, new_mask);
565}
566
567static void sharpen_mask_bmesh(const BMesh &bm,
568 const int mask_offset,
570 FilterLocalData &tls,
571 MutableSpan<float> new_mask)
572{
574
575 tls.node_mask.resize(verts.size());
576 const MutableSpan<float> node_mask = tls.node_mask;
577 gather_mask_bmesh(bm, verts, node_mask);
578
579 average_neighbor_mask_bmesh(mask_offset, verts, new_mask);
580
581 sharpen_masks(node_mask, new_mask);
582
583 copy_old_hidden_mask_bmesh(mask_offset, verts, new_mask);
584}
585
586static void grow_mask_bmesh(const int mask_offset,
588 MutableSpan<float> new_mask)
589{
591
592 Vector<BMVert *, 64> neighbors;
593 int i = 0;
594 for (BMVert *vert : verts) {
595 new_mask[i] = BM_ELEM_CD_GET_FLOAT(vert, mask_offset);
596 for (const BMVert *neighbor : vert_neighbors_get_bmesh(*vert, neighbors)) {
597 new_mask[i] = std::max(BM_ELEM_CD_GET_FLOAT(neighbor, mask_offset), new_mask[i]);
598 }
599 i++;
600 }
601
602 copy_old_hidden_mask_bmesh(mask_offset, verts, new_mask);
603}
604
605static void shrink_mask_bmesh(const int mask_offset,
607 MutableSpan<float> new_mask)
608{
610
611 Vector<BMVert *, 64> neighbors;
612 int i = 0;
613 for (BMVert *vert : verts) {
614 new_mask[i] = BM_ELEM_CD_GET_FLOAT(vert, mask_offset);
615 for (const BMVert *neighbor : vert_neighbors_get_bmesh(*vert, neighbors)) {
616 new_mask[i] = std::min(BM_ELEM_CD_GET_FLOAT(neighbor, mask_offset), new_mask[i]);
617 }
618 i++;
619 }
620
621 copy_old_hidden_mask_bmesh(mask_offset, verts, new_mask);
622}
623
624static bool increase_contrast_mask_bmesh(const Depsgraph &depsgraph,
625 Object &object,
626 const int mask_offset,
628 FilterLocalData &tls)
629{
630 SculptSession &ss = *object.sculpt;
631 BMesh &bm = *ss.bm;
632
634
635 tls.node_mask.resize(verts.size());
636 const MutableSpan<float> node_mask = tls.node_mask;
637 gather_mask_bmesh(bm, verts, node_mask);
638
639 tls.new_mask.resize(verts.size());
640 const MutableSpan<float> new_mask = tls.new_mask;
641 mask_increase_contrast(node_mask, new_mask);
642
643 copy_old_hidden_mask_bmesh(mask_offset, verts, new_mask);
644
645 if (node_mask.as_span() == new_mask.as_span()) {
646 return false;
647 }
648
650 scatter_mask_bmesh(new_mask.as_span(), bm, verts);
651 bke::pbvh::node_update_mask_bmesh(mask_offset, node);
652 return true;
653}
654
655static bool decrease_contrast_mask_bmesh(const Depsgraph &depsgraph,
656 Object &object,
657 const int mask_offset,
659 FilterLocalData &tls)
660{
661 SculptSession &ss = *object.sculpt;
662 BMesh &bm = *ss.bm;
663
665
666 tls.node_mask.resize(verts.size());
667 const MutableSpan<float> node_mask = tls.node_mask;
668 gather_mask_bmesh(bm, verts, node_mask);
669
670 tls.new_mask.resize(verts.size());
671 const MutableSpan<float> new_mask = tls.new_mask;
672 mask_decrease_contrast(node_mask, new_mask);
673
674 copy_old_hidden_mask_bmesh(mask_offset, verts, new_mask);
675
676 if (node_mask.as_span() == new_mask.as_span()) {
677 return false;
678 }
679
681 scatter_mask_bmesh(new_mask.as_span(), bm, verts);
682 bke::pbvh::node_update_mask_bmesh(mask_offset, node);
683 return true;
684}
685
687{
688 const Scene &scene = *CTX_data_scene(C);
691 const FilterType filter_type = FilterType(RNA_enum_get(op->ptr, "filter_type"));
692
693 const View3D *v3d = CTX_wm_view3d(C);
694 const Base *base = CTX_data_active_base(C);
695 if (!BKE_base_is_visible(v3d, base)) {
696 return OPERATOR_CANCELLED;
697 }
698
701
703
704 SculptSession &ss = *ob.sculpt;
706
707 IndexMaskMemory memory;
708 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
709 undo::push_begin(scene, ob, op);
710
711 int iterations = RNA_int_get(op->ptr, "iterations");
712
713 /* Auto iteration count calculates the number of iteration based on the vertices of the mesh to
714 * avoid adding an unnecessary amount of undo steps when using the operator from a shortcut.
715 * One iteration per 50000 vertices in the mesh should be fine in most cases.
716 * Maybe we want this to be configurable. */
717 if (RNA_boolean_get(op->ptr, "auto_iteration_count")) {
718 iterations = int(SCULPT_vertex_count_get(ob) / 50000.0f) + 1;
719 }
720
722 switch (pbvh.type()) {
725 Mesh &mesh = *static_cast<Mesh *>(ob.data);
726 const OffsetIndices<int> faces = mesh.faces();
727 const Span<int> corner_verts = mesh.corner_verts();
728 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
729 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
730 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
731 const VArraySpan hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
732 bke::SpanAttributeWriter mask = attributes.lookup_for_write_span<float>(".sculpt_mask");
733
734 Array<int> node_vert_offset_data;
736 nodes, node_mask, node_vert_offset_data);
737 Array<float> new_masks(node_offsets.total_size());
738
739 for ([[maybe_unused]] const int iteration : IndexRange(iterations)) {
740 switch (filter_type) {
741 case FilterType::Smooth: {
742 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
743 FilterLocalData &tls = all_tls.local();
744 smooth_mask_mesh(faces,
745 corner_verts,
746 vert_to_face_map,
747 hide_poly,
748 hide_vert,
749 mask.span,
750 nodes[i],
751 tls,
752 new_masks.as_mutable_span().slice(node_offsets[pos]));
753 });
754 apply_new_mask_mesh(*depsgraph, ob, node_mask, node_offsets, new_masks, mask.span);
755 break;
756 }
757 case FilterType::Sharpen: {
758 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
759 FilterLocalData &tls = all_tls.local();
760 sharpen_mask_mesh(faces,
761 corner_verts,
762 vert_to_face_map,
763 hide_poly,
764 hide_vert,
765 mask.span,
766 nodes[i],
767 tls,
768 new_masks.as_mutable_span().slice(node_offsets[pos]));
769 });
770 apply_new_mask_mesh(*depsgraph, ob, node_mask, node_offsets, new_masks, mask.span);
771 break;
772 }
773 case FilterType::Grow: {
774 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
775 FilterLocalData &tls = all_tls.local();
776 grow_mask_mesh(faces,
777 corner_verts,
778 vert_to_face_map,
779 hide_poly,
780 hide_vert,
781 mask.span,
782 nodes[i],
783 tls,
784 new_masks.as_mutable_span().slice(node_offsets[pos]));
785 });
786 apply_new_mask_mesh(*depsgraph, ob, node_mask, node_offsets, new_masks, mask.span);
787 break;
788 }
789 case FilterType::Shrink: {
790 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
791 FilterLocalData &tls = all_tls.local();
792 shrink_mask_mesh(faces,
793 corner_verts,
794 vert_to_face_map,
795 hide_poly,
796 hide_vert,
797 mask.span,
798 nodes[i],
799 tls,
800 new_masks.as_mutable_span().slice(node_offsets[pos]));
801 });
802 apply_new_mask_mesh(*depsgraph, ob, node_mask, node_offsets, new_masks, mask.span);
803 break;
804 }
805 case FilterType::ContrastIncrease: {
806 Array<bool> node_changed(node_mask.min_array_size(), false);
807 node_mask.foreach_index(GrainSize(1), [&](const int i) {
808 FilterLocalData &tls = all_tls.local();
809 node_changed[i] = increase_contrast_mask_mesh(
810 *depsgraph, ob, hide_vert, nodes[i], tls, mask.span);
811 });
812 IndexMaskMemory memory;
813 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
814 break;
815 }
816 case FilterType::ContrastDecrease: {
817 Array<bool> node_changed(node_mask.min_array_size(), false);
818 node_mask.foreach_index(GrainSize(1), [&](const int i) {
819 FilterLocalData &tls = all_tls.local();
820 node_changed[i] = decrease_contrast_mask_mesh(
821 *depsgraph, ob, hide_vert, nodes[i], tls, mask.span);
822 });
823 IndexMaskMemory memory;
824 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
825 break;
826 }
827 }
828 }
829 mask.finish();
830 break;
831 }
834 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
835
836 Array<int> node_vert_offset_data;
838 BKE_subdiv_ccg_key_top_level(subdiv_ccg), nodes, node_mask, node_vert_offset_data);
839 Array<float> new_masks(node_offsets.total_size());
840
841 for ([[maybe_unused]] const int iteration : IndexRange(iterations)) {
842 switch (filter_type) {
843 case FilterType::Smooth: {
844 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
846 subdiv_ccg, nodes[i], new_masks.as_mutable_span().slice(node_offsets[pos]));
847 });
848 apply_new_mask_grids(*depsgraph, ob, node_mask, node_offsets, new_masks);
849 break;
850 }
851 case FilterType::Sharpen: {
852 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
853 FilterLocalData &tls = all_tls.local();
855 subdiv_ccg, nodes[i], tls, new_masks.as_mutable_span().slice(node_offsets[pos]));
856 });
857 apply_new_mask_grids(*depsgraph, ob, node_mask, node_offsets, new_masks);
858 break;
859 }
860 case FilterType::Grow: {
861 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
863 subdiv_ccg, nodes[i], new_masks.as_mutable_span().slice(node_offsets[pos]));
864 });
865 apply_new_mask_grids(*depsgraph, ob, node_mask, node_offsets, new_masks);
866 break;
867 }
868 case FilterType::Shrink: {
869 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
871 subdiv_ccg, nodes[i], new_masks.as_mutable_span().slice(node_offsets[pos]));
872 });
873 apply_new_mask_grids(*depsgraph, ob, node_mask, node_offsets, new_masks);
874 break;
875 }
876 case FilterType::ContrastIncrease: {
877 Array<bool> node_changed(node_mask.min_array_size(), false);
878 node_mask.foreach_index(GrainSize(1), [&](const int i) {
879 FilterLocalData &tls = all_tls.local();
880 node_changed[i] = increase_contrast_mask_grids(*depsgraph, ob, nodes[i], tls);
881 });
882 IndexMaskMemory memory;
883 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
884 break;
885 }
886 case FilterType::ContrastDecrease: {
887 Array<bool> node_changed(node_mask.min_array_size(), false);
888 node_mask.foreach_index(GrainSize(1), [&](const int i) {
889 FilterLocalData &tls = all_tls.local();
890 node_changed[i] = decrease_contrast_mask_grids(*depsgraph, ob, nodes[i], tls);
891 });
892 IndexMaskMemory memory;
893 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
894 break;
895 }
896 }
897 }
898 break;
899 }
902 BMesh &bm = *ss.bm;
904 const int mask_offset = CustomData_get_offset_named(
905 &bm.vdata, CD_PROP_FLOAT, ".sculpt_mask");
906
907 Array<int> node_vert_offset_data;
909 nodes, node_mask, node_vert_offset_data);
910 Array<float> new_masks(node_offsets.total_size());
911
912 for ([[maybe_unused]] const int iteration : IndexRange(iterations)) {
913 switch (filter_type) {
914 case FilterType::Smooth: {
915 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
917 mask_offset, nodes[i], new_masks.as_mutable_span().slice(node_offsets[pos]));
918 });
919 apply_new_mask_bmesh(*depsgraph, ob, mask_offset, node_mask, node_offsets, new_masks);
920 break;
921 }
922 case FilterType::Sharpen: {
923 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
924 FilterLocalData &tls = all_tls.local();
926 mask_offset,
927 nodes[i],
928 tls,
929 new_masks.as_mutable_span().slice(node_offsets[pos]));
930 });
931 apply_new_mask_bmesh(*depsgraph, ob, mask_offset, node_mask, node_offsets, new_masks);
932 break;
933 }
934 case FilterType::Grow: {
935 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
937 mask_offset, nodes[i], new_masks.as_mutable_span().slice(node_offsets[pos]));
938 });
939 apply_new_mask_bmesh(*depsgraph, ob, mask_offset, node_mask, node_offsets, new_masks);
940 break;
941 }
942 case FilterType::Shrink: {
943 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
945 mask_offset, nodes[i], new_masks.as_mutable_span().slice(node_offsets[pos]));
946 });
947 apply_new_mask_bmesh(*depsgraph, ob, mask_offset, node_mask, node_offsets, new_masks);
948 break;
949 }
950 case FilterType::ContrastIncrease: {
951 Array<bool> node_changed(node_mask.min_array_size(), false);
952 node_mask.foreach_index(GrainSize(1), [&](const int i) {
953 FilterLocalData &tls = all_tls.local();
954 node_changed[i] = increase_contrast_mask_bmesh(
955 *depsgraph, ob, mask_offset, nodes[i], tls);
956 });
957 IndexMaskMemory memory;
958 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
959 break;
960 }
961 case FilterType::ContrastDecrease: {
962 Array<bool> node_changed(node_mask.min_array_size(), false);
963 node_mask.foreach_index(GrainSize(1), [&](const int i) {
964 FilterLocalData &tls = all_tls.local();
965 node_changed[i] = decrease_contrast_mask_bmesh(
966 *depsgraph, ob, mask_offset, nodes[i], tls);
967 });
968 IndexMaskMemory memory;
969 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
970 break;
971 }
972 }
973 }
974 break;
975 }
976 }
977
978 undo::push_end(ob);
979
982
984
985 return OPERATOR_FINISHED;
986}
987
989{
990 ot->name = "Mask Filter";
991 ot->idname = "SCULPT_OT_mask_filter";
992 ot->description = "Applies a filter to modify the current mask";
993
996
998
999 static EnumPropertyItem type_items[] = {
1000 {int(FilterType::Smooth), "SMOOTH", 0, "Smooth Mask", ""},
1001 {int(FilterType::Sharpen), "SHARPEN", 0, "Sharpen Mask", ""},
1002 {int(FilterType::Grow), "GROW", 0, "Grow Mask", ""},
1003 {int(FilterType::Shrink), "SHRINK", 0, "Shrink Mask", ""},
1004 {int(FilterType::ContrastIncrease), "CONTRAST_INCREASE", 0, "Increase Contrast", ""},
1005 {int(FilterType::ContrastDecrease), "CONTRAST_DECREASE", 0, "Decrease Contrast", ""},
1006 {0, nullptr, 0, nullptr, nullptr},
1007 };
1008
1010 "filter_type",
1011 type_items,
1012 int(FilterType::Smooth),
1013 "Type",
1014 "Filter that is going to be applied to the mask");
1016 "iterations",
1017 1,
1018 1,
1019 100,
1020 "Iterations",
1021 "Number of times that the filter is going to be applied",
1022 1,
1023 100);
1025 ot->srna,
1026 "auto_iteration_count",
1027 true,
1028 "Auto Iteration Count",
1029 "Use an automatic number of iterations based on the number of vertices of the sculpt");
1030}
1031
1032} // 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:2316
void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph, Object *ob_orig, bool is_paint_tool)
Definition paint.cc:2601
void BKE_sculpt_mask_layers_ensure(Depsgraph *depsgraph, Main *bmain, Object *ob, MultiresModifierData *mmd)
Definition paint.cc:2610
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:50
#define BLI_NOINLINE
@ CD_PROP_FLOAT
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define BM_ELEM_CD_GET_FLOAT(ele, offset)
@ BM_ELEM_HIDDEN
#define BM_elem_flag_test(ele, hflag)
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
#define BM_VERT
Span< T > as_span() const
Definition BLI_array.hh:232
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:237
constexpr int64_t size() const
Definition BLI_span.hh:494
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:574
constexpr Span< T > as_span() const
Definition BLI_span.hh:662
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
constexpr bool is_empty() const
Definition BLI_span.hh:261
void resize(const int64_t new_size)
Span< NodeT > nodes() const
void tag_masks_changed(const IndexMask &node_mask)
Definition pbvh.cc:586
static IndexMask from_bools(Span< bool > bools, IndexMaskMemory &memory)
void foreach_index(Fn &&fn) const
const Depsgraph * depsgraph
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
static float verts[][3]
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:2846
IndexMask all_leaf_nodes(const Tree &pbvh, IndexMaskMemory &memory)
Definition pbvh.cc:2612
void node_update_mask_bmesh(int mask_offset, BMeshNode &node)
Definition pbvh.cc:1277
void node_update_mask_mesh(Span< float > mask, MeshNode &node)
Definition pbvh.cc:1219
void node_update_mask_grids(const CCGKey &key, Span< float > masks, GridsNode &node)
Definition pbvh.cc:1247
Span< int > node_visible_verts(const bke::pbvh::MeshNode &node, const Span< bool > hide_vert, Vector< int > &indices)
static void shrink_mask_mesh(const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face_map, 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 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_bmesh(const int mask_offset, bke::pbvh::BMeshNode &node, MutableSpan< float > new_mask)
static void smooth_mask_mesh(const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face_map, 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, MutableSpan< float > new_mask)
static void grow_mask_mesh(const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face_map, 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 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 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 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)
static void sharpen_mask_mesh(const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face_map, 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 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 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 int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
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 Span< Vector< 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, 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:6092
OffsetIndices< int > create_node_vert_offsets_bmesh(const Span< bke::pbvh::BMeshNode > nodes, const IndexMask &nodes_mask, Array< int > &node_data)
Definition sculpt.cc:7318
void flush_update_done(const bContext *C, Object &ob, UpdateType update_type)
Definition sculpt.cc:5055
void flush_update_step(bContext *C, UpdateType update_type)
Definition sculpt.cc:4960
void scatter_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6122
Span< BMVert * > vert_neighbors_get_bmesh(BMVert &vert, Vector< BMVert *, 64 > &r_neighbors)
Definition sculpt.cc:389
void gather_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6082
void calc_vert_neighbors(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face, Span< bool > hide_poly, Span< int > verts, MutableSpan< Vector< int > > result)
Definition sculpt.cc:7330
OffsetIndices< int > create_node_vert_offsets(const Span< bke::pbvh::MeshNode > nodes, const IndexMask &nodes_mask, Array< int > &node_data)
Definition sculpt.cc:7296
void scatter_data_grids(const SubdivCCG &subdiv_ccg, Span< T > node_data, Span< int > grids, MutableSpan< T > dst)
Definition sculpt.cc:6132
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:3560
int SCULPT_vertex_count_get(const Object &object)
Definition sculpt.cc:153
void SCULPT_tag_update_overlays(bContext *C)
Definition sculpt.cc:735
CustomData vdata
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:405
blender::Vector< SubdivCCGCoord, 256 > coords
blender::BitGroupVector grid_hidden
blender::Array< float > masks
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
StructRNA * srna
Definition WM_types.hh:1080
struct PointerRNA * ptr
wmOperatorType * ot
Definition wm_files.cc:4125