Blender V4.5
sculpt.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2006 by Nicholas Bishop. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9
10#include <cmath>
11#include <cstdlib>
12#include <cstring>
13
14#include "MEM_guardedalloc.h"
15
16#include "CLG_log.h"
17
18#include "BLI_array_utils.hh"
20#include "BLI_dial_2d.h"
22#include "BLI_listbase.h"
24#include "BLI_math_geom.h"
25#include "BLI_math_matrix.h"
26#include "BLI_math_matrix.hh"
27#include "BLI_math_rotation.h"
28#include "BLI_rect.h"
29#include "BLI_set.hh"
30#include "BLI_span.hh"
31#include "BLI_task.h"
32#include "BLI_task.hh"
33#include "BLI_utildefines.h"
34#include "BLI_vector.hh"
35
36#include "DNA_brush_types.h"
38#include "DNA_key_types.h"
39#include "DNA_node_types.h"
40#include "DNA_object_types.h"
41#include "DNA_scene_types.h"
42
43#include "BKE_attribute.hh"
44#include "BKE_brush.hh"
45#include "BKE_ccg.hh"
46#include "BKE_colortools.hh"
47#include "BKE_context.hh"
48#include "BKE_customdata.hh"
49#include "BKE_global.hh"
50#include "BKE_image.hh"
51#include "BKE_key.hh"
52#include "BKE_layer.hh"
53#include "BKE_lib_id.hh"
54#include "BKE_mesh.hh"
55#include "BKE_modifier.hh"
56#include "BKE_multires.hh"
57#include "BKE_node_runtime.hh"
58#include "BKE_object.hh"
59#include "BKE_object_types.hh"
60#include "BKE_paint.hh"
61#include "BKE_paint_bvh.hh"
62#include "BKE_report.hh"
63#include "BKE_subdiv_ccg.hh"
64#include "BKE_subsurf.hh"
66#include "BLI_math_vector.hh"
67
68#include "NOD_texture.h"
69
70#include "DEG_depsgraph.hh"
71
72#include "WM_api.hh"
73#include "WM_toolsystem.hh"
74#include "WM_types.hh"
75
76#include "ED_gpencil_legacy.hh"
77#include "ED_paint.hh"
78#include "ED_screen.hh"
79#include "ED_sculpt.hh"
80#include "ED_view3d.hh"
81
82#include "paint_intern.hh"
83#include "sculpt_automask.hh"
84#include "sculpt_boundary.hh"
85#include "sculpt_cloth.hh"
86#include "sculpt_color.hh"
87#include "sculpt_dyntopo.hh"
88#include "sculpt_face_set.hh"
89#include "sculpt_filter.hh"
90#include "sculpt_hide.hh"
91#include "sculpt_intern.hh"
92#include "sculpt_islands.hh"
93#include "sculpt_pose.hh"
94#include "sculpt_undo.hh"
95
96#include "RNA_access.hh"
97#include "RNA_define.hh"
98
99#include "bmesh.hh"
100
102#include "mesh_brush_common.hh"
103
104using blender::float3;
106using blender::Set;
107using blender::Span;
108using blender::Vector;
109
110static CLG_LogRef LOG = {"ed.sculpt_paint"};
111
113
114/* TODO: This should be moved to either BKE_paint.hh or BKE_brush.hh */
116 const Scene &scene,
117 const Brush &brush,
118 const float3 &location,
119 const float scale_factor)
120{
121 if (!BKE_brush_use_locked_size(&scene, &brush)) {
123 vc, location, BKE_brush_size_get(&scene, &brush) * scale_factor);
124 }
125 return BKE_brush_unprojected_radius_get(&scene, &brush) * scale_factor;
126}
127
129{
130 SculptSession &ss = *ob.sculpt;
131
133 if (reports) {
134 BKE_reportf(reports, RPT_ERROR, "The active shape key of %s is locked", ob.id.name + 2);
135 }
136 return true;
137 }
138
139 return false;
140}
141
143{
144 SculptSession &ss = *object.sculpt;
145 if (bke::object::pbvh_get(object)->type() == bke::pbvh::Type::BMesh) {
148 }
149}
150} // namespace blender::ed::sculpt_paint
151
153{
154 const SculptSession &ss = *object.sculpt;
155 switch (blender::bke::object::pbvh_get(object)->type()) {
157 BLI_assert(object.type == OB_MESH);
158 return static_cast<const Mesh *>(object.data)->verts_num;
160 return BM_mesh_elem_count(ss.bm, BM_VERT);
162 return BKE_pbvh_get_grid_num_verts(object);
163 }
164
165 return 0;
166}
167
169
171{
172 const SculptSession &ss = *object.sculpt;
174 if (ss.shapekey_active) {
175 /* Always grab active shape key if the sculpt happens on shapekey. */
177 }
178 /* Otherwise use the base mesh positions. */
179 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
180 return mesh.vert_positions();
181}
182
183} // namespace blender::ed::sculpt_paint
184
186{
187 const Mesh *mesh = static_cast<const Mesh *>(object.data);
188 return ePaintSymmetryFlags(mesh->symmetry);
189}
190
191/* Sculpt Face Sets and Visibility. */
192
194
195namespace face_set {
196
197int active_face_set_get(const Object &object)
198{
199 const SculptSession &ss = *object.sculpt;
200 switch (bke::object::pbvh_get(object)->type()) {
202 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
203 const bke::AttributeAccessor attributes = mesh.attributes();
204 const VArray face_sets = *attributes.lookup<int>(".sculpt_face_set", bke::AttrDomain::Face);
205 if (!face_sets || !ss.active_face_index) {
207 }
208 return face_sets[*ss.active_face_index];
209 }
211 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
212 const bke::AttributeAccessor attributes = mesh.attributes();
213 const VArray face_sets = *attributes.lookup<int>(".sculpt_face_set", bke::AttrDomain::Face);
214 if (!face_sets || !ss.active_grid_index) {
216 }
217 const int face_index = BKE_subdiv_ccg_grid_to_face_index(*ss.subdiv_ccg,
219 return face_sets[face_index];
220 }
223 }
225}
226
227} // namespace face_set
228
229namespace face_set {
230
231int vert_face_set_get(const GroupedSpan<int> vert_to_face_map,
232 const Span<int> face_sets,
233 const int vert)
234{
236 for (const int face : vert_to_face_map[vert]) {
237 face_set = std::max(face_sets[face], face_set);
238 }
239 return face_set;
240}
241
242int vert_face_set_get(const SubdivCCG &subdiv_ccg, const Span<int> face_sets, const int grid)
243{
244 const int face = BKE_subdiv_ccg_grid_to_face_index(subdiv_ccg, grid);
245 return face_sets[face];
246}
247
248int vert_face_set_get(const int /*face_set_offset*/, const BMVert & /*vert*/)
249{
251}
252
253bool vert_has_face_set(const GroupedSpan<int> vert_to_face_map,
254 const Span<int> face_sets,
255 const int vert,
256 const int face_set)
257{
258 if (face_sets.is_empty()) {
260 }
261 const Span<int> faces = vert_to_face_map[vert];
262 return std::any_of(
263 faces.begin(), faces.end(), [&](const int face) { return face_sets[face] == face_set; });
264}
265
266bool vert_has_face_set(const SubdivCCG &subdiv_ccg,
267 const Span<int> face_sets,
268 const int grid,
269 const int face_set)
270{
271 if (face_sets.is_empty()) {
273 }
274 const int face = BKE_subdiv_ccg_grid_to_face_index(subdiv_ccg, grid);
275 return face_sets[face] == face_set;
276}
277
278bool vert_has_face_set(const int face_set_offset, const BMVert &vert, const int face_set)
279{
280 if (face_set_offset == -1) {
282 }
283 BMIter iter;
284 BMFace *face;
285 BM_ITER_ELEM (face, &iter, &const_cast<BMVert &>(vert), BM_FACES_OF_VERT) {
286 if (BM_ELEM_CD_GET_INT(face, face_set_offset) == face_set) {
287 return true;
288 }
289 }
290 return false;
291}
292
293bool vert_has_unique_face_set(const GroupedSpan<int> vert_to_face_map,
294 const Span<int> face_sets,
295 int vert)
296{
297 /* TODO: Move this check higher out of this function. */
298 if (face_sets.is_empty()) {
299 return true;
300 }
301 int face_set = -1;
302 for (const int face_index : vert_to_face_map[vert]) {
303 if (face_set == -1) {
304 face_set = face_sets[face_index];
305 }
306 else {
307 if (face_sets[face_index] != face_set) {
308 return false;
309 }
310 }
311 }
312 return true;
313}
314
320 const GroupedSpan<int> vert_to_face_map,
321 const Span<int> face_sets,
322 const Span<int> corner_verts,
324 int v1,
325 int v2)
326{
327 const Span<int> vert_map = vert_to_face_map[v1];
328 int p1 = -1, p2 = -1;
329 for (int i = 0; i < vert_map.size(); i++) {
330 const int face_i = vert_map[i];
331 for (const int corner : faces[face_i]) {
332 if (corner_verts[corner] == v2) {
333 if (p1 == -1) {
334 p1 = vert_map[i];
335 break;
336 }
337
338 if (p2 == -1) {
339 p2 = vert_map[i];
340 break;
341 }
342 }
343 }
344 }
345
346 if (p1 != -1 && p2 != -1) {
347 return face_sets[p1] == face_sets[p2];
348 }
349 return true;
350}
351
353 const Span<int> corner_verts,
354 const GroupedSpan<int> vert_to_face_map,
355 const Span<int> face_sets,
356 const SubdivCCG &subdiv_ccg,
357 SubdivCCGCoord coord)
358{
359 /* TODO: Move this check higher out of this function. */
360 if (face_sets.is_empty()) {
361 return true;
362 }
363 int v1, v2;
365 subdiv_ccg, coord, corner_verts, faces, v1, v2);
366 switch (adjacency) {
368 return vert_has_unique_face_set(vert_to_face_map, face_sets, v1);
371 vert_to_face_map, face_sets, corner_verts, faces, v1, v2);
373 return true;
374 }
376 return true;
377}
378
379bool vert_has_unique_face_set(const int /*face_set_offset*/, const BMVert & /*vert*/)
380{
381 /* TODO: Obviously not fully implemented yet. Needs to be implemented for Relax Face Sets brush
382 * to work. */
383 return true;
384}
385
386} // namespace face_set
387
389{
390 r_neighbors.clear();
391 BMIter liter;
392 BMLoop *l;
393 BM_ITER_ELEM (l, &liter, &vert, BM_LOOPS_OF_VERT) {
394 for (BMVert *other_vert : {l->prev->v, l->next->v}) {
395 if (other_vert != &vert) {
396 r_neighbors.append(other_vert);
397 }
398 }
399 }
400 return r_neighbors;
401}
402
404{
405 r_neighbors.clear();
406 BMIter liter;
407 BMLoop *l;
408 BM_ITER_ELEM (l, &liter, &vert, BM_LOOPS_OF_VERT) {
409 for (BMVert *other_vert : {l->prev->v, l->next->v}) {
410 if (other_vert != &vert) {
411 r_neighbors.append(other_vert);
412 }
413 }
414 }
415
416 if (BM_vert_is_boundary(&vert)) {
417 if (r_neighbors.size() == 2) {
418 /* Do not include neighbors of corner vertices. */
419 r_neighbors.clear();
420 }
421 else {
422 /* Only include other boundary vertices as neighbors of boundary vertices. */
423 r_neighbors.remove_if([&](const BMVert *vert) { return !BM_vert_is_boundary(vert); });
424 }
425 }
426
427 return r_neighbors;
428}
429
431 const Span<int> corner_verts,
432 const GroupedSpan<int> vert_to_face,
433 const Span<bool> hide_poly,
434 const int vert,
435 Vector<int> &r_neighbors)
436{
437 r_neighbors.clear();
438
439 for (const int face : vert_to_face[vert]) {
440 if (!hide_poly.is_empty() && hide_poly[face]) {
441 continue;
442 }
443 const int2 verts = bke::mesh::face_find_adjacent_verts(faces[face], corner_verts, vert);
444 r_neighbors.append_non_duplicates(verts[0]);
445 r_neighbors.append_non_duplicates(verts[1]);
446 }
447
448 return r_neighbors.as_span();
449}
450
452 const Span<int> corner_verts,
453 const GroupedSpan<int> vert_to_face,
454 const Span<bool> hide_poly,
455 const int vert,
456 Vector<int> &r_data)
457{
458 const int vert_start = r_data.size();
459 for (const int face : vert_to_face[vert]) {
460 if (!hide_poly.is_empty() && hide_poly[face]) {
461 continue;
462 }
463 /* In order to support non-manifold topology, both neighboring vertices are added for each
464 * face corner. That results in half being duplicates for any "normal" topology. */
465 const int2 neighbors = bke::mesh::face_find_adjacent_verts(faces[face], corner_verts, vert);
466 for (const int neighbor : {neighbors[0], neighbors[1]}) {
467 bool found = false;
468 for (int i = r_data.size() - 1; i >= vert_start; i--) {
469 if (r_data[i] == neighbor) {
470 found = true;
471 break;
472 }
473 }
474 if (found) {
475 continue;
476 }
477 r_data.append(neighbor);
478 }
479 }
480}
481
482namespace boundary {
483
484bool vert_is_boundary(const GroupedSpan<int> vert_to_face_map,
485 const Span<bool> hide_poly,
486 const BitSpan boundary,
487 const int vert)
488{
489 if (!hide::vert_all_faces_visible_get(hide_poly, vert_to_face_map, vert)) {
490 return true;
491 }
492 return boundary[vert].test();
493}
494
496 const Span<int> corner_verts,
497 const BitSpan boundary,
498 const SubdivCCG &subdiv_ccg,
499 const SubdivCCGCoord vert)
500{
501 /* TODO: Unlike the base mesh implementation this method does NOT take into account face
502 * visibility. Either this should be noted as a intentional limitation or fixed. */
503 int v1, v2;
505 subdiv_ccg, vert, corner_verts, faces, v1, v2);
506 switch (adjacency) {
508 return boundary[v1].test();
510 return boundary[v1].test() && boundary[v2].test();
512 return false;
513 }
515 return false;
516}
517
519{
520 /* TODO: Unlike the base mesh implementation this method does NOT take into account face
521 * visibility. Either this should be noted as a intentional limitation or fixed. */
522 return BM_vert_is_boundary(vert);
523}
524
525} // namespace boundary
526
527} // namespace blender::ed::sculpt_paint
528
529/* Utilities */
530
532{
533 return cache.mirror_symmetry_pass == 0 && cache.radial_symmetry_pass == 0 &&
534 cache.tile_pass == 0;
535}
536
538{
539 return cache.first_time && cache.mirror_symmetry_pass == 0 && cache.radial_symmetry_pass == 0 &&
540 cache.tile_pass == 0;
541}
542
548
549bool SCULPT_check_vertex_pivot_symmetry(const float vco[3], const float pco[3], const char symm)
550{
551 bool is_in_symmetry_area = true;
552 for (int i = 0; i < 3; i++) {
553 char symm_it = 1 << i;
554 if (symm & symm_it) {
555 if (pco[i] == 0.0f) {
556 if (vco[i] > 0.0f) {
557 is_in_symmetry_area = false;
558 }
559 }
560 if (vco[i] * pco[i] < 0.0f) {
561 is_in_symmetry_area = false;
562 }
563 }
564 }
565 return is_in_symmetry_area;
566}
567
569 const float normal_weight,
570 float grab_delta[3])
571{
572 /* Signed to support grabbing in (to make a hole) as well as out. */
573 const float len_signed = dot_v3v3(ss.cache->sculpt_normal_symm, grab_delta);
574
575 /* This scale effectively projects the offset so dragging follows the cursor,
576 * as the normal points towards the view, the scale increases. */
577 float len_view_scale;
578 {
579 float view_aligned_normal[3];
581 view_aligned_normal, ss.cache->sculpt_normal_symm, ss.cache->view_normal_symm);
582 len_view_scale = fabsf(dot_v3v3(view_aligned_normal, ss.cache->sculpt_normal_symm));
583 len_view_scale = (len_view_scale > FLT_EPSILON) ? 1.0f / len_view_scale : 1.0f;
584 }
585
586 mul_v3_fl(grab_delta, 1.0f - normal_weight);
588 grab_delta, ss.cache->sculpt_normal_symm, (len_signed * normal_weight) * len_view_scale);
589}
590
592
593std::optional<int> nearest_vert_calc_mesh(const bke::pbvh::Tree &pbvh,
594 const Span<float3> vert_positions,
595 const Span<bool> hide_vert,
596 const float3 &location,
597 const float max_distance,
598 const bool use_original)
599{
600 const float max_distance_sq = max_distance * max_distance;
601 IndexMaskMemory memory;
602 const IndexMask nodes_in_sphere = bke::pbvh::search_nodes(
603 pbvh, memory, [&](const bke::pbvh::Node &node) {
604 return node_in_sphere(node, location, max_distance_sq, use_original);
605 });
606 if (nodes_in_sphere.is_empty()) {
607 return std::nullopt;
608 }
609
610 struct NearestData {
611 int vert = -1;
612 float distance_sq = std::numeric_limits<float>::max();
613 };
614
616 const NearestData nearest = threading::parallel_reduce(
617 nodes_in_sphere.index_range(),
618 1,
619 NearestData(),
620 [&](const IndexRange range, NearestData nearest) {
621 nodes_in_sphere.slice(range).foreach_index([&](const int i) {
622 for (const int vert : nodes[i].verts()) {
623 if (!hide_vert.is_empty() && hide_vert[vert]) {
624 continue;
625 }
626 const float distance_sq = math::distance_squared(vert_positions[vert], location);
627 if (distance_sq < nearest.distance_sq) {
628 nearest = {vert, distance_sq};
629 }
630 }
631 });
632 return nearest;
633 },
634 [](const NearestData a, const NearestData b) {
635 return a.distance_sq < b.distance_sq ? a : b;
636 });
637 return nearest.vert;
638}
639
640std::optional<SubdivCCGCoord> nearest_vert_calc_grids(const bke::pbvh::Tree &pbvh,
641 const SubdivCCG &subdiv_ccg,
642 const float3 &location,
643 const float max_distance,
644 const bool use_original)
645{
646 const float max_distance_sq = max_distance * max_distance;
647 IndexMaskMemory memory;
648 const IndexMask nodes_in_sphere = bke::pbvh::search_nodes(
649 pbvh, memory, [&](const bke::pbvh::Node &node) {
650 return node_in_sphere(node, location, max_distance_sq, use_original);
651 });
652 if (nodes_in_sphere.is_empty()) {
653 return std::nullopt;
654 }
655
656 struct NearestData {
657 SubdivCCGCoord coord = {};
658 float distance_sq = std::numeric_limits<float>::max();
659 };
660
661 const BitGroupVector<> grid_hidden = subdiv_ccg.grid_hidden;
662 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
663 const Span<float3> positions = subdiv_ccg.positions;
664
666 const NearestData nearest = threading::parallel_reduce(
667 nodes_in_sphere.index_range(),
668 1,
669 NearestData(),
670 [&](const IndexRange range, NearestData nearest) {
671 nodes_in_sphere.slice(range).foreach_index([&](const int i) {
672 for (const int grid : nodes[i].grids()) {
673 const IndexRange grid_range = bke::ccg::grid_range(key, grid);
674 BKE_subdiv_ccg_foreach_visible_grid_vert(key, grid_hidden, grid, [&](const int i) {
675 const float distance_sq = math::distance_squared(positions[grid_range[i]], location);
676 if (distance_sq < nearest.distance_sq) {
677 SubdivCCGCoord coord{};
678 coord.grid_index = grid;
679 coord.x = i % key.grid_size;
680 coord.y = i / key.grid_size;
681 nearest = {coord, distance_sq};
682 }
683 });
684 }
685 });
686 return nearest;
687 },
688 [](const NearestData a, const NearestData b) {
689 return a.distance_sq < b.distance_sq ? a : b;
690 });
691 return nearest.coord;
692}
693
694std::optional<BMVert *> nearest_vert_calc_bmesh(const bke::pbvh::Tree &pbvh,
695 const float3 &location,
696 const float max_distance,
697 const bool use_original)
698{
699 const float max_distance_sq = max_distance * max_distance;
700 IndexMaskMemory memory;
701 const IndexMask nodes_in_sphere = bke::pbvh::search_nodes(
702 pbvh, memory, [&](const bke::pbvh::Node &node) {
703 return node_in_sphere(node, location, max_distance_sq, use_original);
704 });
705 if (nodes_in_sphere.is_empty()) {
706 return std::nullopt;
707 }
708
709 struct NearestData {
710 BMVert *vert = nullptr;
711 float distance_sq = std::numeric_limits<float>::max();
712 };
713
715 const NearestData nearest = threading::parallel_reduce(
716 nodes_in_sphere.index_range(),
717 1,
718 NearestData(),
719 [&](const IndexRange range, NearestData nearest) {
720 nodes_in_sphere.slice(range).foreach_index([&](const int i) {
721 for (BMVert *vert :
723 {
725 continue;
726 }
727 const float distance_sq = math::distance_squared(float3(vert->co), location);
728 if (distance_sq < nearest.distance_sq) {
729 nearest = {vert, distance_sq};
730 }
731 }
732 });
733 return nearest;
734 },
735 [](const NearestData a, const NearestData b) {
736 return a.distance_sq < b.distance_sq ? a : b;
737 });
738 return nearest.vert;
739}
740
741} // namespace blender::ed::sculpt_paint
742
744 const float br_co[3],
745 float radius,
746 char symm)
747{
748 for (char i = 0; i <= symm; ++i) {
750 continue;
751 }
753 if (len_squared_v3v3(location, vertex) < radius * radius) {
754 return true;
755 }
756 }
757 return false;
758}
759
775
777
779
780/* -------------------------------------------------------------------- */
786
800
801static bool brush_uses_topology_rake(const SculptSession &ss, const Brush &brush)
802{
803 return bke::brush::supports_topology_rake(brush) && (brush.topology_rake_factor > 0.0f) &&
804 (ss.bm != nullptr);
805}
806
829
830static bool brush_needs_rake_rotation(const Brush &brush)
831{
832 return bke::brush::supports_rake_factor(brush) && (brush.rake_factor != 0.0f);
833}
834
836
837static void rake_data_update(SculptRakeData *srd, const float co[3])
838{
839 float rake_dist = len_v3v3(srd->follow_co, co);
840 if (rake_dist > srd->follow_dist) {
841 interp_v3_v3v3(srd->follow_co, srd->follow_co, co, rake_dist - srd->follow_dist);
842 }
843}
844
845/* -------------------------------------------------------------------- */
848
849namespace dyntopo {
850
851bool stroke_is_dyntopo(const Object &object, const Brush &brush)
852{
853 const SculptSession &ss = *object.sculpt;
854 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
855 return ((pbvh.type() == bke::pbvh::Type::BMesh) && (!ss.cache || (!ss.cache->alt_smooth)) &&
856 /* Requires mesh restore, which doesn't work with
857 * dynamic-topology. */
858 !(brush.flag & BRUSH_ANCHORED) && !(brush.flag & BRUSH_DRAG_DOT) &&
860}
861
862} // namespace dyntopo
863
865
866/* -------------------------------------------------------------------- */
869
870namespace undo {
871
873{
874 SculptSession &ss = *object.sculpt;
875 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
876 IndexMaskMemory memory;
877 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
878
879 Array<bool> node_changed(node_mask.min_array_size(), false);
880
881 switch (pbvh.type()) {
884 Mesh &mesh = *static_cast<Mesh *>(object.data);
885 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
887 ".sculpt_mask", bke::AttrDomain::Point);
888 node_mask.foreach_index(GrainSize(1), [&](const int i) {
889 if (const std::optional<Span<float>> orig_data = orig_mask_data_lookup_mesh(object,
890 nodes[i]))
891 {
892 const Span<int> verts = nodes[i].verts();
893 scatter_data_mesh(*orig_data, verts, mask.span);
895 node_changed[i] = true;
896 }
897 });
898 mask.finish();
899 break;
900 }
903 const int offset = CustomData_get_offset_named(&ss.bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
904 if (offset != -1) {
905 node_mask.foreach_index(GrainSize(1), [&](const int i) {
907 if (const float *orig_mask = BM_log_find_original_vert_mask(ss.bm_log, vert)) {
908 BM_ELEM_CD_SET_FLOAT(vert, offset, *orig_mask);
910 node_changed[i] = true;
911 }
912 }
913 });
914 }
915 break;
916 }
919 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
920 const BitGroupVector<> grid_hidden = subdiv_ccg.grid_hidden;
921 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
922 MutableSpan<float> masks = subdiv_ccg.masks;
923 node_mask.foreach_index(GrainSize(1), [&](const int i) {
924 if (const std::optional<Span<float>> orig_data = orig_mask_data_lookup_grids(object,
925 nodes[i]))
926 {
927 int index = 0;
928 for (const int grid : nodes[i].grids()) {
929 const IndexRange grid_range = bke::ccg::grid_range(key, grid);
930 for (const int i : IndexRange(key.grid_area)) {
931 if (grid_hidden.is_empty() || !grid_hidden[grid][i]) {
932 masks[grid_range[i]] = (*orig_data)[index];
933 }
934 index++;
935 }
936 }
938 node_changed[i] = true;
939 }
940 });
941 break;
942 }
943 }
944 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
945}
946
948{
949 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
951 IndexMaskMemory memory;
952 const IndexMask node_mask = IndexMask::from_predicate(
953 nodes.index_range(), GrainSize(64), memory, [&](const int i) {
954 return orig_color_data_lookup_mesh(object, nodes[i]).has_value();
955 });
956
958 Mesh &mesh = *static_cast<Mesh *>(object.data);
959 const OffsetIndices<int> faces = mesh.faces();
960 const Span<int> corner_verts = mesh.corner_verts();
961 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
963 node_mask.foreach_index(GrainSize(1), [&](const int i) {
964 const Span<float4> orig_data = *orig_color_data_lookup_mesh(object, nodes[i]);
965 const Span<int> verts = nodes[i].verts();
966 for (const int i : verts.index_range()) {
968 corner_verts,
969 vert_to_face_map,
970 color_attribute.domain,
971 verts[i],
972 orig_data[i],
973 color_attribute.span);
974 }
975 });
976 pbvh.tag_attribute_changed(node_mask, mesh.active_color_attribute);
977 color_attribute.finish();
978}
979
981{
982 SculptSession &ss = *object.sculpt;
983 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
984 IndexMaskMemory memory;
985 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
986
987 Array<bool> node_changed(node_mask.min_array_size(), false);
988
989 switch (pbvh.type()) {
993 *static_cast<Mesh *>(object.data));
994 node_mask.foreach_index(GrainSize(1), [&](const int i) {
995 if (const std::optional<Span<int>> orig_data = orig_face_set_data_lookup_mesh(object,
996 nodes[i]))
997 {
998 scatter_data_mesh(*orig_data, nodes[i].faces(), attribute.span);
999 node_changed[i] = true;
1000 }
1001 });
1002 attribute.finish();
1003 break;
1004 }
1006 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1009 *static_cast<Mesh *>(object.data));
1011 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1012 Vector<int> &tls = all_tls.local();
1013 if (const std::optional<Span<int>> orig_data = orig_face_set_data_lookup_grids(object,
1014 nodes[i]))
1015 {
1017 subdiv_ccg, nodes[i], tls);
1018 scatter_data_mesh(*orig_data, faces, attribute.span);
1019 node_changed[i] = true;
1020 }
1021 });
1022 attribute.finish();
1023 break;
1024 }
1026 break;
1027 }
1028
1029 pbvh.tag_face_sets_changed(IndexMask::from_bools(node_changed, memory));
1030}
1031
1032void restore_position_from_undo_step(const Depsgraph &depsgraph, Object &object)
1033{
1034 SculptSession &ss = *object.sculpt;
1035 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1036 IndexMaskMemory memory;
1037
1038 switch (pbvh.type()) {
1039 case bke::pbvh::Type::Mesh: {
1041 Mesh &mesh = *static_cast<Mesh *>(object.data);
1043 MutableSpan positions_orig = mesh.vert_positions_for_write();
1044
1045 const IndexMask node_mask = IndexMask::from_predicate(
1046 nodes.index_range(), GrainSize(64), memory, [&](const int i) {
1047 return orig_position_data_lookup_mesh(object, nodes[i]).has_value();
1048 });
1049
1050 struct LocalData {
1051 Vector<float3> translations;
1052 };
1053
1054 std::optional<ShapeKeyData> shape_key_data = ShapeKeyData::from_object(object);
1055 const bool need_translations = !ss.deform_imats.is_empty() || shape_key_data.has_value();
1056
1058 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1060 LocalData &tls = all_tls.local();
1061 const OrigPositionData orig_data = *orig_position_data_lookup_mesh(object, nodes[i]);
1062 const Span<int> verts = nodes[i].verts();
1063 const Span<float3> undo_positions = orig_data.positions;
1064 if (need_translations) {
1065 /* Calculate translations from evaluated positions before they are changed. */
1066 tls.translations.resize(verts.size());
1068 undo_positions, verts, positions_eval, tls.translations);
1069 }
1070
1071 scatter_data_mesh(undo_positions, verts, positions_eval);
1072
1073 if (positions_eval.data() == positions_orig.data()) {
1074 return;
1075 }
1076
1077 const MutableSpan<float3> translations = tls.translations;
1078 if (!ss.deform_imats.is_empty()) {
1080 }
1081
1082 if (shape_key_data) {
1083 for (MutableSpan<float3> data : shape_key_data->dependent_keys) {
1084 apply_translations(translations, verts, data);
1085 }
1086
1087 if (shape_key_data->basis_key_active) {
1088 /* The basis key positions and the mesh positions are always kept in sync. */
1089 apply_translations(translations, verts, positions_orig);
1090 }
1091 apply_translations(translations, verts, shape_key_data->active_key_data);
1092 }
1093 else {
1094 apply_translations(translations, verts, positions_orig);
1095 }
1096 });
1097 });
1098 pbvh.tag_positions_changed(node_mask);
1099 break;
1100 }
1104 return;
1105 }
1106 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1107 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1109 if (const float *orig_co = BM_log_find_original_vert_co(ss.bm_log, vert)) {
1110 copy_v3_v3(vert->co, orig_co);
1111 }
1112 }
1113 });
1114 pbvh.tag_positions_changed(node_mask);
1115 break;
1116 }
1119
1120 const IndexMask node_mask = IndexMask::from_predicate(
1121 nodes.index_range(), GrainSize(64), memory, [&](const int i) {
1122 return orig_position_data_lookup_grids(object, nodes[i]).has_value();
1123 });
1124
1125 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1126 const BitGroupVector<> grid_hidden = subdiv_ccg.grid_hidden;
1127 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
1128 MutableSpan<float3> positions = subdiv_ccg.positions;
1129 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1130 const OrigPositionData orig_data = *orig_position_data_lookup_grids(object, nodes[i]);
1131 int index = 0;
1132 for (const int grid : nodes[i].grids()) {
1133 const IndexRange grid_range = bke::ccg::grid_range(key, grid);
1134 for (const int i : IndexRange(key.grid_area)) {
1135 if (grid_hidden.is_empty() || !grid_hidden[grid][i]) {
1136 positions[grid_range[i]] = orig_data.positions[index];
1137 }
1138 index++;
1139 }
1140 }
1141 });
1142 pbvh.tag_positions_changed(node_mask);
1143 break;
1144 }
1145 }
1146}
1147
1148static void restore_from_undo_step(const Depsgraph &depsgraph, const Sculpt &sd, Object &object)
1149{
1150 SculptSession &ss = *object.sculpt;
1151 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
1152
1153 switch (brush->sculpt_brush_type) {
1156 break;
1160 break;
1162 if (ss.cache->alt_smooth) {
1165 }
1166 else {
1168 }
1169 break;
1170 default:
1173 break;
1174 }
1175}
1176
1177} // namespace undo
1178
1179} // namespace blender::ed::sculpt_paint
1180
1182 char falloff_shape)
1183{
1184 if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
1185 return ss.cache->sculpt_normal_symm;
1186 }
1187 BLI_assert(falloff_shape == PAINT_FALLOFF_SHAPE_TUBE);
1188 return ss.cache->view_normal_symm;
1189}
1190
1191/* ===== Sculpting =====
1192 */
1193
1195 const ePaintSymmetryFlags symm,
1196 const char axis,
1197 const float angle)
1198{
1200
1201 if (axis != 0) {
1202 float mat[3][3];
1203 axis_angle_to_mat3_single(mat, axis, angle);
1204 mul_m3_v3(mat, mirror);
1205 }
1206
1207 const float distsq = len_squared_v3v3(mirror, cache.location);
1208
1209 if (distsq <= 4.0f * (cache.radius_squared)) {
1210 return (2.0f * (cache.radius) - sqrtf(distsq)) / (2.0f * (cache.radius));
1211 }
1212 return 0.0f;
1213}
1214
1217 const ePaintSymmetryFlags symm,
1218 const char axis)
1219{
1220 float overlap = 0.0f;
1221
1222 for (int i = 1; i < sd.radial_symm[axis - 'X']; i++) {
1223 const float angle = 2.0f * M_PI * i / sd.radial_symm[axis - 'X'];
1224 overlap += calc_overlap(cache, symm, axis, angle);
1225 }
1226
1227 return overlap;
1228}
1229
1230static float calc_symmetry_feather(const Sculpt &sd,
1232{
1234 return 1.0f;
1235 }
1236 float overlap;
1237 const int symm = cache.symmetry;
1238
1239 overlap = 0.0f;
1240 for (int i = 0; i <= symm; i++) {
1242 continue;
1243 }
1244
1245 overlap += calc_overlap(cache, ePaintSymmetryFlags(i), 0, 0);
1246
1247 overlap += calc_radial_symmetry_feather(sd, cache, ePaintSymmetryFlags(i), 'X');
1248 overlap += calc_radial_symmetry_feather(sd, cache, ePaintSymmetryFlags(i), 'Y');
1249 overlap += calc_radial_symmetry_feather(sd, cache, ePaintSymmetryFlags(i), 'Z');
1250 }
1251 return 1.0f / overlap;
1252}
1253
1255
1256/* -------------------------------------------------------------------- */
1269
1270namespace blender::ed::sculpt_paint {
1271
1273 /* 0 = towards view, 1 = flipped */
1274 std::array<float3, 2> area_cos;
1275 std::array<int, 2> count_co;
1276
1277 std::array<float3, 2> area_nos;
1278 std::array<int, 2> count_no;
1279};
1280
1282{
1283 float test_radius = ss.cache ? ss.cache->radius : ss.cursor_radius;
1284 if (brush.ob_mode == OB_MODE_SCULPT) {
1285 test_radius *= brush.normal_radius_factor;
1286 }
1287 return test_radius;
1288}
1289
1291 const Brush &brush)
1292{
1293 float test_radius = ss.cache ? ss.cache->radius : ss.cursor_radius;
1294 if (brush.ob_mode == OB_MODE_SCULPT) {
1295 /* Layer brush produces artifacts with normal and area radius */
1296 if (brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_PLANE && brush.area_radius_factor > 0.0f) {
1297 test_radius *= brush.area_radius_factor;
1298 if (ss.cache && brush.flag2 & BRUSH_AREA_RADIUS_PRESSURE) {
1299 test_radius *= ss.cache->pressure;
1300 }
1301 }
1302 else {
1303 test_radius *= brush.normal_radius_factor;
1304 }
1305 }
1306 return test_radius;
1307}
1308
1309/* Weight the normals towards the center. */
1310static float area_normal_calc_weight(const float distance, const float radius_inv)
1311{
1312 float p = 1.0f - (distance * radius_inv);
1313 return std::clamp(3.0f * p * p - 2.0f * p * p * p, 0.0f, 1.0f);
1314}
1315
1316/* Weight the coordinates towards the center. */
1317static float3 area_center_calc_weighted(const float3 &test_location,
1318 const float distance,
1319 const float radius_inv,
1320 const float3 &co)
1321{
1322 /* Weight the coordinates towards the center. */
1323 float p = 1.0f - (distance * radius_inv);
1324 const float afactor = std::clamp(3.0f * p * p - 2.0f * p * p * p, 0.0f, 1.0f);
1325
1326 const float3 disp = (co - test_location) * (1.0f - afactor);
1327 return test_location + disp;
1328}
1329
1330static void accumulate_area_center(const float3 &test_location,
1331 const float3 &position,
1332 const float distance,
1333 const float radius_inv,
1334 const int flip_index,
1335 AreaNormalCenterData &anctd)
1336{
1337 anctd.area_cos[flip_index] += area_center_calc_weighted(
1338 test_location, distance, radius_inv, position);
1339 anctd.count_co[flip_index] += 1;
1340}
1341
1342static void accumulate_area_normal(const float3 &normal,
1343 const float distance,
1344 const float radius_inv,
1345 const int flip_index,
1346 AreaNormalCenterData &anctd)
1347{
1348 anctd.area_nos[flip_index] += normal * area_normal_calc_weight(distance, radius_inv);
1349 anctd.count_no[flip_index] += 1;
1350}
1351
1356
1358 const Span<float3> vert_positions,
1359 const Span<float3> vert_normals,
1360 const Span<bool> hide_vert,
1361 const Brush &brush,
1362 const bool use_area_nos,
1363 const bool use_area_cos,
1364 const bke::pbvh::MeshNode &node,
1365 SampleLocalData &tls,
1366 AreaNormalCenterData &anctd)
1367{
1368 const SculptSession &ss = *object.sculpt;
1369 const float3 &location = ss.cache ? ss.cache->location_symm : ss.cursor_location;
1370 const float3 &view_normal = ss.cache ? ss.cache->view_normal_symm : ss.cursor_view_normal;
1371 const float position_radius = area_normal_and_center_get_position_radius(ss, brush);
1372 const float position_radius_sq = position_radius * position_radius;
1373 const float position_radius_inv = math::rcp(position_radius);
1374 const float normal_radius = area_normal_and_center_get_normal_radius(ss, brush);
1375 const float normal_radius_sq = normal_radius * normal_radius;
1376 const float normal_radius_inv = math::rcp(normal_radius);
1377
1378 const Span<int> verts = node.verts();
1379
1380 if (ss.cache && !ss.cache->accum) {
1381 if (const std::optional<OrigPositionData> orig_data = orig_position_data_lookup_mesh(object,
1382 node))
1383 {
1384 const Span<float3> orig_positions = orig_data->positions;
1385 const Span<float3> orig_normals = orig_data->normals;
1386
1387 tls.distances.reinitialize(verts.size());
1388 const MutableSpan<float> distances_sq = tls.distances;
1390 ss, orig_positions, eBrushFalloffShape(brush.falloff_shape), distances_sq);
1391
1392 for (const int i : verts.index_range()) {
1393 const int vert = verts[i];
1394 if (!hide_vert.is_empty() && hide_vert[vert]) {
1395 continue;
1396 }
1397 const bool normal_test_r = use_area_nos && distances_sq[i] <= normal_radius_sq;
1398 const bool area_test_r = use_area_cos && distances_sq[i] <= position_radius_sq;
1399 if (!normal_test_r && !area_test_r) {
1400 continue;
1401 }
1402 const float3 &normal = orig_normals[i];
1403 const float distance = std::sqrt(distances_sq[i]);
1404 const int flip_index = math::dot(view_normal, normal) <= 0.0f;
1405 if (area_test_r) {
1407 location, orig_positions[i], distance, position_radius_inv, flip_index, anctd);
1408 }
1409 if (normal_test_r) {
1410 accumulate_area_normal(normal, distance, normal_radius_inv, flip_index, anctd);
1411 }
1412 }
1413 return;
1414 }
1415 }
1416
1417 tls.distances.reinitialize(verts.size());
1418 const MutableSpan<float> distances_sq = tls.distances;
1420 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances_sq);
1421
1422 for (const int i : verts.index_range()) {
1423 const int vert = verts[i];
1424 if (!hide_vert.is_empty() && hide_vert[vert]) {
1425 continue;
1426 }
1427 const bool normal_test_r = distances_sq[i] <= normal_radius_sq;
1428 const bool area_test_r = distances_sq[i] <= position_radius_sq;
1429 if (!normal_test_r && !area_test_r) {
1430 continue;
1431 }
1432 const float3 &normal = vert_normals[vert];
1433 const float distance = std::sqrt(distances_sq[i]);
1434 const int flip_index = math::dot(view_normal, normal) <= 0.0f;
1435 if (area_test_r) {
1437 location, vert_positions[vert], distance, position_radius_inv, flip_index, anctd);
1438 }
1439 if (normal_test_r) {
1440 accumulate_area_normal(normal, distance, normal_radius_inv, flip_index, anctd);
1441 }
1442 }
1443}
1444
1446 const Brush &brush,
1447 const bool use_area_nos,
1448 const bool use_area_cos,
1449 const bke::pbvh::GridsNode &node,
1450 SampleLocalData &tls,
1451 AreaNormalCenterData &anctd)
1452{
1453 const SculptSession &ss = *object.sculpt;
1454 const float3 &location = ss.cache ? ss.cache->location_symm : ss.cursor_location;
1455 const float3 &view_normal = ss.cache ? ss.cache->view_normal_symm : ss.cursor_view_normal;
1456 const float position_radius = area_normal_and_center_get_position_radius(ss, brush);
1457 const float position_radius_sq = position_radius * position_radius;
1458 const float position_radius_inv = math::rcp(position_radius);
1459 const float normal_radius = area_normal_and_center_get_normal_radius(ss, brush);
1460 const float normal_radius_sq = normal_radius * normal_radius;
1461 const float normal_radius_inv = math::rcp(normal_radius);
1462
1463 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1465 const Span<float3> normals = subdiv_ccg.normals;
1466 const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
1467 const Span<int> grids = node.grids();
1468
1469 if (ss.cache && !ss.cache->accum) {
1470 if (const std::optional<OrigPositionData> orig_data = orig_position_data_lookup_grids(object,
1471 node))
1472 {
1473 const Span<float3> orig_positions = orig_data->positions;
1474 const Span<float3> orig_normals = orig_data->normals;
1475
1476 tls.distances.reinitialize(orig_positions.size());
1477 const MutableSpan<float> distances_sq = tls.distances;
1479 ss, orig_positions, eBrushFalloffShape(brush.falloff_shape), distances_sq);
1480
1481 for (const int i : grids.index_range()) {
1482 const IndexRange grid_range_node = bke::ccg::grid_range(key, i);
1483 const int grid = grids[i];
1484 for (const int offset : IndexRange(key.grid_area)) {
1485 if (!grid_hidden.is_empty() && grid_hidden[grid][offset]) {
1486 continue;
1487 }
1488 const int node_vert = grid_range_node[offset];
1489
1490 const bool normal_test_r = use_area_nos && distances_sq[node_vert] <= normal_radius_sq;
1491 const bool area_test_r = use_area_cos && distances_sq[node_vert] <= position_radius_sq;
1492 if (!normal_test_r && !area_test_r) {
1493 continue;
1494 }
1495 const float3 &normal = orig_normals[node_vert];
1496 const float distance = std::sqrt(distances_sq[node_vert]);
1497 const int flip_index = math::dot(view_normal, normal) <= 0.0f;
1498 if (area_test_r) {
1499 accumulate_area_center(location,
1500 orig_positions[node_vert],
1501 distance,
1502 position_radius_inv,
1503 flip_index,
1504 anctd);
1505 }
1506 if (normal_test_r) {
1507 accumulate_area_normal(normal, distance, normal_radius_inv, flip_index, anctd);
1508 }
1509 }
1510 }
1511 return;
1512 }
1513 }
1514
1515 const Span<float3> positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
1516 tls.distances.reinitialize(positions.size());
1517 const MutableSpan<float> distances_sq = tls.distances;
1519 ss, positions, eBrushFalloffShape(brush.falloff_shape), distances_sq);
1520
1521 for (const int i : grids.index_range()) {
1522 const IndexRange grid_range_node = bke::ccg::grid_range(key, i);
1523 const int grid = grids[i];
1524 const IndexRange grid_range = bke::ccg::grid_range(key, grid);
1525 for (const int offset : IndexRange(key.grid_area)) {
1526 if (!grid_hidden.is_empty() && grid_hidden[grid][offset]) {
1527 continue;
1528 }
1529 const int node_vert = grid_range_node[offset];
1530 const int vert = grid_range[offset];
1531
1532 const bool normal_test_r = use_area_nos && distances_sq[node_vert] <= normal_radius_sq;
1533 const bool area_test_r = use_area_cos && distances_sq[node_vert] <= position_radius_sq;
1534 if (!normal_test_r && !area_test_r) {
1535 continue;
1536 }
1537 const float3 &normal = normals[vert];
1538 const float distance = std::sqrt(distances_sq[node_vert]);
1539 const int flip_index = math::dot(view_normal, normal) <= 0.0f;
1540 if (area_test_r) {
1542 location, positions[node_vert], distance, position_radius_inv, flip_index, anctd);
1543 }
1544 if (normal_test_r) {
1545 accumulate_area_normal(normal, distance, normal_radius_inv, flip_index, anctd);
1546 }
1547 }
1548 }
1549}
1550
1552 const Brush &brush,
1553 const bool use_area_nos,
1554 const bool use_area_cos,
1555 const bool has_bm_orco,
1556 const bke::pbvh::BMeshNode &node,
1557 SampleLocalData &tls,
1558 AreaNormalCenterData &anctd)
1559{
1560 const SculptSession &ss = *object.sculpt;
1561 const float3 &location = ss.cache ? ss.cache->location_symm : ss.cursor_location;
1562 const float3 &view_normal = ss.cache ? ss.cache->view_normal_symm : ss.cursor_view_normal;
1563 const float position_radius = area_normal_and_center_get_position_radius(ss, brush);
1564 const float position_radius_sq = position_radius * position_radius;
1565 const float position_radius_inv = math::rcp(position_radius);
1566 const float normal_radius = area_normal_and_center_get_normal_radius(ss, brush);
1567 const float normal_radius_sq = normal_radius * normal_radius;
1568 const float normal_radius_inv = math::rcp(normal_radius);
1569
1570 bool use_original = false;
1571 if (ss.cache && !ss.cache->accum) {
1572 use_original = undo::has_bmesh_log_entry();
1573 }
1574
1575 /* When the mesh is edited we can't rely on original coords
1576 * (original mesh may not even have verts in brush radius). */
1577 if (use_original && has_bm_orco) {
1578 Span<float3> orig_positions;
1579 Span<int3> orig_tris;
1580 BKE_pbvh_node_get_bm_orco_data(node, orig_positions, orig_tris);
1581
1582 tls.positions.resize(orig_tris.size());
1583 const MutableSpan<float3> positions = tls.positions;
1584 for (const int i : orig_tris.index_range()) {
1585 const float *co_tri[3] = {
1586 orig_positions[orig_tris[i][0]],
1587 orig_positions[orig_tris[i][1]],
1588 orig_positions[orig_tris[i][2]],
1589 };
1590 closest_on_tri_to_point_v3(positions[i], location, UNPACK3(co_tri));
1591 }
1592
1593 tls.distances.reinitialize(positions.size());
1594 const MutableSpan<float> distances_sq = tls.distances;
1596 ss, positions, eBrushFalloffShape(brush.falloff_shape), distances_sq);
1597
1598 for (const int i : orig_tris.index_range()) {
1599 const bool normal_test_r = use_area_nos && distances_sq[i] <= normal_radius_sq;
1600 const bool area_test_r = use_area_cos && distances_sq[i] <= position_radius_sq;
1601 if (!normal_test_r && !area_test_r) {
1602 continue;
1603 }
1604 const float3 normal = math::normal_tri(float3(orig_positions[orig_tris[i][0]]),
1605 float3(orig_positions[orig_tris[i][1]]),
1606 float3(orig_positions[orig_tris[i][2]]));
1607
1608 const float distance = std::sqrt(distances_sq[i]);
1609 const int flip_index = math::dot(view_normal, normal) <= 0.0f;
1610 if (area_test_r) {
1612 location, positions[i], distance, position_radius_inv, flip_index, anctd);
1613 }
1614 if (normal_test_r) {
1615 accumulate_area_normal(normal, distance, normal_radius_inv, flip_index, anctd);
1616 }
1617 }
1618 return;
1619 }
1620
1622 &const_cast<bke::pbvh::BMeshNode &>(node));
1623 if (use_original) {
1624 tls.positions.resize(verts.size());
1625 const MutableSpan<float3> positions = tls.positions;
1626 Array<float3> normals(verts.size());
1628
1629 tls.distances.reinitialize(positions.size());
1630 const MutableSpan<float> distances_sq = tls.distances;
1632 ss, positions, eBrushFalloffShape(brush.falloff_shape), distances_sq);
1633
1634 int i = 0;
1635 for (BMVert *vert : verts) {
1636 if (BM_elem_flag_test(vert, BM_ELEM_HIDDEN)) {
1637 i++;
1638 continue;
1639 }
1640 const bool normal_test_r = use_area_nos && distances_sq[i] <= normal_radius_sq;
1641 const bool area_test_r = use_area_cos && distances_sq[i] <= position_radius_sq;
1642 if (!normal_test_r && !area_test_r) {
1643 i++;
1644 continue;
1645 }
1646 const float3 &normal = normals[i];
1647 const float distance = std::sqrt(distances_sq[i]);
1648 const int flip_index = math::dot(view_normal, normal) <= 0.0f;
1649 if (area_test_r) {
1651 location, positions[i], distance, position_radius_inv, flip_index, anctd);
1652 }
1653 if (normal_test_r) {
1654 accumulate_area_normal(normal, distance, normal_radius_inv, flip_index, anctd);
1655 }
1656 i++;
1657 }
1658 return;
1659 }
1660
1661 const Span<float3> positions = gather_bmesh_positions(verts, tls.positions);
1662
1663 tls.distances.reinitialize(positions.size());
1664 const MutableSpan<float> distances_sq = tls.distances;
1666 ss, positions, eBrushFalloffShape(brush.falloff_shape), distances_sq);
1667
1668 int i = 0;
1669 for (BMVert *vert : verts) {
1670 if (BM_elem_flag_test(vert, BM_ELEM_HIDDEN)) {
1671 i++;
1672 continue;
1673 }
1674 const bool normal_test_r = use_area_nos && distances_sq[i] <= normal_radius_sq;
1675 const bool area_test_r = use_area_cos && distances_sq[i] <= position_radius_sq;
1676 if (!normal_test_r && !area_test_r) {
1677 i++;
1678 continue;
1679 }
1680 const float3 normal = vert->no;
1681 const float distance = std::sqrt(distances_sq[i]);
1682 const int flip_index = math::dot(view_normal, normal) <= 0.0f;
1683 if (area_test_r) {
1685 location, positions[i], distance, position_radius_inv, flip_index, anctd);
1686 }
1687 if (normal_test_r) {
1688 accumulate_area_normal(normal, distance, normal_radius_inv, flip_index, anctd);
1689 }
1690 i++;
1691 }
1692}
1693
1695 const AreaNormalCenterData &b)
1696{
1697 AreaNormalCenterData joined{};
1698
1699 joined.area_cos[0] = a.area_cos[0] + b.area_cos[0];
1700 joined.area_cos[1] = a.area_cos[1] + b.area_cos[1];
1701 joined.count_co[0] = a.count_co[0] + b.count_co[0];
1702 joined.count_co[1] = a.count_co[1] + b.count_co[1];
1703
1704 joined.area_nos[0] = a.area_nos[0] + b.area_nos[0];
1705 joined.area_nos[1] = a.area_nos[1] + b.area_nos[1];
1706 joined.count_no[0] = a.count_no[0] + b.count_no[0];
1707 joined.count_no[1] = a.count_no[1] + b.count_no[1];
1708
1709 return joined;
1710}
1711
1712void calc_area_center(const Depsgraph &depsgraph,
1713 const Brush &brush,
1714 const Object &ob,
1715 const IndexMask &node_mask,
1716 float r_area_co[3])
1717{
1718 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
1719 const SculptSession &ss = *ob.sculpt;
1720 int n;
1721
1724 switch (pbvh.type()) {
1725 case bke::pbvh::Type::Mesh: {
1726 const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
1727 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
1728 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, ob);
1729 const bke::AttributeAccessor attributes = mesh.attributes();
1730 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
1731
1734 node_mask.index_range(),
1735 1,
1737 [&](const IndexRange range, AreaNormalCenterData anctd) {
1738 SampleLocalData &tls = all_tls.local();
1739 node_mask.slice(range).foreach_index([&](const int i) {
1740 calc_area_normal_and_center_node_mesh(ob,
1741 vert_positions,
1742 vert_normals,
1743 hide_vert,
1744 brush,
1745 false,
1746 true,
1747 nodes[i],
1748 tls,
1749 anctd);
1750 });
1751 return anctd;
1752 },
1754 break;
1755 }
1757 const bool has_bm_orco = ss.bm && dyntopo::stroke_is_dyntopo(ob, brush);
1758
1761 node_mask.index_range(),
1762 1,
1764 [&](const IndexRange range, AreaNormalCenterData anctd) {
1765 SampleLocalData &tls = all_tls.local();
1766 node_mask.slice(range).foreach_index([&](const int i) {
1767 calc_area_normal_and_center_node_bmesh(
1768 ob, brush, false, true, has_bm_orco, nodes[i], tls, anctd);
1769 });
1770 return anctd;
1771 },
1773 break;
1774 }
1778 node_mask.index_range(),
1779 1,
1781 [&](const IndexRange range, AreaNormalCenterData anctd) {
1782 SampleLocalData &tls = all_tls.local();
1783 node_mask.slice(range).foreach_index([&](const int i) {
1784 calc_area_normal_and_center_node_grids(ob, brush, false, true, nodes[i], tls, anctd);
1785 });
1786 return anctd;
1787 },
1789 break;
1790 }
1791 }
1792
1793 /* For flatten center. */
1794 for (n = 0; n < anctd.area_cos.size(); n++) {
1795 if (anctd.count_co[n] == 0) {
1796 continue;
1797 }
1798
1799 mul_v3_v3fl(r_area_co, anctd.area_cos[n], 1.0f / anctd.count_co[n]);
1800 break;
1801 }
1802
1803 if (n == 2) {
1804 zero_v3(r_area_co);
1805 }
1806
1807 if (anctd.count_co[0] == 0 && anctd.count_co[1] == 0) {
1808 if (ss.cache) {
1809 copy_v3_v3(r_area_co, ss.cache->location_symm);
1810 }
1811 }
1812}
1813
1814std::optional<float3> calc_area_normal(const Depsgraph &depsgraph,
1815 const Brush &brush,
1816 const Object &ob,
1817 const IndexMask &node_mask)
1818{
1819 SculptSession &ss = *ob.sculpt;
1820 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
1821
1824 switch (pbvh.type()) {
1825 case bke::pbvh::Type::Mesh: {
1826 const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
1827 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
1828 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, ob);
1829 const bke::AttributeAccessor attributes = mesh.attributes();
1830 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
1831
1834 node_mask.index_range(),
1835 1,
1837 [&](const IndexRange range, AreaNormalCenterData anctd) {
1838 SampleLocalData &tls = all_tls.local();
1839 node_mask.slice(range).foreach_index([&](const int i) {
1840 calc_area_normal_and_center_node_mesh(ob,
1841 vert_positions,
1842 vert_normals,
1843 hide_vert,
1844 brush,
1845 true,
1846 false,
1847 nodes[i],
1848 tls,
1849 anctd);
1850 });
1851 return anctd;
1852 },
1854 break;
1855 }
1857 const bool has_bm_orco = ss.bm && dyntopo::stroke_is_dyntopo(ob, brush);
1858
1861 node_mask.index_range(),
1862 1,
1864 [&](const IndexRange range, AreaNormalCenterData anctd) {
1865 SampleLocalData &tls = all_tls.local();
1866 node_mask.slice(range).foreach_index([&](const int i) {
1867 calc_area_normal_and_center_node_bmesh(
1868 ob,
1869 brush,
1870 true,
1871 false,
1872 has_bm_orco,
1873 static_cast<const blender::bke::pbvh::BMeshNode &>(nodes[i]),
1874 tls,
1875 anctd);
1876 });
1877 return anctd;
1878 },
1880 break;
1881 }
1885 node_mask.index_range(),
1886 1,
1888 [&](const IndexRange range, AreaNormalCenterData anctd) {
1889 SampleLocalData &tls = all_tls.local();
1890 node_mask.slice(range).foreach_index([&](const int i) {
1891 calc_area_normal_and_center_node_grids(ob, brush, true, false, nodes[i], tls, anctd);
1892 });
1893 return anctd;
1894 },
1896 break;
1897 }
1898 }
1899
1900 for (const int i : {0, 1}) {
1901 if (anctd.count_no[i] != 0) {
1902 if (!math::is_zero(anctd.area_nos[i])) {
1903 return math::normalize(anctd.area_nos[i]);
1904 }
1905 }
1906 }
1907 return std::nullopt;
1908}
1909
1910/*
1911 * Stabilizes the position (center) and orientation (normal) of the brush plane during a stroke.
1912 * Implements a smoothing mechanism based on a weighted moving average for both the plane normal
1913 * and the plane center.
1914 *
1915 * The stabilized normal (`r_stabilized_normal`) is computed as the average of the last
1916 * `max_normal_index` plane normals, where `max_normal_index` is determined by the
1917 * `stabilize_normal` parameter of the brush. Each new plane normal is interpolated with the
1918 * previous plane normal, with `stabilize_normal` controlling the interpolation factor.
1919 *
1920 * The stabilized center (`r_stabilized_center`) is computed based on the signed distances
1921 * of the stored plane centers from a reference plane defined by the current stroke step's center
1922 * and the stabilized normal. The signed distances are averaged, and this average is used to
1923 * adjust the position of the stabilized center such that it maintains the average offset of the
1924 * stored centers relative to the reference plane.
1925 */
1926static void calc_stabilized_plane(const Brush &brush,
1927 StrokeCache &cache,
1928 const float3 &plane_normal,
1929 const float3 &plane_center,
1930 float3 &r_stabilized_normal,
1931 float3 &r_stabilized_center)
1932{
1933 auto &plane_cache = cache.plane_brush;
1934
1935 const float normal_weight = brush.stabilize_normal;
1936 const float center_weight = brush.stabilize_plane;
1937
1938 float3 new_plane_normal;
1939 float3 new_plane_center;
1940
1941 if (plane_cache.first_time) {
1942 new_plane_normal = plane_normal;
1943 new_plane_center = plane_center;
1944
1945 const int max_normal_index = int(1 +
1946 normal_weight * (plane_brush_max_rolling_average_num - 1));
1947 const int max_center_index = int(1 +
1948 center_weight * (plane_brush_max_rolling_average_num - 1));
1949
1950 plane_cache.normals.reinitialize(max_normal_index);
1951 plane_cache.centers.reinitialize(max_center_index);
1952 plane_cache.normals.fill(plane_normal);
1953 plane_cache.centers.fill(plane_center);
1954
1955 plane_cache.normal_index = 0;
1956 plane_cache.center_index = 0;
1957 plane_cache.first_time = false;
1958 }
1959 else {
1960 const float3 last_normal = plane_cache.last_normal.value();
1961 const float3 last_center = plane_cache.last_center.value();
1962
1963 /* Interpolate between `plane_normal` and the last plane normal. */
1964 new_plane_normal = math::normalize(
1965 math::interpolate(plane_normal, last_normal, normal_weight));
1966
1967 float4 last_plane;
1968 plane_from_point_normal_v3(last_plane, last_center, last_normal);
1969
1970 /* Projection of `plane_center` on the last plane. */
1971 float3 projected_plane_center;
1972 closest_to_plane_normalized_v3(projected_plane_center, last_plane, plane_center);
1973
1974 new_plane_center = math::interpolate(plane_center, projected_plane_center, center_weight);
1975 }
1976
1977 plane_cache.normals[plane_cache.normal_index] = new_plane_normal;
1978 plane_cache.centers[plane_cache.center_index] = new_plane_center;
1979
1980 plane_cache.normal_index = (plane_cache.normal_index + 1) % plane_cache.normals.size();
1981 plane_cache.center_index = (plane_cache.center_index + 1) % plane_cache.centers.size();
1982
1983 r_stabilized_normal = float3(0.0f);
1984
1985 for (const int i : plane_cache.normals.index_range()) {
1986 r_stabilized_normal += plane_cache.normals[i];
1987 }
1988 r_stabilized_normal = math::normalize(r_stabilized_normal);
1989
1990 float4 reference_plane;
1991 plane_from_point_normal_v3(reference_plane, new_plane_center, r_stabilized_normal);
1992 float total_signed_distance = 0.0f;
1993
1994 for (const int i : plane_cache.centers.index_range()) {
1995 float signed_distance = math::dot(r_stabilized_normal, plane_cache.centers[i]) -
1996 reference_plane.w;
1997 total_signed_distance += signed_distance;
1998 }
1999
2000 const float avg_signed_distance = total_signed_distance / plane_cache.centers.size();
2001 const float new_center_signed_distance = math::dot(r_stabilized_normal, new_plane_center) -
2002 reference_plane.w;
2003 const float adjusted_distance = new_center_signed_distance - avg_signed_distance;
2004 r_stabilized_center = new_plane_center - r_stabilized_normal * adjusted_distance;
2005
2006 plane_cache.last_normal = r_stabilized_normal;
2007 plane_cache.last_center = r_stabilized_center;
2008}
2009
2011 const Brush &brush,
2012 const Object &ob,
2013 const IndexMask &node_mask,
2014 float r_area_no[3],
2015 float r_area_co[3])
2016{
2017 SculptSession &ss = *ob.sculpt;
2018 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
2019 int n;
2020
2023 switch (pbvh.type()) {
2024 case bke::pbvh::Type::Mesh: {
2025 const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
2026 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
2027 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, ob);
2028 const bke::AttributeAccessor attributes = mesh.attributes();
2029 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
2030
2033 node_mask.index_range(),
2034 1,
2036 [&](const IndexRange range, AreaNormalCenterData anctd) {
2037 SampleLocalData &tls = all_tls.local();
2038 node_mask.slice(range).foreach_index([&](const int i) {
2039 calc_area_normal_and_center_node_mesh(ob,
2040 vert_positions,
2041 vert_normals,
2042 hide_vert,
2043 brush,
2044 true,
2045 true,
2046 nodes[i],
2047 tls,
2048 anctd);
2049 });
2050 return anctd;
2051 },
2053 break;
2054 }
2056 const bool has_bm_orco = ss.bm && dyntopo::stroke_is_dyntopo(ob, brush);
2057
2060 node_mask.index_range(),
2061 1,
2063 [&](const IndexRange range, AreaNormalCenterData anctd) {
2064 SampleLocalData &tls = all_tls.local();
2065 node_mask.slice(range).foreach_index([&](const int i) {
2066 calc_area_normal_and_center_node_bmesh(
2067 ob, brush, true, true, has_bm_orco, nodes[i], tls, anctd);
2068 });
2069 return anctd;
2070 },
2072 break;
2073 }
2077 node_mask.index_range(),
2078 1,
2080 [&](const IndexRange range, AreaNormalCenterData anctd) {
2081 SampleLocalData &tls = all_tls.local();
2082 node_mask.slice(range).foreach_index([&](const int i) {
2083 calc_area_normal_and_center_node_grids(ob, brush, true, true, nodes[i], tls, anctd);
2084 });
2085 return anctd;
2086 },
2088 break;
2089 }
2090 }
2091
2092 /* For flatten center. */
2093 for (n = 0; n < anctd.area_cos.size(); n++) {
2094 if (anctd.count_co[n] == 0) {
2095 continue;
2096 }
2097
2098 mul_v3_v3fl(r_area_co, anctd.area_cos[n], 1.0f / anctd.count_co[n]);
2099 break;
2100 }
2101
2102 if (n == 2) {
2103 zero_v3(r_area_co);
2104 }
2105
2106 if (anctd.count_co[0] == 0 && anctd.count_co[1] == 0) {
2107 if (ss.cache) {
2108 copy_v3_v3(r_area_co, ss.cache->location_symm);
2109 }
2110 }
2111
2112 /* For area normal. */
2113 for (n = 0; n < anctd.area_nos.size(); n++) {
2114 if (normalize_v3_v3(r_area_no, anctd.area_nos[n]) != 0.0f) {
2115 break;
2116 }
2117 }
2118
2119 if (brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_PLANE) {
2120 float3 stabilized_normal;
2121 float3 stabilized_center;
2122
2124 brush, *ss.cache, r_area_no, r_area_co, stabilized_normal, stabilized_center);
2125
2126 copy_v3_v3(r_area_no, stabilized_normal);
2127 copy_v3_v3(r_area_co, stabilized_center);
2128 }
2129}
2130
2131} // namespace blender::ed::sculpt_paint
2132
2134
2135/* -------------------------------------------------------------------- */
2138
2143static float brush_flip(const Brush &brush, const blender::ed::sculpt_paint::StrokeCache &cache)
2144{
2145 const float dir = (brush.flag & BRUSH_DIR_IN) ? -1.0f : 1.0f;
2146 const float pen_flip = cache.pen_flip ? -1.0f : 1.0f;
2147 const float invert = cache.invert ? -1.0f : 1.0f;
2148
2149 return dir * pen_flip * invert;
2150}
2151
2157static float brush_strength(const Sculpt &sd,
2159 const float feather,
2160 const UnifiedPaintSettings &ups,
2161 const PaintModeSettings & /*paint_mode_settings*/)
2162{
2163 const Scene *scene = cache.vc->scene;
2164 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
2165
2166 /* Primary strength input; square it to make lower values more sensitive. */
2167 const float root_alpha = BKE_brush_alpha_get(scene, &brush);
2168 const float alpha = root_alpha * root_alpha;
2169 const float pressure = BKE_brush_use_alpha_pressure(&brush) ? cache.pressure : 1.0f;
2170 float overlap = ups.overlap_factor;
2171 /* Spacing is integer percentage of radius, divide by 50 to get
2172 * normalized diameter. */
2173
2174 const float flip = brush_flip(brush, cache);
2175
2176 /* Pressure final value after being tweaked depending on the brush. */
2177 float final_pressure;
2178
2179 switch (brush.sculpt_brush_type) {
2181 final_pressure = pow4f(pressure);
2182 overlap = (1.0f + overlap) / 2.0f;
2183 return 0.25f * alpha * flip * final_pressure * overlap * feather;
2187 return alpha * flip * pressure * overlap * feather;
2189 return alpha * pressure * overlap * feather;
2192 /* Grab deform uses the same falloff as a regular grab brush. */
2193 return root_alpha * feather;
2194 }
2196 return root_alpha * feather * pressure * overlap;
2197 }
2198 else if (brush.cloth_deform_type == BRUSH_CLOTH_DEFORM_EXPAND) {
2199 /* Expand is more sensible to strength as it keeps expanding the cloth when sculpting over
2200 * the same vertices. */
2201 return 0.1f * alpha * flip * pressure * overlap * feather;
2202 }
2203 else {
2204 /* Multiply by 10 by default to get a larger range of strength depending on the size of the
2205 * brush and object. */
2206 return 10.0f * alpha * flip * pressure * overlap * feather;
2207 }
2209 return alpha * pressure * overlap * feather;
2211 return alpha * pressure * overlap * feather * 2.0f;
2213 final_pressure = pressure * pressure;
2214 return final_pressure * overlap * feather;
2217 return alpha * pressure * overlap * feather;
2219 /* Clay Strips needs less strength to compensate the curve. */
2220 final_pressure = powf(pressure, 1.5f);
2221 return alpha * flip * final_pressure * overlap * feather * 0.3f;
2223 final_pressure = pressure * pressure;
2224 return alpha * flip * final_pressure * overlap * feather * 1.3f;
2225
2227 overlap = (1.0f + overlap) / 2.0f;
2228 switch ((BrushMaskTool)brush.mask_tool) {
2229 case BRUSH_MASK_DRAW:
2230 return alpha * flip * pressure * overlap * feather;
2231 case BRUSH_MASK_SMOOTH:
2232 return alpha * pressure * feather;
2233 }
2234 break;
2237 return alpha * flip * pressure * overlap * feather;
2238
2240 if (flip > 0.0f) {
2241 return 0.250f * alpha * flip * pressure * overlap * feather;
2242 }
2243 else {
2244 return 0.125f * alpha * flip * pressure * overlap * feather;
2245 }
2246
2248 overlap = (1.0f + overlap) / 2.0f;
2249 return alpha * flip * pressure * overlap * feather;
2250
2252 if (flip > 0.0f || brush.plane_inversion_mode == BRUSH_PLANE_SWAP_HEIGHT_AND_DEPTH) {
2253 overlap = (1.0f + overlap) / 2.0f;
2254 return alpha * pressure * overlap * feather;
2255 }
2256 /* When the brush is inverted with the Invert Displacement mode (i.e. when the brush adds
2257 * contrast), use a different formula that results in a lower strength. This is done because,
2258 * from an artistic point of view, the contrast would otherwise generally be too strong. Note
2259 * that this behavior is coherent with the way Fill, Scrape and Flatten work. See #136211. */
2260 else {
2261 return 0.5f * alpha * pressure * overlap * feather;
2262 }
2264 return flip * alpha * pressure * feather;
2265
2267 if (flip > 0.0f) {
2268 return alpha * flip * pressure * overlap * feather;
2269 }
2270 else {
2271 return 0.25f * alpha * flip * pressure * overlap * feather;
2272 }
2273
2275 overlap = (1.0f + overlap) / 2.0f;
2276 return alpha * pressure * overlap * feather;
2277
2279 return alpha * pressure * feather;
2280
2282 return root_alpha * feather;
2283
2285 return root_alpha * feather;
2286
2288 return alpha * pressure * feather;
2289
2293 return root_alpha * feather;
2295 /* The Dyntopo Density brush does not use a normal brush workflow to calculate the effect,
2296 * and this strength value is unused. */
2297 return 0.0f;
2298 }
2300 return 0.0f;
2301}
2302
2304 const Brush &brush,
2305 const float brush_point[3],
2306 const int thread_id,
2307 float *r_value,
2308 float r_rgba[4])
2309{
2311 const Scene *scene = cache.vc->scene;
2312 const MTex *mtex = BKE_brush_mask_texture_get(&brush, OB_MODE_SCULPT);
2313
2314 if (!mtex->tex) {
2315 *r_value = 1.0f;
2316 copy_v4_fl(r_rgba, 1.0f);
2317 return;
2318 }
2319
2320 float point[3];
2321 sub_v3_v3v3(point, brush_point, cache.plane_offset);
2322
2323 if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
2324 /* Get strength by feeding the vertex location directly into a texture. */
2325 *r_value = BKE_brush_sample_tex_3d(scene, &brush, mtex, point, r_rgba, 0, ss.tex_pool);
2326 }
2327 else {
2328 /* If the active area is being applied for symmetry, flip it
2329 * across the symmetry axis and rotate it back to the original
2330 * position in order to project it. This insures that the
2331 * brush texture will be oriented correctly. */
2332 if (cache.radial_symmetry_pass) {
2333 mul_m4_v3(cache.symm_rot_mat_inv.ptr(), point);
2334 }
2336 cache.mirror_symmetry_pass);
2337
2338 /* Still no symmetry supported for other paint modes.
2339 * Sculpt does it DIY. */
2340 if (mtex->brush_map_mode == MTEX_MAP_MODE_AREA) {
2341 /* Similar to fixed mode, but projects from brush angle
2342 * rather than view direction. */
2343
2344 mul_m4_v3(cache.brush_local_mat.ptr(), symm_point);
2345
2346 float x = symm_point[0];
2347 float y = symm_point[1];
2348
2349 x *= mtex->size[0];
2350 y *= mtex->size[1];
2351
2352 x += mtex->ofs[0];
2353 y += mtex->ofs[1];
2354
2355 paint_get_tex_pixel(mtex, x, y, ss.tex_pool, thread_id, r_value, r_rgba);
2356
2357 add_v3_fl(r_rgba, brush.texture_sample_bias); // v3 -> Ignore alpha
2358 *r_value -= brush.texture_sample_bias;
2359 }
2360 else {
2362 cache.vc->region, symm_point, cache.projection_mat);
2363 const float point_3d[3] = {point_2d[0], point_2d[1], 0.0f};
2364 *r_value = BKE_brush_sample_tex_3d(scene, &brush, mtex, point_3d, r_rgba, 0, ss.tex_pool);
2365 }
2366 }
2367}
2368
2370 const Brush &brush,
2371 float translation[3])
2372{
2373 mul_v3_fl(translation, ss.cache->bstrength);
2374 /* Handle brush inversion */
2375 if (ss.cache->bstrength < 0) {
2376 translation[0] *= -1;
2377 translation[1] *= -1;
2378 }
2379
2380 /* Apply texture size */
2381 for (int i = 0; i < 3; ++i) {
2382 translation[i] *= blender::math::safe_divide(1.0f, pow2f(brush.mtex.size[i]));
2383 }
2384
2385 /* Transform vector to object space */
2386 mul_mat3_m4_v3(ss.cache->brush_local_mat_inv.ptr(), translation);
2387
2388 /* Handle symmetry */
2389 if (ss.cache->radial_symmetry_pass) {
2390 mul_m4_v3(ss.cache->symm_rot_mat.ptr(), translation);
2391 }
2392 copy_v3_v3(
2393 translation,
2395}
2396
2397namespace blender::ed::sculpt_paint {
2398
2400{
2402 return true;
2403 }
2405 return true;
2406 }
2407 return false;
2408}
2409
2411 const float3 &location,
2412 const float radius_sq,
2413 const bool original)
2414{
2415 const Bounds<float3> &bounds = original ? node.bounds_orig() : node.bounds();
2416 const float3 nearest = math::clamp(location, bounds.min, bounds.max);
2417 return math::distance_squared(location, nearest) < radius_sq;
2418}
2419
2420bool node_in_cylinder(const DistRayAABB_Precalc &ray_dist_precalc,
2421 const bke::pbvh::Node &node,
2422 const float radius_sq,
2423 const bool original)
2424{
2425 const Bounds<float3> &bounds = original ? node.bounds_orig() : node.bounds();
2426
2427 float dummy_co[3], dummy_depth;
2428 const float dist_sq = dist_squared_ray_to_aabb_v3(
2429 &ray_dist_precalc, bounds.min, bounds.max, dummy_co, &dummy_depth);
2430
2431 /* TODO: Solve issues and enable distance check. */
2432 return dist_sq < radius_sq || true;
2433}
2434
2435static IndexMask pbvh_gather_cursor_update(Object &ob, bool use_original, IndexMaskMemory &memory)
2436{
2437 SculptSession &ss = *ob.sculpt;
2438 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
2439 const float3 center = ss.cache ? ss.cache->location_symm : ss.cursor_location;
2440 return bke::pbvh::search_nodes(pbvh, memory, [&](const bke::pbvh::Node &node) {
2441 return node_in_sphere(node, center, ss.cursor_radius, use_original);
2442 });
2443}
2444
2447 const Brush &brush,
2448 const bool use_original,
2449 const float radius_scale,
2450 IndexMaskMemory &memory)
2451{
2452 SculptSession &ss = *ob.sculpt;
2453 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
2454
2455 const float3 center = ss.cache->location_symm;
2456 const float radius_sq = math::square(ss.cache->radius * radius_scale);
2457 const bool ignore_ineffective = brush.sculpt_brush_type != SCULPT_BRUSH_TYPE_MASK;
2458 switch (brush.falloff_shape) {
2460 return bke::pbvh::search_nodes(pbvh, memory, [&](const bke::pbvh::Node &node) {
2461 if (ignore_ineffective && node_fully_masked_or_hidden(node)) {
2462 return false;
2463 }
2464 return node_in_sphere(node, center, radius_sq, use_original);
2465 });
2466 }
2467
2470 center, ss.cache->view_normal_symm);
2471 return bke::pbvh::search_nodes(pbvh, memory, [&](const bke::pbvh::Node &node) {
2472 if (ignore_ineffective && node_fully_masked_or_hidden(node)) {
2473 return false;
2474 }
2475 return node_in_cylinder(ray_dist_precalc, node, radius_sq, use_original);
2476 });
2477 }
2478 }
2479
2480 return {};
2481}
2482
2484 const eBrushFalloffShape falloff_shape,
2485 const bool use_original,
2486 const float3 &location,
2487 const float radius_sq,
2488 const std::optional<float3> &ray_direction,
2489 IndexMaskMemory &memory)
2490{
2491 switch (falloff_shape) {
2493 return bke::pbvh::search_nodes(pbvh, memory, [&](const bke::pbvh::Node &node) {
2494 if (node_fully_masked_or_hidden(node)) {
2495 return false;
2496 }
2497 return node_in_sphere(node, location, radius_sq, use_original);
2498 });
2499 }
2500
2502 BLI_assert(ray_direction);
2504 location, ray_direction.value_or(float3(0.0f)));
2505 return bke::pbvh::search_nodes(pbvh, memory, [&](const bke::pbvh::Node &node) {
2506 if (node_fully_masked_or_hidden(node)) {
2507 return false;
2508 }
2509 return node_in_cylinder(ray_dist_precalc, node, radius_sq, use_original);
2510 });
2511 }
2512 }
2514 return {};
2515}
2516
2518 const Brush &brush,
2519 const bool use_original,
2520 const float radius_scale,
2521 IndexMaskMemory &memory)
2522{
2523 return pbvh_gather_generic(ob, brush, use_original, radius_scale, memory);
2524}
2525
2526/* Calculate primary direction of movement for many brushes. */
2527static float3 calc_sculpt_normal(const Depsgraph &depsgraph,
2528 const Sculpt &sd,
2529 Object &ob,
2530 const IndexMask &node_mask)
2531{
2532 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
2533 const SculptSession &ss = *ob.sculpt;
2534 switch (brush.sculpt_plane) {
2536 return calc_area_normal(depsgraph, brush, ob, node_mask).value_or(float3(0));
2538 return ss.cache->view_normal;
2539 case SCULPT_DISP_DIR_X:
2540 return float3(1, 0, 0);
2541 case SCULPT_DISP_DIR_Y:
2542 return float3(0, 1, 0);
2543 case SCULPT_DISP_DIR_Z:
2544 return float3(0, 0, 1);
2545 }
2547 return {};
2548}
2549
2550static void update_sculpt_normal(const Depsgraph &depsgraph,
2551 const Sculpt &sd,
2552 Object &ob,
2553 const brushes::CursorSampleResult &cursor_sample_result)
2554{
2555 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
2556 StrokeCache &cache = *ob.sculpt->cache;
2557 /* Grab brush does not update the sculpt normal during a stroke. */
2558 const bool update_normal = !(brush.flag & BRUSH_ORIGINAL_NORMAL) &&
2561 !(brush.flag & BRUSH_ANCHORED)) &&
2564 cache.normal_weight > 0.0f);
2565
2566 if (cache.mirror_symmetry_pass == 0 && cache.radial_symmetry_pass == 0 &&
2568 {
2569 if (cursor_sample_result.plane_normal) {
2570 cache.sculpt_normal = *cursor_sample_result.plane_normal;
2571 }
2572 else {
2573 cache.sculpt_normal = calc_sculpt_normal(depsgraph, sd, ob, cursor_sample_result.node_mask);
2577 }
2578 }
2580 }
2581 else {
2584 }
2585}
2586
2588 const float center[3],
2589 const float screen_dir[2],
2590 float r_local_dir[3])
2591{
2592 Object &ob = *vc.obact;
2593 float loc[3];
2594
2595 mul_v3_m4v3(loc, ob.object_to_world().ptr(), center);
2596 const float zfac = ED_view3d_calc_zfac(vc.rv3d, loc);
2597
2598 ED_view3d_win_to_delta(vc.region, screen_dir, zfac, r_local_dir);
2599 normalize_v3(r_local_dir);
2600
2601 add_v3_v3(r_local_dir, ob.loc);
2602 mul_m4_v3(ob.world_to_object().ptr(), r_local_dir);
2603}
2604
2605static void calc_brush_local_mat(const float rotation,
2606 const Object &ob,
2607 float local_mat[4][4],
2608 float local_mat_inv[4][4])
2609{
2610 const StrokeCache *cache = ob.sculpt->cache;
2611 float tmat[4][4];
2612 float mat[4][4];
2613 float scale[4][4];
2614 float angle, v[3];
2615
2616 /* Ensure `ob.world_to_object` is up to date. */
2617 invert_m4_m4(ob.runtime->world_to_object.ptr(), ob.object_to_world().ptr());
2618
2619 /* Initialize last column of matrix. */
2620 mat[0][3] = 0.0f;
2621 mat[1][3] = 0.0f;
2622 mat[2][3] = 0.0f;
2623 mat[3][3] = 1.0f;
2624
2625 /* Read rotation (user angle, rake, etc.) to find the view's movement direction (negative X of
2626 * the brush). */
2627 angle = rotation + cache->special_rotation;
2628 /* By convention, motion direction points down the brush's Y axis, the angle represents the X
2629 * axis, normal is a 90 deg CCW rotation of the motion direction. */
2630 float motion_normal_screen[2];
2631 motion_normal_screen[0] = cosf(angle);
2632 motion_normal_screen[1] = sinf(angle);
2633 /* Convert view's brush transverse direction to object-space,
2634 * i.e. the normal of the plane described by the motion */
2635 float motion_normal_local[3];
2637 *cache->vc, cache->location_symm, motion_normal_screen, motion_normal_local);
2638
2639 /* Calculate the movement direction for the local matrix.
2640 * Note that there is a deliberate prioritization here: Our calculations are
2641 * designed such that the _motion vector_ gets projected into the tangent space;
2642 * in most cases this will be more intuitive than projecting the transverse
2643 * direction (which is orthogonal to the motion direction and therefore less
2644 * apparent to the user).
2645 * The Y-axis of the brush-local frame has to lie in the intersection of the tangent plane
2646 * and the motion plane. */
2647
2648 cross_v3_v3v3(v, cache->sculpt_normal, motion_normal_local);
2649 normalize_v3_v3(mat[1], v);
2650
2651 /* Get other axes. */
2652 cross_v3_v3v3(mat[0], mat[1], cache->sculpt_normal);
2653 copy_v3_v3(mat[2], cache->sculpt_normal);
2654
2655 /* Set location. */
2656 copy_v3_v3(mat[3], cache->location_symm);
2657
2658 /* Scale by brush radius. */
2659 float radius = cache->radius;
2660
2661 normalize_m4(mat);
2662 scale_m4_fl(scale, radius);
2663 mul_m4_m4m4(tmat, mat, scale);
2664
2665 /* Return tmat as is (for converting from local area coords to model-space coords). */
2666 copy_m4_m4(local_mat_inv, tmat);
2667 /* Return inverse (for converting from model-space coords to local area coords). */
2668 invert_m4_m4(local_mat, tmat);
2669}
2670
2672 const float4x4 &view_inverse,
2673 const float3 &normal,
2674 const float2 &tilt,
2675 const float tilt_strength)
2676{
2677 const float3 world_space = math::transform_direction(object.object_to_world(), normal);
2678
2679 /* Tweaked based on initial user feedback, with a value of 1.0, higher brush tilt strength
2680 * lead to the stroke surface direction becoming inverted due to extreme rotations. */
2681 constexpr float tilt_sensitivity = 0.7f;
2682 const float rot_max = M_PI_2 * tilt_strength * tilt_sensitivity;
2683 const float3 normal_tilt_y = math::rotate_direction_around_axis(
2684 world_space, view_inverse.x_axis(), tilt.y * rot_max);
2685 const float3 normal_tilt_xy = math::rotate_direction_around_axis(
2686 normal_tilt_y, view_inverse.y_axis(), tilt.x * rot_max);
2687
2688 return math::normalize(math::transform_direction(object.world_to_object(), normal_tilt_xy));
2689}
2690
2692 const StrokeCache &cache,
2693 const float tilt_strength)
2694{
2695 return tilt_apply_to_normal(
2696 *cache.vc->obact, float4x4(cache.vc->rv3d->viewinv), normal, cache.tilt, tilt_strength);
2697}
2698
2703
2704} // namespace blender::ed::sculpt_paint
2705
2706static void update_brush_local_mat(const Sculpt &sd, Object &ob)
2707{
2708 using namespace blender::ed::sculpt_paint;
2709 StrokeCache *cache = ob.sculpt->cache;
2710
2711 if (cache->mirror_symmetry_pass == 0 && cache->radial_symmetry_pass == 0) {
2712 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
2713 const MTex *mask_tex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT);
2715 mask_tex->rot, ob, cache->brush_local_mat.ptr(), cache->brush_local_mat_inv.ptr());
2716 }
2717}
2718
2720
2721/* -------------------------------------------------------------------- */
2724
2725static bool sculpt_needs_pbvh_pixels(PaintModeSettings &paint_mode_settings,
2726 const Brush &brush,
2727 Object &ob)
2728{
2730 USER_EXPERIMENTAL_TEST(&U, use_sculpt_texture_paint))
2731 {
2732 Image *image;
2733 ImageUser *image_user;
2734 return SCULPT_paint_image_canvas_get(paint_mode_settings, ob, &image, &image_user);
2735 }
2736
2737 return false;
2738}
2739
2740static void sculpt_pbvh_update_pixels(const Depsgraph &depsgraph,
2741 PaintModeSettings &paint_mode_settings,
2742 Object &ob)
2743{
2744 using namespace blender;
2745 BLI_assert(ob.type == OB_MESH);
2746
2747 Image *image;
2748 ImageUser *image_user;
2749 if (!SCULPT_paint_image_canvas_get(paint_mode_settings, ob, &image, &image_user)) {
2750 return;
2751 }
2752
2753 bke::pbvh::build_pixels(depsgraph, ob, *image, *image_user);
2754}
2755
2757
2758/* -------------------------------------------------------------------- */
2761namespace blender::ed::sculpt_paint {
2762
2786
2804} // namespace blender::ed::sculpt_paint
2805
2807{
2809 if (co[0] < 0.0f) {
2810 symm_area |= PAINT_SYMM_AREA_X;
2811 }
2812 if (co[1] < 0.0f) {
2813 symm_area |= PAINT_SYMM_AREA_Y;
2814 }
2815 if (co[2] < 0.0f) {
2816 symm_area |= PAINT_SYMM_AREA_Z;
2817 }
2818 return symm_area;
2819}
2820
2821static void flip_qt_qt(float out[4], const float in[4], const ePaintSymmetryFlags symm)
2822{
2823 float axis[3], angle;
2824
2825 quat_to_axis_angle(axis, &angle, in);
2826 normalize_v3(axis);
2827
2828 if (symm & PAINT_SYMM_X) {
2829 axis[0] *= -1.0f;
2830 angle *= -1.0f;
2831 }
2832 if (symm & PAINT_SYMM_Y) {
2833 axis[1] *= -1.0f;
2834 angle *= -1.0f;
2835 }
2836 if (symm & PAINT_SYMM_Z) {
2837 axis[2] *= -1.0f;
2838 angle *= -1.0f;
2839 }
2840
2842}
2843
2844static void flip_qt(float quat[4], const ePaintSymmetryFlags symm)
2845{
2846 flip_qt_qt(quat, quat, symm);
2847}
2848
2850 const ePaintSymmetryFlags symm,
2851 const ePaintSymmetryAreas symmarea,
2852 const float3 &pivot)
2853{
2855 for (int i = 0; i < 3; i++) {
2857 if (!(symm & symm_it)) {
2858 continue;
2859 }
2860 if (symmarea & symm_it) {
2862 }
2863 if (pivot[i] < 0.0f) {
2865 }
2866 }
2867 return result;
2868}
2869
2871 const ePaintSymmetryFlags symm,
2872 const ePaintSymmetryAreas symmarea,
2873 const float pivot[3])
2874{
2875 for (int i = 0; i < 3; i++) {
2877 if (!(symm & symm_it)) {
2878 continue;
2879 }
2880 if (symmarea & symm_it) {
2881 flip_qt(quat, symm_it);
2882 }
2883 if (pivot[i] < 0.0f) {
2884 flip_qt(quat, symm_it);
2885 }
2886 }
2887}
2888
2889namespace blender::ed::sculpt_paint {
2890
2891void calc_brush_plane(const Depsgraph &depsgraph,
2892 const Brush &brush,
2893 Object &ob,
2894 const IndexMask &node_mask,
2895 float3 &r_area_no,
2896 float3 &r_area_co)
2897{
2898 const SculptSession &ss = *ob.sculpt;
2899
2900 r_area_no = float3(0.0f);
2901 r_area_co = float3(0.0f);
2902
2903 const bool use_original_plane = (brush.flag & BRUSH_ORIGINAL_PLANE) &&
2905 const bool use_original_normal = (brush.flag & BRUSH_ORIGINAL_NORMAL) &&
2907
2908 const bool needs_recalculation = SCULPT_stroke_is_first_brush_step_of_symmetry_pass(*ss.cache) ||
2909 !use_original_plane || !use_original_normal;
2910
2911 if (SCULPT_stroke_is_main_symmetry_pass(*ss.cache) && needs_recalculation) {
2912 switch (brush.sculpt_plane) {
2914 r_area_no = ss.cache->view_normal;
2915 break;
2916
2917 case SCULPT_DISP_DIR_X:
2918 r_area_no = float3(1.0f, 0.0f, 0.0f);
2919 break;
2920
2921 case SCULPT_DISP_DIR_Y:
2922 r_area_no = float3(0.0f, 1.0f, 0.0f);
2923 break;
2924
2925 case SCULPT_DISP_DIR_Z:
2926 r_area_no = float3(0.0f, 0.0f, 1.0f);
2927 break;
2928
2930 calc_area_normal_and_center(depsgraph, brush, ob, node_mask, r_area_no, r_area_co);
2932 project_plane_v3_v3v3(r_area_no, r_area_no, ss.cache->view_normal_symm);
2933 r_area_no = math::normalize(r_area_no);
2934 }
2935 break;
2936 }
2937
2938 /* Flatten center has not been calculated yet if we are not using the area normal. */
2939 if (brush.sculpt_plane != SCULPT_DISP_DIR_AREA) {
2940 BLI_assert(math::is_zero(r_area_co));
2941 calc_area_center(depsgraph, brush, ob, node_mask, r_area_co);
2942 }
2943
2944 if (!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(*ss.cache) && use_original_normal) {
2945 r_area_no = ss.cache->sculpt_normal;
2946 }
2947 else {
2948 ss.cache->sculpt_normal = r_area_no;
2949 }
2950
2951 if (!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(*ss.cache) && use_original_plane) {
2952 r_area_co = ss.cache->last_center;
2953 }
2954 else {
2955 ss.cache->last_center = r_area_co;
2956 }
2957 }
2958 else {
2960
2961 r_area_no = ss.cache->sculpt_normal;
2962 r_area_no = symmetry_flip(r_area_no, ss.cache->mirror_symmetry_pass);
2963 r_area_no = math::transform_direction(ss.cache->symm_rot_mat, r_area_no);
2964
2965 r_area_co = ss.cache->last_center;
2966 r_area_co = symmetry_flip(r_area_co, ss.cache->mirror_symmetry_pass);
2967 r_area_co = math::transform_point(ss.cache->symm_rot_mat, r_area_co);
2968
2969 /* Shift the plane for the current tile. */
2970 r_area_co += ss.cache->plane_offset;
2971 }
2972}
2973
2974float brush_plane_offset_get(const Brush &brush, const SculptSession &ss)
2975{
2976 return brush.flag & BRUSH_OFFSET_PRESSURE ? brush.plane_offset * ss.cache->pressure :
2977 brush.plane_offset;
2978}
2979
2980} // namespace blender::ed::sculpt_paint
2981
2983
2984/* -------------------------------------------------------------------- */
2987
2988namespace blender::ed::sculpt_paint {
2989
2990static void dynamic_topology_update(const Depsgraph &depsgraph,
2991 const Scene & /*scene*/,
2992 const Sculpt &sd,
2993 Object &ob,
2994 const Brush &brush,
2995 UnifiedPaintSettings & /*ups*/,
2996 PaintModeSettings & /*paint_mode_settings*/)
2997{
2998 SculptSession &ss = *ob.sculpt;
3000
3001 /* Build a list of all nodes that are potentially within the brush's area of influence. */
3002 const bool use_original = brush_type_needs_original(brush.sculpt_brush_type) ? true :
3003 !ss.cache->accum;
3004 constexpr float radius_scale = 1.25f;
3005
3006 IndexMaskMemory memory;
3007 const IndexMask node_mask = pbvh_gather_generic(ob, brush, use_original, radius_scale, memory);
3008 if (node_mask.is_empty()) {
3009 return;
3010 }
3011
3013
3014 /* Free index based vertex info as it will become invalid after modifying the topology during the
3015 * stroke. */
3017
3019
3020 if (!(sd.flags & SCULPT_DYNTOPO_DETAIL_MANUAL)) {
3022 mode |= PBVH_Subdivide;
3023 }
3024
3025 if ((sd.flags & SCULPT_DYNTOPO_COLLAPSE) ||
3027 {
3028 mode |= PBVH_Collapse;
3029 }
3030 }
3031
3034 }
3035 else {
3037 }
3038 pbvh.tag_positions_changed(node_mask);
3039 pbvh.tag_topology_changed(node_mask);
3040 node_mask.foreach_index([&](const int i) { BKE_pbvh_node_mark_topology_update(nodes[i]); });
3041 node_mask.foreach_index(GrainSize(1), [&](const int i) {
3042 BKE_pbvh_bmesh_node_save_orig(ss.bm, ss.bm_log, &nodes[i], false);
3043 });
3044
3045 float max_edge_len;
3048 }
3049 else if (sd.flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
3051 }
3052 else {
3054 sd.detail_size, ss.cache->radius, ss.cache->dyntopo_pixel_radius, U.pixelsize);
3055 }
3056 const float min_edge_len = max_edge_len * dyntopo::detail_size::EDGE_LENGTH_MIN_FACTOR;
3057
3059 pbvh,
3060 *ss.bm_log,
3061 mode,
3062 min_edge_len,
3063 max_edge_len,
3064 ss.cache->location_symm,
3066 ss.cache->radius,
3067 (brush.flag & BRUSH_FRONTFACE) != 0,
3069}
3070
3072{
3074 /* Elastic deformations in any brush need all nodes to avoid artifacts as the effect
3075 * of the Kelvinlet is not constrained by the radius. */
3076 return true;
3077 }
3078
3080 /* Pose needs all nodes because it applies all symmetry iterations at the same time
3081 * and the IK chain can grow to any area of the model. */
3082 /* TODO: This can be optimized by filtering the nodes after calculating the chain. */
3083 return true;
3084 }
3085
3087 /* Boundary needs all nodes because it is not possible to know where the boundary
3088 * deformation is going to be propagated before calculating it. */
3089 /* TODO: after calculating the boundary info in the first iteration, it should be
3090 * possible to get the nodes that have vertices included in any boundary deformation
3091 * and cache them. */
3092 return true;
3093 }
3094
3097 {
3098 /* Snake hook in elastic deform type has same requirements as the elastic deform brush. */
3099 return true;
3100 }
3101 return false;
3102}
3103
3106 Object &ob,
3107 const Brush &brush,
3108 IndexMaskMemory &memory)
3109{
3110 const SculptSession &ss = *ob.sculpt;
3111 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
3112
3113 const bool use_original = brush_type_needs_original(brush.sculpt_brush_type) ? true :
3114 !ss.cache->accum;
3115 /* Build a list of all nodes that are potentially within the brush's area of influence */
3116
3118 /* These brushes need to update all nodes as they are not constrained by the brush radius */
3119 return {all_leaf_nodes(pbvh, memory), std::nullopt, std::nullopt};
3120 }
3122 return brushes::plane::calc_node_mask(depsgraph, ob, brush, memory);
3123 }
3125 return brushes::clay_strips::calc_node_mask(depsgraph, ob, brush, memory);
3126 }
3128 return {cloth::brush_affected_nodes_gather(ob, brush, memory), std::nullopt, std::nullopt};
3129 }
3130
3131 float radius_scale = 1.0f;
3132 /* Corners of square brushes can go outside the brush radius. */
3134 radius_scale = M_SQRT2;
3135 }
3136
3137 /* With these options enabled not all required nodes are inside the original brush radius, so
3138 * the brush can produce artifacts in some situations. */
3140 radius_scale = 2.0f;
3141 }
3142 return {pbvh_gather_generic(ob, brush, use_original, radius_scale, memory),
3143 std::nullopt,
3144 std::nullopt};
3145}
3146
3147static void push_undo_nodes(const Depsgraph &depsgraph,
3148 Object &ob,
3149 const Brush &brush,
3150 const IndexMask &node_mask)
3151{
3152 SculptSession &ss = *ob.sculpt;
3153 bool need_coords = ss.cache->supports_gravity;
3154
3156 /* Draw face sets in smooth mode moves the vertices. */
3157 if (ss.cache->alt_smooth) {
3158 need_coords = true;
3159 }
3160 else {
3162 }
3163 }
3164 else if (brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_MASK) {
3166 }
3167 else if (brush_type_is_paint(brush.sculpt_brush_type)) {
3169 }
3170 else {
3171 need_coords = true;
3172 }
3173
3174 if (need_coords) {
3176 }
3177}
3178
3179static void do_brush_action(const Depsgraph &depsgraph,
3180 const Scene &scene,
3181 const Sculpt &sd,
3182 Object &ob,
3183 const Brush &brush,
3185 PaintModeSettings &paint_mode_settings)
3186{
3187 SculptSession &ss = *ob.sculpt;
3188 IndexMaskMemory memory;
3189 IndexMask texnode_mask;
3190
3191 const bool use_original = brush_type_needs_original(brush.sculpt_brush_type) ? true :
3192 !ss.cache->accum;
3193 const bool use_pixels = sculpt_needs_pbvh_pixels(paint_mode_settings, brush, ob);
3194
3195 if (sculpt_needs_pbvh_pixels(paint_mode_settings, brush, ob)) {
3196 sculpt_pbvh_update_pixels(depsgraph, paint_mode_settings, ob);
3197
3198 texnode_mask = pbvh_gather_texpaint(ob, brush, use_original, 1.0f, memory);
3199
3200 if (texnode_mask.is_empty()) {
3201 return;
3202 }
3203 }
3204
3205 const brushes::CursorSampleResult cursor_sample_result = calc_brush_node_mask(
3206 depsgraph, ob, brush, memory);
3207 const IndexMask node_mask = cursor_sample_result.node_mask;
3208
3209 /* Only act if some verts are inside the brush area. */
3210 if (node_mask.is_empty()) {
3211 return;
3212 }
3213
3214 if (auto_mask::is_enabled(sd, ob, &brush)) {
3217 cache.calc_cavity_factor(depsgraph, ob, node_mask);
3218 }
3219 }
3220
3221 if (!use_pixels) {
3222 push_undo_nodes(depsgraph, ob, brush, node_mask);
3223 }
3224
3225 /* There are issues with the underlying normals cache / mesh data that can cause the data to
3226 * become out of date.
3227 *
3228 * For EEVEE and Workbench, this is partially mitigated by the fact that the Paint BVH is used
3229 * to signal this update when drawing.
3230 *
3231 * TODO: See #141417
3232 */
3233 const bool external_engine = ss.rv3d && ss.rv3d->view_render != nullptr;
3234 if (external_engine) {
3237 }
3238 if (sculpt_brush_needs_normal(ss, brush)) {
3239 update_sculpt_normal(depsgraph, sd, ob, cursor_sample_result);
3240 }
3241
3242 update_brush_local_mat(sd, ob);
3243
3245 if (!ss.cache->cloth_sim) {
3247 depsgraph, ob, 1.0f, 0.0f, 0.0f, false, true);
3248 }
3251 ob,
3252 node_mask,
3253 *ss.cache->cloth_sim,
3254 ss.cache->location_symm,
3255 std::numeric_limits<float>::max());
3256 }
3257
3258 bool invert = ss.cache->pen_flip || ss.cache->invert;
3259 if (brush.flag & BRUSH_DIR_IN) {
3260 invert = !invert;
3261 }
3262
3263 /* Apply one type of brush action. */
3264 switch (brush.sculpt_brush_type) {
3266 if (brush_uses_vector_displacement(brush)) {
3268 }
3269 else {
3270 brushes::do_draw_brush(depsgraph, sd, ob, node_mask);
3271 }
3272 break;
3273 }
3276 /* NOTE: The enhance brush needs to initialize its state on the first brush step. The
3277 * stroke strength can become 0 during the stroke, but it can not change sign (the sign is
3278 * determined in the beginning of the stroke. So here it is important to not switch to
3279 * enhance brush in the middle of the stroke. */
3281 /* Invert mode, intensify details. */
3282 brushes::do_enhance_details_brush(depsgraph, sd, ob, node_mask);
3283 }
3284 else {
3286 depsgraph, sd, ob, node_mask, std::clamp(ss.cache->bstrength, 0.0f, 1.0f));
3287 }
3288 }
3290 brushes::do_surface_smooth_brush(depsgraph, sd, ob, node_mask);
3291 }
3292 break;
3294 brushes::do_crease_brush(depsgraph, scene, sd, ob, node_mask);
3295 break;
3297 brushes::do_blob_brush(depsgraph, scene, sd, ob, node_mask);
3298 break;
3300 brushes::do_pinch_brush(depsgraph, sd, ob, node_mask);
3301 break;
3303 brushes::do_inflate_brush(depsgraph, sd, ob, node_mask);
3304 break;
3306 brushes::do_grab_brush(depsgraph, sd, ob, node_mask);
3307 break;
3309 brushes::do_rotate_brush(depsgraph, sd, ob, node_mask);
3310 break;
3312 brushes::do_snake_hook_brush(depsgraph, sd, ob, node_mask);
3313 break;
3315 brushes::do_nudge_brush(depsgraph, sd, ob, node_mask);
3316 break;
3318 brushes::do_thumb_brush(depsgraph, sd, ob, node_mask);
3319 break;
3321 brushes::do_layer_brush(depsgraph, sd, ob, node_mask);
3322 break;
3324 brushes::do_clay_brush(depsgraph, sd, ob, node_mask);
3325 break;
3327 BLI_assert(cursor_sample_result.plane_normal && cursor_sample_result.plane_center);
3329 sd,
3330 ob,
3331 node_mask,
3332 *cursor_sample_result.plane_normal,
3333 *cursor_sample_result.plane_center);
3334 break;
3337 break;
3339 brushes::do_clay_thumb_brush(depsgraph, sd, ob, node_mask);
3340 break;
3342 switch ((BrushMaskTool)brush.mask_tool) {
3343 case BRUSH_MASK_DRAW:
3344 brushes::do_mask_brush(depsgraph, sd, ob, node_mask);
3345 break;
3346 case BRUSH_MASK_SMOOTH:
3347 brushes::do_smooth_mask_brush(depsgraph, sd, ob, node_mask, ss.cache->bstrength);
3348 break;
3349 }
3350 break;
3352 pose::do_pose_brush(depsgraph, sd, ob, node_mask);
3353 break;
3355 brushes::do_draw_sharp_brush(depsgraph, sd, ob, node_mask);
3356 break;
3358 brushes::do_elastic_deform_brush(depsgraph, sd, ob, node_mask);
3359 break;
3361 if (ss.cache->alt_smooth) {
3362 brushes::do_topology_relax_brush(depsgraph, sd, ob, node_mask);
3363 }
3364 else {
3365 brushes::do_topology_slide_brush(depsgraph, sd, ob, node_mask);
3366 }
3367 break;
3369 boundary::do_boundary_brush(depsgraph, sd, ob, node_mask);
3370 break;
3372 cloth::do_cloth_brush(depsgraph, sd, ob, node_mask);
3373 break;
3375 if (!ss.cache->alt_smooth) {
3376 brushes::do_draw_face_sets_brush(depsgraph, sd, ob, node_mask);
3377 }
3378 else {
3379 brushes::do_relax_face_sets_brush(depsgraph, sd, ob, node_mask);
3380 }
3381 break;
3384 break;
3387 break;
3390 scene, depsgraph, paint_mode_settings, sd, ob, node_mask, texnode_mask);
3391 break;
3393 color::do_smear_brush(depsgraph, sd, ob, node_mask);
3394 break;
3396 BLI_assert(cursor_sample_result.plane_normal && cursor_sample_result.plane_center);
3398 sd,
3399 ob,
3400 node_mask,
3401 *cursor_sample_result.plane_normal,
3402 *cursor_sample_result.plane_center);
3403 break;
3404 }
3405
3407 brush.autosmooth_factor > 0)
3408 {
3409 if (brush.flag & BRUSH_INVERSE_SMOOTH_PRESSURE) {
3411 depsgraph, sd, ob, node_mask, brush.autosmooth_factor * (1.0f - ss.cache->pressure));
3412 }
3413 else {
3414 brushes::do_smooth_brush(depsgraph, sd, ob, node_mask, brush.autosmooth_factor);
3415 }
3416 }
3417
3418 if (brush_uses_topology_rake(ss, brush)) {
3420 depsgraph, sd, ob, node_mask, brush.topology_rake_factor);
3421 }
3422
3423 /* The cloth brush adds the gravity as a regular force and it is processed in the solver. */
3425 brushes::do_gravity_brush(depsgraph, sd, ob, node_mask);
3426 }
3427
3430 cloth::sim_activate_nodes(ob, *ss.cache->cloth_sim, node_mask);
3431 cloth::do_simulation_step(depsgraph, sd, ob, *ss.cache->cloth_sim, node_mask);
3432 }
3433 }
3434
3435 /* Update average stroke position. */
3436 const float3 world_location = math::project_point(ob.object_to_world(), ss.cache->location);
3437
3438 add_v3_v3(ups.average_stroke_accum, world_location);
3440 /* Update last stroke position. */
3441 ups.last_stroke_valid = true;
3442}
3443
3444} // namespace blender::ed::sculpt_paint
3445
3447 const ePaintSymmetryFlags symm,
3448 const char axis,
3449 const float angle)
3450{
3451 using namespace blender;
3456
3459
3460 /* XXX This reduces the length of the grab delta if it approaches the line of symmetry
3461 * XXX However, a different approach appears to be needed. */
3462#if 0
3463 if (sd->paint.symmetry_flags & PAINT_SYMMETRY_FEATHER) {
3464 float frac = 1.0f / max_overlap_count(sd);
3465 float reduce = (feather - frac) / (1.0f - frac);
3466
3467 printf("feather: %f frac: %f reduce: %f\n", feather, frac, reduce);
3468
3469 if (frac < 1.0f) {
3470 mul_v3_fl(cache.grab_delta_symmetry, reduce);
3471 }
3472 }
3473#endif
3474
3477 zero_v3(cache.plane_offset);
3478
3479 /* Expects XYZ. */
3480 if (axis) {
3481 rotate_m4(cache.symm_rot_mat.ptr(), axis, angle);
3482 rotate_m4(cache.symm_rot_mat_inv.ptr(), axis, -angle);
3483 }
3484
3485 mul_m4_v3(cache.symm_rot_mat.ptr(), cache.location_symm);
3486 mul_m4_v3(cache.symm_rot_mat.ptr(), cache.grab_delta_symm);
3487
3488 if (cache.supports_gravity) {
3491 }
3492
3493 if (cache.rake_rotation) {
3494 float4 new_quat;
3495 float4 existing(cache.rake_rotation->w,
3496 cache.rake_rotation->x,
3497 cache.rake_rotation->y,
3498 cache.rake_rotation->z);
3499 flip_qt_qt(new_quat, existing, symm);
3500 cache.rake_rotation_symm = math::Quaternion(new_quat);
3501 }
3502}
3503
3504namespace blender::ed::sculpt_paint {
3505
3506using BrushActionFunc = void (*)(const Depsgraph &depsgraph,
3507 const Scene &scene,
3508 const Sculpt &sd,
3509 Object &ob,
3510 const Brush &brush,
3512 PaintModeSettings &paint_mode_settings);
3513
3514static void do_tiled(const Depsgraph &depsgraph,
3515 const Scene &scene,
3516 const Sculpt &sd,
3517 Object &ob,
3518 const Brush &brush,
3520 PaintModeSettings &paint_mode_settings,
3521 const BrushActionFunc action)
3522{
3523 SculptSession &ss = *ob.sculpt;
3524 StrokeCache *cache = ss.cache;
3525 const float radius = cache->radius;
3526 const Bounds<float3> bb = *BKE_object_boundbox_get(&ob);
3527 const float *bbMin = bb.min;
3528 const float *bbMax = bb.max;
3529 const float *step = sd.paint.tile_offset;
3530
3531 /* These are integer locations, for real location: multiply with step and add orgLoc.
3532 * So 0,0,0 is at orgLoc. */
3533 int start[3];
3534 int end[3];
3535 int cur[3];
3536
3537 /* Position of the "prototype" stroke for tiling. */
3538 float orgLoc[3];
3539 float original_initial_location[3];
3540 copy_v3_v3(orgLoc, cache->location_symm);
3541 copy_v3_v3(original_initial_location, cache->initial_location_symm);
3542
3543 for (int dim = 0; dim < 3; dim++) {
3544 if ((sd.paint.symmetry_flags & (PAINT_TILE_X << dim)) && step[dim] > 0) {
3545 start[dim] = (bbMin[dim] - orgLoc[dim] - radius) / step[dim];
3546 end[dim] = (bbMax[dim] - orgLoc[dim] + radius) / step[dim];
3547 }
3548 else {
3549 start[dim] = end[dim] = 0;
3550 }
3551 }
3552
3553 /* First do the "un-tiled" position to initialize the stroke for this location. */
3554 cache->tile_pass = 0;
3555 action(depsgraph, scene, sd, ob, brush, ups, paint_mode_settings);
3556
3557 /* Now do it for all the tiles. */
3558 copy_v3_v3_int(cur, start);
3559 for (cur[0] = start[0]; cur[0] <= end[0]; cur[0]++) {
3560 for (cur[1] = start[1]; cur[1] <= end[1]; cur[1]++) {
3561 for (cur[2] = start[2]; cur[2] <= end[2]; cur[2]++) {
3562 if (!cur[0] && !cur[1] && !cur[2]) {
3563 /* Skip tile at orgLoc, this was already handled before all others. */
3564 continue;
3565 }
3566
3567 ++cache->tile_pass;
3568
3569 for (int dim = 0; dim < 3; dim++) {
3570 cache->location_symm[dim] = cur[dim] * step[dim] + orgLoc[dim];
3571 cache->plane_offset[dim] = cur[dim] * step[dim];
3572 cache->initial_location_symm[dim] = cur[dim] * step[dim] +
3573 original_initial_location[dim];
3574 }
3575 action(depsgraph, scene, sd, ob, brush, ups, paint_mode_settings);
3576 }
3577 }
3578 }
3579}
3580
3581static void do_radial_symmetry(const Depsgraph &depsgraph,
3582 const Scene &scene,
3583 const Sculpt &sd,
3584 Object &ob,
3585 const Brush &brush,
3587 PaintModeSettings &paint_mode_settings,
3588 const BrushActionFunc action,
3589 const ePaintSymmetryFlags symm,
3590 const int axis,
3591 const float /*feather*/)
3592{
3593 SculptSession &ss = *ob.sculpt;
3594
3595 for (int i = 1; i < sd.radial_symm[axis - 'X']; i++) {
3596 const float angle = 2.0f * M_PI * i / sd.radial_symm[axis - 'X'];
3599 do_tiled(depsgraph, scene, sd, ob, brush, ups, paint_mode_settings, action);
3600 }
3601}
3602
3607static void sculpt_fix_noise_tear(const Sculpt &sd, Object &ob)
3608{
3609 SculptSession &ss = *ob.sculpt;
3610 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
3611 const MTex *mtex = BKE_brush_mask_texture_get(&brush, OB_MODE_SCULPT);
3612
3613 if (ss.multires.active && mtex->tex && mtex->tex->type == TEX_NOISE) {
3615 }
3616}
3617
3618static void do_symmetrical_brush_actions(const Depsgraph &depsgraph,
3619 const Scene &scene,
3620 const Sculpt &sd,
3621 Object &ob,
3622 const BrushActionFunc action,
3624 PaintModeSettings &paint_mode_settings)
3625{
3626 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
3627 SculptSession &ss = *ob.sculpt;
3628 StrokeCache &cache = *ss.cache;
3629 const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
3630
3631 float feather = calc_symmetry_feather(sd, *ss.cache);
3632
3633 cache.bstrength = brush_strength(sd, cache, feather, ups, paint_mode_settings);
3634 cache.symmetry = symm;
3635
3636 /* `symm` is a bit combination of XYZ -
3637 * 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
3638 for (int i = 0; i <= symm; i++) {
3639 if (!is_symmetry_iteration_valid(i, symm)) {
3640 continue;
3641 }
3643 cache.mirror_symmetry_pass = symm;
3644 cache.radial_symmetry_pass = 0;
3645
3646 SCULPT_cache_calc_brushdata_symm(cache, symm, 0, 0);
3647 do_tiled(depsgraph, scene, sd, ob, brush, ups, paint_mode_settings, action);
3648
3650 depsgraph, scene, sd, ob, brush, ups, paint_mode_settings, action, symm, 'X', feather);
3652 depsgraph, scene, sd, ob, brush, ups, paint_mode_settings, action, symm, 'Y', feather);
3654 depsgraph, scene, sd, ob, brush, ups, paint_mode_settings, action, symm, 'Z', feather);
3655 }
3656}
3657
3658} // namespace blender::ed::sculpt_paint
3659
3661{
3663 return ob && ob->mode & OB_MODE_SCULPT;
3664}
3665
3667{
3668 using namespace blender::ed::sculpt_paint;
3670}
3671
3677
3686{
3689 ScrArea *area = CTX_wm_area(C);
3690 ARegion *region = CTX_wm_region(C);
3691
3692 if (paint && ob && BKE_paint_brush(paint) &&
3693 (area && ELEM(area->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) &&
3694 (region && region->regiontype == RGN_TYPE_WINDOW))
3695 {
3696 bToolRef *tref = area->runtime.tool;
3697 if (tref && tref->runtime && tref->runtime->keymap[0]) {
3698 std::array<wmOperatorType *, 7> trim_operators = {
3699 WM_operatortype_find("SCULPT_OT_trim_box_gesture", false),
3700 WM_operatortype_find("SCULPT_OT_trim_lasso_gesture", false),
3701 WM_operatortype_find("SCULPT_OT_trim_line_gesture", false),
3702 WM_operatortype_find("SCULPT_OT_trim_polyline_gesture", false),
3703 WM_operatortype_find("SCULPT_OT_mesh_filter", false),
3704 WM_operatortype_find("SCULPT_OT_cloth_filter", false),
3705 WM_operatortype_find("SCULPT_OT_color_filter", false),
3706 };
3707
3708 return std::any_of(trim_operators.begin(), trim_operators.end(), [tref](wmOperatorType *ot) {
3709 PointerRNA ptr;
3710 return WM_toolsystem_ref_properties_get_from_operator(tref, ot, &ptr);
3711 });
3712 }
3713 }
3714 return false;
3715}
3716
3722
3723static const char *sculpt_brush_type_name(const Sculpt &sd)
3724{
3725 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
3726
3727 switch (eBrushSculptType(brush.sculpt_brush_type)) {
3729 return "Draw Brush";
3731 return "Smooth Brush";
3733 return "Crease Brush";
3735 return "Blob Brush";
3737 return "Pinch Brush";
3739 return "Inflate Brush";
3741 return "Grab Brush";
3743 return "Nudge Brush";
3745 return "Thumb Brush";
3747 return "Layer Brush";
3749 return "Clay Brush";
3751 return "Clay Strips Brush";
3753 return "Clay Thumb Brush";
3755 return "Snake Hook Brush";
3757 return "Rotate Brush";
3759 return "Mask Brush";
3761 return "Simplify Brush";
3763 return "Draw Sharp Brush";
3765 return "Elastic Deform Brush";
3767 return "Pose Brush";
3769 return "Multi-plane Scrape Brush";
3771 return "Slide/Relax Brush";
3773 return "Boundary Brush";
3775 return "Cloth Brush";
3777 return "Draw Face Sets";
3779 return "Multires Displacement Eraser";
3781 return "Multires Displacement Smear";
3783 return "Paint Brush";
3785 return "Smear Brush";
3787 return "Plane Brush";
3788 }
3789
3790 return "Sculpting";
3791}
3792
3793namespace blender::ed::sculpt_paint {
3794
3795StrokeCache::StrokeCache() = default;
3796
3798{
3799 if (this->dial) {
3800 BLI_dial_free(this->dial);
3801 }
3802}
3803
3804} // namespace blender::ed::sculpt_paint
3805
3806enum class StrokeFlags : uint8_t {
3810};
3811
3812namespace blender::ed::sculpt_paint {
3813
3814/* Initialize mirror modifier clipping. */
3815static void sculpt_init_mirror_clipping(const Object &ob, const SculptSession &ss)
3816{
3818
3820 if (!(md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime))) {
3821 continue;
3822 }
3824
3825 if (!(mmd->flag & MOD_MIR_CLIPPING)) {
3826 continue;
3827 }
3828 /* Check each axis for mirroring. */
3829 for (int i = 0; i < 3; i++) {
3830 if (!(mmd->flag & (MOD_MIR_AXIS_X << i))) {
3831 continue;
3832 }
3833 /* Enable sculpt clipping. */
3835
3836 /* Update the clip tolerance. */
3837 ss.cache->mirror_modifier_clip.tolerance[i] = std::max(
3839
3840 /* Store matrix for mirror object clipping. */
3841 if (mmd->mirror_ob) {
3842 const float4x4 mirror_ob_inv = math::invert(mmd->mirror_ob->object_to_world());
3844 mirror_ob_inv.ptr(),
3845 ob.object_to_world().ptr());
3846 }
3847 }
3848 }
3850}
3851
3853{
3854 Main *bmain = CTX_data_main(C);
3855 Scene *scene = CTX_data_scene(C);
3856 Brush *cur_brush = BKE_paint_brush(paint);
3857
3858 if (cur_brush->sculpt_brush_type == SCULPT_BRUSH_TYPE_MASK) {
3859 cache->saved_mask_brush_tool = cur_brush->mask_tool;
3860 cur_brush->mask_tool = BRUSH_MASK_SMOOTH;
3861 return;
3862 }
3863
3864 if (ELEM(cur_brush->sculpt_brush_type,
3869 {
3870 /* Do nothing, this brush has its own smooth mode. */
3871 return;
3872 }
3873
3874 /* Switch to the smooth brush if possible. */
3875 BKE_paint_brush_set_essentials(bmain, paint, "Smooth");
3876 Brush *smooth_brush = BKE_paint_brush(paint);
3877
3878 if (!smooth_brush) {
3879 BKE_paint_brush_set(paint, cur_brush);
3880 CLOG_WARN(&LOG, "Switching to the smooth brush not possible, corresponding brush not");
3881 cache->saved_active_brush = nullptr;
3882 return;
3883 }
3884
3885 int cur_brush_size = BKE_brush_size_get(scene, cur_brush);
3886
3887 cache->saved_active_brush = cur_brush;
3888
3889 cache->saved_smooth_size = BKE_brush_size_get(scene, smooth_brush);
3890 BKE_brush_size_set(scene, smooth_brush, cur_brush_size);
3891 BKE_curvemapping_init(smooth_brush->curve);
3892}
3893
3895{
3896 Brush &brush = *BKE_paint_brush(paint);
3897
3899 brush.mask_tool = cache->saved_mask_brush_tool;
3900 return;
3901 }
3902
3903 if (ELEM(brush.sculpt_brush_type,
3908 {
3909 /* Do nothing. */
3910 return;
3911 }
3912
3913 /* If saved_active_brush is not set, brush was not switched/affected in
3914 * smooth_brush_toggle_on(). */
3915 if (cache->saved_active_brush) {
3916 Scene *scene = CTX_data_scene(C);
3917 BKE_brush_size_set(scene, &brush, cache->saved_smooth_size);
3919 cache->saved_active_brush = nullptr;
3920 }
3921}
3922
3923/* Initialize the stroke cache invariants from operator properties. */
3925 bContext *C, Sculpt &sd, SculptSession &ss, const wmOperator &op, const float mval[2])
3926{
3927 StrokeCache *cache = MEM_new<StrokeCache>(__func__);
3928 ToolSettings *tool_settings = CTX_data_tool_settings(C);
3929 UnifiedPaintSettings *ups = &tool_settings->unified_paint_settings;
3930 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
3933
3934 ss.cache = cache;
3935
3936 /* Set scaling adjustment. */
3937 float max_scale = 0.0f;
3938 for (int i = 0; i < 3; i++) {
3939 max_scale = max_ff(max_scale, fabsf(ob.scale[i]));
3940 }
3941 cache->scale[0] = max_scale / ob.scale[0];
3942 cache->scale[1] = max_scale / ob.scale[1];
3943 cache->scale[2] = max_scale / ob.scale[2];
3944
3945 cache->plane_trim_squared = brush->plane_trim * brush->plane_trim;
3946
3947 cache->mirror_modifier_clip.flag = 0;
3948
3950
3951 /* Initial mouse location. */
3952 cache->initial_mouse = mval ? float2(mval) : float2(0.0f);
3953
3956
3958 cache->initial_normal = ss.cursor_sampled_normal.value_or(ss.cursor_normal);
3959
3960 const int mode = RNA_enum_get(op.ptr, "mode");
3961 cache->pen_flip = RNA_boolean_get(op.ptr, "pen_flip");
3962 cache->invert = mode == BRUSH_STROKE_INVERT;
3963 cache->alt_smooth = mode == BRUSH_STROKE_SMOOTH;
3964
3965 cache->normal_weight = brush->normal_weight;
3966
3967 /* Interpret invert as following normal, for grab brushes. */
3969 if (cache->invert) {
3970 cache->invert = false;
3971 cache->normal_weight = (cache->normal_weight == 0.0f);
3972 }
3973 }
3974
3975 /* Not very nice, but with current events system implementation
3976 * we can't handle brush appearance inversion hotkey separately (sergey). */
3977 if (cache->invert) {
3978 ups->draw_inverted = true;
3979 }
3980 else {
3981 ups->draw_inverted = false;
3982 }
3983
3984 /* Alt-Smooth. */
3985 if (cache->alt_smooth) {
3986 smooth_brush_toggle_on(C, &sd.paint, cache);
3987 /* Refresh the brush pointer in case we switched brush in the toggle function. */
3988 brush = BKE_paint_brush(&sd.paint);
3989 }
3990
3991 cache->mouse = cache->initial_mouse;
3992 cache->mouse_event = cache->initial_mouse;
3993 copy_v2_v2(ups->tex_mouse, cache->initial_mouse);
3994
3995 cache->initial_direction_flipped = brush_flip(*brush, *cache) < 0.0f;
3996
3997 /* Truly temporary data that isn't stored in properties. */
3998 cache->vc = vc;
3999 cache->brush = brush;
4000
4001 /* Cache projection matrix. */
4002 cache->projection_mat = ED_view3d_ob_project_mat_get(cache->vc->rv3d, &ob);
4003
4004 const float3 z_axis(0.0f, 0.0f, 1.0f);
4005 ob.runtime->world_to_object = math::invert(ob.object_to_world());
4007 ob.world_to_object() * float4x4(cache->vc->rv3d->viewinv), z_axis));
4008
4009 cache->supports_gravity = bke::brush::supports_gravity(*brush) && sd.gravity_factor > 0.0f;
4010 /* Get gravity vector in world space. */
4011 if (cache->supports_gravity) {
4012 if (sd.gravity_object) {
4013 const Object *gravity_object = sd.gravity_object;
4014 cache->gravity_direction = gravity_object->object_to_world().z_axis();
4015 }
4016 else {
4017 cache->gravity_direction = {0.0f, 0.0f, 1.0f};
4018 }
4019
4020 /* Transform to sculpted object space. */
4022 math::transform_direction(ob.world_to_object(), cache->gravity_direction));
4023 }
4024
4025 cache->accum = true;
4026
4027 /* Make copies of the mesh vertex locations and normals for some brushes. */
4028 if (brush->flag & BRUSH_ANCHORED) {
4029 cache->accum = false;
4030 }
4031
4032 /* Draw sharp does not need the original coordinates to produce the accumulate effect, so it
4033 * should work the opposite way. */
4035 cache->accum = false;
4036 }
4037
4038 if (bke::brush::supports_accumulate(*brush)) {
4039 if (!(brush->flag & BRUSH_ACCUMULATE)) {
4040 cache->accum = false;
4042 cache->accum = true;
4043 }
4044 }
4045 }
4046
4047 /* Original coordinates require the sculpt undo system, which isn't used
4048 * for image brushes. It's also not necessary, just disable it. */
4049 if (brush && brush->sculpt_brush_type == SCULPT_BRUSH_TYPE_PAINT &&
4050 SCULPT_use_image_paint_brush(tool_settings->paint_mode, ob))
4051 {
4052 cache->accum = true;
4053 }
4054
4057 }
4058 cache->first_time = true;
4059 cache->plane_brush.first_time = true;
4060
4062 constexpr int pixel_input_threshold = 5;
4063 cache->dial = BLI_dial_init(cache->initial_mouse, pixel_input_threshold);
4064 }
4065}
4066
4067static float brush_dynamic_size_get(const Brush &brush,
4068 const StrokeCache &cache,
4069 float initial_size)
4070{
4071 switch (brush.sculpt_brush_type) {
4073 return max_ff(initial_size * 0.20f, initial_size * pow3f(cache.pressure));
4075 return max_ff(initial_size * 0.30f, initial_size * powf(cache.pressure, 1.5f));
4077 float clay_stabilized_pressure = brushes::clay_thumb_get_stabilized_pressure(cache);
4078 return initial_size * clay_stabilized_pressure;
4079 }
4080 default:
4081 return initial_size * cache.pressure;
4082 }
4083}
4084
4085/* In these brushes the grab delta is calculated always from the initial stroke location, which is
4086 * generally used to create grab deformations. */
4088{
4090 return true;
4091 }
4092
4093 if (ELEM(brush.sculpt_brush_type,
4099 {
4100 return true;
4101 }
4104 {
4105 return true;
4106 }
4107 return false;
4108}
4109
4110/* In these brushes the grab delta is calculated from the previous stroke location, which is used
4111 * to calculate to orientate the brush tip and deformation towards the stroke direction. */
4125
4126static void brush_delta_update(const Depsgraph &depsgraph,
4128 const Object &ob,
4129 const Brush &brush)
4130{
4131 SculptSession &ss = *ob.sculpt;
4132 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
4133 StrokeCache *cache = ss.cache;
4134 const float mval[2] = {
4135 cache->mouse_event[0],
4136 cache->mouse_event[1],
4137 };
4138 int brush_type = brush.sculpt_brush_type;
4139
4140 if (!ELEM(brush_type,
4156 !brush_uses_topology_rake(ss, brush))
4157 {
4158 return;
4159 }
4160 float grab_location[3], imat[4][4], delta[3], loc[3];
4161
4163 if (brush_type == SCULPT_BRUSH_TYPE_GRAB && brush.flag & BRUSH_GRAB_ACTIVE_VERTEX &&
4164 !std::holds_alternative<std::monostate>(ss.active_vert()))
4165 {
4166 if (pbvh.type() == bke::pbvh::Type::Mesh) {
4168 cache->orig_grab_location = positions[std::get<int>(ss.active_vert())];
4169 }
4170 else {
4172 }
4173 }
4174 else {
4175 copy_v3_v3(cache->orig_grab_location, cache->location);
4176 }
4177 }
4178 else if (brush_type == SCULPT_BRUSH_TYPE_SNAKE_HOOK ||
4179 (brush_type == SCULPT_BRUSH_TYPE_CLOTH &&
4181 {
4182 add_v3_v3(cache->location, cache->grab_delta);
4183 }
4184
4185 /* Compute 3d coordinate at same z from original location + mval. */
4186 mul_v3_m4v3(loc, ob.object_to_world().ptr(), cache->orig_grab_location);
4187 ED_view3d_win_to_3d(cache->vc->v3d, cache->vc->region, loc, mval, grab_location);
4188
4189 /* Compute delta to move verts by. */
4192 sub_v3_v3v3(delta, grab_location, cache->old_grab_location);
4193 invert_m4_m4(imat, ob.object_to_world().ptr());
4194 mul_mat3_m4_v3(imat, delta);
4195 add_v3_v3(cache->grab_delta, delta);
4196 }
4197 else if (need_delta_for_tip_orientation(brush)) {
4198 if (brush.flag & BRUSH_ANCHORED) {
4199 float orig[3];
4200 mul_v3_m4v3(orig, ob.object_to_world().ptr(), cache->orig_grab_location);
4201 sub_v3_v3v3(cache->grab_delta, grab_location, orig);
4202 }
4203 else {
4204 sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
4205 }
4206 invert_m4_m4(imat, ob.object_to_world().ptr());
4207 mul_mat3_m4_v3(imat, cache->grab_delta);
4208 }
4209 else {
4210 /* Use for 'Brush.topology_rake_factor'. */
4211 sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
4212 }
4213 }
4214 else {
4215 zero_v3(cache->grab_delta);
4216 }
4217
4220 }
4221
4222 copy_v3_v3(cache->old_grab_location, grab_location);
4223
4225 /* Location stays the same for finding vertices in brush radius. */
4226 copy_v3_v3(cache->location, cache->orig_grab_location);
4227
4228 ups.draw_anchored = true;
4230 ups.anchored_size = ups.pixel_radius;
4231 }
4232
4233 /* Handle 'rake' */
4234 cache->rake_rotation = std::nullopt;
4235 cache->rake_rotation_symm = std::nullopt;
4236 invert_m4_m4(imat, ob.object_to_world().ptr());
4237 mul_mat3_m4_v3(imat, grab_location);
4238
4240 copy_v3_v3(cache->rake_data.follow_co, grab_location);
4241 }
4242
4243 if (!brush_needs_rake_rotation(brush)) {
4244 return;
4245 }
4247
4248 if (!is_zero_v3(cache->grab_delta)) {
4249 const float eps = 0.00001f;
4250
4251 float v1[3], v2[3];
4252
4253 copy_v3_v3(v1, cache->rake_data.follow_co);
4255 sub_v3_v3(v2, cache->grab_delta);
4256
4257 sub_v3_v3(v1, grab_location);
4258 sub_v3_v3(v2, grab_location);
4259
4260 if ((normalize_v3(v2) > eps) && (normalize_v3(v1) > eps) && (len_squared_v3v3(v1, v2) > eps)) {
4261 const float rake_dist_sq = len_squared_v3v3(cache->rake_data.follow_co, grab_location);
4262 const float rake_fade = (rake_dist_sq > square_f(cache->rake_data.follow_dist)) ?
4263 1.0f :
4264 sqrtf(rake_dist_sq) / cache->rake_data.follow_dist;
4265
4266 const math::AxisAngle between_vecs(v1, v2);
4267 const math::AxisAngle rotated(between_vecs.axis(),
4268 between_vecs.angle() * brush.rake_factor * rake_fade);
4269 cache->rake_rotation = math::to_quaternion(rotated);
4270 }
4271 }
4272 rake_data_update(&cache->rake_data, grab_location);
4273}
4274
4275static void cache_paint_invariants_update(StrokeCache &cache, const Brush &brush)
4276{
4277 cache.hardness = brush.hardness;
4280 1.0f - cache.pressure :
4281 cache.pressure;
4282 }
4283
4284 cache.paint_brush.flow = brush.flow;
4287 1.0f - cache.pressure :
4288 cache.pressure;
4289 }
4290
4291 cache.paint_brush.wet_mix = brush.wet_mix;
4294 1.0f - cache.pressure :
4295 cache.pressure;
4296
4297 /* This makes wet mix more sensible in higher values, which allows to create brushes that have
4298 * a wider pressure range were they only blend colors without applying too much of the brush
4299 * color. */
4300 cache.paint_brush.wet_mix = 1.0f - pow2f(1.0f - cache.paint_brush.wet_mix);
4301 }
4302
4307 1.0f - cache.pressure :
4308 cache.pressure;
4309 }
4310
4311 cache.paint_brush.density = brush.density;
4314 1.0f - cache.pressure :
4315 cache.pressure;
4316 }
4317}
4318
4319/* Initialize the stroke cache variants from operator properties. */
4321{
4322 Scene &scene = *CTX_data_scene(C);
4323 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
4325 SculptSession &ss = *ob.sculpt;
4326 StrokeCache &cache = *ss.cache;
4327 Brush &brush = *BKE_paint_brush(&sd.paint);
4328
4330 !((brush.flag & BRUSH_ANCHORED) ||
4334 {
4335 RNA_float_get_array(ptr, "location", cache.location);
4336 }
4337
4338 RNA_float_get_array(ptr, "mouse", cache.mouse);
4339 RNA_float_get_array(ptr, "mouse_event", cache.mouse_event);
4340
4341 /* XXX: Use pressure value from first brush step for brushes which don't support strokes (grab,
4342 * thumb). They depends on initial state and brush coord/pressure/etc.
4343 * It's more an events design issue, which doesn't split coordinate/pressure/angle changing
4344 * events. We should avoid this after events system re-design. */
4346 cache.pressure = RNA_float_get(ptr, "pressure");
4347 }
4348
4349 cache.tilt = {RNA_float_get(ptr, "x_tilt"), RNA_float_get(ptr, "y_tilt")};
4350
4351 /* Truly temporary data that isn't stored in properties. */
4353 cache.initial_radius = object_space_radius_get(*cache.vc, scene, brush, cache.location);
4354
4355 if (!BKE_brush_use_locked_size(&scene, &brush)) {
4356 BKE_brush_unprojected_radius_set(&scene, &brush, cache.initial_radius);
4357 }
4358 }
4359
4360 /* Clay stabilized pressure. */
4365 }
4366 else {
4368 cache.pressure;
4372 {
4374 }
4375 }
4376 }
4377
4379 {
4380 cache.radius = brush_dynamic_size_get(brush, cache, cache.initial_radius);
4382 }
4383 else {
4384 cache.radius = cache.initial_radius;
4386 }
4387
4388 cache_paint_invariants_update(cache, brush);
4389
4390 cache.radius_squared = cache.radius * cache.radius;
4391
4392 if (brush.flag & BRUSH_ANCHORED) {
4393 /* True location has been calculated as part of the stroke system already here. */
4394 if (brush.flag & BRUSH_EDGE_TO_EDGE) {
4395 RNA_float_get_array(ptr, "location", cache.location);
4396 }
4397
4398 cache.radius = paint_calc_object_space_radius(*cache.vc, cache.location, ups.pixel_radius);
4399 cache.radius_squared = cache.radius * cache.radius;
4400 }
4401
4402 brush_delta_update(depsgraph, ups, ob, brush);
4403
4405 cache.vertex_rotation = -BLI_dial_angle(cache.dial, cache.mouse) * cache.bstrength;
4406
4407 ups.draw_anchored = true;
4409 ups.anchored_size = ups.pixel_radius;
4410 }
4411
4412 cache.special_rotation = ups.brush_rotation;
4413
4414 cache.iteration_count++;
4415}
4416
4417/* Returns true if any of the smoothing modes are active (currently
4418 * one of smooth brush, autosmooth, mask smooth, or shift-key
4419 * smooth). */
4421 const Brush &brush,
4422 const Object &object,
4423 int stroke_mode)
4424{
4425 SculptSession &ss = *object.sculpt;
4426 const bke::pbvh::Tree *pbvh = bke::object::pbvh_get(object);
4427 if (pbvh && auto_mask::is_enabled(sd, object, &brush)) {
4428 return true;
4429 }
4430 return ((stroke_mode == BRUSH_STROKE_SMOOTH) || (ss.cache && ss.cache->alt_smooth) ||
4433 (brush.mask_tool == BRUSH_MASK_SMOOTH)) ||
4443}
4444
4445} // namespace blender::ed::sculpt_paint
4446
4447void SCULPT_stroke_modifiers_check(const bContext *C, Object &ob, const Brush &brush)
4448{
4449 using namespace blender::ed::sculpt_paint;
4450 SculptSession &ss = *ob.sculpt;
4452 const Sculpt &sd = *CTX_data_tool_settings(C)->sculpt;
4453
4454 bool need_pmap = sculpt_needs_connectivity_info(sd, brush, ob, 0);
4456 (!BKE_sculptsession_use_pbvh_draw(&ob, rv3d) && need_pmap))
4457 {
4461 }
4462}
4463
4464namespace blender::ed::sculpt_paint {
4465static void sculpt_raycast_cb(bke::pbvh::Node &node, RaycastData &rd, float *tmin)
4466{
4467 if (BKE_pbvh_node_get_tmin(&node) >= *tmin) {
4468 return;
4469 }
4470
4472 bool use_origco = false;
4473 Span<float3> origco;
4474 if (rd.use_original && rd.is_mid_stroke) {
4475 switch (pbvh.type()) {
4477 if (const std::optional<OrigPositionData> orig_data =
4479 *rd.object, static_cast<const bke::pbvh::MeshNode &>(node)))
4480 {
4481 use_origco = true;
4482 origco = orig_data->positions;
4483 }
4484 break;
4486 if (const std::optional<OrigPositionData> orig_data = orig_position_data_lookup_grids(
4487 *rd.object, static_cast<const bke::pbvh::GridsNode &>(node)))
4488 {
4489 use_origco = true;
4490 origco = orig_data->positions;
4491 }
4492 break;
4494 use_origco = true;
4495 break;
4496 }
4497 }
4498
4500 return;
4501 }
4502
4503 bool hit = false;
4504 switch (pbvh.type()) {
4505 case bke::pbvh::Type::Mesh: {
4506 int mesh_active_vert;
4507 hit = bke::pbvh::node_raycast_mesh(static_cast<bke::pbvh::MeshNode &>(node),
4508 origco,
4509 rd.vert_positions,
4510 rd.faces,
4511 rd.corner_verts,
4512 rd.corner_tris,
4513 rd.hide_poly,
4514 rd.ray_start,
4515 rd.ray_normal,
4516 &rd.isect_precalc,
4517 &rd.depth,
4518 mesh_active_vert,
4520 rd.face_normal);
4521 if (hit) {
4522 rd.active_vertex = mesh_active_vert;
4523 }
4524 break;
4525 }
4527 SubdivCCGCoord grids_active_vert;
4529 static_cast<bke::pbvh::GridsNode &>(node),
4530 origco,
4531 rd.ray_start,
4532 rd.ray_normal,
4533 &rd.isect_precalc,
4534 &rd.depth,
4535 grids_active_vert,
4537 rd.face_normal);
4538 if (hit) {
4539 rd.active_vertex = grids_active_vert.to_index(
4541 }
4542 break;
4543 }
4545 BMVert *bmesh_active_vert;
4546 hit = bke::pbvh::node_raycast_bmesh(static_cast<bke::pbvh::BMeshNode &>(node),
4547 rd.ray_start,
4548 rd.ray_normal,
4549 &rd.isect_precalc,
4550 &rd.depth,
4551 use_origco,
4552 &bmesh_active_vert,
4553 rd.face_normal);
4554 if (hit) {
4555 rd.active_vertex = bmesh_active_vert;
4556 }
4557 break;
4558 }
4559 }
4560
4561 if (hit) {
4562 rd.hit = true;
4563 *tmin = rd.depth;
4564 }
4565}
4566
4568 FindNearestToRayData &fntrd,
4569 float *tmin)
4570{
4571 if (BKE_pbvh_node_get_tmin(&node) >= *tmin) {
4572 return;
4573 }
4575 bool use_origco = false;
4576 Span<float3> origco;
4577 if (fntrd.use_original && fntrd.is_mid_stroke) {
4578 switch (pbvh.type()) {
4580 if (const std::optional<OrigPositionData> orig_data =
4582 *fntrd.object, static_cast<const bke::pbvh::MeshNode &>(node)))
4583 {
4584 use_origco = true;
4585 origco = orig_data->positions;
4586 }
4587 break;
4589 if (const std::optional<OrigPositionData> orig_data = orig_position_data_lookup_grids(
4590 *fntrd.object, static_cast<const bke::pbvh::GridsNode &>(node)))
4591 {
4592 use_origco = true;
4593 origco = orig_data->positions;
4594 }
4595
4596 break;
4598 use_origco = true;
4599 break;
4600 }
4601 }
4602
4604 node,
4605 origco,
4606 use_origco,
4607 fntrd.vert_positions,
4608 fntrd.faces,
4609 fntrd.corner_verts,
4610 fntrd.corner_tris,
4611 fntrd.hide_poly,
4612 fntrd.subdiv_ccg,
4613 fntrd.ray_start,
4614 fntrd.ray_normal,
4615 &fntrd.depth,
4616 &fntrd.dist_sq_to_ray))
4617 {
4618 fntrd.hit = true;
4619 *tmin = fntrd.dist_sq_to_ray;
4620 }
4621}
4622
4624 const float2 &mval,
4625 float3 &r_ray_start,
4626 float3 &r_ray_end,
4627 float3 &r_ray_normal,
4628 bool original)
4629{
4630 Object &ob = *vc->obact;
4631 RegionView3D *rv3d = vc->rv3d;
4632 View3D *v3d = vc->v3d;
4633
4634 /* TODO: what if the segment is totally clipped? (return == 0). */
4636 vc->depsgraph, vc->region, vc->v3d, mval, r_ray_start, r_ray_end, true);
4637
4638 const float4x4 &world_to_object = ob.world_to_object();
4639 r_ray_start = math::transform_point(world_to_object, r_ray_start);
4640 r_ray_end = math::transform_point(world_to_object, r_ray_end);
4641
4642 float dist;
4643 r_ray_normal = math::normalize_and_get_length(r_ray_end - r_ray_start, dist);
4644
4645 if (rv3d->is_persp || RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
4646 return dist;
4647 }
4648
4649 /* Get the view origin without the addition
4650 * of -ray_normal * clip_start that
4651 * ED_view3d_win_to_segment_clipped gave us.
4652 * This is necessary to avoid floating point overflow.
4653 */
4654 float3 view_origin;
4655 ED_view3d_win_to_origin(vc->region, mval, view_origin);
4656 r_ray_start = math::transform_point(world_to_object, view_origin);
4657
4659 bke::pbvh::clip_ray_ortho(pbvh, original, r_ray_start, r_ray_end, r_ray_normal);
4660
4661 return math::distance(r_ray_start, r_ray_end);
4662}
4663
4666 const float2 &mval,
4667 const bool use_sampled_normal)
4668{
4670 Scene *scene = CTX_data_scene(C);
4672 bool original = false;
4673
4675
4676 Object &ob = *vc.obact;
4677 SculptSession &ss = *ob.sculpt;
4678
4679 const View3D *v3d = CTX_wm_view3d(C);
4680 const Base *base = CTX_data_active_base(C);
4681
4683
4684 if (!pbvh || !vc.rv3d || !BKE_base_is_visible(v3d, base)) {
4685 out->location = float3(0.0f);
4686 out->normal = float3(0.0f);
4687 out->active_vertex_co = float3(0.0f);
4688 ss.clear_active_elements(false);
4689 return false;
4690 }
4691
4692 /* bke::pbvh::Tree raycast to get active vertex and face normal. */
4693 float3 ray_start;
4694 float3 ray_end;
4695 float3 ray_normal;
4696 float depth = raycast_init(&vc, mval, ray_start, ray_end, ray_normal, original);
4697 SCULPT_stroke_modifiers_check(C, ob, brush);
4698
4699 RaycastData srd{};
4700 srd.use_original = original;
4701 srd.object = &ob;
4702 srd.is_mid_stroke = ob.sculpt->cache != nullptr;
4703 srd.hit = false;
4704 if (pbvh->type() == bke::pbvh::Type::Mesh) {
4705 const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
4707 srd.faces = mesh.faces();
4708 srd.corner_verts = mesh.corner_verts();
4709 srd.corner_tris = mesh.corner_tris();
4710 const bke::AttributeAccessor attributes = mesh.attributes();
4711 srd.hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
4712 }
4713 else if (pbvh->type() == bke::pbvh::Type::Grids) {
4714 srd.subdiv_ccg = ss.subdiv_ccg;
4715 }
4717 srd.ray_start = ray_start;
4718 srd.ray_normal = ray_normal;
4719 srd.depth = depth;
4720
4723 *pbvh,
4724 [&](bke::pbvh::Node &node, float *tmin) { sculpt_raycast_cb(node, srd, tmin); },
4725 ray_start,
4726 ray_normal,
4727 srd.use_original);
4728
4729 /* Cursor is not over the mesh, return default values. */
4730 if (!srd.hit) {
4731 out->location = float3(0.0f);
4732 out->normal = float3(0.0f);
4733 out->active_vertex_co = float3(0.0f);
4734 ss.clear_active_elements(true);
4735 return false;
4736 }
4737
4738 /* Update the active vertex of the SculptSession. */
4740 out->active_vertex_co = ss.active_vert_position(*depsgraph, ob);
4741
4742 switch (pbvh->type()) {
4745 ss.active_grid_index = std::nullopt;
4746 break;
4748 ss.active_face_index = std::nullopt;
4750 break;
4752 ss.active_face_index = std::nullopt;
4753 ss.active_grid_index = std::nullopt;
4754 break;
4755 }
4756
4757 out->location = ray_start + ray_normal * srd.depth;
4758
4759 /* Option to return the face normal directly for performance o accuracy reasons. */
4760 if (!use_sampled_normal) {
4761 out->normal = srd.face_normal;
4762 return srd.hit;
4763 }
4764
4765 /* Sampled normal calculation. */
4766
4767 /* Update cursor data in SculptSession. */
4768 const float3 z_axis = {0.0f, 0.0f, 1.0f};
4769 ob.runtime->world_to_object = math::invert(ob.object_to_world());
4771 math::transform_direction(ob.world_to_object() * float4x4(vc.rv3d->viewinv), z_axis));
4772 ss.cursor_normal = srd.face_normal;
4773 ss.cursor_location = out->location;
4774 ss.rv3d = vc.rv3d;
4775 ss.v3d = vc.v3d;
4776
4777 ss.cursor_radius = object_space_radius_get(vc, *scene, brush, out->location);
4778
4779 IndexMaskMemory memory;
4780 const IndexMask node_mask = pbvh_gather_cursor_update(ob, original, memory);
4781
4782 /* In case there are no nodes under the cursor, return the face normal. */
4783 if (node_mask.is_empty()) {
4784 out->normal = srd.face_normal;
4785 return true;
4786 }
4787
4789
4790 /* Calculate the sampled normal. */
4791 if (const std::optional<float3> sampled_normal = calc_area_normal(
4792 *depsgraph, brush, ob, node_mask))
4793 {
4794 out->normal = *sampled_normal;
4795 ss.cursor_sampled_normal = *sampled_normal;
4796 }
4797 else {
4798 /* Use face normal when there are no vertices to sample inside the cursor radius. */
4799 out->normal = srd.face_normal;
4800 }
4801 return true;
4802}
4803
4809 float3 &out,
4810 const float2 &mval,
4811 const bool force_original,
4812 const bool check_closest,
4813 const bool limit_closest_radius)
4814{
4816
4818
4819 Object &ob = *vc.obact;
4820
4821 SculptSession &ss = *ob.sculpt;
4822 StrokeCache *cache = ss.cache;
4823 const bool original = force_original || ((cache) ? !cache->accum : false);
4824
4826
4827 SCULPT_stroke_modifiers_check(C, ob, brush);
4828
4829 float3 ray_start;
4830 float3 ray_end;
4831 float3 ray_normal;
4832 const float depth = raycast_init(&vc, mval, ray_start, ray_end, ray_normal, original);
4833
4835
4836 bool hit = false;
4837 {
4838 RaycastData rd;
4839 rd.object = &ob;
4840 rd.is_mid_stroke = ob.sculpt->cache != nullptr;
4841 rd.ray_start = ray_start;
4842 rd.ray_normal = ray_normal;
4843 rd.hit = false;
4844 if (pbvh.type() == bke::pbvh::Type::Mesh) {
4845 const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
4847 rd.faces = mesh.faces();
4848 rd.corner_verts = mesh.corner_verts();
4849 rd.corner_tris = mesh.corner_tris();
4850 const bke::AttributeAccessor attributes = mesh.attributes();
4851 rd.hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
4852 }
4853 else if (pbvh.type() == bke::pbvh::Type::Grids) {
4854 rd.subdiv_ccg = ss.subdiv_ccg;
4855 }
4857 rd.depth = depth;
4858 rd.use_original = original;
4860
4862 pbvh,
4863 [&](bke::pbvh::Node &node, float *tmin) { sculpt_raycast_cb(node, rd, tmin); },
4864 ray_start,
4865 ray_normal,
4866 rd.use_original);
4867 if (rd.hit) {
4868 hit = true;
4869 out = ray_start + ray_normal * rd.depth;
4870 }
4871 }
4872
4873 if (hit || !check_closest) {
4874 return hit;
4875 }
4876
4877 FindNearestToRayData fntrd{};
4878 fntrd.use_original = original;
4879 fntrd.object = &ob;
4880 fntrd.is_mid_stroke = ss.cache != nullptr;
4881 fntrd.hit = false;
4882 if (pbvh.type() == bke::pbvh::Type::Mesh) {
4883 const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
4885 fntrd.faces = mesh.faces();
4886 fntrd.corner_verts = mesh.corner_verts();
4887 fntrd.corner_tris = mesh.corner_tris();
4888 const bke::AttributeAccessor attributes = mesh.attributes();
4889 fntrd.hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
4890 }
4891 else if (pbvh.type() == bke::pbvh::Type::Grids) {
4892 fntrd.subdiv_ccg = ss.subdiv_ccg;
4893 }
4894 fntrd.ray_start = ray_start;
4895 fntrd.ray_normal = ray_normal;
4896 fntrd.depth = std::numeric_limits<float>::max();
4897 fntrd.dist_sq_to_ray = std::numeric_limits<float>::max();
4898
4900 pbvh,
4901 [&](bke::pbvh::Node &node, float *tmin) {
4902 sculpt_find_nearest_to_ray_cb(node, fntrd, tmin);
4903 },
4904 ray_start,
4905 ray_normal,
4906 fntrd.use_original);
4907 if (fntrd.hit && fntrd.dist_sq_to_ray) {
4908 hit = true;
4909 out = ray_start + ray_normal * fntrd.depth;
4910 }
4911
4912 float closest_radius_sq = std::numeric_limits<float>::max();
4913 if (limit_closest_radius) {
4914 closest_radius_sq = object_space_radius_get(vc, *CTX_data_scene(C), brush, out);
4915 closest_radius_sq *= closest_radius_sq;
4916 }
4917
4918 return hit && fntrd.dist_sq_to_ray < closest_radius_sq;
4919}
4920
4922 float out[3],
4923 const float mval[2],
4924 const bool force_original)
4925{
4927 const bool check_closest = brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE;
4928
4929 float3 location;
4931 C, location, mval, force_original, check_closest, true);
4932 if (result) {
4933 copy_v3_v3(out, location);
4934 }
4935 return result;
4936}
4937} // namespace blender::ed::sculpt_paint
4938
4939static void brush_init_tex(const Sculpt &sd, SculptSession &ss)
4940{
4941 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
4942 const MTex *mask_tex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT);
4943
4944 /* Init mtex nodes. */
4945 if (mask_tex->tex && mask_tex->tex->nodetree) {
4946 /* Has internal flag to detect it only does it once. */
4948 }
4949
4950 if (ss.tex_pool == nullptr) {
4952 }
4953}
4954
4956{
4958 ToolSettings *tool_settings = CTX_data_tool_settings(C);
4959 const Sculpt &sd = *tool_settings->sculpt;
4961 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
4962
4963 if (!G.background) {
4965 }
4966 brush_init_tex(sd, ss);
4967
4968 const bool needs_colors = blender::ed::sculpt_paint::brush_type_is_paint(
4969 brush->sculpt_brush_type) &&
4970 !SCULPT_use_image_paint_brush(tool_settings->paint_mode, ob);
4971
4972 if (needs_colors) {
4974 }
4975
4976 /* CTX_data_ensure_evaluated_depsgraph should be used at the end to include the updates of
4977 * earlier steps modifying the data. */
4981
4983}
4984
4986 const Sculpt &sd,
4987 Object &ob)
4988{
4989 using namespace blender::ed::sculpt_paint;
4990 SculptSession &ss = *ob.sculpt;
4991 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
4992
4993 /* Brushes that use original coordinates and need a "restore" step. This has to happen separately
4994 * rather than in the brush deformation calculation because that is called once for each symmetry
4995 * pass, potentially within the same BVH node.
4996 *
4997 * NOTE: Despite the Cloth and Boundary brush using original coordinates, the brushes do not
4998 * expect this restoration to happen on every stroke step. Performing this restoration causes
4999 * issues with the cloth simulation mode for those brushes.
5000 */
5001 if (ELEM(brush->sculpt_brush_type,
5006 {
5008 return;
5009 }
5010
5011 /* For the cloth brush it makes more sense to not restore the mesh state to keep running the
5012 * simulation from the previous state. */
5014 return;
5015 }
5016
5017 /* Restore the mesh before continuing with anchored stroke. */
5018 if ((brush->flag & BRUSH_ANCHORED) ||
5021 (brush->flag & BRUSH_DRAG_DOT))
5022 {
5023
5025
5026 if (ss.cache) {
5027 /* Temporary data within the StrokeCache that is usually cleared at the end of the stroke
5028 * needs to be invalidated here so that the brushes do not accumulate and apply extra data.
5029 * See #129069. */
5031 ss.cache->paint_brush.mix_colors = {};
5032 }
5033 }
5034}
5035
5036namespace blender::ed::sculpt_paint {
5037
5038static void tag_mesh_positions_changed(Object &object, const bool use_pbvh_draw)
5039{
5040 Mesh &mesh = *static_cast<Mesh *>(object.data);
5041
5042 /* Various operations inside sculpt mode can cause either the #MeshRuntimeData or the entire
5043 * Mesh to be changed (e.g. Undoing the very first operation after opening a file, performing
5044 * remesh, etc).
5045 *
5046 * This isn't an ideal fix for the core issue here, but to mitigate the drastic performance
5047 * falloff, we refreeze the cache before we do any operation that would tag this runtime
5048 * cache as dirty.
5049 *
5050 * See #130636. */
5051 if (!mesh.runtime->corner_tris_cache.frozen) {
5052 mesh.runtime->corner_tris_cache.freeze();
5053 }
5054
5055 /* Updating mesh positions without marking caches dirty is generally not good, but since
5056 * sculpt mode has special requirements and is expected to have sole ownership of the mesh it
5057 * modifies, it's generally okay. */
5058 if (use_pbvh_draw) {
5059 /* When drawing from bke::pbvh::Tree is used, vertex and face normals are updated
5060 * later in #bke::pbvh::update_normals. However, we update the mesh's bounds eagerly here
5061 * since they are trivial to access from the bke::pbvh::Tree. Updating the
5062 * object's evaluated geometry bounding box is necessary because sculpt strokes don't cause
5063 * an object reevaluation. */
5064 mesh.tag_positions_changed_no_normals();
5065 /* Sculpt mode does not use or recalculate face corner normals, so they are cleared. */
5066 mesh.runtime->corner_normals_cache.tag_dirty();
5067 }
5068 else {
5069 /* Drawing happens from the modifier stack evaluation result.
5070 * Tag both coordinates and normals as modified, as both needed for proper drawing and the
5071 * modifier stack is not guaranteed to tag normals for update. */
5072 mesh.tag_positions_changed();
5073 }
5074
5075 if (const bke::pbvh::Tree *pbvh = bke::object::pbvh_get(object)) {
5076 mesh.bounds_set_eager(bke::pbvh::bounds_get(*pbvh));
5077 if (object.runtime->bounds_eval) {
5078 object.runtime->bounds_eval = mesh.bounds_min_max();
5079 }
5080 }
5081}
5082
5083void flush_update_step(const bContext *C, const UpdateType update_type)
5084{
5087
5088 if (rv3d) {
5089 /* Mark for faster 3D viewport redraws. */
5090 rv3d->rflag |= RV3D_PAINTING;
5091 }
5092
5093 const SculptSession &ss = *ob.sculpt;
5094 const MultiresModifierData *mmd = ss.multires.modifier;
5095 if (mmd != nullptr) {
5096 Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
5098 }
5099
5100 ARegion &region = *CTX_wm_region(C);
5101 if (update_type == UpdateType::Image) {
5102 ED_region_tag_redraw(&region);
5103 if (update_type == UpdateType::Image) {
5104 /* Early exit when only need to update the images. We don't want to tag any geometry updates
5105 * that would rebuild the bke::pbvh::Tree. */
5106 return;
5107 }
5108 }
5109
5111
5112 const bool use_pbvh_draw = BKE_sculptsession_use_pbvh_draw(&ob, rv3d);
5113 /* Only current viewport matters, slower update for all viewports will
5114 * be done in sculpt_flush_update_done. */
5115 if (!use_pbvh_draw) {
5116 /* Slow update with full dependency graph update and all that comes with it.
5117 * Needed when there are modifiers or full shading in the 3D viewport. */
5119 }
5120
5121 ED_region_tag_redraw(&region);
5122
5124 if (update_type == UpdateType::Position && !ss.shapekey_active) {
5125 if (pbvh.type() == bke::pbvh::Type::Mesh) {
5126 tag_mesh_positions_changed(ob, use_pbvh_draw);
5127 }
5128 }
5129}
5130
5131void flush_update_done(const bContext *C, Object &ob, const UpdateType update_type)
5132{
5133 /* After we are done drawing the stroke, check if we need to do a more
5134 * expensive depsgraph tag to update geometry. */
5135 const Mesh &mesh = *static_cast<Mesh *>(ob.data);
5136
5137 /* Always needed for linked duplicates. */
5138 bool need_tag = ID_REAL_USERS(&mesh.id) > 1;
5139
5140 RegionView3D *current_rv3d = CTX_wm_region_view3d(C);
5141 if (current_rv3d) {
5142 current_rv3d->rflag &= ~RV3D_PAINTING;
5143 }
5144
5146 LISTBASE_FOREACH (wmWindow *, win, &wm.windows) {
5147 const bScreen &screen = *WM_window_get_active_screen(win);
5148 LISTBASE_FOREACH (ScrArea *, area, &screen.areabase) {
5149 const SpaceLink &sl = *static_cast<SpaceLink *>(area->spacedata.first);
5150 if (sl.spacetype != SPACE_VIEW3D) {
5151 continue;
5152 }
5153
5154 /* Tag all 3D viewports for redraw now that we are done. Other
5155 * viewports did not get a full redraw, and anti-aliasing for the
5156 * current viewport was deactivated. */
5157 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
5158 if (region->regiontype == RGN_TYPE_WINDOW) {
5159 const RegionView3D *other_rv3d = static_cast<RegionView3D *>(region->regiondata);
5160 if (other_rv3d != current_rv3d) {
5161 need_tag |= !BKE_sculptsession_use_pbvh_draw(&ob, other_rv3d);
5162 }
5163
5164 ED_region_tag_redraw(region);
5165 }
5166 }
5167 }
5168
5169 if (update_type == UpdateType::Image) {
5170 LISTBASE_FOREACH (ScrArea *, area, &screen.areabase) {
5171 const SpaceLink &sl = *static_cast<SpaceLink *>(area->spacedata.first);
5172 if (sl.spacetype != SPACE_IMAGE) {
5173 continue;
5174 }
5176 }
5177 }
5178 }
5179
5181
5182 if (update_type == UpdateType::Position) {
5184
5185 /* Coordinates were modified, so fake neighbors are not longer valid. */
5187 }
5188
5189 if (update_type == UpdateType::Position) {
5190 if (pbvh.type() == bke::pbvh::Type::BMesh) {
5191 SculptSession &ss = *ob.sculpt;
5193 }
5194 }
5195
5196 if (need_tag) {
5198 }
5199}
5200
5201/* Replace an entire attribute using implicit sharing to avoid copies when possible. */
5202static void replace_attribute(const bke::AttributeAccessor src_attributes,
5203 const StringRef name,
5204 const bke::AttrDomain domain,
5205 const eCustomDataType data_type,
5206 bke::MutableAttributeAccessor dst_attributes)
5207{
5208 dst_attributes.remove(name);
5209 bke::GAttributeReader src = src_attributes.lookup(name, domain, data_type);
5210 if (!src) {
5211 return;
5212 }
5213 if (src.sharing_info && src.varray.is_span()) {
5215 dst_attributes.add(name, domain, data_type, init);
5216 }
5217 else {
5218 const bke::AttributeInitVArray init(*src);
5219 dst_attributes.add(name, domain, data_type, init);
5220 }
5221}
5222
5225 const StringRef name)
5226{
5227 const bke::GAttributeReader a_attr = a.lookup(name);
5228 const bke::GAttributeReader b_attr = b.lookup(name);
5229 if (!a_attr.sharing_info || !b_attr.sharing_info) {
5230 return false;
5231 }
5232 return a_attr.sharing_info == b_attr.sharing_info;
5233}
5234
5235static bool topology_matches(const Mesh &a, const Mesh &b)
5236{
5237 if (a.verts_num != b.verts_num || a.edges_num != b.edges_num || a.faces_num != b.faces_num ||
5238 a.corners_num != b.corners_num)
5239 {
5240 return false;
5241 }
5242 if (a.runtime->face_offsets_sharing_info != b.runtime->face_offsets_sharing_info) {
5243 return false;
5244 }
5245 const bke::AttributeAccessor a_attributes = a.attributes();
5246 const bke::AttributeAccessor b_attributes = b.attributes();
5247 if (!attribute_matches(a_attributes, b_attributes, ".edge_verts") ||
5248 !attribute_matches(a_attributes, b_attributes, ".corner_vert") ||
5249 !attribute_matches(a_attributes, b_attributes, ".corner_edge"))
5250 {
5251 return false;
5252 }
5253 return true;
5254}
5255
5257 const Scene &scene,
5258 Object &object,
5259 Mesh *new_mesh)
5260{
5261 Mesh &mesh = *static_cast<Mesh *>(object.data);
5262 sculpt_paint::undo::geometry_begin(scene, object, &op);
5263 BKE_mesh_nomain_to_mesh(new_mesh, &mesh, &object);
5266}
5267
5269{
5270 const int layer_index = CustomData_get_layer_index(&mesh.vert_data, CD_MDEFORMVERT);
5271 if (layer_index == -1) {
5272 return nullptr;
5273 }
5274 return mesh.vert_data.layers[layer_index].sharing_info;
5275}
5276
5278 const Scene &scene,
5279 const Depsgraph &depsgraph,
5280 const RegionView3D *rv3d,
5281 Object &object,
5282 Mesh *new_mesh)
5283{
5284 Mesh &mesh = *static_cast<Mesh *>(object.data);
5285 const bool changed_topology = !topology_matches(mesh, *new_mesh);
5286 const bool use_pbvh_draw = BKE_sculptsession_use_pbvh_draw(&object, rv3d);
5287 bool entire_mesh_changed = false;
5288
5289 if (changed_topology) {
5290 store_sculpt_entire_mesh(op, scene, object, new_mesh);
5291 entire_mesh_changed = true;
5292 }
5293 else {
5294 /* Detect attributes present in the new mesh which no longer match the original. */
5295 VectorSet<StringRef> vertex_group_names;
5296 LISTBASE_FOREACH (const bDeformGroup *, vertex_group, &mesh.vertex_group_names) {
5297 vertex_group_names.add(vertex_group->name);
5298 }
5299
5300 VectorSet<StringRef> changed_attributes;
5301 new_mesh->attributes().foreach_attribute([&](const bke::AttributeIter &iter) {
5302 if (ELEM(iter.name, ".edge_verts", ".corner_vert", ".corner_edge")) {
5303 return;
5304 }
5305 if (vertex_group_names.contains(iter.name)) {
5306 /* Vertex group changes are handled separately. */
5307 return;
5308 }
5309 const bke::GAttributeReader attribute = iter.get();
5310 if (attribute_matches(new_mesh->attributes(), mesh.attributes(), iter.name)) {
5311 return;
5312 }
5313 changed_attributes.add(iter.name);
5314 });
5315 /* Detect attributes that were removed in the new mesh. */
5316 mesh.attributes().foreach_attribute([&](const bke::AttributeIter &iter) {
5317 if (!new_mesh->attributes().contains(iter.name)) {
5318 changed_attributes.add(iter.name);
5319 }
5320 });
5321
5322 /* Vertex groups aren't handled fully by the attribute system, we need to use CustomData. */
5323 const bool vertex_groups_changed = get_vertex_group_sharing_info(mesh) !=
5325
5326 if (vertex_groups_changed) {
5327 changed_attributes.add_multiple(vertex_group_names);
5328 }
5329
5330 /* Try to use the few specialized sculpt undo types that result in better performance, mainly
5331 * because redo avoids clearing the BVH, but also because some other updates can be skipped. */
5332 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
5333 IndexMaskMemory memory;
5334 const IndexMask leaf_nodes = bke::pbvh::all_leaf_nodes(pbvh, memory);
5335 if (changed_attributes.as_span() == Span<StringRef>{"position"}) {
5336 undo::push_begin(scene, object, &op);
5337 undo::push_nodes(depsgraph, object, leaf_nodes, undo::Type::Position);
5338 undo::push_end(object);
5339 CustomData_free_layer_named(&mesh.vert_data, "position");
5340 mesh.attributes_for_write().remove("position");
5341 const bke::AttributeReader position = new_mesh->attributes().lookup<float3>("position");
5342 if (position.sharing_info) {
5343 /* Use lower level API to add the position attribute to avoid copying the array and to
5344 * allow using #tag_positions_changed_no_normals instead of #tag_positions_changed (which
5345 * would be called by the attribute API). */
5347 &mesh.vert_data,
5349 const_cast<float3 *>(position.varray.get_internal_span().data()),
5350 mesh.verts_num,
5351 "position",
5352 position.sharing_info);
5353 }
5354 else {
5355 mesh.vert_positions_for_write().copy_from(VArraySpan(*position));
5356 }
5357
5358 pbvh.tag_positions_changed(leaf_nodes);
5359 pbvh.update_bounds(depsgraph, object);
5360 tag_mesh_positions_changed(object, use_pbvh_draw);
5361 BKE_mesh_copy_parameters(&mesh, new_mesh);
5362 BKE_id_free(nullptr, new_mesh);
5363 }
5364 else if (changed_attributes.as_span() == Span<StringRef>{".sculpt_mask"}) {
5365 undo::push_begin(scene, object, &op);
5366 undo::push_nodes(depsgraph, object, leaf_nodes, undo::Type::Mask);
5367 undo::push_end(object);
5368 replace_attribute(new_mesh->attributes(),
5369 ".sculpt_mask",
5372 mesh.attributes_for_write());
5373 pbvh.tag_masks_changed(leaf_nodes);
5374 BKE_mesh_copy_parameters(&mesh, new_mesh);
5375 BKE_id_free(nullptr, new_mesh);
5376 }
5377 else if (changed_attributes.as_span() == Span<StringRef>{".sculpt_face_set"}) {
5378 undo::push_begin(scene, object, &op);
5379 undo::push_nodes(depsgraph, object, leaf_nodes, undo::Type::FaceSet);
5380 undo::push_end(object);
5381 replace_attribute(new_mesh->attributes(),
5382 ".sculpt_face_set",
5385 mesh.attributes_for_write());
5386 pbvh.tag_face_sets_changed(leaf_nodes);
5387 BKE_mesh_copy_parameters(&mesh, new_mesh);
5388 BKE_id_free(nullptr, new_mesh);
5389 }
5390 else {
5391 /* Non-geometry-type sculpt undo steps can only handle a single change at a time. When
5392 * multiple attributes or attributes that don't have their own undo type are changed, we're
5393 * forced to fall back to the slower geometry undo type. */
5394 store_sculpt_entire_mesh(op, scene, object, new_mesh);
5395 entire_mesh_changed = true;
5396 }
5397 }
5399 if (!use_pbvh_draw || entire_mesh_changed) {
5401 }
5402}
5403
5404} // namespace blender::ed::sculpt_paint
5405
5406/* Returns whether the mouse/stylus is over the mesh (1)
5407 * or over the background (0). */
5408static bool over_mesh(bContext *C, wmOperator * /*op*/, const float mval[2])
5409{
5410 float3 co_dummy;
5412 Brush *brush = BKE_paint_brush(&sd->paint);
5413
5414 const bool check_closest = brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE;
5415
5417 C, co_dummy, mval, false, check_closest, true);
5418}
5419
5420static void stroke_undo_begin(const bContext *C, wmOperator *op)
5421{
5422 using namespace blender::ed::sculpt_paint;
5423 const Scene &scene = *CTX_data_scene(C);
5425 const Sculpt &sd = *CTX_data_tool_settings(C)->sculpt;
5426 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
5427 ToolSettings *tool_settings = CTX_data_tool_settings(C);
5428
5429 /* Setup the correct undo system. Image painting and sculpting are mutual exclusive.
5430 * Color attributes are part of the sculpting undo system. */
5431 if (brush && brush->sculpt_brush_type == SCULPT_BRUSH_TYPE_PAINT &&
5432 SCULPT_use_image_paint_brush(tool_settings->paint_mode, ob))
5433 {
5435 }
5436 else {
5438 }
5439}
5440
5441static void stroke_undo_end(const bContext *C, Brush *brush)
5442{
5443 using namespace blender::ed::sculpt_paint;
5445 ToolSettings *tool_settings = CTX_data_tool_settings(C);
5446
5447 if (brush && brush->sculpt_brush_type == SCULPT_BRUSH_TYPE_PAINT &&
5448 SCULPT_use_image_paint_brush(tool_settings->paint_mode, ob))
5449 {
5451 }
5452 else {
5453 undo::push_end(ob);
5454 }
5455}
5456
5457namespace blender::ed::sculpt_paint {
5458
5460{
5461 if (const SculptSession &ss = *object.sculpt; ss.bm) {
5462 BKE_report(reports, RPT_ERROR, "Not supported in dynamic topology mode");
5463 return false;
5464 }
5465 if (BKE_sculpt_multires_active(&scene, &object)) {
5466 BKE_report(reports, RPT_ERROR, "Not supported in multiresolution mode");
5467 return false;
5468 }
5469
5470 return true;
5471}
5472
5473static bool stroke_test_start(bContext *C, wmOperator *op, const float mval[2])
5474{
5475 /* Don't start the stroke until `mval` goes over the mesh.
5476 * NOTE: `mval` will only be null when re-executing the saved stroke.
5477 * We have exception for 'exec' strokes since they may not set `mval`,
5478 * only 'location', see: #52195. */
5479 if (((op->flag & OP_IS_INVOKE) == 0) || (mval == nullptr) || over_mesh(C, op, mval)) {
5481 SculptSession &ss = *ob.sculpt;
5483 Brush *brush = BKE_paint_brush(&sd.paint);
5484 ToolSettings *tool_settings = CTX_data_tool_settings(C);
5485
5486 /* NOTE: This should be removed when paint mode is available. Paint mode can force based on the
5487 * canvas it is painting on. (ref. use_sculpt_texture_paint). */
5488 if (brush && brush_type_is_paint(brush->sculpt_brush_type) &&
5489 !SCULPT_use_image_paint_brush(tool_settings->paint_mode, ob))
5490 {
5491 View3D *v3d = CTX_wm_view3d(C);
5492 if (v3d->shading.type == OB_SOLID) {
5494 }
5495 }
5496
5498
5499 sculpt_update_cache_invariants(C, sd, ss, *op, mval);
5500
5502 cursor_geometry_info_update(C, &cgi, mval, false);
5503
5504 stroke_undo_begin(C, op);
5505
5506 return true;
5507 }
5508 return false;
5509}
5510
5512 wmOperator * /*op*/,
5513 PaintStroke *stroke,
5514 PointerRNA *itemptr)
5515{
5517 const Scene &scene = *CTX_data_scene(C);
5518 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
5521 SculptSession &ss = *ob.sculpt;
5522 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
5523 ToolSettings &tool_settings = *CTX_data_tool_settings(C);
5524 StrokeCache *cache = ss.cache;
5526
5527 SCULPT_stroke_modifiers_check(C, ob, brush);
5528 sculpt_update_cache_variants(C, sd, ob, itemptr);
5530
5531 if (dyntopo::stroke_is_dyntopo(ob, brush)) {
5533 depsgraph, scene, sd, ob, dynamic_topology_update, ups, tool_settings.paint_mode);
5534 }
5535
5537 depsgraph, scene, sd, ob, do_brush_action, ups, tool_settings.paint_mode);
5538
5539 /* Hack to fix noise texture tearing mesh. */
5540 sculpt_fix_noise_tear(sd, ob);
5541
5542 ss.cache->first_time = false;
5544
5545 /* Cleanup. */
5548 }
5549 else if (brush_type_is_paint(brush.sculpt_brush_type)) {
5550 if (SCULPT_use_image_paint_brush(tool_settings.paint_mode, ob)) {
5552 }
5553 else {
5555 }
5556 }
5557 else {
5559 }
5560}
5561
5562static void brush_exit_tex(Sculpt &sd)
5563{
5564 Brush *brush = BKE_paint_brush(&sd.paint);
5565 const MTex *mask_tex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT);
5566
5567 if (mask_tex->tex && mask_tex->tex->nodetree) {
5568 ntreeTexEndExecTree(mask_tex->tex->nodetree->runtime->execdata);
5569 }
5570}
5571
5572static void stroke_done(const bContext *C, PaintStroke * /*stroke*/)
5573{
5575 SculptSession &ss = *ob.sculpt;
5577 ToolSettings *tool_settings = CTX_data_tool_settings(C);
5578
5579 /* Finished. */
5580 if (!ss.cache) {
5581 brush_exit_tex(sd);
5582 return;
5583 }
5585 Brush *brush = BKE_paint_brush(&sd.paint);
5586 BLI_assert(brush == ss.cache->brush); /* const, so we shouldn't change. */
5587 ups->draw_inverted = false;
5588
5589 SCULPT_stroke_modifiers_check(C, ob, *brush);
5590
5591 /* Alt-Smooth. */
5592 if (ss.cache->alt_smooth) {
5594 /* Refresh the brush pointer in case we switched brush in the toggle function. */
5595 brush = BKE_paint_brush(&sd.paint);
5596 }
5597
5598 MEM_delete(ss.cache);
5599 ss.cache = nullptr;
5600
5601 stroke_undo_end(C, brush);
5602
5605 }
5606 else if (brush->sculpt_brush_type == SCULPT_BRUSH_TYPE_PAINT) {
5607 if (SCULPT_use_image_paint_brush(tool_settings->paint_mode, ob)) {
5609 }
5610 else {
5612 }
5613 }
5614 else {
5616 }
5617
5619 brush_exit_tex(sd);
5620}
5621
5623 wmOperator *op,
5624 const wmEvent *event)
5625{
5626 PaintStroke *stroke;
5627 int ignore_background_click;
5629 Scene &scene = *CTX_data_scene(C);
5630 const View3D *v3d = CTX_wm_view3d(C);
5631 const Base *base = CTX_data_active_base(C);
5632 /* Test that ob is visible; otherwise we won't be able to get evaluated data
5633 * from the depsgraph. We do this here instead of SCULPT_mode_poll
5634 * to avoid falling through to the translate operator in the
5635 * global view3d keymap. */
5636 if (!BKE_base_is_visible(v3d, base)) {
5637 return OPERATOR_CANCELLED;
5638 }
5639
5641
5643 Brush &brush = *BKE_paint_brush(&sd.paint);
5644
5646 !color_supported_check(scene, ob, op->reports))
5647 {
5648 return OPERATOR_CANCELLED;
5649 }
5653 }
5656 {
5657 return OPERATOR_CANCELLED;
5658 }
5659 if (ELEM(brush.sculpt_brush_type,
5662 {
5664 if (!pbvh || pbvh->type() != bke::pbvh::Type::Grids) {
5665 BKE_report(op->reports, RPT_ERROR, "Only supported in multiresolution mode");
5666 return OPERATOR_CANCELLED;
5667 }
5668 }
5669
5670 stroke = paint_stroke_new(C,
5671 op,
5675 nullptr,
5677 event->type);
5678
5679 op->customdata = stroke;
5680
5681 /* For tablet rotation. */
5682 ignore_background_click = RNA_boolean_get(op->ptr, "ignore_background_click");
5683 const float mval[2] = {float(event->mval[0]), float(event->mval[1])};
5684 if (ignore_background_click && !over_mesh(C, op, mval)) {
5685 paint_stroke_free(C, op, static_cast<PaintStroke *>(op->customdata));
5686 return OPERATOR_PASS_THROUGH;
5687 }
5688
5689 const wmOperatorStatus retval = op->type->modal(C, op, event);
5690 OPERATOR_RETVAL_CHECK(retval);
5691
5693 paint_stroke_free(C, op, static_cast<PaintStroke *>(op->customdata));
5694 return retval;
5695 }
5696 /* Add modal handler. */
5698
5700
5702}
5703
5705{
5707
5709 op,
5713 nullptr,
5715 0);
5716
5717 /* Frees op->customdata. */
5718 paint_stroke_exec(C, op, static_cast<PaintStroke *>(op->customdata));
5719
5720 return OPERATOR_FINISHED;
5721}
5722
5724{
5725 using namespace blender::ed::sculpt_paint;
5726 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
5728 SculptSession &ss = *ob.sculpt;
5730 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
5731
5732 /* XXX Canceling strokes that way does not work with dynamic topology,
5733 * user will have to do real undo for now. See #46456. */
5734 if (ss.cache && !dyntopo::stroke_is_dyntopo(ob, brush)) {
5736 }
5737
5738 paint_stroke_cancel(C, op, static_cast<PaintStroke *>(op->customdata));
5739
5740 MEM_delete(ss.cache);
5741 ss.cache = nullptr;
5742
5743 brush_exit_tex(sd);
5744}
5745
5747{
5748 return paint_stroke_modal(C, op, event, (PaintStroke **)&op->customdata);
5749}
5750
5751static void redo_empty_ui(bContext * /*C*/, wmOperator * /*op*/) {}
5752
5754{
5755 /* Identifiers. */
5756 ot->name = "Sculpt";
5757 ot->idname = "SCULPT_OT_brush_stroke";
5758 ot->description = "Sculpt a stroke into the geometry";
5759
5760 /* API callbacks. */
5762 ot->modal = brush_stroke_modal;
5764 ot->poll = SCULPT_poll;
5766 ot->ui = redo_empty_ui;
5767
5768 /* Flags (sculpt does its own undo? (ton)). */
5769 ot->flag = OPTYPE_BLOCKING;
5770
5771 /* Properties. */
5772
5774
5776 ot->srna,
5777 "override_location",
5778 false,
5779 "Override Location",
5780 "Override the given `location` array by recalculating object space positions from the "
5781 "provided `mouse_event` positions");
5783
5784 RNA_def_boolean(ot->srna,
5785 "ignore_background_click",
5786 false,
5787 "Ignore Background Click",
5788 "Clicks on the background do not start the stroke");
5789}
5790
5791/* Fake Neighbors. */
5792
5793static void fake_neighbor_init(Object &object, const float max_dist)
5794{
5795 SculptSession &ss = *object.sculpt;
5796 const int totvert = SCULPT_vertex_count_get(object);
5799}
5800
5805
5807 int vert = -1;
5808 float distance_sq = std::numeric_limits<float>::max();
5809
5811 {
5812 NearestVertData joined = a;
5813 if (joined.vert == -1) {
5814 joined.vert = b.vert;
5815 joined.distance_sq = b.distance_sq;
5816 }
5817 else if (b.distance_sq < joined.distance_sq) {
5818 joined.vert = b.vert;
5819 joined.distance_sq = b.distance_sq;
5820 }
5821 return joined;
5822 }
5823};
5824
5826 const Span<float3> vert_positions,
5827 const Span<bool> hide_vert,
5828 const float3 &location,
5829 const float max_distance_sq,
5830 const int island_id,
5831 const bke::pbvh::MeshNode &node,
5832 NearestVertData &nvtd)
5833{
5834 for (const int vert : node.verts()) {
5835 if (!hide_vert.is_empty() && hide_vert[vert]) {
5836 continue;
5837 }
5839 continue;
5840 }
5841 if (islands::vert_id_get(ss, vert) == island_id) {
5842 continue;
5843 }
5844 const float distance_sq = math::distance_squared(vert_positions[vert], location);
5845 if (distance_sq < max_distance_sq && distance_sq < nvtd.distance_sq) {
5846 nvtd.vert = vert;
5847 nvtd.distance_sq = distance_sq;
5848 }
5849 }
5850}
5851
5853 const CCGKey &key,
5854 const Span<float3> positions,
5855 const BitGroupVector<> &grid_hidden,
5856 const float3 &location,
5857 const float max_distance_sq,
5858 const int island_id,
5859 const bke::pbvh::GridsNode &node,
5860 NearestVertData &nvtd)
5861{
5862 for (const int grid : node.grids()) {
5863 const IndexRange grid_range = bke::ccg::grid_range(key, grid);
5864 BKE_subdiv_ccg_foreach_visible_grid_vert(key, grid_hidden, grid, [&](const int offset) {
5865 const int vert = grid_range[offset];
5867 return;
5868 }
5869 if (islands::vert_id_get(ss, vert) == island_id) {
5870 return;
5871 }
5872 const float distance_sq = math::distance_squared(positions[vert], location);
5873 if (distance_sq < max_distance_sq && distance_sq < nvtd.distance_sq) {
5874 nvtd.vert = vert;
5875 nvtd.distance_sq = distance_sq;
5876 }
5877 });
5878 }
5879}
5880
5882 const float3 &location,
5883 const float max_distance_sq,
5884 const int island_id,
5885 const bke::pbvh::BMeshNode &node,
5886 NearestVertData &nvtd)
5887{
5888 for (const BMVert *bm_vert :
5890 {
5891 if (BM_elem_flag_test(bm_vert, BM_ELEM_HIDDEN)) {
5892 continue;
5893 }
5894 const int vert = BM_elem_index_get(bm_vert);
5896 continue;
5897 }
5898 if (islands::vert_id_get(ss, vert) == island_id) {
5899 continue;
5900 }
5901 const float distance_sq = math::distance_squared(float3(bm_vert->co), location);
5902 if (distance_sq < max_distance_sq && distance_sq < nvtd.distance_sq) {
5903 nvtd.vert = vert;
5904 nvtd.distance_sq = distance_sq;
5905 }
5906 }
5907}
5908
5909static void fake_neighbor_search(const Depsgraph &depsgraph,
5910 const Object &ob,
5911 const float max_distance_sq,
5912 MutableSpan<int> fake_neighbors)
5913{
5914 /* NOTE: This algorithm is extremely slow, it has O(n^2) runtime for the entire mesh. This looks
5915 * like the "closest pair of points" problem which should have far better solutions. */
5916 SculptSession &ss = *ob.sculpt;
5917 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
5918
5919 switch (pbvh.type()) {
5920 case bke::pbvh::Type::Mesh: {
5921 const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
5922 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
5923 const bke::AttributeAccessor attributes = mesh.attributes();
5924 const VArraySpan<bool> hide_vert = *attributes.lookup<bool>(".hide_vert",
5926 for (const int vert : vert_positions.index_range()) {
5927 if (fake_neighbors[vert] != FAKE_NEIGHBOR_NONE) {
5928 continue;
5929 }
5930 const int island_id = islands::vert_id_get(ss, vert);
5931 const float3 &location = vert_positions[vert];
5932
5933 IndexMaskMemory memory;
5934 const IndexMask nodes_in_sphere = bke::pbvh::search_nodes(
5935 pbvh, memory, [&](const bke::pbvh::Node &node) {
5936 return node_in_sphere(node, location, max_distance_sq, false);
5937 });
5938 if (nodes_in_sphere.is_empty()) {
5939 continue;
5940 }
5943 nodes_in_sphere.index_range(),
5944 1,
5946 [&](const IndexRange range, NearestVertData nvtd) {
5947 nodes_in_sphere.slice(range).foreach_index([&](const int i) {
5949 vert_positions,
5950 hide_vert,
5951 location,
5952 max_distance_sq,
5953 island_id,
5954 nodes[i],
5955 nvtd);
5956 });
5957 return nvtd;
5958 },
5960 if (nvtd.vert == -1) {
5961 continue;
5962 }
5963 fake_neighbors[vert] = nvtd.vert;
5964 fake_neighbors[nvtd.vert] = vert;
5965 }
5966 break;
5967 }
5969 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
5970 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
5971 const Span<float3> positions = subdiv_ccg.positions;
5972 const BitGroupVector<> grid_hidden = subdiv_ccg.grid_hidden;
5973 for (const int vert : positions.index_range()) {
5974 if (fake_neighbors[vert] != FAKE_NEIGHBOR_NONE) {
5975 continue;
5976 }
5977 const int island_id = islands::vert_id_get(ss, vert);
5978 const float3 &location = positions[vert];
5979 IndexMaskMemory memory;
5980 const IndexMask nodes_in_sphere = bke::pbvh::search_nodes(
5981 pbvh, memory, [&](const bke::pbvh::Node &node) {
5982 return node_in_sphere(node, location, max_distance_sq, false);
5983 });
5984 if (nodes_in_sphere.is_empty()) {
5985 continue;
5986 }
5989 nodes_in_sphere.index_range(),
5990 1,
5992 [&](const IndexRange range, NearestVertData nvtd) {
5993 nodes_in_sphere.slice(range).foreach_index([&](const int i) {
5995 key,
5996 positions,
5997 grid_hidden,
5998 location,
5999 max_distance_sq,
6000 island_id,
6001 nodes[i],
6002 nvtd);
6003 });
6004 return nvtd;
6005 },
6007 if (nvtd.vert == -1) {
6008 continue;
6009 }
6010 fake_neighbors[vert] = nvtd.vert;
6011 fake_neighbors[nvtd.vert] = vert;
6012 }
6013 break;
6014 }
6016 const BMesh &bm = *ss.bm;
6017 for (const int vert : IndexRange(bm.totvert)) {
6018 if (fake_neighbors[vert] != FAKE_NEIGHBOR_NONE) {
6019 continue;
6020 }
6021 const int island_id = islands::vert_id_get(ss, vert);
6022 const float3 location = BM_vert_at_index(&const_cast<BMesh &>(bm), vert)->co;
6023 IndexMaskMemory memory;
6024 const IndexMask nodes_in_sphere = bke::pbvh::search_nodes(
6025 pbvh, memory, [&](const bke::pbvh::Node &node) {
6026 return node_in_sphere(node, location, max_distance_sq, false);
6027 });
6028 if (nodes_in_sphere.is_empty()) {
6029 continue;
6030 }
6033 nodes_in_sphere.index_range(),
6034 1,
6036 [&](const IndexRange range, NearestVertData nvtd) {
6037 nodes_in_sphere.slice(range).foreach_index([&](const int i) {
6039 ss, location, max_distance_sq, island_id, nodes[i], nvtd);
6040 });
6041 return nvtd;
6042 },
6044 if (nvtd.vert == -1) {
6045 continue;
6046 }
6047 fake_neighbors[vert] = nvtd.vert;
6048 fake_neighbors[nvtd.vert] = vert;
6049 }
6050 break;
6051 }
6052 }
6053}
6054
6055} // namespace blender::ed::sculpt_paint
6056
6058
6060{
6061 SculptSession &ss = *object.sculpt;
6062 if (!ss.vertex_info.boundary.is_empty()) {
6063 return;
6064 }
6065
6066 Mesh *base_mesh = BKE_mesh_from_object(&object);
6067
6068 ss.vertex_info.boundary.resize(base_mesh->verts_num);
6069 Array<int> adjacent_faces_edge_count(base_mesh->edges_num, 0);
6070 array_utils::count_indices(base_mesh->corner_edges(), adjacent_faces_edge_count);
6071
6072 const Span<int2> edges = base_mesh->edges();
6073 for (const int e : edges.index_range()) {
6074 if (adjacent_faces_edge_count[e] < 2) {
6075 const int2 &edge = edges[e];
6076 ss.vertex_info.boundary[edge[0]].set();
6077 ss.vertex_info.boundary[edge[1]].set();
6078 }
6079 }
6080}
6081
6082} // namespace blender::ed::sculpt_paint::boundary
6083
6085 Object &ob,
6086 const float max_dist)
6087{
6088 using namespace blender::ed::sculpt_paint;
6089 SculptSession &ss = *ob.sculpt;
6090
6091 /* Fake neighbors were already initialized with the same distance, so no need to be
6092 * recalculated. */
6094 ss.fake_neighbors.current_max_distance == max_dist)
6095 {
6097 }
6098
6100 fake_neighbor_init(ob, max_dist);
6102
6104}
6105
6107{
6108 using namespace blender::ed::sculpt_paint;
6109 SculptSession &ss = *ob.sculpt;
6111}
6112
6113namespace blender::ed::sculpt_paint {
6114bool vertex_is_occluded(const Depsgraph &depsgraph,
6115 const Object &object,
6116 const float3 &position,
6117 bool original)
6118{
6119 SculptSession &ss = *object.sculpt;
6120
6121 ViewContext *vc = ss.cache ? ss.cache->vc : &ss.filter_cache->vc;
6122
6124 vc->region, position, ss.cache ? ss.cache->projection_mat : ss.filter_cache->viewmat);
6125
6126 float3 ray_start;
6127 float3 ray_end;
6128 float3 ray_normal;
6129 float depth = raycast_init(vc, mouse, ray_end, ray_start, ray_normal, original);
6130
6131 ray_normal = ray_normal * -1.0f;
6132 ray_start = position + ray_normal * 0.002f;
6133
6134 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(const_cast<Object &>(object));
6135
6136 RaycastData srd = {nullptr};
6137 srd.use_original = original;
6138 srd.object = &const_cast<Object &>(object);
6139 srd.is_mid_stroke = ss.cache != nullptr;
6140 srd.hit = false;
6141 srd.ray_start = ray_start;
6142 srd.ray_normal = ray_normal;
6143 srd.depth = depth;
6144 if (pbvh.type() == bke::pbvh::Type::Mesh) {
6145 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
6147 srd.faces = mesh.faces();
6148 srd.corner_verts = mesh.corner_verts();
6149 srd.corner_tris = mesh.corner_tris();
6150 }
6151 else if (pbvh.type() == bke::pbvh::Type::Grids) {
6152 srd.subdiv_ccg = ss.subdiv_ccg;
6153 }
6154 vert_random_access_ensure(const_cast<Object &>(object));
6155
6158 pbvh,
6159 [&](bke::pbvh::Node &node, float *tmin) { sculpt_raycast_cb(node, srd, tmin); },
6160 ray_start,
6161 ray_normal,
6162 srd.use_original);
6163
6164 return srd.hit;
6165}
6166} // namespace blender::ed::sculpt_paint
6167
6169
6170int vert_id_get(const SculptSession &ss, const int vert)
6171{
6173 if (!ss.topology_island_cache) {
6174 /* The cache should be calculated whenever it's necessary.
6175 * Still avoid crashing in release builds though. */
6176 return 0;
6177 }
6179 if (!cache.vert_island_ids.is_empty()) {
6180 return cache.vert_island_ids[vert];
6181 }
6182 return 0;
6183}
6184
6186{
6187 ss.topology_island_cache.reset();
6188}
6189
6191 const int verts_num)
6192{
6193 Array<int> island_indices(verts_num);
6194 const int islands_num = vert_sets.calc_reduced_ids(island_indices);
6195 if (islands_num == 1) {
6196 return {};
6197 }
6198
6199 Array<uint8_t> island_ids(island_indices.size());
6200 threading::parallel_for(island_ids.index_range(), 4096, [&](const IndexRange range) {
6201 for (const int i : range) {
6202 island_ids[i] = uint8_t(island_indices[i]);
6203 }
6204 });
6205
6207 cache.vert_island_ids = std::move(island_ids);
6208 return cache;
6209}
6210
6212{
6213 const OffsetIndices<int> faces = mesh.faces();
6214 const Span<int> corner_verts = mesh.corner_verts();
6215 const bke::AttributeAccessor attributes = mesh.attributes();
6216 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
6217 IndexMaskMemory memory;
6218 const IndexMask visible_faces = hide_poly.is_empty() ?
6219 IndexMask(faces.size()) :
6221 faces.index_range(), hide_poly, memory);
6222
6223 AtomicDisjointSet disjoint_set(mesh.verts_num);
6224 visible_faces.foreach_index(GrainSize(1024), [&](const int face) {
6225 const Span<int> face_verts = corner_verts.slice(faces[face]);
6226 for (const int i : face_verts.index_range().drop_front(1)) {
6227 disjoint_set.join(face_verts.first(), face_verts[i]);
6228 }
6229 });
6230 return vert_disjoint_set_to_islands(disjoint_set, mesh.verts_num);
6231}
6232
6237{
6238 const SculptSession &ss = *object.sculpt;
6239 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
6240 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
6241 AtomicDisjointSet disjoint_set(subdiv_ccg.positions.size());
6242 threading::parallel_for(IndexRange(subdiv_ccg.grids_num), 512, [&](const IndexRange range) {
6243 for (const int grid : range) {
6244 SubdivCCGNeighbors neighbors;
6245 for (const short y : IndexRange(key.grid_size)) {
6246 for (const short x : IndexRange(key.grid_size)) {
6247 const SubdivCCGCoord coord{grid, x, y};
6248 SubdivCCGNeighbors neighbors;
6249 BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, coord, true, neighbors);
6250 for (const SubdivCCGCoord neighbor : neighbors.coords) {
6251 disjoint_set.join(coord.to_index(key), neighbor.to_index(key));
6252 }
6253 }
6254 }
6255 }
6256 });
6257
6258 return vert_disjoint_set_to_islands(disjoint_set, subdiv_ccg.positions.size());
6259}
6260
6262{
6263 const SculptSession &ss = *object.sculpt;
6264 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
6266 BMesh &bm = *ss.bm;
6267 vert_random_access_ensure(const_cast<Object &>(object));
6268
6269 IndexMaskMemory memory;
6270 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
6271 AtomicDisjointSet disjoint_set(bm.totvert);
6272 node_mask.foreach_index(GrainSize(1), [&](const int i) {
6273 for (const BMFace *face :
6275 {
6276 if (BM_elem_flag_test(face, BM_ELEM_HIDDEN)) {
6277 continue;
6278 }
6279 disjoint_set.join(BM_elem_index_get(face->l_first->v),
6280 BM_elem_index_get(face->l_first->next->v));
6281 disjoint_set.join(BM_elem_index_get(face->l_first->v),
6282 BM_elem_index_get(face->l_first->next->next->v));
6283 }
6284 });
6285
6286 return vert_disjoint_set_to_islands(disjoint_set, bm.totvert);
6287}
6288
6290{
6291 switch (bke::object::pbvh_get(object)->type()) {
6293 return calc_topology_islands_mesh(*static_cast<const Mesh *>(object.data));
6295 return calc_topology_islands_grids(object);
6297 return calc_topology_islands_bmesh(object);
6298 }
6300 return {};
6301}
6302
6304{
6305 SculptSession &ss = *object.sculpt;
6306 if (ss.topology_island_cache) {
6307 return;
6308 }
6309 ss.topology_island_cache = std::make_unique<SculptTopologyIslandCache>(calculate_cache(object));
6310}
6311
6312} // namespace blender::ed::sculpt_paint::islands
6313
6314void SCULPT_cube_tip_init(const Sculpt & /*sd*/,
6315 const Object &ob,
6316 const Brush &brush,
6317 float mat[4][4])
6318{
6319 using namespace blender::ed::sculpt_paint;
6320 SculptSession &ss = *ob.sculpt;
6321 float scale[4][4];
6322 float tmat[4][4];
6323 float unused[4][4];
6324
6325 zero_m4(mat);
6326 calc_brush_local_mat(0.0, ob, unused, mat);
6327
6328 /* NOTE: we ignore the radius scaling done inside of calc_brush_local_mat to
6329 * duplicate prior behavior.
6330 *
6331 * TODO: try disabling this and check that all edge cases work properly.
6332 */
6333 normalize_m4(mat);
6334
6335 scale_m4_fl(scale, ss.cache->radius);
6336 mul_m4_m4m4(tmat, mat, scale);
6337 mul_v3_fl(tmat[1], brush.tip_scale_x);
6338 invert_m4_m4(mat, tmat);
6339}
6340
6341
6342namespace blender::ed::sculpt_paint {
6343
6345{
6346 const bke::AttributeAccessor attributes = mesh.attributes();
6347 this->mask = *attributes.lookup<float>(".sculpt_mask", bke::AttrDomain::Point);
6348 this->hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
6349 this->hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
6350 this->face_sets = *attributes.lookup<int>(".sculpt_face_set", bke::AttrDomain::Face);
6351}
6352
6354{
6355 BLI_assert(verts.size() == positions.size());
6356
6357 int i = 0;
6358 for (const BMVert *vert : verts) {
6359 positions[i] = vert->co;
6360 i++;
6361 }
6362}
6363
6364void gather_grids_normals(const SubdivCCG &subdiv_ccg,
6365 const Span<int> grids,
6367{
6368 gather_data_grids(subdiv_ccg, subdiv_ccg.normals.as_span(), grids, normals);
6369}
6370
6372{
6373 int i = 0;
6374 for (const BMVert *vert : verts) {
6375 normals[i] = vert->no;
6376 i++;
6377 }
6378}
6379
6380template<typename T>
6382{
6383 BLI_assert(indices.size() == dst.size());
6384
6385 for (const int i : indices.index_range()) {
6386 dst[i] = src[indices[i]];
6387 }
6388}
6389
6390template<typename T>
6391void gather_data_grids(const SubdivCCG &subdiv_ccg,
6392 const Span<T> src,
6393 const Span<int> grids,
6394 const MutableSpan<T> node_data)
6395{
6396 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
6397 BLI_assert(grids.size() * key.grid_area == node_data.size());
6398
6399 for (const int i : grids.index_range()) {
6400 const IndexRange grids_range = bke::ccg::grid_range(key, grids[i]);
6401 const IndexRange node_range = bke::ccg::grid_range(key, i);
6402 node_data.slice(node_range).copy_from(src.slice(grids_range));
6403 }
6404}
6405
6406template<typename T>
6408 const Set<BMVert *, 0> &verts,
6409 const MutableSpan<T> node_data)
6410{
6411 BLI_assert(verts.size() == node_data.size());
6412
6413 int i = 0;
6414 for (const BMVert *vert : verts) {
6415 node_data[i] = src[BM_elem_index_get(vert)];
6416 i++;
6417 }
6418}
6419
6420template<typename T>
6422{
6423 BLI_assert(indices.size() == src.size());
6424
6425 for (const int i : indices.index_range()) {
6426 dst[indices[i]] = src[i];
6427 }
6428}
6429
6430template<typename T>
6431void scatter_data_grids(const SubdivCCG &subdiv_ccg,
6432 const Span<T> node_data,
6433 const Span<int> grids,
6434 const MutableSpan<T> dst)
6435{
6436 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
6437 BLI_assert(grids.size() * key.grid_area == node_data.size());
6438
6439 for (const int i : grids.index_range()) {
6440 const IndexRange grids_range = bke::ccg::grid_range(key, grids[i]);
6441 const IndexRange node_range = bke::ccg::grid_range(key, i);
6442 dst.slice(grids_range).copy_from(node_data.slice(node_range));
6443 }
6444}
6445
6446template<typename T>
6447void scatter_data_bmesh(const Span<T> node_data,
6448 const Set<BMVert *, 0> &verts,
6449 const MutableSpan<T> dst)
6450{
6451 BLI_assert(verts.size() == node_data.size());
6452
6453 int i = 0;
6454 for (const BMVert *vert : verts) {
6455 dst[BM_elem_index_get(vert)] = node_data[i];
6456 i++;
6457 }
6458}
6459
6468 Span<int>,
6472 Span<int>,
6477 const Set<BMVert *, 0> &,
6479
6487 Span<int>,
6491 Span<int>,
6495 const Set<BMVert *, 0> &,
6497
6499 const Brush &brush,
6500 const Object &object,
6501 const MeshAttributeData &attribute_data,
6502 const Span<float3> vert_positions,
6503 const Span<float3> vert_normals,
6504 const bke::pbvh::MeshNode &node,
6505 Vector<float> &r_factors,
6506 Vector<float> &r_distances)
6507{
6508 const Span<int> verts = node.verts();
6509 r_factors.resize(verts.size());
6510 r_distances.resize(verts.size());
6511
6513 brush,
6514 object,
6515 attribute_data,
6516 vert_positions,
6517 vert_normals,
6518 node,
6519 r_factors.as_mutable_span(),
6520 r_distances.as_mutable_span());
6521}
6523 const Brush &brush,
6524 const Object &object,
6525 const MeshAttributeData &attribute_data,
6526 const Span<float3> vert_positions,
6527 const Span<float3> vert_normals,
6528 const bke::pbvh::MeshNode &node,
6529 const MutableSpan<float> factors,
6530 const MutableSpan<float> distances)
6531{
6532 const SculptSession &ss = *object.sculpt;
6533 const StrokeCache &cache = *ss.cache;
6534
6535 const Span<int> verts = node.verts();
6536
6537 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
6538 filter_region_clip_factors(ss, vert_positions, verts, factors);
6539 if (brush.flag & BRUSH_FRONTFACE) {
6540 calc_front_face(cache.view_normal_symm, vert_normals, verts, factors);
6541 }
6542
6544 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
6545 filter_distances_with_radius(cache.radius, distances, factors);
6546 apply_hardness_to_distances(cache, distances);
6547 calc_brush_strength_factors(cache, brush, distances, factors);
6548
6549 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
6550
6551 calc_brush_texture_factors(ss, brush, vert_positions, verts, factors);
6552}
6553
6555 const Brush &brush,
6556 const Object &object,
6557 const MeshAttributeData &attribute_data,
6558 const Span<float3> positions,
6559 const Span<float3> vert_normals,
6560 const bke::pbvh::MeshNode &node,
6561 Vector<float> &r_factors,
6562 Vector<float> &r_distances)
6563{
6564 const SculptSession &ss = *object.sculpt;
6565 const StrokeCache &cache = *ss.cache;
6566
6567 const Span<int> verts = node.verts();
6568
6569 r_factors.resize(verts.size());
6570 const MutableSpan<float> factors = r_factors;
6571 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
6572 filter_region_clip_factors(ss, positions, factors);
6573 if (brush.flag & BRUSH_FRONTFACE) {
6574 calc_front_face(cache.view_normal_symm, vert_normals, verts, factors);
6575 }
6576
6577 r_distances.resize(verts.size());
6578 const MutableSpan<float> distances = r_distances;
6579 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
6580 filter_distances_with_radius(cache.radius, distances, factors);
6581 apply_hardness_to_distances(cache, distances);
6582 calc_brush_strength_factors(cache, brush, distances, factors);
6583
6584 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
6585
6586 calc_brush_texture_factors(ss, brush, positions, factors);
6587}
6588
6590 const Brush &brush,
6591 const Object &object,
6592 const Span<float3> positions,
6593 const bke::pbvh::GridsNode &node,
6594 Vector<float> &r_factors,
6595 Vector<float> &r_distances)
6596{
6597 const SculptSession &ss = *object.sculpt;
6598 const StrokeCache &cache = *ss.cache;
6599 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
6600
6601 const Span<int> grids = node.grids();
6602
6603 r_factors.resize(positions.size());
6604 const MutableSpan<float> factors = r_factors;
6605 fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
6606 filter_region_clip_factors(ss, positions, factors);
6607 if (brush.flag & BRUSH_FRONTFACE) {
6608 calc_front_face(cache.view_normal_symm, subdiv_ccg, grids, factors);
6609 }
6610
6611 r_distances.resize(positions.size());
6612 const MutableSpan<float> distances = r_distances;
6613 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
6614 filter_distances_with_radius(cache.radius, distances, factors);
6615 apply_hardness_to_distances(cache, distances);
6616 calc_brush_strength_factors(cache, brush, distances, factors);
6617
6618 auto_mask::calc_grids_factors(depsgraph, object, cache.automasking.get(), node, grids, factors);
6619
6620 calc_brush_texture_factors(ss, brush, positions, factors);
6621}
6622
6624 const Brush &brush,
6625 const Object &object,
6626 const Span<float3> positions,
6628 Vector<float> &r_factors,
6629 Vector<float> &r_distances)
6630{
6631 const SculptSession &ss = *object.sculpt;
6632 const StrokeCache &cache = *ss.cache;
6633
6635
6636 r_factors.resize(verts.size());
6637 const MutableSpan<float> factors = r_factors;
6639 filter_region_clip_factors(ss, positions, factors);
6640 if (brush.flag & BRUSH_FRONTFACE) {
6641 calc_front_face(cache.view_normal_symm, verts, factors);
6642 }
6643
6644 r_distances.resize(verts.size());
6645 const MutableSpan<float> distances = r_distances;
6646 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
6647 filter_distances_with_radius(cache.radius, distances, factors);
6648 apply_hardness_to_distances(cache, distances);
6649 calc_brush_strength_factors(cache, brush, distances, factors);
6650
6651 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
6652
6653 calc_brush_texture_factors(ss, brush, positions, factors);
6654}
6655
6657 const Brush &brush,
6658 const Object &object,
6659 const MeshAttributeData &attribute_data,
6660 const Span<float3> positions,
6661 const Span<float3> normals,
6662 const bke::pbvh::MeshNode &node,
6663 Vector<float> &r_factors,
6664 Vector<float> &r_distances)
6665{
6666 const SculptSession &ss = *object.sculpt;
6667 const StrokeCache &cache = *ss.cache;
6668
6669 const Span<int> verts = node.verts();
6670
6671 r_factors.resize(verts.size());
6672 const MutableSpan<float> factors = r_factors;
6673 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
6674 filter_region_clip_factors(ss, positions, factors);
6675
6676 if (brush.flag & BRUSH_FRONTFACE) {
6677 calc_front_face(cache.view_normal_symm, normals, factors);
6678 }
6679
6680 r_distances.resize(verts.size());
6681 const MutableSpan<float> distances = r_distances;
6682 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
6683 filter_distances_with_radius(cache.radius, distances, factors);
6684 apply_hardness_to_distances(cache, distances);
6685 calc_brush_strength_factors(cache, brush, distances, factors);
6686
6687 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
6688
6689 calc_brush_texture_factors(ss, brush, positions, factors);
6690}
6691
6693 const Brush &brush,
6694 const Object &object,
6695 const Span<float3> positions,
6696 const Span<float3> normals,
6697 const bke::pbvh::GridsNode &node,
6698 Vector<float> &r_factors,
6699 Vector<float> &r_distances)
6700{
6701 SculptSession &ss = *object.sculpt;
6702 const StrokeCache &cache = *ss.cache;
6703 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
6704
6705 const Span<int> grids = node.grids();
6706
6707 r_factors.resize(positions.size());
6708 const MutableSpan<float> factors = r_factors;
6709 fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
6710 filter_region_clip_factors(ss, positions, factors);
6711 if (brush.flag & BRUSH_FRONTFACE) {
6712 calc_front_face(cache.view_normal_symm, normals, factors);
6713 }
6714
6715 r_distances.resize(positions.size());
6716 const MutableSpan<float> distances = r_distances;
6717 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
6718 filter_distances_with_radius(cache.radius, distances, factors);
6719 apply_hardness_to_distances(cache, distances);
6720 calc_brush_strength_factors(cache, brush, distances, factors);
6721
6722 auto_mask::calc_grids_factors(depsgraph, object, cache.automasking.get(), node, grids, factors);
6723
6724 calc_brush_texture_factors(ss, brush, positions, factors);
6725}
6726
6728 const Brush &brush,
6729 const Object &object,
6730 const Span<float3> positions,
6731 const Span<float3> normals,
6733 Vector<float> &r_factors,
6734 Vector<float> &r_distances)
6735{
6736 SculptSession &ss = *object.sculpt;
6737 const StrokeCache &cache = *ss.cache;
6738
6740
6741 r_factors.resize(verts.size());
6742 const MutableSpan<float> factors = r_factors;
6744 filter_region_clip_factors(ss, positions, factors);
6745 if (brush.flag & BRUSH_FRONTFACE) {
6746 calc_front_face(cache.view_normal_symm, normals, factors);
6747 }
6748
6749 r_distances.resize(verts.size());
6750 const MutableSpan<float> distances = r_distances;
6751 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
6752 filter_distances_with_radius(cache.radius, distances, factors);
6753 apply_hardness_to_distances(cache, distances);
6754 calc_brush_strength_factors(cache, brush, distances, factors);
6755
6756 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
6757
6758 calc_brush_texture_factors(ss, brush, positions, factors);
6759}
6760
6762 const Span<int> verts,
6763 const MutableSpan<float> r_factors)
6764{
6765 BLI_assert(verts.size() == r_factors.size());
6766
6767 if (!hide_vert.is_empty()) {
6768 for (const int i : verts.index_range()) {
6769 r_factors[i] = hide_vert[verts[i]] ? 0.0f : 1.0f;
6770 }
6771 }
6772 else {
6773 r_factors.fill(1.0f);
6774 }
6775}
6776
6777void fill_factor_from_hide(const SubdivCCG &subdiv_ccg,
6778 const Span<int> grids,
6779 const MutableSpan<float> r_factors)
6780{
6781 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
6782 BLI_assert(grids.size() * key.grid_area == r_factors.size());
6783
6784 const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
6785 if (grid_hidden.is_empty()) {
6786 r_factors.fill(1.0f);
6787 return;
6788 }
6789 for (const int i : grids.index_range()) {
6790 const BitSpan hidden = grid_hidden[grids[i]];
6791 const int start = i * key.grid_area;
6792 for (const int offset : IndexRange(key.grid_area)) {
6793 r_factors[start + offset] = hidden[offset] ? 0.0f : 1.0f;
6794 }
6795 }
6796}
6797
6799{
6800 BLI_assert(verts.size() == r_factors.size());
6801
6802 int i = 0;
6803 for (const BMVert *vert : verts) {
6804 r_factors[i] = BM_elem_flag_test_bool(vert, BM_ELEM_HIDDEN) ? 0.0f : 1.0f;
6805 i++;
6806 }
6807}
6808
6810 const Span<float> mask,
6811 const Span<int> verts,
6812 const MutableSpan<float> r_factors)
6813{
6814 BLI_assert(verts.size() == r_factors.size());
6815
6816 if (!mask.is_empty()) {
6817 for (const int i : verts.index_range()) {
6818 r_factors[i] = 1.0f - mask[verts[i]];
6819 }
6820 }
6821 else {
6822 r_factors.fill(1.0f);
6823 }
6824
6825 if (!hide_vert.is_empty()) {
6826 for (const int i : verts.index_range()) {
6827 if (hide_vert[verts[i]]) {
6828 r_factors[i] = 0.0f;
6829 }
6830 }
6831 }
6832}
6833
6835 const Set<BMVert *, 0> &verts,
6836 const MutableSpan<float> r_factors)
6837{
6838 BLI_assert(verts.size() == r_factors.size());
6839
6840 /* TODO: Avoid overhead of accessing attributes for every bke::pbvh::Tree node. */
6841 const int mask_offset = CustomData_get_offset_named(&bm.vdata, CD_PROP_FLOAT, ".sculpt_mask");
6842 int i = 0;
6843 for (const BMVert *vert : verts) {
6844 r_factors[i] = (mask_offset == -1) ? 1.0f : 1.0f - BM_ELEM_CD_GET_FLOAT(vert, mask_offset);
6845 if (BM_elem_flag_test(vert, BM_ELEM_HIDDEN)) {
6846 r_factors[i] = 0.0f;
6847 }
6848 i++;
6849 }
6850}
6851
6853 const Span<int> grids,
6854 const MutableSpan<float> r_factors)
6855{
6856 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
6857 BLI_assert(grids.size() * key.grid_area == r_factors.size());
6858
6859 if (!subdiv_ccg.masks.is_empty()) {
6860 const Span<float> masks = subdiv_ccg.masks;
6861 for (const int i : grids.index_range()) {
6862 const Span src = masks.slice(bke::ccg::grid_range(key, grids[i]));
6863 MutableSpan dst = r_factors.slice(bke::ccg::grid_range(key, i));
6864 for (const int offset : dst.index_range()) {
6865 dst[offset] = 1.0f - src[offset];
6866 }
6867 }
6868 }
6869 else {
6870 r_factors.fill(1.0f);
6871 }
6872
6873 const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
6874 if (!grid_hidden.is_empty()) {
6875 for (const int i : grids.index_range()) {
6876 const BitSpan hidden = grid_hidden[grids[i]];
6877 const int start = i * key.grid_area;
6878 for (const int offset : IndexRange(key.grid_area)) {
6879 if (hidden[offset]) {
6880 r_factors[start + offset] = 0.0f;
6881 }
6882 }
6883 }
6884 }
6885}
6886
6887void calc_front_face(const float3 &view_normal,
6888 const Span<float3> vert_normals,
6889 const Span<int> verts,
6890 const MutableSpan<float> factors)
6891{
6892 BLI_assert(verts.size() == factors.size());
6893
6894 for (const int i : verts.index_range()) {
6895 const float dot = math::dot(view_normal, vert_normals[verts[i]]);
6896 factors[i] *= std::max(dot, 0.0f);
6897 }
6898}
6899
6900void calc_front_face(const float3 &view_normal,
6901 const Span<float3> normals,
6902 const MutableSpan<float> factors)
6903{
6904 BLI_assert(normals.size() == factors.size());
6905
6906 for (const int i : normals.index_range()) {
6907 const float dot = math::dot(view_normal, normals[i]);
6908 factors[i] *= std::max(dot, 0.0f);
6909 }
6910}
6911void calc_front_face(const float3 &view_normal,
6912 const SubdivCCG &subdiv_ccg,
6913 const Span<int> grids,
6914 const MutableSpan<float> factors)
6915{
6916 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
6917 const Span<float3> normals = subdiv_ccg.normals;
6918 BLI_assert(grids.size() * key.grid_area == factors.size());
6919
6920 for (const int i : grids.index_range()) {
6921 const Span<float3> grid_normals = normals.slice(bke::ccg::grid_range(key, grids[i]));
6922 MutableSpan<float> grid_factors = factors.slice(bke::ccg::grid_range(key, i));
6923 for (const int offset : grid_factors.index_range()) {
6924 const float dot = math::dot(view_normal, grid_normals[offset]);
6925 grid_factors[offset] *= std::max(dot, 0.0f);
6926 }
6927 }
6928}
6929
6930void calc_front_face(const float3 &view_normal,
6931 const Set<BMVert *, 0> &verts,
6932 const MutableSpan<float> factors)
6933{
6934 BLI_assert(verts.size() == factors.size());
6935
6936 int i = 0;
6937 for (const BMVert *vert : verts) {
6938 const float dot = math::dot(view_normal, float3(vert->no));
6939 factors[i] *= std::max(dot, 0.0f);
6940 i++;
6941 }
6942}
6943
6944void calc_front_face(const float3 &view_normal,
6945 const Set<BMFace *, 0> &faces,
6946 const MutableSpan<float> factors)
6947{
6948 BLI_assert(faces.size() == factors.size());
6949
6950 int i = 0;
6951 for (const BMFace *face : faces) {
6952 const float dot = math::dot(view_normal, float3(face->no));
6953 factors[i] *= std::max(dot, 0.0f);
6954 i++;
6955 }
6956}
6957
6959 const Span<float3> positions,
6960 const Span<int> verts,
6961 const MutableSpan<float> factors)
6962{
6963 BLI_assert(verts.size() == factors.size());
6964
6965 const RegionView3D *rv3d = ss.cache ? ss.cache->vc->rv3d : ss.rv3d;
6966 const View3D *v3d = ss.cache ? ss.cache->vc->v3d : ss.v3d;
6967 if (!RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
6968 return;
6969 }
6970
6971 const ePaintSymmetryFlags mirror_symmetry_pass = ss.cache ? ss.cache->mirror_symmetry_pass :
6973 const int radial_symmetry_pass = ss.cache ? ss.cache->radial_symmetry_pass : 0;
6974 const float4x4 symm_rot_mat_inv = ss.cache ? ss.cache->symm_rot_mat_inv : float4x4::identity();
6975 for (const int i : verts.index_range()) {
6976 float3 symm_co = symmetry_flip(positions[verts[i]], mirror_symmetry_pass);
6977 if (radial_symmetry_pass) {
6978 symm_co = math::transform_point(symm_rot_mat_inv, symm_co);
6979 }
6980 if (ED_view3d_clipping_test(rv3d, symm_co, true)) {
6981 factors[i] = 0.0f;
6982 }
6983 }
6984}
6985
6987 const Span<float3> positions,
6988 const MutableSpan<float> factors)
6989{
6990 BLI_assert(positions.size() == factors.size());
6991
6992 const RegionView3D *rv3d = ss.cache ? ss.cache->vc->rv3d : ss.rv3d;
6993 const View3D *v3d = ss.cache ? ss.cache->vc->v3d : ss.v3d;
6994 if (!RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
6995 return;
6996 }
6997
6998 const ePaintSymmetryFlags mirror_symmetry_pass = ss.cache ? ss.cache->mirror_symmetry_pass :
7000 const int radial_symmetry_pass = ss.cache ? ss.cache->radial_symmetry_pass : 0;
7001 const float4x4 symm_rot_mat_inv = ss.cache ? ss.cache->symm_rot_mat_inv : float4x4::identity();
7002 for (const int i : positions.index_range()) {
7003 float3 symm_co = symmetry_flip(positions[i], mirror_symmetry_pass);
7004 if (radial_symmetry_pass) {
7005 symm_co = math::transform_point(symm_rot_mat_inv, symm_co);
7006 }
7007 if (ED_view3d_clipping_test(rv3d, symm_co, true)) {
7008 factors[i] = 0.0f;
7009 }
7010 }
7011}
7012
7014 const Span<float3> positions,
7015 const Span<int> verts,
7016 const eBrushFalloffShape falloff_shape,
7017 const MutableSpan<float> r_distances)
7018{
7019 BLI_assert(verts.size() == r_distances.size());
7020
7021 const float3 &test_location = ss.cache ? ss.cache->location_symm : ss.cursor_location;
7022 if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE && (ss.cache || ss.filter_cache)) {
7023 /* The tube falloff shape requires the cached view normal. */
7024 const float3 &view_normal = ss.cache ? ss.cache->view_normal_symm :
7026 float4 test_plane;
7027 plane_from_point_normal_v3(test_plane, test_location, view_normal);
7028 for (const int i : verts.index_range()) {
7029 float3 projected;
7030 closest_to_plane_normalized_v3(projected, test_plane, positions[verts[i]]);
7031 r_distances[i] = math::distance_squared(projected, test_location);
7032 }
7033 }
7034 else {
7035 for (const int i : verts.index_range()) {
7036 r_distances[i] = math::distance_squared(test_location, positions[verts[i]]);
7037 }
7038 }
7039}
7040
7042 const Span<float3> positions,
7043 const Span<int> verts,
7044 const eBrushFalloffShape falloff_shape,
7045 const MutableSpan<float> r_distances)
7046{
7047 calc_brush_distances_squared(ss, positions, verts, falloff_shape, r_distances);
7048 for (float &value : r_distances) {
7049 value = std::sqrt(value);
7050 }
7051}
7052
7054 const Span<float3> positions,
7055 const eBrushFalloffShape falloff_shape,
7056 const MutableSpan<float> r_distances)
7057{
7058 BLI_assert(positions.size() == r_distances.size());
7059
7060 const float3 &test_location = ss.cache ? ss.cache->location_symm : ss.cursor_location;
7061 if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE && (ss.cache || ss.filter_cache)) {
7062 /* The tube falloff shape requires the cached view normal. */
7063 const float3 &view_normal = ss.cache ? ss.cache->view_normal_symm :
7065 float4 test_plane;
7066 plane_from_point_normal_v3(test_plane, test_location, view_normal);
7067 for (const int i : positions.index_range()) {
7068 float3 projected;
7069 closest_to_plane_normalized_v3(projected, test_plane, positions[i]);
7070 r_distances[i] = math::distance_squared(projected, test_location);
7071 }
7072 }
7073 else {
7074 for (const int i : positions.index_range()) {
7075 r_distances[i] = math::distance_squared(test_location, positions[i]);
7076 }
7077 }
7078}
7079
7081 const Span<float3> positions,
7082 const eBrushFalloffShape falloff_shape,
7083 const MutableSpan<float> r_distances)
7084{
7085 calc_brush_distances_squared(ss, positions, falloff_shape, r_distances);
7086 for (float &value : r_distances) {
7087 value = std::sqrt(value);
7088 }
7089}
7090
7091void filter_distances_with_radius(const float radius,
7092 const Span<float> distances,
7093 const MutableSpan<float> factors)
7094{
7095 for (const int i : distances.index_range()) {
7096 if (distances[i] >= radius) {
7097 factors[i] = 0.0f;
7098 }
7099 }
7100}
7101
7102template<typename T>
7104 const Span<T> positions,
7105 const MutableSpan<float> r_distances)
7106{
7107 BLI_assert(r_distances.size() == positions.size());
7108
7109 const float roundness = brush.tip_roundness;
7110 const float roundness_rcp = math::safe_rcp(roundness);
7111 const float hardness = 1.0f - roundness;
7112
7113 for (const int i : positions.index_range()) {
7114 const T local = math::abs(positions[i]);
7115
7116 if (math::reduce_max(local) > 1.0f) {
7117 r_distances[i] = 1.0f;
7118 continue;
7119 }
7120 if (std::min(local.x, local.y) > hardness) {
7121 /* Corner, distance to the center of the corner circle. */
7122 r_distances[i] = math::distance(float2(hardness), float2(local)) * roundness_rcp;
7123 continue;
7124 }
7125 if (std::max(local.x, local.y) > hardness) {
7126 /* Side, distance to the square XY axis. */
7127 r_distances[i] = (std::max(local.x, local.y) - hardness) * roundness_rcp;
7128 continue;
7129 }
7130
7131 /* Inside the square, constant distance. */
7132 r_distances[i] = 0.0f;
7133 }
7134}
7135template void calc_brush_cube_distances<float2>(const Brush &brush,
7136 const Span<float2> positions,
7137 MutableSpan<float> r_distances);
7138template void calc_brush_cube_distances<float3>(const Brush &brush,
7139 const Span<float3> positions,
7140 MutableSpan<float> r_distances);
7141
7142void apply_hardness_to_distances(const float radius,
7143 const float hardness,
7144 const MutableSpan<float> distances)
7145{
7146 if (hardness == 0.0f) {
7147 return;
7148 }
7149 const float threshold = hardness * radius;
7150 if (hardness == 1.0f) {
7151 for (const int i : distances.index_range()) {
7152 distances[i] = distances[i] < threshold ? 0.0f : radius;
7153 }
7154 return;
7155 }
7156 const float radius_inv = math::rcp(radius);
7157 const float hardness_inv_rcp = math::rcp(1.0f - hardness);
7158 for (const int i : distances.index_range()) {
7159 if (distances[i] < threshold) {
7160 distances[i] = 0.0f;
7161 }
7162 else {
7163 const float radius_factor = (distances[i] * radius_inv - hardness) * hardness_inv_rcp;
7164 distances[i] = radius_factor * radius;
7165 }
7166 }
7167}
7168
7170 const Brush &brush,
7171 const Span<float> distances,
7172 const MutableSpan<float> factors)
7173{
7175 eBrushCurvePreset(brush.curve_preset), brush.curve, distances, cache.radius, factors);
7176}
7177
7179 const Brush &brush,
7180 const Span<float3> vert_positions,
7181 const Span<int> verts,
7182 const MutableSpan<float> factors)
7183{
7184 BLI_assert(verts.size() == factors.size());
7185
7186 const int thread_id = BLI_task_parallel_thread_id(nullptr);
7187 const MTex *mtex = BKE_brush_mask_texture_get(&brush, OB_MODE_SCULPT);
7188 if (!mtex->tex) {
7189 return;
7190 }
7191
7192 for (const int i : verts.index_range()) {
7193 if (factors[i] == 0.0f) {
7194 continue;
7195 }
7196 float texture_value;
7197 float4 texture_rgba;
7198 /* NOTE: This is not a thread-safe call. */
7200 ss, brush, vert_positions[verts[i]], thread_id, &texture_value, texture_rgba);
7201
7202 factors[i] *= texture_value;
7203 }
7204}
7205
7207 const Brush &brush,
7208 const Span<float3> positions,
7209 const MutableSpan<float> factors)
7210{
7211 BLI_assert(positions.size() == factors.size());
7212
7213 const int thread_id = BLI_task_parallel_thread_id(nullptr);
7214 const MTex *mtex = BKE_brush_mask_texture_get(&brush, OB_MODE_SCULPT);
7215 if (!mtex->tex) {
7216 return;
7217 }
7218
7219 for (const int i : positions.index_range()) {
7220 if (factors[i] == 0.0f) {
7221 continue;
7222 }
7223 float texture_value;
7224 float4 texture_rgba;
7225 /* NOTE: This is not a thread-safe call. */
7226 sculpt_apply_texture(ss, brush, positions[i], thread_id, &texture_value, texture_rgba);
7227
7228 factors[i] *= texture_value;
7229 }
7230}
7231
7233 const Span<float3> positions,
7234 const Span<float3> orig_positions)
7235{
7236 BLI_assert(translations.size() == orig_positions.size());
7237 BLI_assert(translations.size() == positions.size());
7238 for (const int i : translations.index_range()) {
7239 const float3 prev_translation = positions[i] - orig_positions[i];
7240 translations[i] -= prev_translation;
7241 }
7242}
7243
7244#ifndef NDEBUG
7245static bool contains_nan(const Span<float> values)
7246{
7247 return std::any_of(values.begin(), values.end(), [&](const float v) { return std::isnan(v); });
7248}
7249#endif
7250
7251void apply_translations(const Span<float3> translations,
7252 const Span<int> verts,
7253 const MutableSpan<float3> positions)
7254{
7255 BLI_assert(verts.size() == translations.size());
7256 BLI_assert(!contains_nan(translations.cast<float>()));
7257
7258 for (const int i : verts.index_range()) {
7259 const int vert = verts[i];
7260 positions[vert] += translations[i];
7261 }
7262}
7263
7264void apply_translations(const Span<float3> translations,
7265 const Span<int> grids,
7266 SubdivCCG &subdiv_ccg)
7267{
7268 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
7269 MutableSpan<float3> positions = subdiv_ccg.positions;
7270 BLI_assert(grids.size() * key.grid_area == translations.size());
7271 BLI_assert(!contains_nan(translations.cast<float>()));
7272
7273 for (const int i : grids.index_range()) {
7274 const Span<float3> grid_translations = translations.slice(bke::ccg::grid_range(key, i));
7275 MutableSpan<float3> grid_positions = positions.slice(bke::ccg::grid_range(key, grids[i]));
7276 for (const int offset : grid_positions.index_range()) {
7277 grid_positions[offset] += grid_translations[offset];
7278 }
7279 }
7280}
7281
7283{
7284 BLI_assert(verts.size() == translations.size());
7285 BLI_assert(!contains_nan(translations.cast<float>()));
7286
7287 int i = 0;
7288 for (BMVert *vert : verts) {
7289 add_v3_v3(vert->co, translations[i]);
7290 i++;
7291 }
7292}
7293
7294void project_translations(const MutableSpan<float3> translations, const float3 &plane)
7295{
7296 /* Equivalent to #project_plane_v3_v3v3. */
7297 const float len_sq = math::length_squared(plane);
7298 if (len_sq < std::numeric_limits<float>::epsilon()) {
7299 return;
7300 }
7301 const float dot_factor = -math::rcp(len_sq);
7302 for (const int i : translations.index_range()) {
7303 translations[i] += plane * math::dot(translations[i], plane) * dot_factor;
7304 }
7305}
7306
7308 const Span<int> verts,
7309 const MutableSpan<float3> translations)
7310{
7311 BLI_assert(verts.size() == translations.size());
7312
7313 for (const int i : verts.index_range()) {
7314 translations[i] = math::transform_point(deform_imats[verts[i]], translations[i]);
7315 }
7316}
7317
7319 const SculptSession &ss,
7320 const Span<float3> positions,
7321 const Span<int> verts,
7322 const MutableSpan<float3> translations)
7323{
7324 BLI_assert(verts.size() == translations.size());
7325
7326 const StrokeCache *cache = ss.cache;
7327 if (!cache) {
7328 return;
7329 }
7330 for (const int axis : IndexRange(3)) {
7331 if (sd.flags & (SCULPT_LOCK_X << axis)) {
7332 for (float3 &translation : translations) {
7333 translation[axis] = 0.0f;
7334 }
7335 continue;
7336 }
7337
7338 if (!(cache->mirror_modifier_clip.flag & (uint8_t(StrokeFlags::ClipX) << axis))) {
7339 continue;
7340 }
7341
7342 const float4x4 mirror(cache->mirror_modifier_clip.mat);
7343 const float4x4 mirror_inverse(cache->mirror_modifier_clip.mat_inv);
7344 for (const int i : verts.index_range()) {
7345 const int vert = verts[i];
7346
7347 /* Transform into the space of the mirror plane, check translations, then transform back. */
7348 float3 co_mirror = math::transform_point(mirror, positions[vert]);
7349 if (math::abs(co_mirror[axis]) > cache->mirror_modifier_clip.tolerance[axis]) {
7350 continue;
7351 }
7352 /* Clear the translation in the local space of the mirror object. */
7353 co_mirror[axis] = 0.0f;
7354 const float3 co_local = math::transform_point(mirror_inverse, co_mirror);
7355 translations[i][axis] = co_local[axis] - positions[vert][axis];
7356 }
7357 }
7358}
7359
7361 const SculptSession &ss,
7362 const Span<float3> positions,
7363 const MutableSpan<float3> translations)
7364{
7365 BLI_assert(positions.size() == translations.size());
7366
7367 const StrokeCache *cache = ss.cache;
7368 if (!cache) {
7369 return;
7370 }
7371 for (const int axis : IndexRange(3)) {
7372 if (sd.flags & (SCULPT_LOCK_X << axis)) {
7373 for (float3 &translation : translations) {
7374 translation[axis] = 0.0f;
7375 }
7376 continue;
7377 }
7378
7379 if (!(cache->mirror_modifier_clip.flag & (uint8_t(StrokeFlags::ClipX) << axis))) {
7380 continue;
7381 }
7382
7383 const float4x4 mirror(cache->mirror_modifier_clip.mat);
7384 const float4x4 mirror_inverse(cache->mirror_modifier_clip.mat_inv);
7385 for (const int i : positions.index_range()) {
7386 /* Transform into the space of the mirror plane, check translations, then transform back. */
7387 float3 co_mirror = math::transform_point(mirror, positions[i]);
7388 if (math::abs(co_mirror[axis]) > cache->mirror_modifier_clip.tolerance[axis]) {
7389 continue;
7390 }
7391 /* Clear the translation in the local space of the mirror object. */
7392 co_mirror[axis] = 0.0f;
7393 const float3 co_local = math::transform_point(mirror_inverse, co_mirror);
7394 translations[i][axis] = co_local[axis] - positions[i][axis];
7395 }
7396 }
7397}
7398
7399std::optional<ShapeKeyData> ShapeKeyData::from_object(Object &object)
7400{
7401 Mesh &mesh = *static_cast<Mesh *>(object.data);
7402 Key *keys = mesh.key;
7403 if (!keys) {
7404 return std::nullopt;
7405 }
7406 const int active_index = object.shapenr - 1;
7407 const KeyBlock *active_key = BKE_keyblock_find_by_index(keys, active_index);
7408 if (!active_key) {
7409 return std::nullopt;
7410 }
7412 data.active_key_data = {static_cast<float3 *>(active_key->data), active_key->totelem};
7413 data.basis_key_active = active_key == keys->refkey;
7414 if (const std::optional<Array<bool>> dependent = BKE_keyblock_get_dependent_keys(keys,
7415 active_index))
7416 {
7417 int i;
7418 LISTBASE_FOREACH_INDEX (KeyBlock *, other_key, &keys->block, i) {
7419 if ((other_key != active_key) && (*dependent)[i]) {
7420 data.dependent_keys.append({static_cast<float3 *>(other_key->data), other_key->totelem});
7421 }
7422 }
7423 }
7424 return data;
7425}
7426
7428{
7429 Mesh &mesh = *static_cast<Mesh *>(object_orig.data);
7430 this->eval = bke::pbvh::vert_positions_eval(depsgraph, object_orig);
7431
7432 if (!object_orig.sculpt->deform_imats.is_empty()) {
7433 deform_imats_ = object_orig.sculpt->deform_imats;
7434 }
7435 orig_ = mesh.vert_positions_for_write();
7436
7438 if (eval_mut.data() != orig_.data()) {
7439 eval_mut_ = eval_mut;
7440 }
7441
7442 shape_key_data_ = ShapeKeyData::from_object(object_orig);
7443}
7444
7446{
7447 if (eval_mut_) {
7448 /* Apply translations to the evaluated mesh. This is necessary because multiple brush
7449 * evaluations can happen in between object reevaluations (otherwise just deforming the
7450 * original positions would be enough). */
7451 apply_translations(translations, verts, *eval_mut_);
7452 }
7453
7454 if (deform_imats_) {
7455 /* Apply the reverse procedural deformation, since subsequent translation happens to the state
7456 * from "before" deforming modifiers. */
7457 apply_crazyspace_to_translations(*deform_imats_, verts, translations);
7458 }
7459
7460 if (shape_key_data_) {
7461 if (!shape_key_data_->dependent_keys.is_empty()) {
7462 for (MutableSpan<float3> data : shape_key_data_->dependent_keys) {
7463 apply_translations(translations, verts, data);
7464 }
7465 }
7466
7467 if (shape_key_data_->basis_key_active) {
7468 /* The basis key positions and the mesh positions are always kept in sync. */
7469 apply_translations(translations, verts, orig_);
7470 }
7471 apply_translations(translations, verts, shape_key_data_->active_key_data);
7472 }
7473 else {
7474 apply_translations(translations, verts, orig_);
7475 }
7476}
7477
7478void filter_translations(const MutableSpan<float3> translations, const Span<float> factors)
7479{
7480 for (const int i : translations.index_range()) {
7481 if (factors[i] == 0.0f) {
7482 translations[i] = float3(0.0f);
7483 }
7484 }
7485}
7486
7487void scale_translations(const MutableSpan<float3> translations, const Span<float> factors)
7488{
7489 for (const int i : translations.index_range()) {
7490 translations[i] *= factors[i];
7491 }
7492}
7493
7494void scale_translations(const MutableSpan<float3> translations, const float factor)
7495{
7496 if (factor == 1.0f) {
7497 return;
7498 }
7499 for (const int i : translations.index_range()) {
7500 translations[i] *= factor;
7501 }
7502}
7503
7504void scale_factors(const MutableSpan<float> factors, const float strength)
7505{
7506 if (strength == 1.0f) {
7507 return;
7508 }
7509 for (float &factor : factors) {
7510 factor *= strength;
7511 }
7512}
7513
7514void scale_factors(const MutableSpan<float> factors, const Span<float> strengths)
7515{
7516 BLI_assert(factors.size() == strengths.size());
7517
7518 for (const int i : factors.index_range()) {
7519 factors[i] *= strengths[i];
7520 }
7521}
7522
7524 const Span<float> factors,
7525 const MutableSpan<float3> r_translations)
7526{
7527 BLI_assert(r_translations.size() == factors.size());
7528
7529 for (const int i : factors.index_range()) {
7530 r_translations[i] = offset * factors[i];
7531 }
7532}
7533
7535 const Span<int> verts,
7536 const Span<float3> old_positions,
7537 const MutableSpan<float3> translations)
7538{
7539 BLI_assert(new_positions.size() == verts.size());
7540 for (const int i : verts.index_range()) {
7541 translations[i] = new_positions[i] - old_positions[verts[i]];
7542 }
7543}
7544
7546 const Span<float3> old_positions,
7547 const MutableSpan<float3> translations)
7548{
7549 BLI_assert(new_positions.size() == old_positions.size());
7550 for (const int i : new_positions.index_range()) {
7551 translations[i] = new_positions[i] - old_positions[i];
7552 }
7553}
7554
7556 const float4x4 &transform,
7557 const MutableSpan<float3> dst)
7558{
7559 BLI_assert(src.size() == dst.size());
7560
7561 for (const int i : src.index_range()) {
7562 dst[i] = math::transform_point(transform, src[i]);
7563 }
7564}
7565
7567{
7568 for (const int i : positions.index_range()) {
7569 positions[i] = math::transform_point(transform, positions[i]);
7570 }
7571}
7572
7574 const IndexMask &node_mask,
7575 Array<int> &node_data)
7576{
7577 node_data.reinitialize(node_mask.size() + 1);
7578 node_mask.foreach_index(
7579 [&](const int i, const int pos) { node_data[pos] = nodes[i].verts().size(); });
7581}
7582
7585 const IndexMask &node_mask,
7586 Array<int> &node_data)
7587{
7588 node_data.reinitialize(node_mask.size() + 1);
7589 node_mask.foreach_index([&](const int i, const int pos) {
7590 node_data[pos] = nodes[i].grids().size() * key.grid_area;
7591 });
7593}
7594
7596 const IndexMask &node_mask,
7597 Array<int> &node_data)
7598{
7599 node_data.reinitialize(node_mask.size() + 1);
7600 node_mask.foreach_index([&](const int i, const int pos) {
7601 node_data[pos] =
7603 });
7605}
7606
7608 const Span<int> corner_verts,
7609 const GroupedSpan<int> vert_to_face,
7610 const Span<bool> hide_poly,
7611 const Span<int> verts,
7612 Vector<int> &r_offset_data,
7613 Vector<int> &r_data)
7614{
7615 BLI_assert(corner_verts.size() == faces.total_size());
7616 r_offset_data.resize(verts.size() + 1);
7617 r_data.clear();
7618 for (const int i : verts.index_range()) {
7619 r_offset_data[i] = r_data.size();
7620 append_neighbors_to_vector(faces, corner_verts, vert_to_face, hide_poly, verts[i], r_data);
7621 }
7622 r_offset_data.last() = r_data.size();
7623 return GroupedSpan<int>(r_offset_data.as_span(), r_data.as_span());
7624}
7625
7627 const Span<int> grids,
7628 Vector<int> &r_offset_data,
7629 Vector<int> &r_data)
7630{
7631 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
7632 SubdivCCGNeighbors neighbors;
7633
7634 r_offset_data.resize(key.grid_area * grids.size() + 1);
7635 r_data.clear();
7636
7637 for (const int i : grids.index_range()) {
7638 const int grid = grids[i];
7639 const int node_verts_start = i * key.grid_area;
7640 r_offset_data[node_verts_start] = r_data.size();
7641
7642 for (const short y : IndexRange(key.grid_size)) {
7643 for (const short x : IndexRange(key.grid_size)) {
7644 SubdivCCGCoord coord{};
7645 coord.grid_index = grid;
7646 coord.x = x;
7647 coord.y = y;
7648 BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, coord, false, neighbors);
7649 for (const SubdivCCGCoord neighbor : neighbors.coords) {
7650 r_data.append(neighbor.to_index(key));
7651 }
7652 }
7653 }
7654 }
7655 return GroupedSpan<int>(r_offset_data.as_span(), r_data.as_span());
7656}
7657
7659 Vector<int> &r_offset_data,
7660 Vector<BMVert *> &r_data)
7661{
7662 r_offset_data.resize(verts.size() + 1);
7663 r_data.clear();
7664
7665 BMeshNeighborVerts neighbor_data;
7666 int i = 0;
7667 for (BMVert *vert : verts) {
7668 r_offset_data[i] = r_data.size();
7669 r_data.extend(vert_neighbors_get_bmesh(*vert, neighbor_data));
7670 i++;
7671 }
7672 r_offset_data.last() = r_data.size();
7673 return GroupedSpan<BMVert *>(r_offset_data.as_span(), r_data.as_span());
7674}
7675
7676template<bool use_factors>
7678 const Span<int> corner_verts,
7679 const GroupedSpan<int> vert_to_face,
7680 const BitSpan boundary_verts,
7681 const Span<bool> hide_poly,
7682 const Span<int> verts,
7683 const Span<float> factors,
7684 Vector<int> &r_offset_data,
7685 Vector<int> &r_data)
7686{
7687 BLI_assert(corner_verts.size() == faces.total_size());
7688 if constexpr (use_factors) {
7689 BLI_assert(verts.size() == factors.size());
7690 }
7691
7692 r_offset_data.resize(verts.size() + 1);
7693 r_data.clear();
7694
7695 for (const int i : verts.index_range()) {
7696 const int vert = verts[i];
7697 const int vert_start = r_data.size();
7698 r_offset_data[i] = vert_start;
7699 if constexpr (use_factors) {
7700 if (factors[i] == 0.0f) {
7701 continue;
7702 }
7703 }
7704 append_neighbors_to_vector(faces, corner_verts, vert_to_face, hide_poly, vert, r_data);
7705
7706 if (boundary_verts[vert]) {
7707 /* Do not include neighbors of corner vertices. */
7708 if (r_data.size() == vert_start + 2) {
7709 r_data.resize(vert_start);
7710 }
7711 else {
7712 /* Only include other boundary vertices as neighbors of boundary vertices. */
7713 for (int neighbor_i = r_data.size() - 1; neighbor_i >= vert_start; neighbor_i--) {
7714 if (!boundary_verts[r_data[neighbor_i]]) {
7715 r_data.remove_and_reorder(neighbor_i);
7716 }
7717 }
7718 }
7719 }
7720 }
7721 r_offset_data.last() = r_data.size();
7722 return GroupedSpan<int>(r_offset_data.as_span(), r_data.as_span());
7723}
7724
7726 const Span<int> corner_verts,
7727 const GroupedSpan<int> vert_to_face,
7728 const BitSpan boundary_verts,
7729 const Span<bool> hide_poly,
7730 const Span<int> verts,
7731 const Span<float> factors,
7732 Vector<int> &r_offset_data,
7733 Vector<int> &r_data)
7734{
7736 corner_verts,
7737 vert_to_face,
7738 boundary_verts,
7739 hide_poly,
7740 verts,
7741 factors,
7742 r_offset_data,
7743 r_data);
7744}
7745
7747 const Span<int> corner_verts,
7748 const GroupedSpan<int> vert_to_face,
7749 const BitSpan boundary_verts,
7750 const Span<bool> hide_poly,
7751 const Span<int> verts,
7752 Vector<int> &r_offset_data,
7753 Vector<int> &r_data)
7754{
7756 corner_verts,
7757 vert_to_face,
7758 boundary_verts,
7759 hide_poly,
7760 verts,
7761 {},
7762 r_offset_data,
7763 r_data);
7764}
7765
7767 const Span<int> corner_verts,
7768 const BitSpan boundary_verts,
7769 const SubdivCCG &subdiv_ccg,
7770 const Span<int> grids,
7772{
7773 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
7774
7775 BLI_assert(grids.size() * key.grid_area == result.size());
7776
7777 for (const int i : grids.index_range()) {
7778 const int grid = grids[i];
7779 const int node_verts_start = i * key.grid_area;
7780
7781 /* TODO: This loop could be optimized in the future by skipping unnecessary logic for
7782 * non-boundary grid vertices. */
7783 for (const int y : IndexRange(key.grid_size)) {
7784 for (const int x : IndexRange(key.grid_size)) {
7785 const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
7786 const int node_vert_index = node_verts_start + offset;
7787
7788 SubdivCCGCoord coord{};
7789 coord.grid_index = grid;
7790 coord.x = x;
7791 coord.y = y;
7792
7793 SubdivCCGNeighbors neighbors;
7794 BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, coord, false, neighbors);
7795
7797 faces, corner_verts, boundary_verts, subdiv_ccg, coord))
7798 {
7799 if (neighbors.coords.size() == 2) {
7800 /* Do not include neighbors of corner vertices. */
7801 neighbors.coords.clear();
7802 }
7803 else {
7804 /* Only include other boundary vertices as neighbors of boundary vertices. */
7805 neighbors.coords.remove_if([&](const SubdivCCGCoord coord) {
7807 faces, corner_verts, boundary_verts, subdiv_ccg, coord);
7808 });
7809 }
7810 }
7811 result[node_vert_index] = neighbors.coords;
7812 }
7813 }
7814 }
7815}
7816
7819{
7820 BLI_assert(verts.size() == result.size());
7821 BMeshNeighborVerts neighbor_data;
7822
7823 int i = 0;
7824 for (BMVert *vert : verts) {
7825 vert_neighbors_get_interior_bmesh(*vert, neighbor_data);
7826 result[i] = neighbor_data;
7827 i++;
7828 }
7829}
7830
7832 const Span<int> verts,
7833 const float4 &plane,
7834 const MutableSpan<float3> translations)
7835{
7836 for (const int i : verts.index_range()) {
7837 const float3 &position = vert_positions[verts[i]];
7839 closest_to_plane_normalized_v3(closest, plane, position);
7840 translations[i] = closest - position;
7841 }
7842}
7843
7845 const float4 &plane,
7846 const MutableSpan<float3> translations)
7847{
7848 for (const int i : positions.index_range()) {
7849 const float3 &position = positions[i];
7851 closest_to_plane_normalized_v3(closest, plane, position);
7852 translations[i] = closest - position;
7853 }
7854}
7855
7857 const float3 &pivot,
7858 const ePaintSymmetryFlags symm,
7859 const MutableSpan<float> factors)
7860{
7861 BLI_assert(positions.size() == factors.size());
7862
7863 for (const int i : positions.index_range()) {
7864 if (!SCULPT_check_vertex_pivot_symmetry(positions[i], pivot, symm)) {
7865 factors[i] = 0.0f;
7866 }
7867 }
7868}
7869
7871 const StrokeCache &cache,
7872 const Span<float3> translations,
7873 const MutableSpan<float> factors)
7874{
7875 if (!(brush.flag & BRUSH_PLANE_TRIM)) {
7876 return;
7877 }
7878 const float threshold = cache.radius_squared * cache.plane_trim_squared;
7879 for (const int i : translations.index_range()) {
7880 if (math::length_squared(translations[i]) > threshold) {
7881 factors[i] = 0.0f;
7882 }
7883 }
7884}
7885
7887 const Span<int> verts,
7888 const float4 &plane,
7889 const MutableSpan<float> factors)
7890{
7891 for (const int i : verts.index_range()) {
7892 if (plane_point_side_v3(plane, vert_positions[verts[i]]) <= 0.0f) {
7893 factors[i] = 0.0f;
7894 }
7895 }
7896}
7897
7899 const float4 &plane,
7900 const MutableSpan<float> factors)
7901{
7902 for (const int i : positions.index_range()) {
7903 if (plane_point_side_v3(plane, positions[i]) <= 0.0f) {
7904 factors[i] = 0.0f;
7905 }
7906 }
7907}
7908
7910 const Span<int> verts,
7911 const float4 &plane,
7912 const MutableSpan<float> factors)
7913{
7914 for (const int i : verts.index_range()) {
7915 if (plane_point_side_v3(plane, vert_positions[verts[i]]) > 0.0f) {
7916 factors[i] = 0.0f;
7917 }
7918 }
7919}
7920
7922 const float4 &plane,
7923 const MutableSpan<float> factors)
7924{
7925 for (const int i : positions.index_range()) {
7926 if (plane_point_side_v3(plane, positions[i]) > 0.0f) {
7927 factors[i] = 0.0f;
7928 }
7929 }
7930}
7931
7932} // namespace blender::ed::sculpt_paint
bool BKE_brush_use_alpha_pressure(const Brush *brush)
Definition brush.cc:1231
float BKE_brush_unprojected_radius_get(const Scene *scene, const Brush *brush)
Definition brush.cc:1249
int BKE_brush_size_get(const Scene *scene, const Brush *brush)
Definition brush.cc:1210
void BKE_brush_unprojected_radius_set(Scene *scene, Brush *brush, float unprojected_radius)
Definition brush.cc:1236
void BKE_brush_size_set(Scene *scene, Brush *brush, int size)
Definition brush.cc:1194
float BKE_brush_sample_tex_3d(const Scene *scene, const Brush *br, const MTex *mtex, const float point[3], float rgba[4], int thread, ImagePool *pool)
Definition brush.cc:877
bool BKE_brush_use_size_pressure(const Brush *brush)
Definition brush.cc:1226
bool BKE_brush_has_cube_tip(const Brush *brush, PaintMode paint_mode)
Definition brush.cc:1636
const std::optional< BrushColorJitterSettings > BKE_brush_color_jitter_get_settings(const Scene *scene, const Paint *paint, const Brush *brush)
Definition brush.cc:1137
float BKE_brush_alpha_get(const Scene *scene, const Brush *brush)
Definition brush.cc:1269
bool BKE_brush_use_locked_size(const Scene *scene, const Brush *brush)
Definition brush.cc:1218
void BKE_brush_calc_curve_factors(eBrushCurvePreset preset, const CurveMapping *cumap, blender::Span< float > distances, float brush_radius, blender::MutableSpan< float > factors)
Definition brush.cc:1381
const MTex * BKE_brush_mask_texture_get(const Brush *brush, eObjectMode object_mode)
Definition brush.cc:861
int CCG_grid_xy_to_index(const int grid_size, const int x, const int y)
Definition BKE_ccg.hh:77
void BKE_curvemapping_init(CurveMapping *cumap)
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Base * CTX_data_active_base(const bContext *C)
Main * CTX_data_main(const bContext *C)
ToolSettings * CTX_data_tool_settings(const bContext *C)
RegionView3D * CTX_wm_region_view3d(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_offset_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
int CustomData_get_layer_index(const CustomData *data, eCustomDataType type)
const void * CustomData_add_layer_named_with_data(CustomData *data, eCustomDataType type, void *layer_data, int totelem, blender::StringRef name, const blender::ImplicitSharingInfo *sharing_info)
bool CustomData_free_layer_named(CustomData *data, blender::StringRef name)
ImagePool * BKE_image_pool_new()
KeyBlock * BKE_keyblock_find_by_index(Key *key, int index)
Definition key.cc:1940
std::optional< blender::Array< bool > > BKE_keyblock_get_dependent_keys(const Key *key, int index)
Definition key.cc:2404
bool BKE_base_is_visible(const View3D *v3d, const Base *base)
void BKE_id_free(Main *bmain, void *idv)
void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob)
void BKE_mesh_copy_parameters(Mesh *me_dst, const Mesh *me_src)
Mesh * BKE_mesh_from_object(Object *ob)
void multires_stitch_grids(Object *)
Definition multires.cc:1174
void multires_mark_as_modified(Depsgraph *depsgraph, Object *object, MultiresModifiedFlags flags)
Definition multires.cc:365
General operations, lookup, etc. for blender objects.
std::optional< blender::Bounds< blender::float3 > > BKE_object_boundbox_get(const Object *ob)
bool BKE_paint_brush_set_essentials(Main *bmain, Paint *paint, const char *name)
Definition paint.cc:1089
std::variant< std::monostate, int, BMVert * > ActiveVert
Definition BKE_paint.hh:380
#define PAINT_SYMM_AREA_DEFAULT
Definition BKE_paint.hh:134
bool BKE_paint_brush_set(Paint *paint, Brush *brush)
Definition paint.cc:701
bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const RegionView3D *rv3d)
Definition paint.cc:2928
ePaintSymmetryAreas
Definition BKE_paint.hh:136
@ PAINT_SYMM_AREA_Z
Definition BKE_paint.hh:139
@ PAINT_SYMM_AREA_X
Definition BKE_paint.hh:137
@ PAINT_SYMM_AREA_Y
Definition BKE_paint.hh:138
blender::float3 seed_hsv_jitter()
#define SCULPT_FACE_SET_NONE
Definition BKE_paint.hh:344
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:641
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_color_layer_create_if_needed(Object *object)
Definition paint.cc:2633
Paint * BKE_paint_get_active_from_context(const bContext *C)
Definition paint.cc:467
void BKE_sculptsession_free_pbvh(Object &object)
Definition paint.cc:2146
Brush * BKE_paint_brush(Paint *paint)
Definition paint.cc:636
void BKE_sculpt_mask_layers_ensure(Depsgraph *depsgraph, Main *bmain, Object *ob, MultiresModifierData *mmd)
Definition paint.cc:2666
A BVH for high poly meshes.
bool BKE_pbvh_node_fully_hidden_get(const blender::bke::pbvh::Node &node)
Definition pbvh.cc:1539
void BKE_pbvh_node_mark_topology_update(blender::bke::pbvh::Node &node)
int BKE_pbvh_get_grid_num_verts(const Object &object)
Definition pbvh.cc:1491
float BKE_pbvh_node_get_tmin(const blender::bke::pbvh::Node *node)
Definition pbvh.cc:773
bool BKE_pbvh_node_fully_masked_get(const blender::bke::pbvh::Node &node)
Definition pbvh.cc:1557
void BKE_pbvh_bmesh_after_stroke(BMesh &bm, blender::bke::pbvh::Tree &pbvh)
const blender::Set< BMFace *, 0 > & BKE_pbvh_bmesh_node_faces(blender::bke::pbvh::BMeshNode *node)
PBVHTopologyUpdateMode
@ PBVH_Collapse
@ PBVH_Subdivide
const blender::Set< BMVert *, 0 > & BKE_pbvh_bmesh_node_unique_verts(blender::bke::pbvh::BMeshNode *node)
void BKE_pbvh_bmesh_node_save_orig(BMesh *bm, BMLog *log, blender::bke::pbvh::BMeshNode *node, bool use_original)
void BKE_pbvh_node_get_bm_orco_data(const blender::bke::pbvh::BMeshNode &node, blender::Span< blender::float3 > &r_orig_positions, blender::Span< blender::int3 > &r_orig_tris)
Definition pbvh.cc:1602
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
bool BKE_subdiv_ccg_coord_is_mesh_boundary(blender::OffsetIndices< int > faces, blender::Span< int > corner_verts, blender::BitSpan boundary_verts, const SubdivCCG &subdiv_ccg, SubdivCCGCoord coord)
int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG &subdiv_ccg, const int grid_index)
CCGKey BKE_subdiv_ccg_key_top_level(const SubdivCCG &subdiv_ccg)
SubdivCCGAdjacencyType
@ SUBDIV_CCG_ADJACENT_EDGE
@ SUBDIV_CCG_ADJACENT_VERTEX
@ SUBDIV_CCG_ADJACENT_NONE
void BKE_subdiv_ccg_foreach_visible_grid_vert(const CCGKey &key, const blender::BitGroupVector<> &grid_hidden, const int grid, const Fn &fn)
SubdivCCGAdjacencyType BKE_subdiv_ccg_coarse_mesh_adjacency_info_get(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord, blender::Span< int > corner_verts, blender::OffsetIndices< int > faces, int &r_v1, int &r_v2)
void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord, bool include_duplicates, SubdivCCGNeighbors &r_neighbors)
@ MULTIRES_COORDS_MODIFIED
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
void BLI_dial_free(Dial *dial)
Dial * BLI_dial_init(const float start_position[2], float threshold)
float BLI_dial_angle(Dial *dial, const float current_position[2])
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
MINLINE float max_ff(float a, float b)
MINLINE float pow2f(float x)
MINLINE float square_f(float a)
MINLINE float pow3f(float x)
MINLINE float pow4f(float x)
#define M_SQRT2
#define M_PI_2
#define M_PI
void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3])
Definition math_geom.cc:217
void isect_ray_tri_watertight_v3_precalc(struct IsectRayPrecalc *isect_precalc, const float ray_direction[3])
struct DistRayAABB_Precalc dist_squared_ray_to_aabb_v3_precalc(const float ray_origin[3], const float ray_direction[3])
Definition math_geom.cc:685
MINLINE float plane_point_side_v3(const float plane[4], const float co[3])
void closest_to_plane_normalized_v3(float r_close[3], const float plane[4], const float pt[3])
Definition math_geom.cc:442
void closest_on_tri_to_point_v3(float r[3], const float p[3], const float v1[3], const float v2[3], const float v3[3])
float dist_squared_ray_to_aabb_v3(const struct DistRayAABB_Precalc *data, const float bb_min[3], const float bb_max[3], float r_point[3], float *r_depth)
void mul_m3_v3(const float M[3][3], float r[3])
void zero_m4(float m[4][4])
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void mul_m4_v3(const float M[4][4], float r[3])
void scale_m4_fl(float R[4][4], float scale)
void copy_m4_m4(float m1[4][4], const float m2[4][4])
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
void rotate_m4(float mat[4][4], char axis, float angle)
void mul_mat3_m4_v3(const float mat[4][4], float r[3])
void normalize_m4(float R[4][4]) ATTR_NONNULL()
void axis_angle_to_mat3_single(float R[3][3], char axis, float angle)
void axis_angle_normalized_to_quat(float r[4], const float axis[3], float angle)
void quat_to_axis_angle(float axis[3], float *angle, const float q[4])
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_fl(float r[3], float f)
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void copy_v3_v3_int(int r[3], const int a[3])
void project_plane_v3_v3v3(float out[3], const float p[3], const float v_plane[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float normalize_v3_v3(float r[3], const float a[3])
MINLINE bool is_zero_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v3(float r[3])
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE void copy_v4_fl(float r[4], float f)
MINLINE float normalize_v3(float n[3])
int BLI_task_parallel_thread_id(const TaskParallelTLS *tls)
#define UNPACK3(a)
#define ELEM(...)
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:181
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_SHADING
Definition DNA_ID.h:1002
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:982
@ BRUSH_PLANE_SWAP_HEIGHT_AND_DEPTH
eBrushCurvePreset
@ BRUSH_AUTOMASKING_CAVITY_ALL
@ BRUSH_DEFORM_TARGET_CLOTH_SIM
eBrushSculptType
@ SCULPT_BRUSH_TYPE_DRAW_SHARP
@ SCULPT_BRUSH_TYPE_THUMB
@ SCULPT_BRUSH_TYPE_GRAB
@ SCULPT_BRUSH_TYPE_BOUNDARY
@ SCULPT_BRUSH_TYPE_DISPLACEMENT_SMEAR
@ SCULPT_BRUSH_TYPE_MASK
@ SCULPT_BRUSH_TYPE_DRAW_FACE_SETS
@ SCULPT_BRUSH_TYPE_DRAW
@ SCULPT_BRUSH_TYPE_NUDGE
@ SCULPT_BRUSH_TYPE_CLAY
@ SCULPT_BRUSH_TYPE_CLOTH
@ SCULPT_BRUSH_TYPE_PINCH
@ SCULPT_BRUSH_TYPE_SMEAR
@ SCULPT_BRUSH_TYPE_POSE
@ SCULPT_BRUSH_TYPE_CLAY_THUMB
@ SCULPT_BRUSH_TYPE_MULTIPLANE_SCRAPE
@ SCULPT_BRUSH_TYPE_SIMPLIFY
@ SCULPT_BRUSH_TYPE_SNAKE_HOOK
@ SCULPT_BRUSH_TYPE_CREASE
@ SCULPT_BRUSH_TYPE_LAYER
@ SCULPT_BRUSH_TYPE_SLIDE_RELAX
@ SCULPT_BRUSH_TYPE_ELASTIC_DEFORM
@ SCULPT_BRUSH_TYPE_SMOOTH
@ SCULPT_BRUSH_TYPE_PAINT
@ SCULPT_BRUSH_TYPE_DISPLACEMENT_ERASER
@ SCULPT_BRUSH_TYPE_PLANE
@ SCULPT_BRUSH_TYPE_INFLATE
@ SCULPT_BRUSH_TYPE_BLOB
@ SCULPT_BRUSH_TYPE_ROTATE
@ SCULPT_BRUSH_TYPE_CLAY_STRIPS
@ BRUSH_OFFSET_PRESSURE
@ BRUSH_ORIGINAL_NORMAL
@ BRUSH_FRONTFACE
@ BRUSH_DRAG_DOT
@ BRUSH_GRAB_ACTIVE_VERTEX
@ BRUSH_EDGE_TO_EDGE
@ BRUSH_ORIGINAL_PLANE
@ BRUSH_ACCUMULATE
@ BRUSH_DIR_IN
@ BRUSH_ANCHORED
@ BRUSH_PLANE_TRIM
@ BRUSH_INVERSE_SMOOTH_PRESSURE
@ BRUSH_CLOTH_DEFORM_EXPAND
@ BRUSH_CLOTH_DEFORM_GRAB
@ BRUSH_CLOTH_DEFORM_SNAKE_HOOK
@ BRUSH_SNAKE_HOOK_DEFORM_ELASTIC
eBrushFalloffShape
@ PAINT_FALLOFF_SHAPE_SPHERE
@ PAINT_FALLOFF_SHAPE_TUBE
@ BRUSH_SMOOTH_DEFORM_SURFACE
@ BRUSH_SMOOTH_DEFORM_LAPLACIAN
@ BRUSH_PAINT_WET_MIX_PRESSURE
@ BRUSH_PAINT_HARDNESS_PRESSURE
@ BRUSH_PAINT_FLOW_PRESSURE
@ BRUSH_PAINT_DENSITY_PRESSURE
@ BRUSH_PAINT_WET_PERSISTENCE_PRESSURE
@ BRUSH_PAINT_WET_MIX_PRESSURE_INVERT
@ BRUSH_PAINT_HARDNESS_PRESSURE_INVERT
@ BRUSH_PAINT_FLOW_PRESSURE_INVERT
@ BRUSH_PAINT_DENSITY_PRESSURE_INVERT
@ BRUSH_PAINT_WET_PERSISTENCE_PRESSURE_INVERT
@ BRUSH_AREA_RADIUS_PRESSURE
BrushMaskTool
@ BRUSH_MASK_DRAW
@ BRUSH_MASK_SMOOTH
@ SCULPT_DISP_DIR_VIEW
@ SCULPT_DISP_DIR_X
@ SCULPT_DISP_DIR_Z
@ SCULPT_DISP_DIR_Y
@ SCULPT_DISP_DIR_AREA
@ CD_PROP_FLOAT
@ CD_PROP_FLOAT3
@ CD_MDEFORMVERT
@ CD_PROP_INT32
@ KEYBLOCK_LOCKED_SHAPE
@ eModifierMode_Realtime
@ MOD_MIR_CLIPPING
@ MOD_MIR_AXIS_X
@ eModifierType_Mirror
@ OB_SOLID
@ OB_MODE_SCULPT
Object is a sort of wrapper for general info.
@ OB_MESH
ePaintSymmetryFlags
@ PAINT_SYMM_Y
@ PAINT_SYMMETRY_FEATHER
@ PAINT_TILE_X
@ PAINT_SYMM_X
@ PAINT_SYMM_Z
@ SCULPT_DYNTOPO_SUBDIVIDE
@ SCULPT_DYNTOPO_DETAIL_MANUAL
@ SCULPT_LOCK_X
@ SCULPT_DYNTOPO_DETAIL_CONSTANT
@ SCULPT_DYNTOPO_COLLAPSE
@ SCULPT_DYNTOPO_DETAIL_BRUSH
@ RGN_TYPE_WINDOW
@ SPACE_IMAGE
@ SPACE_VIEW3D
@ MTEX_MAP_MODE_AREA
@ MTEX_MAP_MODE_3D
@ TEX_NOISE
#define USER_EXPERIMENTAL_TEST(userdef, member)
@ V3D_SHADING_VERTEX_COLOR
#define RV3D_CLIPPING_ENABLED(v3d, rv3d)
@ RV3D_PAINTING
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
#define OPERATOR_RETVAL_CHECK(ret)
void ED_image_undo_push_begin(const char *name, PaintMode paint_mode)
void ED_image_undo_push_end()
void ED_image_paint_brush_type_update_sticky_shading_color(bContext *C, Object *ob)
void ED_area_tag_redraw_regiontype(ScrArea *area, int regiontype)
Definition area.cc:732
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:639
blender::float2 ED_view3d_project_float_v2_m4(const ARegion *region, const float co[3], const blender::float4x4 &mat)
void ED_view3d_win_to_3d(const View3D *v3d, const ARegion *region, const float depth_pt[3], const float mval[2], float r_out[3])
void ED_view3d_init_mats_rv3d(const Object *ob, RegionView3D *rv3d)
ViewContext ED_view3d_viewcontext_init(bContext *C, Depsgraph *depsgraph)
void ED_view3d_win_to_delta(const ARegion *region, const float xy_delta[2], float zfac, float r_out[3])
blender::float4x4 ED_view3d_ob_project_mat_get(const RegionView3D *rv3d, const Object *ob)
bool ED_view3d_win_to_segment_clipped(const Depsgraph *depsgraph, const ARegion *region, const View3D *v3d, const float mval[2], float r_ray_start[3], float r_ray_end[3], bool do_clip_planes)
void ED_view3d_win_to_origin(const ARegion *region, const float mval[2], float r_out[3])
float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3])
void view3d_operator_needs_gpu(const bContext *C)
bool ED_view3d_clipping_test(const RegionView3D *rv3d, const float co[3], bool is_local)
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
Read Guarded memory(de)allocation.
void ntreeTexEndExecTree(struct bNodeTreeExec *exec)
struct bNodeTreeExec * ntreeTexBeginExecTree(struct bNodeTree *ntree)
@ PROP_SKIP_SAVE
Definition RNA_types.hh:330
@ PROP_HIDDEN
Definition RNA_types.hh:324
#define C
Definition RandGen.cpp:29
#define ND_DRAW
Definition WM_types.hh:458
ReportList * reports
Definition WM_types.hh:1025
#define NC_OBJECT
Definition WM_types.hh:376
@ OPTYPE_BLOCKING
Definition WM_types.hh:184
#define U
#define BM_ELEM_CD_SET_FLOAT(ele, offset, f)
#define BM_ELEM_CD_GET_FLOAT(ele, offset)
@ BM_ELEM_HIDDEN
#define BM_ELEM_CD_GET_INT(ele, offset)
#define BM_elem_index_get(ele)
#define BM_elem_flag_test(ele, hflag)
#define BM_elem_flag_test_bool(ele, hflag)
#define BM_ITER_ELEM(ele, iter, data, itype)
@ BM_FACES_OF_VERT
@ BM_LOOPS_OF_VERT
BMesh const char void * data
BMesh * bm
return true
const float * BM_log_find_original_vert_mask(BMLog *log, BMVert *v)
Definition bmesh_log.cc:864
const float * BM_log_find_original_vert_co(BMLog *log, BMVert *v)
Definition bmesh_log.cc:853
int BM_mesh_elem_count(BMesh *bm, const char htype)
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
#define BM_VERT
bool BM_vert_is_boundary(const BMVert *v)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
BPy_StructRNA * depsgraph
SIMD_FORCE_INLINE void invalidate()
void init()
bool closest(btVector3 &v)
bool is_empty() const
Definition BLI_array.hh:253
AttributeSet attributes
int64_t size() const
Definition BLI_set.hh:587
void reinitialize(const int64_t new_size)
int64_t size() const
Definition BLI_array.hh:245
IndexRange index_range() const
Definition BLI_array.hh:349
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:398
int calc_reduced_ids(MutableSpan< int > result) const
const void * data() const
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
static IndexMask from_bools(Span< bool > bools, IndexMaskMemory &memory)
static IndexMask from_bools_inverse(const VArray< bool > &bools, IndexMaskMemory &memory)
constexpr IndexRange drop_front(int64_t n) const
constexpr int64_t size() const
Definition BLI_span.hh:493
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:573
constexpr T * data() const
Definition BLI_span.hh:539
constexpr void fill(const T &value) const
Definition BLI_span.hh:517
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
constexpr void copy_from(Span< T > values) const
Definition BLI_span.hh:739
Span< NewT > constexpr cast() const
Definition BLI_span.hh:418
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
constexpr const T & first() const
Definition BLI_span.hh:315
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr const T * end() const
Definition BLI_span.hh:224
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr const T * begin() const
Definition BLI_span.hh:220
constexpr bool is_empty() const
Definition BLI_span.hh:260
bool add(const Key &key)
void add_multiple(Span< Key > keys)
bool contains(const Key &key) const
Span< Key > as_span() const
int64_t size() const
void remove_and_reorder(const int64_t index)
int64_t remove_if(Predicate &&predicate)
void append(const T &value)
const T & last(const int64_t n=0) const
void resize(const int64_t new_size)
MutableSpan< T > as_mutable_span()
void extend(Span< T > array)
void append_non_duplicates(const T &value)
Span< T > as_span() const
void resize(const int64_t new_size_in_bits, const bool value=false)
GAttributeReader lookup(const StringRef attribute_id) const
GAttributeReader get() const
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
bool remove(const StringRef attribute_id)
bool add(const StringRef attribute_id, const AttrDomain domain, const eCustomDataType data_type, const AttributeInit &initializer)
const Bounds< float3 > & bounds() const
const Bounds< float3 > & bounds_orig() const
void tag_attribute_changed(const IndexMask &node_mask, StringRef attribute_name)
Definition pbvh.cc:600
void tag_positions_changed(const IndexMask &node_mask)
Definition pbvh.cc:559
Span< NodeT > nodes() const
void update_bounds(const Depsgraph &depsgraph, const Object &object)
Definition pbvh.cc:1202
void tag_face_sets_changed(const IndexMask &node_mask)
Definition pbvh.cc:586
void tag_masks_changed(const IndexMask &node_mask)
Definition pbvh.cc:593
void tag_topology_changed(const IndexMask &node_mask)
Definition pbvh.cc:579
void deform(MutableSpan< float3 > translations, Span< int > verts) const
Definition sculpt.cc:7445
PositionDeformData(const Depsgraph &depsgraph, Object &object_orig)
Definition sculpt.cc:7427
IndexMask slice(IndexRange range) const
void foreach_index(Fn &&fn) const
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
CCL_NAMESPACE_BEGIN ccl_device_inline float frac(const float x, ccl_private int *ix)
#define sinf(x)
#define cosf(x)
#define powf(x, y)
#define fabsf(x)
#define sqrtf(x)
static ushort indices[]
static float verts[][3]
static float normals[][3]
uint pos
VecBase< float, 2 > float2
VecBase< float, 4 > float4
#define in
#define out
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
#define printf(...)
float distance(VecOp< float, D >, VecOp< float, D >) RET
#define ID_REAL_USERS(id)
static void transform_positions(const Span< blender::float3 > src, const blender::float4x4 &transform, blender::MutableSpan< blender::float3 > dst)
CCL_NAMESPACE_BEGIN ccl_device float invert(const float color, const float factor)
Definition invert.h:11
#define LOG(severity)
Definition log.h:32
#define T
static char faces[256]
#define G(x, y, z)
void count_indices(Span< int > indices, MutableSpan< int > counts)
bool supports_rake_factor(const Brush &brush)
Definition brush.cc:1752
bool supports_accumulate(const Brush &brush)
Definition brush.cc:1689
bool supports_gravity(const Brush &brush)
Definition brush.cc:1851
bool supports_dyntopo(const Brush &brush)
Definition brush.cc:1665
bool supports_topology_rake(const Brush &brush)
Definition brush.cc:1704
bool supports_normal_weight(const Brush &brush)
Definition brush.cc:1745
IndexRange grid_range(const int grid_area, const int grid)
int2 face_find_adjacent_verts(const IndexRange face, const Span< int > corner_verts, const int vert)
Definition BKE_mesh.hh:322
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:2912
void raycast(Tree &pbvh, FunctionRef< void(Node &node, float *tmin)> hit_fn, const float3 &ray_start, const float3 &ray_normal, bool original)
IndexMask search_nodes(const Tree &pbvh, IndexMaskMemory &memory, FunctionRef< bool(const Node &)> filter_fn)
Definition pbvh.cc:2579
void update_normals(const Depsgraph &depsgraph, Object &object_orig, Tree &pbvh)
Definition pbvh.cc:1073
IndexMask all_leaf_nodes(const Tree &pbvh, IndexMaskMemory &memory)
Definition pbvh.cc:2544
void clip_ray_ortho(Tree &pbvh, bool original, float ray_start[3], float ray_end[3], float ray_normal[3])
Definition pbvh.cc:1998
bool node_raycast_mesh(const MeshNode &node, Span< float3 > node_positions, Span< float3 > vert_positions, OffsetIndices< int > faces, Span< int > corner_verts, Span< int3 > corner_tris, Span< bool > hide_poly, const float3 &ray_start, const float3 &ray_normal, IsectRayPrecalc *isect_precalc, float *depth, int &r_active_vertex, int &r_active_face_index, float3 &r_face_normal)
Definition pbvh.cc:1792
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
bool node_raycast_bmesh(BMeshNode &node, const float3 &ray_start, const float3 &ray_normal, const IsectRayPrecalc *isect_precalc, float *depth, bool use_original, BMVert **r_active_vertex, float3 &r_face_normal)
void node_update_mask_grids(const CCGKey &key, Span< float > masks, GridsNode &node)
Definition pbvh.cc:1265
bool node_raycast_grids(const SubdivCCG &subdiv_ccg, GridsNode &node, Span< float3 > node_positions, const float3 &ray_start, const float3 &ray_normal, const IsectRayPrecalc *isect_precalc, float *depth, SubdivCCGCoord &r_active_vertex, int &r_active_grid_index, float3 &r_face_normal)
Definition pbvh.cc:1908
Bounds< float3 > bounds_get(const Tree &pbvh)
Definition pbvh.cc:1477
Span< float3 > vert_normals_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2435
MutableSpan< float3 > vert_positions_eval_for_write(const Depsgraph &depsgraph, Object &object_orig)
Definition pbvh.cc:2429
bool bmesh_update_topology(BMesh &bm, Tree &pbvh, BMLog &bm_log, PBVHTopologyUpdateMode mode, float min_edge_len, float max_edge_len, const float3 &center, const std::optional< float3 > &view_normal, float radius, bool use_frontface, bool use_projected)
void build_pixels(const Depsgraph &depsgraph, Object &object, Image &image, ImageUser &image_user)
bool find_nearest_to_ray_node(Tree &pbvh, Node &node, Span< float3 > node_positions, bool use_origco, Span< float3 > vert_positions, const OffsetIndices< int > faces, Span< int > corner_verts, Span< int3 > corner_tris, Span< bool > hide_poly, const SubdivCCG *subdiv_ccg, const float ray_start[3], const float ray_normal[3], float *depth, float *dist_sq)
Definition pbvh.cc:2248
void store_bounds_orig(Tree &pbvh)
Definition pbvh.cc:1224
Span< int > node_face_indices_calc_grids(const SubdivCCG &subdiv_ccg, const GridsNode &node, Vector< int > &faces)
Definition pbvh.cc:1583
Span< float3 > vert_positions_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2416
void find_nearest_to_ray(Tree &pbvh, const FunctionRef< void(Node &node, float *tmin)> fn, const float3 &ray_start, const float3 &ray_normal, bool original)
Definition pbvh.cc:2110
Cache & stroke_cache_ensure(const Depsgraph &depsgraph, const Sculpt &sd, const Brush *brush, Object &ob)
void calc_vert_factors(const Depsgraph &depsgraph, const Object &object, const Cache &automasking, const bke::pbvh::MeshNode &node, Span< int > verts, MutableSpan< float > factors)
void calc_grids_factors(const Depsgraph &depsgraph, const Object &object, const Cache &automasking, const bke::pbvh::GridsNode &node, Span< int > grids, MutableSpan< float > factors)
bool is_enabled(const Sculpt &sd, const Object &object, const Brush *br)
bool vert_is_boundary(const GroupedSpan< int > vert_to_face_map, const Span< bool > hide_poly, const BitSpan boundary, const int vert)
Definition sculpt.cc:484
void do_boundary_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob, const IndexMask &node_mask)
void ensure_boundary_info(Object &object)
Definition sculpt.cc:6059
CursorSampleResult calc_node_mask(const Depsgraph &depsgraph, Object &ob, const Brush &brush, IndexMaskMemory &memory)
CursorSampleResult calc_node_mask(const Depsgraph &depsgraph, Object &ob, const Brush &brush, IndexMaskMemory &memory)
Definition plane.cc:471
void do_snake_hook_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask)
void do_smooth_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask, float brush_strength)
Definition smooth.cc:224
void do_mask_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask)
void do_draw_face_sets_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask)
void do_draw_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask)
Definition draw.cc:178
void do_displacement_eraser_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob, const IndexMask &node_mask)
void do_elastic_deform_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask)
void do_draw_vector_displacement_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask)
void do_crease_brush(const Depsgraph &depsgraph, const Scene &scene, const Sculpt &sd, Object &ob, const IndexMask &node_mask)
Definition crease.cc:266
void do_topology_relax_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask)
Definition relax.cc:794
void do_thumb_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask)
Definition thumb.cc:133
void do_clay_thumb_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob, const IndexMask &node_mask)
void do_rotate_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask)
void do_topology_slide_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask)
void do_displacement_smear_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob, const IndexMask &node_mask)
void do_clay_strips_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob, const IndexMask &node_mask, const float3 &plane_normal, const float3 &plane_center)
void do_surface_smooth_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask)
void do_plane_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask, const float3 &plane_normal, const float3 &plane_center)
Definition plane.cc:361
void do_enhance_details_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask)
void do_blob_brush(const Depsgraph &depsgraph, const Scene &scene, const Sculpt &sd, Object &ob, const IndexMask &node_mask)
Definition crease.cc:275
void do_bmesh_topology_rake_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask, const float input_strength)
void do_layer_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask)
void do_nudge_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask)
Definition draw.cc:194
void do_inflate_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob, const IndexMask &node_mask)
Definition inflate.cc:130
void do_relax_face_sets_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask)
Definition relax.cc:760
void do_draw_sharp_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask)
void do_multiplane_scrape_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask)
void do_pinch_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask)
Definition pinch.cc:172
void do_smooth_mask_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask, float brush_strength)
void do_gravity_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob, const IndexMask &node_mask)
Definition draw.cc:208
float clay_thumb_get_stabilized_pressure(const StrokeCache &cache)
void do_clay_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob, const IndexMask &node_mask)
Definition clay.cc:150
void do_grab_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob, const IndexMask &node_mask)
Definition grab.cc:164
bool is_cloth_deform_brush(const Brush &brush)
void brush_store_simulation_state(const Depsgraph &depsgraph, const Object &object, SimulationData &cloth_sim)
void ensure_nodes_constraints(const Sculpt &sd, Object &object, const IndexMask &node_mask, SimulationData &cloth_sim, const float3 &initial_location, const float radius)
void sim_activate_nodes(Object &object, SimulationData &cloth_sim, const IndexMask &node_mask)
IndexMask brush_affected_nodes_gather(const Object &object, const Brush &brush, IndexMaskMemory &memory)
void do_simulation_step(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, SimulationData &cloth_sim, const IndexMask &node_mask)
std::unique_ptr< SimulationData > brush_simulation_create(const Depsgraph &depsgraph, Object &ob, const float cloth_mass, const float cloth_damping, const float cloth_softbody_strength, const bool use_collisions, const bool needs_deform_coords)
void do_cloth_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob, const IndexMask &node_mask)
bke::GSpanAttributeWriter active_color_attribute_for_write(Mesh &mesh)
void do_smear_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob, const IndexMask &node_mask)
void color_vert_set(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face_map, bke::AttrDomain color_domain, int vert, const float4 &color, GMutableSpan color_attribute)
void do_paint_brush(const Scene &scene, const Depsgraph &depsgraph, PaintModeSettings &paint_mode_settings, const Sculpt &sd, Object &ob, const IndexMask &node_mask, const IndexMask &texnode_mask)
float relative_to_detail_size(const float relative_detail, const float brush_radius, const float pixel_radius, const float pixel_size)
float constant_to_detail_size(const float constant_detail, const Object &ob)
float brush_to_detail_size(const float brush_percent, const float brush_radius)
bool stroke_is_dyntopo(const Object &object, const Brush &brush)
Definition sculpt.cc:851
int vert_face_set_get(const GroupedSpan< int > vert_to_face_map, const Span< int > face_sets, const int vert)
Definition sculpt.cc:231
bool vert_has_unique_face_set(const GroupedSpan< int > vert_to_face_map, const Span< int > face_sets, int vert)
Definition sculpt.cc:293
bool vert_has_face_set(const GroupedSpan< int > vert_to_face_map, const Span< int > face_sets, const int vert, const int face_set)
Definition sculpt.cc:253
bke::SpanAttributeWriter< int > ensure_face_sets_mesh(Mesh &mesh)
int active_face_set_get(const Object &object)
Definition sculpt.cc:197
static bool sculpt_check_unique_face_set_for_edge_in_base_mesh(const GroupedSpan< int > vert_to_face_map, const Span< int > face_sets, const Span< int > corner_verts, const OffsetIndices< int > faces, int v1, int v2)
Definition sculpt.cc:319
bool vert_all_faces_visible_get(const Span< bool > hide_poly, const GroupedSpan< int > vert_to_face_map, const int vert)
void ensure_cache(Object &object)
Definition sculpt.cc:6303
static SculptTopologyIslandCache calc_topology_islands_grids(const Object &object)
Definition sculpt.cc:6236
static SculptTopologyIslandCache vert_disjoint_set_to_islands(const AtomicDisjointSet &vert_sets, const int verts_num)
Definition sculpt.cc:6190
static SculptTopologyIslandCache calc_topology_islands_mesh(const Mesh &mesh)
Definition sculpt.cc:6211
static SculptTopologyIslandCache calculate_cache(const Object &object)
Definition sculpt.cc:6289
static SculptTopologyIslandCache calc_topology_islands_bmesh(const Object &object)
Definition sculpt.cc:6261
int vert_id_get(const SculptSession &ss, const int vert)
Definition sculpt.cc:6170
void do_pose_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob, const IndexMask &node_mask)
void push_nodes(const Depsgraph &depsgraph, Object &object, const IndexMask &node_mask, const Type type)
static void restore_from_undo_step(const Depsgraph &depsgraph, const Sculpt &sd, Object &object)
Definition sculpt.cc:1148
static void restore_color_from_undo_step(Object &object)
Definition sculpt.cc:947
static void restore_face_set_from_undo_step(Object &object)
Definition sculpt.cc:980
void push_begin_ex(const Scene &, Object &ob, const char *name)
void restore_position_from_undo_step(const Depsgraph &depsgraph, Object &object)
Definition sculpt.cc:1032
void geometry_begin(const Scene &scene, Object &ob, const wmOperator *op)
static void restore_mask_from_undo_step(Object &object)
Definition sculpt.cc:872
void push_begin(const Scene &scene, Object &ob, const wmOperator *op)
bool stroke_get_location_bvh(bContext *C, float out[3], const float mval[2], const bool force_original)
Definition sculpt.cc:4921
void fill_factor_from_hide_and_mask(Span< bool > hide_vert, Span< float > mask, Span< int > verts, MutableSpan< float > r_factors)
Definition sculpt.cc:6809
static void calc_local_from_screen(const ViewContext &vc, const float center[3], const float screen_dir[2], float r_local_dir[3])
Definition sculpt.cc:2587
float object_space_radius_get(const ViewContext &vc, const Scene &scene, const Brush &brush, const float3 &location, const float scale_factor)
Definition sculpt.cc:115
std::optional< Span< float > > orig_mask_data_lookup_grids(const Object &object, const bke::pbvh::GridsNode &node)
static brushes::CursorSampleResult calc_brush_node_mask(const Depsgraph &depsgraph, Object &ob, const Brush &brush, IndexMaskMemory &memory)
Definition sculpt.cc:3105
static bool stroke_test_start(bContext *C, wmOperator *op, const float mouse[2])
static bool brush_needs_rake_rotation(const Brush &brush)
Definition sculpt.cc:830
MutableSpan< float3 > gather_grids_positions(const SubdivCCG &subdiv_ccg, const Span< int > grids, Vector< float3 > &positions)
static float brush_dynamic_size_get(const Brush &brush, const StrokeCache &cache, float initial_size)
Definition sculpt.cc:4067
static void fake_neighbor_search_mesh(const SculptSession &ss, const Span< float3 > vert_positions, const Span< bool > hide_vert, const float3 &location, const float max_distance_sq, const int island_id, const bke::pbvh::MeshNode &node, NearestVertData &nvtd)
Definition sculpt.cc:5825
static bool attribute_matches(const bke::AttributeAccessor a, const bke::AttributeAccessor b, const StringRef name)
Definition sculpt.cc:5223
bool node_in_sphere(const bke::pbvh::Node &node, const float3 &location, const float radius_sq, const bool original)
Definition sculpt.cc:2410
void scatter_data_bmesh(Span< T > node_data, const Set< BMVert *, 0 > &verts, MutableSpan< T > dst)
Definition sculpt.cc:6447
bool node_in_cylinder(const DistRayAABB_Precalc &ray_dist_precalc, const bke::pbvh::Node &node, const float radius_sq, const bool original)
Definition sculpt.cc:2420
void calc_factors_common_from_orig_data_grids(const Depsgraph &depsgraph, const Brush &brush, const Object &object, Span< float3 > positions, Span< float3 > normals, const bke::pbvh::GridsNode &node, Vector< float > &r_factors, Vector< float > &r_distances)
Definition sculpt.cc:6692
static void do_radial_symmetry(const Depsgraph &depsgraph, const Scene &scene, const Sculpt &sd, Object &ob, const Brush &brush, UnifiedPaintSettings &ups, PaintModeSettings &paint_mode_settings, const BrushActionFunc action, const ePaintSymmetryFlags symm, const int axis, const float)
Definition sculpt.cc:3581
void gather_bmesh_positions(const Set< BMVert *, 0 > &verts, MutableSpan< float3 > positions)
Definition sculpt.cc:6353
static void tag_mesh_positions_changed(Object &object, const bool use_pbvh_draw)
Definition sculpt.cc:5038
void calc_brush_strength_factors(const StrokeCache &cache, const Brush &brush, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:7169
std::optional< Span< int > > orig_face_set_data_lookup_mesh(const Object &object, const bke::pbvh::MeshNode &node)
void gather_data_grids(const SubdivCCG &subdiv_ccg, Span< T > src, Span< int > grids, MutableSpan< T > node_data)
Definition sculpt.cc:6391
static void redo_empty_ui(bContext *, wmOperator *)
Definition sculpt.cc:5751
void vert_random_access_ensure(Object &object)
Definition sculpt.cc:142
std::optional< int > nearest_vert_calc_mesh(const bke::pbvh::Tree &pbvh, const Span< float3 > vert_positions, const Span< bool > hide_vert, const float3 &location, const float max_distance, const bool use_original)
Definition sculpt.cc:593
void filter_below_plane_factors(Span< float3 > vert_positions, Span< int > verts, const float4 &plane, MutableSpan< float > factors)
Definition sculpt.cc:7886
wmOperatorStatus paint_stroke_exec(bContext *C, wmOperator *op, PaintStroke *stroke)
static void stroke_update_step(bContext *C, wmOperator *op, PaintStroke *, PointerRNA *stroke_element)
void apply_hardness_to_distances(float radius, float hardness, MutableSpan< float > distances)
Definition sculpt.cc:7142
void calc_factors_common_grids(const Depsgraph &depsgraph, const Brush &brush, const Object &object, Span< float3 > positions, const bke::pbvh::GridsNode &node, Vector< float > &r_factors, Vector< float > &r_distances)
Definition sculpt.cc:6589
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
void gather_bmesh_normals(const Set< BMVert *, 0 > &verts, MutableSpan< float3 > normals)
Definition sculpt.cc:6371
static void pose_fake_neighbors_free(SculptSession &ss)
Definition sculpt.cc:5801
static GroupedSpan< int > calc_vert_neighbors_interior_impl(const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face, const BitSpan boundary_verts, const Span< bool > hide_poly, const Span< int > verts, const Span< float > factors, Vector< int > &r_offset_data, Vector< int > &r_data)
Definition sculpt.cc:7677
bool node_fully_masked_or_hidden(const bke::pbvh::Node &node)
Definition sculpt.cc:2399
float3 tilt_effective_normal_get(const SculptSession &ss, const Brush &brush)
Definition sculpt.cc:2699
void filter_translations(MutableSpan< float3 > translations, Span< float > factors)
Definition sculpt.cc:7478
Vector< BMVert *, 64 > BMeshNeighborVerts
void calc_factors_common_mesh_indexed(const Depsgraph &depsgraph, const Brush &brush, const Object &object, const MeshAttributeData &attribute_data, Span< float3 > vert_positions, Span< float3 > vert_normals, const bke::pbvh::MeshNode &node, Vector< float > &r_factors, Vector< float > &r_distances)
Definition sculpt.cc:6498
void filter_distances_with_radius(float radius, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:7091
std::optional< OrigPositionData > orig_position_data_lookup_grids(const Object &object, const bke::pbvh::GridsNode &node)
static void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache *cache)
Definition sculpt.cc:3894
static const ImplicitSharingInfo * get_vertex_group_sharing_info(const Mesh &mesh)
Definition sculpt.cc:5268
static void cache_paint_invariants_update(StrokeCache &cache, const Brush &brush)
Definition sculpt.cc:4275
void filter_region_clip_factors(const SculptSession &ss, Span< float3 > vert_positions, Span< int > verts, MutableSpan< float > factors)
Definition sculpt.cc:6958
void gather_data_bmesh(Span< T > src, const Set< BMVert *, 0 > &verts, MutableSpan< T > node_data)
Definition sculpt.cc:6407
static void fake_neighbor_init(Object &object, const float max_dist)
Definition sculpt.cc:5793
void reset_translations_to_original(MutableSpan< float3 > translations, Span< float3 > positions, Span< float3 > orig_positions)
Definition sculpt.cc:7232
float3 symmetry_flip(const float3 &src, const ePaintSymmetryFlags symm)
static int sculpt_brush_needs_normal(const SculptSession &ss, const Brush &brush)
Definition sculpt.cc:810
void orig_position_data_gather_bmesh(const BMLog &bm_log, const Set< BMVert *, 0 > &verts, MutableSpan< float3 > positions, MutableSpan< float3 > normals)
static float area_normal_calc_weight(const float distance, const float radius_inv)
Definition sculpt.cc:1310
void scale_translations(MutableSpan< float3 > translations, Span< float > factors)
Definition sculpt.cc:7487
void paint_stroke_cancel(bContext *C, wmOperator *op, PaintStroke *stroke)
static bool brush_type_needs_original(const char sculpt_brush_type)
Definition sculpt.cc:787
bool paint_supports_dynamic_size(const Brush &br, PaintMode mode)
static void replace_attribute(const bke::AttributeAccessor src_attributes, const StringRef name, const bke::AttrDomain domain, const eCustomDataType data_type, bke::MutableAttributeAccessor dst_attributes)
Definition sculpt.cc:5202
static void sculpt_init_mirror_clipping(const Object &ob, const SculptSession &ss)
Definition sculpt.cc:3815
static IndexMask pbvh_gather_texpaint(Object &ob, const Brush &brush, const bool use_original, const float radius_scale, IndexMaskMemory &memory)
Definition sculpt.cc:2517
static void stroke_done(const bContext *C, PaintStroke *stroke)
static void brush_exit_tex(Sculpt &sd)
Definition sculpt.cc:5562
bool color_supported_check(const Scene &scene, Object &object, ReportList *reports)
Definition sculpt.cc:5459
static bool need_delta_from_anchored_origin(const Brush &brush)
Definition sculpt.cc:4087
static wmOperatorStatus brush_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition sculpt.cc:5746
static bool sculpt_needs_connectivity_info(const Sculpt &sd, const Brush &brush, const Object &object, int stroke_mode)
Definition sculpt.cc:4420
bool report_if_shape_key_is_locked(const Object &ob, ReportList *reports)
Definition sculpt.cc:128
static void store_sculpt_entire_mesh(const wmOperator &op, const Scene &scene, Object &object, Mesh *new_mesh)
Definition sculpt.cc:5256
float raycast_init(ViewContext *vc, const float2 &mval, float3 &r_ray_start, float3 &r_ray_end, float3 &r_ray_normal, bool original)
Definition sculpt.cc:4623
static void calc_area_normal_and_center_node_bmesh(const Object &object, const Brush &brush, const bool use_area_nos, const bool use_area_cos, const bool has_bm_orco, const bke::pbvh::BMeshNode &node, SampleLocalData &tls, AreaNormalCenterData &anctd)
Definition sculpt.cc:1551
static bool brush_type_needs_all_pbvh_nodes(const Brush &brush)
Definition sculpt.cc:3071
void filter_verts_outside_symmetry_area(Span< float3 > positions, const float3 &pivot, ePaintSymmetryFlags symm, MutableSpan< float > factors)
Definition sculpt.cc:7856
static void accumulate_area_center(const float3 &test_location, const float3 &position, const float distance, const float radius_inv, const int flip_index, AreaNormalCenterData &anctd)
Definition sculpt.cc:1330
static void rake_data_update(SculptRakeData *srd, const float co[3])
Definition sculpt.cc:837
void calc_translations_to_plane(Span< float3 > vert_positions, Span< int > verts, const float4 &plane, MutableSpan< float3 > translations)
Definition sculpt.cc:7831
void scale_factors(MutableSpan< float > factors, float strength)
Definition sculpt.cc:7504
void calc_factors_common_from_orig_data_mesh(const Depsgraph &depsgraph, const Brush &brush, const Object &object, const MeshAttributeData &attribute_data, Span< float3 > positions, Span< float3 > normals, const bke::pbvh::MeshNode &node, Vector< float > &r_factors, Vector< float > &r_distances)
Definition sculpt.cc:6656
static void smooth_brush_toggle_on(const bContext *C, Paint *paint, StrokeCache *cache)
Definition sculpt.cc:3852
static float3 calc_sculpt_normal(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob, const IndexMask &node_mask)
Definition sculpt.cc:2527
bool brush_type_is_paint(const int tool)
void translations_from_new_positions(Span< float3 > new_positions, Span< int > verts, Span< float3 > old_positions, MutableSpan< float3 > translations)
Definition sculpt.cc:7534
static bool need_delta_for_tip_orientation(const Brush &brush)
Definition sculpt.cc:4112
void clip_and_lock_translations(const Sculpt &sd, const SculptSession &ss, Span< float3 > positions, Span< int > verts, MutableSpan< float3 > translations)
Definition sculpt.cc:7318
bool cursor_geometry_info_update(bContext *C, CursorGeometryInfo *out, const float2 &mval, const bool use_sampled_normal)
Definition sculpt.cc:4664
static void sculpt_brush_stroke_cancel(bContext *C, wmOperator *op)
Definition sculpt.cc:5723
IndexMask gather_nodes(const bke::pbvh::Tree &pbvh, const eBrushFalloffShape falloff_shape, const bool use_original, const float3 &location, const float radius_sq, const std::optional< float3 > &ray_direction, IndexMaskMemory &memory)
Definition sculpt.cc:2483
static void do_brush_action(const Depsgraph &depsgraph, const Scene &scene, const Sculpt &sd, Object &ob, const Brush &brush, UnifiedPaintSettings &ups, PaintModeSettings &paint_mode_settings)
Definition sculpt.cc:3179
static void push_undo_nodes(const Depsgraph &depsgraph, Object &ob, const Brush &brush, const IndexMask &node_mask)
Definition sculpt.cc:3147
void flush_update_done(const bContext *C, Object &ob, const UpdateType update_type)
Definition sculpt.cc:5131
std::optional< Span< float4 > > orig_color_data_lookup_mesh(const Object &object, const bke::pbvh::MeshNode &node)
void scatter_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6421
static bool contains_nan(const Span< float > values)
Definition sculpt.cc:7245
wmOperatorStatus paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event, PaintStroke **stroke_p)
void calc_brush_distances(const SculptSession &ss, Span< float3 > vert_positions, Span< int > vert, eBrushFalloffShape falloff_shape, MutableSpan< float > r_distances)
Definition sculpt.cc:7041
void SCULPT_OT_brush_stroke(wmOperatorType *ot)
Definition sculpt.cc:5753
void project_translations(MutableSpan< float3 > translations, const float3 &plane)
Definition sculpt.cc:7294
static void dynamic_topology_update(const Depsgraph &depsgraph, const Scene &, const Sculpt &sd, Object &ob, const Brush &brush, UnifiedPaintSettings &, PaintModeSettings &)
Definition sculpt.cc:2990
void calc_brush_plane(const Depsgraph &depsgraph, const Brush &brush, Object &ob, const IndexMask &node_mask, float3 &r_area_no, float3 &r_area_co)
Definition sculpt.cc:2891
Span< BMVert * > vert_neighbors_get_interior_bmesh(BMVert &vert, BMeshNeighborVerts &r_neighbors)
Definition sculpt.cc:403
static void calc_brush_local_mat(const float rotation, const Object &ob, float local_mat[4][4], float local_mat_inv[4][4])
Definition sculpt.cc:2605
std::optional< float3 > calc_area_normal(const Depsgraph &depsgraph, const Brush &brush, const Object &ob, const IndexMask &node_mask)
Definition sculpt.cc:1814
void filter_plane_trim_limit_factors(const Brush &brush, const StrokeCache &cache, Span< float3 > translations, MutableSpan< float > factors)
Definition sculpt.cc:7870
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 apply_translations(Span< float3 > translations, Span< int > verts, MutableSpan< float3 > positions)
Definition sculpt.cc:7251
void calc_factors_common_mesh(const Depsgraph &depsgraph, const Brush &brush, const Object &object, const MeshAttributeData &attribute_data, Span< float3 > positions, Span< float3 > vert_normals, const bke::pbvh::MeshNode &node, Vector< float > &r_factors, Vector< float > &r_distances)
Definition sculpt.cc:6554
bool vertex_is_occluded(const Depsgraph &depsgraph, const Object &object, const float3 &position, bool original)
Definition sculpt.cc:6114
ViewContext * paint_stroke_view_context(PaintStroke *stroke)
void gather_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6381
void(*)(const Depsgraph &depsgraph, const Scene &scene, const Sculpt &sd, Object &ob, const Brush &brush, UnifiedPaintSettings &ups, PaintModeSettings &paint_mode_settings) BrushActionFunc
Definition sculpt.cc:3506
void calc_brush_texture_factors(const SculptSession &ss, const Brush &brush, Span< float3 > vert_positions, Span< int > vert, MutableSpan< float > factors)
Definition sculpt.cc:7178
static void fake_neighbor_search_bmesh(const SculptSession &ss, const float3 &location, const float max_distance_sq, const int island_id, const bke::pbvh::BMeshNode &node, NearestVertData &nvtd)
Definition sculpt.cc:5881
bool paint_brush_cursor_poll(bContext *C)
static void sculpt_fix_noise_tear(const Sculpt &sd, Object &ob)
Definition sculpt.cc:3607
static AreaNormalCenterData calc_area_normal_and_center_reduce(const AreaNormalCenterData &a, const AreaNormalCenterData &b)
Definition sculpt.cc:1694
void filter_above_plane_factors(Span< float3 > vert_positions, Span< int > verts, const float4 &plane, MutableSpan< float > factors)
Definition sculpt.cc:7909
void calc_area_center(const Depsgraph &depsgraph, const Brush &brush, const Object &ob, const IndexMask &node_mask, float r_area_co[3])
Definition sculpt.cc:1712
void flush_update_step(const bContext *C, const UpdateType update_type)
Definition sculpt.cc:5083
BLI_INLINE bool brush_type_is_attribute_only(const int tool)
static void sculpt_update_cache_variants(bContext *C, Sculpt &sd, Object &ob, PointerRNA *ptr)
Definition sculpt.cc:4320
static constexpr int plane_brush_max_rolling_average_num
float brush_plane_offset_get(const Brush &brush, const SculptSession &ss)
Definition sculpt.cc:2974
static wmOperatorStatus sculpt_brush_stroke_exec(bContext *C, wmOperator *op)
Definition sculpt.cc:5704
static void calc_stabilized_plane(const Brush &brush, StrokeCache &cache, const float3 &plane_normal, const float3 &plane_center, float3 &r_stabilized_normal, float3 &r_stabilized_center)
Definition sculpt.cc:1926
void apply_crazyspace_to_translations(Span< float3x3 > deform_imats, Span< int > verts, MutableSpan< float3 > translations)
Definition sculpt.cc:7307
static void sculpt_find_nearest_to_ray_cb(bke::pbvh::Node &node, FindNearestToRayData &fntrd, float *tmin)
Definition sculpt.cc:4567
static bool topology_matches(const Mesh &a, const Mesh &b)
Definition sculpt.cc:5235
static void brush_delta_update(const Depsgraph &depsgraph, UnifiedPaintSettings &ups, const Object &ob, const Brush &brush)
Definition sculpt.cc:4126
std::optional< BMVert * > nearest_vert_calc_bmesh(const bke::pbvh::Tree &pbvh, const float3 &location, const float max_distance, const bool use_original)
Definition sculpt.cc:694
static void sculpt_raycast_cb(bke::pbvh::Node &node, RaycastData &rd, float *tmin)
Definition sculpt.cc:4465
static void fake_neighbor_search(const Depsgraph &depsgraph, const Object &ob, const float max_distance_sq, MutableSpan< int > fake_neighbors)
Definition sculpt.cc:5909
static wmOperatorStatus sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition sculpt.cc:5622
void calc_front_face(const float3 &view_normal, Span< float3 > normals, MutableSpan< float > factors)
Definition sculpt.cc:6900
static void calc_area_normal_and_center_node_grids(const Object &object, const Brush &brush, const bool use_area_nos, const bool use_area_cos, const bke::pbvh::GridsNode &node, SampleLocalData &tls, AreaNormalCenterData &anctd)
Definition sculpt.cc:1445
static void do_symmetrical_brush_actions(const Depsgraph &depsgraph, const Scene &scene, const Sculpt &sd, Object &ob, const BrushActionFunc action, UnifiedPaintSettings &ups, PaintModeSettings &paint_mode_settings)
Definition sculpt.cc:3618
float paint_stroke_distance_get(PaintStroke *stroke)
static float3 area_center_calc_weighted(const float3 &test_location, const float distance, const float radius_inv, const float3 &co)
Definition sculpt.cc:1317
static void fake_neighbor_search_grids(const SculptSession &ss, const CCGKey &key, const Span< float3 > positions, const BitGroupVector<> &grid_hidden, const float3 &location, const float max_distance_sq, const int island_id, const bke::pbvh::GridsNode &node, NearestVertData &nvtd)
Definition sculpt.cc:5852
std::optional< Span< float > > orig_mask_data_lookup_mesh(const Object &object, const bke::pbvh::MeshNode &node)
std::optional< SubdivCCGCoord > nearest_vert_calc_grids(const bke::pbvh::Tree &pbvh, const SubdivCCG &subdiv_ccg, const float3 &location, const float max_distance, const bool use_original)
Definition sculpt.cc:640
std::optional< OrigPositionData > orig_position_data_lookup_mesh_all_verts(const Object &object, const bke::pbvh::MeshNode &node)
static IndexMask pbvh_gather_cursor_update(Object &ob, bool use_original, IndexMaskMemory &memory)
Definition sculpt.cc:2435
static bool brush_uses_topology_rake(const SculptSession &ss, const Brush &brush)
Definition sculpt.cc:801
static void calc_area_normal_and_center_node_mesh(const Object &object, const Span< float3 > vert_positions, const Span< float3 > vert_normals, const Span< bool > hide_vert, const Brush &brush, const bool use_area_nos, const bool use_area_cos, const bke::pbvh::MeshNode &node, SampleLocalData &tls, AreaNormalCenterData &anctd)
Definition sculpt.cc:1357
void calc_brush_distances_squared(const SculptSession &ss, Span< float3 > positions, Span< int > verts, eBrushFalloffShape falloff_shape, MutableSpan< float > r_distances)
Definition sculpt.cc:7013
void gather_grids_normals(const SubdivCCG &subdiv_ccg, Span< int > grids, MutableSpan< float3 > normals)
Definition sculpt.cc:6364
static void sculpt_update_cache_invariants(bContext *C, Sculpt &sd, SculptSession &ss, const wmOperator &op, const float mval[2])
Definition sculpt.cc:3924
void calc_area_normal_and_center(const Depsgraph &depsgraph, const Brush &brush, const Object &ob, const IndexMask &node_mask, float r_area_no[3], float r_area_co[3])
Definition sculpt.cc:2010
void paint_stroke_free(bContext *C, wmOperator *op, PaintStroke *stroke)
PaintStroke * paint_stroke_new(bContext *C, wmOperator *op, StrokeGetLocation get_location, StrokeTestStart test_start, StrokeUpdateStep update_step, StrokeRedraw redraw, StrokeDone done, int event_type)
void translations_from_offset_and_factors(const float3 &offset, Span< float > factors, MutableSpan< float3 > r_translations)
Definition sculpt.cc:7523
void calc_brush_cube_distances(const Brush &brush, const Span< T > positions, const MutableSpan< float > r_distances)
Definition sculpt.cc:7103
static float area_normal_and_center_get_normal_radius(const SculptSession &ss, const Brush &brush)
Definition sculpt.cc:1281
static void do_tiled(const Depsgraph &depsgraph, const Scene &scene, const Sculpt &sd, Object &ob, const Brush &brush, UnifiedPaintSettings &ups, PaintModeSettings &paint_mode_settings, const BrushActionFunc action)
Definition sculpt.cc:3514
std::optional< OrigPositionData > orig_position_data_lookup_mesh(const Object &object, const bke::pbvh::MeshNode &node)
void store_mesh_from_eval(const wmOperator &op, const Scene &scene, const Depsgraph &depsgraph, const RegionView3D *rv3d, Object &object, Mesh *new_mesh)
Definition sculpt.cc:5277
void append_neighbors_to_vector(const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face, const Span< bool > hide_poly, const int vert, Vector< int > &r_data)
Definition sculpt.cc:451
std::optional< Span< int > > orig_face_set_data_lookup_grids(const Object &object, const bke::pbvh::GridsNode &node)
Span< int > vert_neighbors_get_mesh(const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face, const Span< bool > hide_poly, const int vert, Vector< int > &r_neighbors)
Definition sculpt.cc:430
void fill_factor_from_hide(Span< bool > hide_vert, Span< int > verts, MutableSpan< float > r_factors)
Definition sculpt.cc:6761
void scatter_data_grids(const SubdivCCG &subdiv_ccg, Span< T > node_data, Span< int > grids, MutableSpan< T > dst)
Definition sculpt.cc:6431
bool brush_uses_vector_displacement(const Brush &brush)
OffsetIndices< int > create_node_vert_offsets_bmesh(Span< bke::pbvh::BMeshNode > nodes, const IndexMask &node_mask, Array< int > &node_data)
Definition sculpt.cc:7595
void calc_factors_common_bmesh(const Depsgraph &depsgraph, const Brush &brush, const Object &object, Span< float3 > positions, bke::pbvh::BMeshNode &node, Vector< float > &r_factors, Vector< float > &r_distances)
Definition sculpt.cc:6623
GroupedSpan< int > calc_vert_neighbors_interior(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face, BitSpan boundary_verts, Span< bool > hide_poly, Span< int > verts, Vector< int > &r_offset_data, Vector< int > &r_data)
Definition sculpt.cc:7746
static void update_sculpt_normal(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob, const brushes::CursorSampleResult &cursor_sample_result)
Definition sculpt.cc:2550
bool brush_type_is_mask(const int tool)
static void accumulate_area_normal(const float3 &normal, const float distance, const float radius_inv, const int flip_index, AreaNormalCenterData &anctd)
Definition sculpt.cc:1342
bool paint_brush_tool_poll(bContext *C)
void calc_factors_common_from_orig_data_bmesh(const Depsgraph &depsgraph, const Brush &brush, const Object &object, Span< float3 > positions, Span< float3 > normals, bke::pbvh::BMeshNode &node, Vector< float > &r_factors, Vector< float > &r_distances)
Definition sculpt.cc:6727
static bool stroke_get_location_bvh_ex(bContext *C, float3 &out, const float2 &mval, const bool force_original, const bool check_closest, const bool limit_closest_radius)
Definition sculpt.cc:4808
Span< float3 > vert_positions_for_grab_active_get(const Depsgraph &depsgraph, const Object &object)
Definition sculpt.cc:170
float3 tilt_apply_to_normal(const Object &object, const float4x4 &view_inverse, const float3 &normal, const float2 &tilt, const float tilt_strength)
Definition sculpt.cc:2671
static float area_normal_and_center_get_position_radius(const SculptSession &ss, const Brush &brush)
Definition sculpt.cc:1290
static IndexMask pbvh_gather_generic(Object &ob, const Brush &brush, const bool use_original, const float radius_scale, IndexMaskMemory &memory)
Definition sculpt.cc:2446
bool is_symmetry_iteration_valid(const char i, const char symm)
QuaternionBase< float > Quaternion
T length_squared(const VecBase< T, Size > &a)
VecBase< T, 3 > normal_tri(const VecBase< T, 3 > &v1, const VecBase< T, 3 > &v2, const VecBase< T, 3 > &v3)
T clamp(const T &a, const T &min, const T &max)
T safe_rcp(const T &a)
QuaternionBase< T > to_quaternion(const AxisAngleBase< T, AngleT > &axis_angle)
T safe_divide(const T &a, const T &b)
T reduce_max(const VecBase< T, Size > &a)
T distance(const T &a, const T &b)
AxisAngleBase< float, AngleRadianBase< float > > AxisAngle
QuaternionBase< T > normalize_and_get_length(const QuaternionBase< T > &q, T &out_length)
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
bool is_zero(const T &a)
CartesianBasis invert(const CartesianBasis &basis)
float3 rotate_direction_around_axis(const float3 &direction, const float3 &axis, float angle)
VectorT project_point(const MatT &mat, const VectorT &point)
T interpolate(const T &a, const T &b, const FactorT &t)
T rcp(const T &a)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
T square(const T &a)
T distance_squared(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
T abs(const T &a)
VecBase< T, 3 > transform_direction(const MatBase< T, 3, 3 > &mat, const VecBase< T, 3 > &direction)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
OffsetIndices< int > accumulate_counts_to_offsets(MutableSpan< int > counts_to_offsets, int start_offset=0)
void isolate_task(const Function &function)
Definition BLI_task.hh:248
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
Value parallel_reduce(IndexRange range, int64_t grain_size, const Value &identity, const Function &function, const Reduction &reduction)
Definition BLI_task.hh:151
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< float, 3 > float3
static void init(bNodeTree *, bNode *node)
@ BRUSH_STROKE_SMOOTH
@ BRUSH_STROKE_INVERT
float paint_calc_object_space_radius(const ViewContext &vc, const blender::float3 &center, float pixel_radius)
bool paint_get_tex_pixel(const MTex *mtex, float u, float v, ImagePool *pool, int thread, float *r_intensity, float r_rgba[4])
void paint_stroke_operator_properties(wmOperatorType *ot)
const btScalar eps
Definition poly34.cpp:11
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
float RNA_float_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_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
static void stroke_undo_end(const bContext *C, Brush *brush)
Definition sculpt.cc:5441
bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(const blender::ed::sculpt_paint::StrokeCache &cache)
Definition sculpt.cc:543
bool SCULPT_brush_cursor_poll(bContext *C)
Definition sculpt.cc:3717
ePaintSymmetryFlags SCULPT_mesh_symmetry_xyz_get(const Object &object)
Definition sculpt.cc:185
static void restore_from_undo_step_if_necessary(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob)
Definition sculpt.cc:4985
StrokeFlags
Definition sculpt.cc:3806
static float calc_symmetry_feather(const Sculpt &sd, const blender::ed::sculpt_paint::StrokeCache &cache)
Definition sculpt.cc:1230
static void brush_stroke_init(bContext *C)
Definition sculpt.cc:4955
const float * SCULPT_brush_frontface_normal_from_falloff_shape(const SculptSession &ss, char falloff_shape)
Definition sculpt.cc:1181
Span< int > SCULPT_fake_neighbors_ensure(const Depsgraph &depsgraph, Object &ob, const float max_dist)
Definition sculpt.cc:6084
static void brush_init_tex(const Sculpt &sd, SculptSession &ss)
Definition sculpt.cc:4939
static bool sculpt_needs_pbvh_pixels(PaintModeSettings &paint_mode_settings, const Brush &brush, Object &ob)
Definition sculpt.cc:2725
static bool over_mesh(bContext *C, wmOperator *, const float mval[2])
Definition sculpt.cc:5408
void SCULPT_stroke_modifiers_check(const bContext *C, Object &ob, const Brush &brush)
Definition sculpt.cc:4447
void sculpt_apply_texture(const SculptSession &ss, const Brush &brush, const float brush_point[3], const int thread_id, float *r_value, float r_rgba[4])
Definition sculpt.cc:2303
static void sculpt_pbvh_update_pixels(const Depsgraph &depsgraph, PaintModeSettings &paint_mode_settings, Object &ob)
Definition sculpt.cc:2740
static const char * sculpt_brush_type_name(const Sculpt &sd)
Definition sculpt.cc:3723
void SCULPT_cache_calc_brushdata_symm(blender::ed::sculpt_paint::StrokeCache &cache, const ePaintSymmetryFlags symm, const char axis, const float angle)
Definition sculpt.cc:3446
bool SCULPT_mode_poll_view3d(bContext *C)
Definition sculpt.cc:3666
static float brush_flip(const Brush &brush, const blender::ed::sculpt_paint::StrokeCache &cache)
Definition sculpt.cc:2143
float3 SCULPT_flip_v3_by_symm_area(const float3 &vector, const ePaintSymmetryFlags symm, const ePaintSymmetryAreas symmarea, const float3 &pivot)
Definition sculpt.cc:2849
bool SCULPT_mode_poll(bContext *C)
Definition sculpt.cc:3660
static void stroke_undo_begin(const bContext *C, wmOperator *op)
Definition sculpt.cc:5420
void SCULPT_calc_vertex_displacement(const SculptSession &ss, const Brush &brush, float translation[3])
Definition sculpt.cc:2369
static bool is_brush_related_tool(bContext *C)
Definition sculpt.cc:3685
bool SCULPT_stroke_is_main_symmetry_pass(const blender::ed::sculpt_paint::StrokeCache &cache)
Definition sculpt.cc:531
static void flip_qt(float quat[4], const ePaintSymmetryFlags symm)
Definition sculpt.cc:2844
static void flip_qt_qt(float out[4], const float in[4], const ePaintSymmetryFlags symm)
Definition sculpt.cc:2821
int SCULPT_vertex_count_get(const Object &object)
Definition sculpt.cc:152
void sculpt_project_v3_normal_align(const SculptSession &ss, const float normal_weight, float grab_delta[3])
Definition sculpt.cc:568
static void update_brush_local_mat(const Sculpt &sd, Object &ob)
Definition sculpt.cc:2706
void SCULPT_cube_tip_init(const Sculpt &, const Object &ob, const Brush &brush, float mat[4][4])
Definition sculpt.cc:6314
void SCULPT_fake_neighbors_free(Object &ob)
Definition sculpt.cc:6106
bool SCULPT_is_vertex_inside_brush_radius_symm(const float vertex[3], const float br_co[3], float radius, char symm)
Definition sculpt.cc:743
bool SCULPT_check_vertex_pivot_symmetry(const float vco[3], const float pco[3], const char symm)
Definition sculpt.cc:549
bool SCULPT_poll(bContext *C)
Definition sculpt.cc:3672
ePaintSymmetryAreas SCULPT_get_vertex_symm_area(const float co[3])
Definition sculpt.cc:2806
static float calc_overlap(const blender::ed::sculpt_paint::StrokeCache &cache, const ePaintSymmetryFlags symm, const char axis, const float angle)
Definition sculpt.cc:1194
static float brush_strength(const Sculpt &sd, const blender::ed::sculpt_paint::StrokeCache &cache, const float feather, const UnifiedPaintSettings &ups, const PaintModeSettings &)
Definition sculpt.cc:2157
void SCULPT_flip_quat_by_symm_area(float quat[4], const ePaintSymmetryFlags symm, const ePaintSymmetryAreas symmarea, const float pivot[3])
Definition sculpt.cc:2870
bool SCULPT_stroke_is_first_brush_step(const blender::ed::sculpt_paint::StrokeCache &cache)
Definition sculpt.cc:537
static float calc_radial_symmetry_feather(const Sculpt &sd, const blender::ed::sculpt_paint::StrokeCache &cache, const ePaintSymmetryFlags symm, const char axis)
Definition sculpt.cc:1215
void SCULPT_tag_update_overlays(bContext *C)
Definition sculpt.cc:760
#define SCULPT_RAKE_BRUSH_FACTOR
#define FAKE_NEIGHBOR_NONE
bool SCULPT_use_image_paint_brush(PaintModeSettings &settings, Object &ob)
bool SCULPT_paint_image_canvas_get(PaintModeSettings &paint_mode_settings, Object &ob, Image **r_image, ImageUser **r_image_user) ATTR_NONNULL()
Get the image canvas for painting on the given object.
float co[3]
CustomData vdata
float topology_rake_factor
char sculpt_brush_type
int plane_inversion_mode
int sculpt_plane
int cloth_deform_type
float area_radius_factor
int snake_hook_deform_type
float density
float normal_radius_factor
struct MTex mtex
float normal_weight
float rake_factor
float stabilize_normal
short ob_mode
int curve_preset
struct CurveMapping * curve
float tip_scale_x
float texture_sample_bias
float stabilize_plane
float plane_trim
char falloff_shape
float tilt_strength_factor
float hardness
char mask_tool
int smooth_deform_type
float wet_mix
float wet_persistence
int deform_target
float plane_offset
float tip_roundness
float autosmooth_factor
int paint_flags
int grid_size
Definition BKE_ccg.hh:33
int grid_area
Definition BKE_ccg.hh:35
char name[66]
Definition DNA_ID.h:415
void * data
ListBase block
KeyBlock * refkey
char brush_map_mode
float ofs[3]
float size[3]
struct Tex * tex
int corners_num
char symmetry
int edges_num
MeshRuntimeHandle * runtime
int faces_num
int verts_num
struct Object * mirror_ob
ObjectRuntimeHandle * runtime
ListBase modifiers
float loc[3]
float scale[3]
struct SculptSession * sculpt
float tile_offset[3]
int symmetry_flags
struct ViewRender * view_render
float viewinv[4][4]
struct ToolSettings * toolsettings
struct bToolRef * tool
ScrArea_Runtime runtime
blender::Array< int > fake_neighbor_index
Definition BKE_paint.hh:369
blender::float3 follow_co
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:437
BMLog * bm_log
Definition BKE_paint.hh:412
std::optional< int > active_grid_index
Definition BKE_paint.hh:443
RegionView3D * rv3d
Definition BKE_paint.hh:456
blender::ed::sculpt_paint::filter::Cache * filter_cache
Definition BKE_paint.hh:438
std::optional< int > active_face_index
Definition BKE_paint.hh:442
KeyBlock * shapekey_active
Definition BKE_paint.hh:397
blender::float3 cursor_normal
Definition BKE_paint.hh:451
SculptVertexInfo vertex_info
Definition BKE_paint.hh:482
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:415
blender::float3 cursor_view_normal
Definition BKE_paint.hh:453
float cursor_radius
Definition BKE_paint.hh:449
ActiveVert active_vert() const
Definition paint.cc:2227
blender::float3 cursor_location
Definition BKE_paint.hh:450
blender::float3 active_vert_position(const Depsgraph &depsgraph, const Object &object) const
Definition paint.cc:2263
struct SculptSession::@323057044041335216000265171165256227034374206114 multires
ImagePool * tex_pool
Definition BKE_paint.hh:435
std::unique_ptr< SculptTopologyIslandCache > topology_island_cache
Definition BKE_paint.hh:537
View3D * v3d
Definition BKE_paint.hh:457
std::optional< blender::float3 > cursor_sampled_normal
Definition BKE_paint.hh:452
blender::Array< blender::float3x3, 0 > deform_imats
Definition BKE_paint.hh:425
MultiresModifierData * modifier
Definition BKE_paint.hh:393
SculptFakeNeighbors fake_neighbors
Definition BKE_paint.hh:483
bool deform_modifiers_active
Definition BKE_paint.hh:421
void set_active_vert(ActiveVert vert)
Definition paint.cc:2297
void clear_active_elements(bool persist_last_active)
Definition paint.cc:2282
blender::Array< uint8_t > vert_island_ids
Definition BKE_paint.hh:377
blender::BitVector boundary
Definition BKE_paint.hh:354
struct Object * gravity_object
float detail_percent
int radial_symm[3]
float detail_size
float gravity_factor
float constant_detail
int to_index(const CCGKey &key) const
SubdivCCGNeighborCoords coords
blender::Array< blender::float3 > normals
blender::BitGroupVector grid_hidden
blender::Array< float > masks
blender::Array< blender::float3 > positions
struct bNodeTree * nodetree
struct PaintModeSettings paint_mode
struct UnifiedPaintSettings unified_paint_settings
View3DShading shading
RegionView3D * rv3d
Definition ED_view3d.hh:80
ARegion * region
Definition ED_view3d.hh:77
Scene * scene
Definition ED_view3d.hh:73
View3D * v3d
Definition ED_view3d.hh:78
Object * obact
Definition ED_view3d.hh:75
Depsgraph * depsgraph
Definition ED_view3d.hh:72
bNodeTreeRuntimeHandle * runtime
ListBase areabase
bToolRef_Runtime * runtime
const c_style_mat & ptr() const
VecBase< T, 3 > xyz() const
const ImplicitSharingInfo * sharing_info
const ImplicitSharingInfo * sharing_info
static NearestVertData join(const NearestVertData &a, const NearestVertData &b)
Definition sculpt.cc:5810
static std::optional< ShapeKeyData > from_object(Object &object)
Definition sculpt.cc:7399
struct blender::ed::sculpt_paint::StrokeCache::@311364231114302125055074143272255322205255231210 mirror_modifier_clip
std::optional< math::Quaternion > rake_rotation
struct blender::ed::sculpt_paint::StrokeCache::@304264133216251371224021372200355026016144364316 clay_thumb_brush
std::unique_ptr< auto_mask::Cache > automasking
struct blender::ed::sculpt_paint::StrokeCache::@140233062077157027106001372232256125135050036057 paint_brush
struct blender::ed::sculpt_paint::StrokeCache::@356307137154005365075150012170202326075161346056 plane_brush
std::optional< math::Quaternion > rake_rotation_symm
std::unique_ptr< cloth::SimulationData > cloth_sim
std::array< float, 10 > pressure_stabilizer
std::optional< blender::float3 > initial_hsv_jitter
void calc_cavity_factor(const Depsgraph &depsgraph, const Object &object, const IndexMask &node_mask)
wmEventType type
Definition WM_types.hh:754
int mval[2]
Definition WM_types.hh:760
const char * name
Definition WM_types.hh:1030
wmOperatorStatus(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1078
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
i
Definition text_draw.cc:230
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4227
wmOperatorType * ot
Definition wm_files.cc:4226
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
bScreen * WM_window_get_active_screen(const wmWindow *win)