Blender V5.0
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_paint_types.hh"
63#include "BKE_report.hh"
64#include "BKE_subdiv_ccg.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_paint.hh"
77#include "ED_screen.hh"
78#include "ED_sculpt.hh"
79#include "ED_view3d.hh"
80
81#include "paint_intern.hh"
82#include "sculpt_automask.hh"
83#include "sculpt_boundary.hh"
84#include "sculpt_cloth.hh"
85#include "sculpt_color.hh"
86#include "sculpt_dyntopo.hh"
87#include "sculpt_face_set.hh"
88#include "sculpt_filter.hh"
89#include "sculpt_hide.hh"
90#include "sculpt_intern.hh"
91#include "sculpt_islands.hh"
92#include "sculpt_pose.hh"
93#include "sculpt_undo.hh"
94
95#include "RNA_access.hh"
96#include "RNA_define.hh"
97
98#include "bmesh.hh"
99
101#include "mesh_brush_common.hh"
102
103using blender::float3;
105using blender::Set;
106using blender::Span;
107using blender::Vector;
108
109static CLG_LogRef LOG = {"sculpt"};
110
112
113/* TODO: This should be moved to either BKE_paint.hh or BKE_brush.hh */
115 const Paint &paint,
116 const Brush &brush,
117 const float3 &location,
118 const float scale_factor)
119{
120 if (!BKE_brush_use_locked_size(&paint, &brush)) {
122 vc, location, BKE_brush_radius_get(&paint, &brush) * scale_factor);
123 }
124 return BKE_brush_unprojected_radius_get(&paint, &brush) * scale_factor;
125}
126
128{
129 SculptSession &ss = *ob.sculpt;
130
132 if (reports) {
133 BKE_reportf(reports, RPT_ERROR, "The active shape key of %s is locked", ob.id.name + 2);
134 }
135 return true;
136 }
137
138 return false;
139}
140
142{
143 SculptSession &ss = *object.sculpt;
144 if (bke::object::pbvh_get(object)->type() == bke::pbvh::Type::BMesh) {
147 }
148}
149} // namespace blender::ed::sculpt_paint
150
152{
153 const SculptSession &ss = *object.sculpt;
154 switch (blender::bke::object::pbvh_get(object)->type()) {
156 BLI_assert(object.type == OB_MESH);
157 return static_cast<const Mesh *>(object.data)->verts_num;
159 return BM_mesh_elem_count(ss.bm, BM_VERT);
161 return BKE_pbvh_get_grid_num_verts(object);
162 }
163
164 return 0;
165}
166
168
170{
171 const SculptSession &ss = *object.sculpt;
173 if (ss.shapekey_active) {
174 /* Always grab active shape key if the sculpt happens on shapekey. */
176 }
177 /* Otherwise use the base mesh positions. */
178 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
179 return mesh.vert_positions();
180}
181
182} // namespace blender::ed::sculpt_paint
183
185{
186 const Mesh *mesh = static_cast<const Mesh *>(object.data);
187 return ePaintSymmetryFlags(mesh->symmetry);
188}
189
190/* Sculpt Face Sets and Visibility. */
191
193
194namespace face_set {
195
196int active_face_set_get(const Object &object)
197{
198 const SculptSession &ss = *object.sculpt;
199 switch (bke::object::pbvh_get(object)->type()) {
201 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
202 const bke::AttributeAccessor attributes = mesh.attributes();
203 const VArray face_sets = *attributes.lookup<int>(".sculpt_face_set", bke::AttrDomain::Face);
204 if (!face_sets || !ss.active_face_index) {
206 }
207 return face_sets[*ss.active_face_index];
208 }
210 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
211 const bke::AttributeAccessor attributes = mesh.attributes();
212 const VArray face_sets = *attributes.lookup<int>(".sculpt_face_set", bke::AttrDomain::Face);
213 if (!face_sets || !ss.active_grid_index) {
215 }
216 const int face_index = BKE_subdiv_ccg_grid_to_face_index(*ss.subdiv_ccg,
218 return face_sets[face_index];
219 }
222 }
224}
225
226} // namespace face_set
227
228namespace face_set {
229
230int vert_face_set_get(const GroupedSpan<int> vert_to_face_map,
231 const Span<int> face_sets,
232 const int vert)
233{
235 for (const int face : vert_to_face_map[vert]) {
236 face_set = std::max(face_sets[face], face_set);
237 }
238 return face_set;
239}
240
241int vert_face_set_get(const SubdivCCG &subdiv_ccg, const Span<int> face_sets, const int grid)
242{
243 const int face = BKE_subdiv_ccg_grid_to_face_index(subdiv_ccg, grid);
244 return face_sets[face];
245}
246
247int vert_face_set_get(const int /*face_set_offset*/, const BMVert & /*vert*/)
248{
250}
251
252bool vert_has_face_set(const GroupedSpan<int> vert_to_face_map,
253 const Span<int> face_sets,
254 const int vert,
255 const int face_set)
256{
257 if (face_sets.is_empty()) {
259 }
260 const Span<int> faces = vert_to_face_map[vert];
261 return std::any_of(
262 faces.begin(), faces.end(), [&](const int face) { return face_sets[face] == face_set; });
263}
264
265bool vert_has_face_set(const SubdivCCG &subdiv_ccg,
266 const Span<int> face_sets,
267 const int grid,
268 const int face_set)
269{
270 if (face_sets.is_empty()) {
272 }
273 const int face = BKE_subdiv_ccg_grid_to_face_index(subdiv_ccg, grid);
274 return face_sets[face] == face_set;
275}
276
277bool vert_has_face_set(const int face_set_offset, const BMVert &vert, const int face_set)
278{
279 if (face_set_offset == -1) {
281 }
282 BMIter iter;
283 BMFace *face;
284 BM_ITER_ELEM (face, &iter, &const_cast<BMVert &>(vert), BM_FACES_OF_VERT) {
285 if (BM_ELEM_CD_GET_INT(face, face_set_offset) == face_set) {
286 return true;
287 }
288 }
289 return false;
290}
291
292bool vert_has_unique_face_set(const GroupedSpan<int> vert_to_face_map,
293 const Span<int> face_sets,
294 int vert)
295{
296 /* TODO: Move this check higher out of this function. */
297 if (face_sets.is_empty()) {
298 return true;
299 }
300 int face_set = -1;
301 for (const int face_index : vert_to_face_map[vert]) {
302 if (face_set == -1) {
303 face_set = face_sets[face_index];
304 }
305 else {
306 if (face_sets[face_index] != face_set) {
307 return false;
308 }
309 }
310 }
311 return true;
312}
313
319 const GroupedSpan<int> vert_to_face_map,
320 const Span<int> face_sets,
321 const Span<int> corner_verts,
323 int v1,
324 int v2)
325{
326 const Span<int> vert_map = vert_to_face_map[v1];
327 int p1 = -1, p2 = -1;
328 for (int i = 0; i < vert_map.size(); i++) {
329 const int face_i = vert_map[i];
330 for (const int corner : faces[face_i]) {
331 if (corner_verts[corner] == v2) {
332 if (p1 == -1) {
333 p1 = vert_map[i];
334 break;
335 }
336
337 if (p2 == -1) {
338 p2 = vert_map[i];
339 break;
340 }
341 }
342 }
343 }
344
345 if (p1 != -1 && p2 != -1) {
346 return face_sets[p1] == face_sets[p2];
347 }
348 return true;
349}
350
352 const Span<int> corner_verts,
353 const GroupedSpan<int> vert_to_face_map,
354 const Span<int> face_sets,
355 const SubdivCCG &subdiv_ccg,
356 SubdivCCGCoord coord)
357{
358 /* TODO: Move this check higher out of this function. */
359 if (face_sets.is_empty()) {
360 return true;
361 }
362 int v1, v2;
364 subdiv_ccg, coord, corner_verts, faces, v1, v2);
365 switch (adjacency) {
367 return vert_has_unique_face_set(vert_to_face_map, face_sets, v1);
370 vert_to_face_map, face_sets, corner_verts, faces, v1, v2);
372 return true;
373 }
375 return true;
376}
377
378bool vert_has_unique_face_set(const int /*face_set_offset*/, const BMVert & /*vert*/)
379{
380 /* TODO: Obviously not fully implemented yet. Needs to be implemented for Relax Face Sets brush
381 * to work. */
382 return true;
383}
384
385} // namespace face_set
386
388{
389 r_neighbors.clear();
390 BMIter liter;
391 BMLoop *l;
392 BM_ITER_ELEM (l, &liter, &vert, BM_LOOPS_OF_VERT) {
393 for (BMVert *other_vert : {l->prev->v, l->next->v}) {
394 if (other_vert != &vert) {
395 r_neighbors.append(other_vert);
396 }
397 }
398 }
399 return r_neighbors;
400}
401
403{
404 r_neighbors.clear();
405 BMIter liter;
406 BMLoop *l;
407 BM_ITER_ELEM (l, &liter, &vert, BM_LOOPS_OF_VERT) {
408 for (BMVert *other_vert : {l->prev->v, l->next->v}) {
409 if (other_vert != &vert) {
410 r_neighbors.append(other_vert);
411 }
412 }
413 }
414
415 if (BM_vert_is_boundary(&vert)) {
416 if (r_neighbors.size() == 2) {
417 /* Do not include neighbors of corner vertices. */
418 r_neighbors.clear();
419 }
420 else {
421 /* Only include other boundary vertices as neighbors of boundary vertices. */
422 r_neighbors.remove_if([&](const BMVert *vert) { return !BM_vert_is_boundary(vert); });
423 }
424 }
425
426 return r_neighbors;
427}
428
430 const Span<int> corner_verts,
431 const GroupedSpan<int> vert_to_face,
432 const Span<bool> hide_poly,
433 const int vert,
434 Vector<int> &r_neighbors)
435{
436 r_neighbors.clear();
437
438 for (const int face : vert_to_face[vert]) {
439 if (!hide_poly.is_empty() && hide_poly[face]) {
440 continue;
441 }
442 const int2 verts = bke::mesh::face_find_adjacent_verts(faces[face], corner_verts, vert);
443 r_neighbors.append_non_duplicates(verts[0]);
444 r_neighbors.append_non_duplicates(verts[1]);
445 }
446
447 return r_neighbors.as_span();
448}
449
451 const Span<int> corner_verts,
452 const GroupedSpan<int> vert_to_face,
453 const Span<bool> hide_poly,
454 const int vert,
455 Vector<int> &r_data)
456{
457 const int vert_start = r_data.size();
458 for (const int face : vert_to_face[vert]) {
459 if (!hide_poly.is_empty() && hide_poly[face]) {
460 continue;
461 }
462 /* In order to support non-manifold topology, both neighboring vertices are added for each
463 * face corner. That results in half being duplicates for any "normal" topology. */
464 const int2 neighbors = bke::mesh::face_find_adjacent_verts(faces[face], corner_verts, vert);
465 for (const int neighbor : {neighbors[0], neighbors[1]}) {
466 bool found = false;
467 for (int i = r_data.size() - 1; i >= vert_start; i--) {
468 if (r_data[i] == neighbor) {
469 found = true;
470 break;
471 }
472 }
473 if (found) {
474 continue;
475 }
476 r_data.append(neighbor);
477 }
478 }
479}
480
481namespace boundary {
482
483bool vert_is_boundary(const GroupedSpan<int> vert_to_face_map,
484 const Span<bool> hide_poly,
485 const BitSpan boundary,
486 const int vert)
487{
488 if (!hide::vert_all_faces_visible_get(hide_poly, vert_to_face_map, vert)) {
489 return true;
490 }
491 return boundary[vert].test();
492}
493
495 const Span<int> corner_verts,
496 const BitSpan boundary,
497 const SubdivCCG &subdiv_ccg,
498 const SubdivCCGCoord vert)
499{
500 /* TODO: Unlike the base mesh implementation this method does NOT take into account face
501 * visibility. Either this should be noted as a intentional limitation or fixed. */
502 int v1, v2;
504 subdiv_ccg, vert, corner_verts, faces, v1, v2);
505 switch (adjacency) {
507 return boundary[v1].test();
509 return boundary[v1].test() && boundary[v2].test();
511 return false;
512 }
514 return false;
515}
516
518{
519 /* TODO: Unlike the base mesh implementation this method does NOT take into account face
520 * visibility. Either this should be noted as a intentional limitation or fixed. */
521 return BM_vert_is_boundary(vert);
522}
523
524} // namespace boundary
525
526} // namespace blender::ed::sculpt_paint
527
528/* Utilities */
529
531{
532 return cache.mirror_symmetry_pass == 0 && cache.radial_symmetry_pass == 0 &&
533 cache.tile_pass == 0;
534}
535
537{
538 return cache.first_time && cache.mirror_symmetry_pass == 0 && cache.radial_symmetry_pass == 0 &&
539 cache.tile_pass == 0;
540}
541
547
548bool SCULPT_check_vertex_pivot_symmetry(const float vco[3], const float pco[3], const char symm)
549{
550 bool is_in_symmetry_area = true;
551 for (int i = 0; i < 3; i++) {
552 char symm_it = 1 << i;
553 if (symm & symm_it) {
554 if (pco[i] == 0.0f) {
555 if (vco[i] > 0.0f) {
556 is_in_symmetry_area = false;
557 }
558 }
559 if (vco[i] * pco[i] < 0.0f) {
560 is_in_symmetry_area = false;
561 }
562 }
563 }
564 return is_in_symmetry_area;
565}
566
568 const float normal_weight,
569 float grab_delta[3])
570{
571 /* Signed to support grabbing in (to make a hole) as well as out. */
572 const float len_signed = dot_v3v3(ss.cache->sculpt_normal_symm, grab_delta);
573
574 /* This scale effectively projects the offset so dragging follows the cursor,
575 * as the normal points towards the view, the scale increases. */
576 float len_view_scale;
577 {
578 float view_aligned_normal[3];
580 view_aligned_normal, ss.cache->sculpt_normal_symm, ss.cache->view_normal_symm);
581 len_view_scale = fabsf(dot_v3v3(view_aligned_normal, ss.cache->sculpt_normal_symm));
582 len_view_scale = (len_view_scale > FLT_EPSILON) ? 1.0f / len_view_scale : 1.0f;
583 }
584
585 mul_v3_fl(grab_delta, 1.0f - normal_weight);
587 grab_delta, ss.cache->sculpt_normal_symm, (len_signed * normal_weight) * len_view_scale);
588}
589
591
592std::optional<int> nearest_vert_calc_mesh(const bke::pbvh::Tree &pbvh,
593 const Span<float3> vert_positions,
594 const Span<bool> hide_vert,
595 const float3 &location,
596 const float max_distance,
597 const bool use_original)
598{
599 const float max_distance_sq = max_distance * max_distance;
600 IndexMaskMemory memory;
601 const IndexMask nodes_in_sphere = bke::pbvh::search_nodes(
602 pbvh, memory, [&](const bke::pbvh::Node &node) {
603 return node_in_sphere(node, location, max_distance_sq, use_original);
604 });
605 if (nodes_in_sphere.is_empty()) {
606 return std::nullopt;
607 }
608
609 struct NearestData {
610 int vert = -1;
611 float distance_sq = std::numeric_limits<float>::max();
612 };
613
615 const NearestData nearest = threading::parallel_reduce(
616 nodes_in_sphere.index_range(),
617 1,
618 NearestData(),
619 [&](const IndexRange range, NearestData nearest) {
620 nodes_in_sphere.slice(range).foreach_index([&](const int i) {
621 for (const int vert : nodes[i].verts()) {
622 if (!hide_vert.is_empty() && hide_vert[vert]) {
623 continue;
624 }
625 const float distance_sq = math::distance_squared(vert_positions[vert], location);
626 if (distance_sq < nearest.distance_sq) {
627 nearest = {vert, distance_sq};
628 }
629 }
630 });
631 return nearest;
632 },
633 [](const NearestData a, const NearestData b) {
634 return a.distance_sq < b.distance_sq ? a : b;
635 });
636 return nearest.vert;
637}
638
639std::optional<SubdivCCGCoord> nearest_vert_calc_grids(const bke::pbvh::Tree &pbvh,
640 const SubdivCCG &subdiv_ccg,
641 const float3 &location,
642 const float max_distance,
643 const bool use_original)
644{
645 const float max_distance_sq = max_distance * max_distance;
646 IndexMaskMemory memory;
647 const IndexMask nodes_in_sphere = bke::pbvh::search_nodes(
648 pbvh, memory, [&](const bke::pbvh::Node &node) {
649 return node_in_sphere(node, location, max_distance_sq, use_original);
650 });
651 if (nodes_in_sphere.is_empty()) {
652 return std::nullopt;
653 }
654
655 struct NearestData {
656 SubdivCCGCoord coord = {};
657 float distance_sq = std::numeric_limits<float>::max();
658 };
659
660 const BitGroupVector<> grid_hidden = subdiv_ccg.grid_hidden;
661 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
662 const Span<float3> positions = subdiv_ccg.positions;
663
665 const NearestData nearest = threading::parallel_reduce(
666 nodes_in_sphere.index_range(),
667 1,
668 NearestData(),
669 [&](const IndexRange range, NearestData nearest) {
670 nodes_in_sphere.slice(range).foreach_index([&](const int i) {
671 for (const int grid : nodes[i].grids()) {
672 const IndexRange grid_range = bke::ccg::grid_range(key, grid);
673 BKE_subdiv_ccg_foreach_visible_grid_vert(key, grid_hidden, grid, [&](const int i) {
674 const float distance_sq = math::distance_squared(positions[grid_range[i]], location);
675 if (distance_sq < nearest.distance_sq) {
676 SubdivCCGCoord coord{};
677 coord.grid_index = grid;
678 coord.x = i % key.grid_size;
679 coord.y = i / key.grid_size;
680 nearest = {coord, distance_sq};
681 }
682 });
683 }
684 });
685 return nearest;
686 },
687 [](const NearestData a, const NearestData b) {
688 return a.distance_sq < b.distance_sq ? a : b;
689 });
690 return nearest.coord;
691}
692
693std::optional<BMVert *> nearest_vert_calc_bmesh(const bke::pbvh::Tree &pbvh,
694 const float3 &location,
695 const float max_distance,
696 const bool use_original)
697{
698 const float max_distance_sq = max_distance * max_distance;
699 IndexMaskMemory memory;
700 const IndexMask nodes_in_sphere = bke::pbvh::search_nodes(
701 pbvh, memory, [&](const bke::pbvh::Node &node) {
702 return node_in_sphere(node, location, max_distance_sq, use_original);
703 });
704 if (nodes_in_sphere.is_empty()) {
705 return std::nullopt;
706 }
707
708 struct NearestData {
709 BMVert *vert = nullptr;
710 float distance_sq = std::numeric_limits<float>::max();
711 };
712
714 const NearestData nearest = threading::parallel_reduce(
715 nodes_in_sphere.index_range(),
716 1,
717 NearestData(),
718 [&](const IndexRange range, NearestData nearest) {
719 nodes_in_sphere.slice(range).foreach_index([&](const int i) {
720 for (BMVert *vert :
722 {
724 continue;
725 }
726 const float distance_sq = math::distance_squared(float3(vert->co), location);
727 if (distance_sq < nearest.distance_sq) {
728 nearest = {vert, distance_sq};
729 }
730 }
731 });
732 return nearest;
733 },
734 [](const NearestData a, const NearestData b) {
735 return a.distance_sq < b.distance_sq ? a : b;
736 });
737 return nearest.vert;
738}
739
740} // namespace blender::ed::sculpt_paint
741
743 const float br_co[3],
744 float radius,
745 char symm)
746{
747 for (char i = 0; i <= symm; ++i) {
749 continue;
750 }
752 if (len_squared_v3v3(location, vertex) < radius * radius) {
753 return true;
754 }
755 }
756 return false;
757}
758
774
776
778
779/* -------------------------------------------------------------------- */
785
799
800static bool brush_uses_topology_rake(const SculptSession &ss, const Brush &brush)
801{
802 return bke::brush::supports_topology_rake(brush) && (brush.topology_rake_factor > 0.0f) &&
803 (ss.bm != nullptr);
804}
805
828
829static bool brush_needs_rake_rotation(const Brush &brush)
830{
831 return bke::brush::supports_rake_factor(brush) && (brush.rake_factor != 0.0f);
832}
833
835
836static void rake_data_update(SculptRakeData *srd, const float co[3])
837{
838 float rake_dist = len_v3v3(srd->follow_co, co);
839 if (rake_dist > srd->follow_dist) {
840 interp_v3_v3v3(srd->follow_co, srd->follow_co, co, rake_dist - srd->follow_dist);
841 }
842}
843
844/* -------------------------------------------------------------------- */
847
848namespace dyntopo {
849
850bool stroke_is_dyntopo(const Object &object, const Brush &brush)
851{
852 const SculptSession &ss = *object.sculpt;
853 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
854 return ((pbvh.type() == bke::pbvh::Type::BMesh) && (!ss.cache || (!ss.cache->alt_smooth)) &&
855 /* Requires mesh restore, which doesn't work with
856 * dynamic-topology. */
857 !(brush.flag & BRUSH_ANCHORED) && !(brush.flag & BRUSH_DRAG_DOT) &&
859}
860
861} // namespace dyntopo
862
864
865/* -------------------------------------------------------------------- */
868
869namespace undo {
870
872{
873 SculptSession &ss = *object.sculpt;
874 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
875 IndexMaskMemory memory;
876 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
877
878 Array<bool> node_changed(node_mask.min_array_size(), false);
879
880 switch (pbvh.type()) {
883 Mesh &mesh = *static_cast<Mesh *>(object.data);
884 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
886 ".sculpt_mask", bke::AttrDomain::Point);
887 node_mask.foreach_index(GrainSize(1), [&](const int i) {
888 if (const std::optional<Span<float>> orig_data = orig_mask_data_lookup_mesh(object,
889 nodes[i]))
890 {
891 const Span<int> verts = nodes[i].verts();
892 scatter_data_mesh(*orig_data, verts, mask.span);
894 node_changed[i] = true;
895 }
896 });
897 mask.finish();
898 break;
899 }
902 const int offset = CustomData_get_offset_named(&ss.bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
903 if (offset != -1) {
904 node_mask.foreach_index(GrainSize(1), [&](const int i) {
906 if (const float *orig_mask = BM_log_find_original_vert_mask(ss.bm_log, vert)) {
907 BM_ELEM_CD_SET_FLOAT(vert, offset, *orig_mask);
909 node_changed[i] = true;
910 }
911 }
912 });
913 }
914 break;
915 }
918 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
919 const BitGroupVector<> grid_hidden = subdiv_ccg.grid_hidden;
920 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
921 MutableSpan<float> masks = subdiv_ccg.masks;
922 node_mask.foreach_index(GrainSize(1), [&](const int i) {
923 if (const std::optional<Span<float>> orig_data = orig_mask_data_lookup_grids(object,
924 nodes[i]))
925 {
926 int index = 0;
927 for (const int grid : nodes[i].grids()) {
928 const IndexRange grid_range = bke::ccg::grid_range(key, grid);
929 for (const int i : IndexRange(key.grid_area)) {
930 if (grid_hidden.is_empty() || !grid_hidden[grid][i]) {
931 masks[grid_range[i]] = (*orig_data)[index];
932 }
933 index++;
934 }
935 }
937 node_changed[i] = true;
938 }
939 });
940 break;
941 }
942 }
943 pbvh.tag_masks_changed(IndexMask::from_bools(node_changed, memory));
944}
945
947{
948 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
950 IndexMaskMemory memory;
951 const IndexMask node_mask = IndexMask::from_predicate(
952 nodes.index_range(), GrainSize(64), memory, [&](const int i) {
953 return orig_color_data_lookup_mesh(object, nodes[i]).has_value();
954 });
955
957 Mesh &mesh = *static_cast<Mesh *>(object.data);
958 const OffsetIndices<int> faces = mesh.faces();
959 const Span<int> corner_verts = mesh.corner_verts();
960 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
962 node_mask.foreach_index(GrainSize(1), [&](const int i) {
963 const Span<float4> orig_data = *orig_color_data_lookup_mesh(object, nodes[i]);
964 const Span<int> verts = nodes[i].verts();
965 for (const int i : verts.index_range()) {
967 corner_verts,
968 vert_to_face_map,
969 color_attribute.domain,
970 verts[i],
971 orig_data[i],
972 color_attribute.span);
973 }
974 });
975 pbvh.tag_attribute_changed(node_mask, mesh.active_color_attribute);
976 color_attribute.finish();
977}
978
980{
981 SculptSession &ss = *object.sculpt;
982 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
983 IndexMaskMemory memory;
984 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
985
986 Array<bool> node_changed(node_mask.min_array_size(), false);
987
988 switch (pbvh.type()) {
992 *static_cast<Mesh *>(object.data));
993 node_mask.foreach_index(GrainSize(1), [&](const int i) {
994 if (const std::optional<Span<int>> orig_data = orig_face_set_data_lookup_mesh(object,
995 nodes[i]))
996 {
997 scatter_data_mesh(*orig_data, nodes[i].faces(), attribute.span);
998 node_changed[i] = true;
999 }
1000 });
1001 attribute.finish();
1002 break;
1003 }
1005 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1008 *static_cast<Mesh *>(object.data));
1010 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1011 Vector<int> &tls = all_tls.local();
1012 if (const std::optional<Span<int>> orig_data = orig_face_set_data_lookup_grids(object,
1013 nodes[i]))
1014 {
1016 subdiv_ccg, nodes[i], tls);
1017 scatter_data_mesh(*orig_data, faces, attribute.span);
1018 node_changed[i] = true;
1019 }
1020 });
1021 attribute.finish();
1022 break;
1023 }
1025 break;
1026 }
1027
1028 pbvh.tag_face_sets_changed(IndexMask::from_bools(node_changed, memory));
1029}
1030
1031void restore_position_from_undo_step(const Depsgraph &depsgraph, Object &object)
1032{
1033 SculptSession &ss = *object.sculpt;
1034 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1035 IndexMaskMemory memory;
1036
1037 switch (pbvh.type()) {
1038 case bke::pbvh::Type::Mesh: {
1040 Mesh &mesh = *static_cast<Mesh *>(object.data);
1042 MutableSpan positions_orig = mesh.vert_positions_for_write();
1043
1044 const IndexMask node_mask = IndexMask::from_predicate(
1045 nodes.index_range(), GrainSize(64), memory, [&](const int i) {
1046 return orig_position_data_lookup_mesh(object, nodes[i]).has_value();
1047 });
1048
1049 struct LocalData {
1050 Vector<float3> translations;
1051 };
1052
1053 std::optional<ShapeKeyData> shape_key_data = ShapeKeyData::from_object(object);
1054 const bool need_translations = !ss.deform_imats.is_empty() || shape_key_data.has_value();
1055
1057 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1059 LocalData &tls = all_tls.local();
1060 const OrigPositionData orig_data = *orig_position_data_lookup_mesh(object, nodes[i]);
1061 const Span<int> verts = nodes[i].verts();
1062 const Span<float3> undo_positions = orig_data.positions;
1063 if (need_translations) {
1064 /* Calculate translations from evaluated positions before they are changed. */
1065 tls.translations.resize(verts.size());
1067 undo_positions, verts, positions_eval, tls.translations);
1068 }
1069
1070 scatter_data_mesh(undo_positions, verts, positions_eval);
1071
1072 if (positions_eval.data() == positions_orig.data()) {
1073 return;
1074 }
1075
1076 const MutableSpan<float3> translations = tls.translations;
1077 if (!ss.deform_imats.is_empty()) {
1079 }
1080
1081 if (shape_key_data) {
1082 for (MutableSpan<float3> data : shape_key_data->dependent_keys) {
1083 apply_translations(translations, verts, data);
1084 }
1085
1086 if (shape_key_data->basis_key_active) {
1087 /* The basis key positions and the mesh positions are always kept in sync. */
1088 apply_translations(translations, verts, positions_orig);
1089 }
1090 apply_translations(translations, verts, shape_key_data->active_key_data);
1091 }
1092 else {
1093 apply_translations(translations, verts, positions_orig);
1094 }
1095 });
1096 });
1097 pbvh.tag_positions_changed(node_mask);
1098 break;
1099 }
1103 return;
1104 }
1105 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1106 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1108 if (const float *orig_co = BM_log_find_original_vert_co(ss.bm_log, vert)) {
1109 copy_v3_v3(vert->co, orig_co);
1110 }
1111 }
1112 });
1113 pbvh.tag_positions_changed(node_mask);
1114 break;
1115 }
1118
1119 const IndexMask node_mask = IndexMask::from_predicate(
1120 nodes.index_range(), GrainSize(64), memory, [&](const int i) {
1121 return orig_position_data_lookup_grids(object, nodes[i]).has_value();
1122 });
1123
1124 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1125 const BitGroupVector<> grid_hidden = subdiv_ccg.grid_hidden;
1126 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
1127 MutableSpan<float3> positions = subdiv_ccg.positions;
1128 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1129 const OrigPositionData orig_data = *orig_position_data_lookup_grids(object, nodes[i]);
1130 int index = 0;
1131 for (const int grid : nodes[i].grids()) {
1132 const IndexRange grid_range = bke::ccg::grid_range(key, grid);
1133 for (const int i : IndexRange(key.grid_area)) {
1134 if (grid_hidden.is_empty() || !grid_hidden[grid][i]) {
1135 positions[grid_range[i]] = orig_data.positions[index];
1136 }
1137 index++;
1138 }
1139 }
1140 });
1141 pbvh.tag_positions_changed(node_mask);
1142 break;
1143 }
1144 }
1145}
1146
1147static void restore_from_undo_step(const Depsgraph &depsgraph, const Sculpt &sd, Object &object)
1148{
1149 SculptSession &ss = *object.sculpt;
1150 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
1151
1152 switch (brush->sculpt_brush_type) {
1155 break;
1159 break;
1161 if (ss.cache->alt_smooth) {
1164 }
1165 else {
1167 }
1168 break;
1169 default:
1172 break;
1173 }
1174}
1175
1176} // namespace undo
1177
1178} // namespace blender::ed::sculpt_paint
1179
1181 char falloff_shape)
1182{
1183 if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
1184 return ss.cache->sculpt_normal_symm;
1185 }
1186 BLI_assert(falloff_shape == PAINT_FALLOFF_SHAPE_TUBE);
1187 return ss.cache->view_normal_symm;
1188}
1189
1190/* ===== Sculpting =====
1191 */
1192
1194 const ePaintSymmetryFlags symm,
1195 const char axis,
1196 const float angle)
1197{
1199
1200 if (axis != 0) {
1201 float mat[3][3];
1202 axis_angle_to_mat3_single(mat, axis, angle);
1203 mul_m3_v3(mat, mirror);
1204 }
1205
1206 const float distsq = len_squared_v3v3(mirror, cache.location);
1207
1208 if (distsq <= 4.0f * (cache.radius_squared)) {
1209 return (2.0f * (cache.radius) - sqrtf(distsq)) / (2.0f * (cache.radius));
1210 }
1211 return 0.0f;
1212}
1213
1216 const ePaintSymmetryFlags symm,
1217 const char axis)
1218{
1219 float overlap = 0.0f;
1220
1221 for (int i = 1; i < mesh.radial_symmetry[axis - 'X']; i++) {
1222 const float angle = 2.0f * M_PI * i / mesh.radial_symmetry[axis - 'X'];
1223 overlap += calc_overlap(cache, symm, axis, angle);
1224 }
1225
1226 return overlap;
1227}
1228
1229static float calc_symmetry_feather(const Sculpt &sd,
1230 const Mesh &mesh,
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(mesh, cache, ePaintSymmetryFlags(i), 'X');
1248 overlap += calc_radial_symmetry_feather(mesh, cache, ePaintSymmetryFlags(i), 'Y');
1249 overlap += calc_radial_symmetry_feather(mesh, 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
1357enum class AverageDataFlags : uint8_t {
1358 Position = 1 << 0,
1359 Normal = 1 << 1,
1360
1362};
1364
1366 const Span<float3> vert_positions,
1367 const Span<float3> vert_normals,
1368 const Span<bool> hide_vert,
1369 const Brush &brush,
1370 const AverageDataFlags flag,
1371 const bke::pbvh::MeshNode &node,
1372 SampleLocalData &tls,
1373 AreaNormalCenterData &anctd)
1374{
1375 const SculptSession &ss = *object.sculpt;
1376 const float3 &location = ss.cache ? ss.cache->location_symm : ss.cursor_location;
1377 const float3 &view_normal = ss.cache ? ss.cache->view_normal_symm : ss.cursor_view_normal;
1378 const float position_radius = area_normal_and_center_get_position_radius(ss, brush);
1379 const float position_radius_sq = position_radius * position_radius;
1380 const float position_radius_inv = math::rcp(position_radius);
1381 const float normal_radius = area_normal_and_center_get_normal_radius(ss, brush);
1382 const float normal_radius_sq = normal_radius * normal_radius;
1383 const float normal_radius_inv = math::rcp(normal_radius);
1384
1385 const Span<int> verts = node.verts();
1386
1387 if (ss.cache && !ss.cache->accum) {
1388 if (const std::optional<OrigPositionData> orig_data = orig_position_data_lookup_mesh(object,
1389 node))
1390 {
1391 const Span<float3> orig_positions = orig_data->positions;
1392 const Span<float3> orig_normals = orig_data->normals;
1393
1394 tls.distances.reinitialize(verts.size());
1395 const MutableSpan<float> distances_sq = tls.distances;
1397 ss, orig_positions, eBrushFalloffShape(brush.falloff_shape), distances_sq);
1398
1399 for (const int i : verts.index_range()) {
1400 const int vert = verts[i];
1401 if (!hide_vert.is_empty() && hide_vert[vert]) {
1402 continue;
1403 }
1404 const bool needs_normal = bool(flag & AverageDataFlags::Normal) &&
1405 distances_sq[i] <= normal_radius_sq;
1406 const bool needs_center = bool(flag & AverageDataFlags::Position) &&
1407 distances_sq[i] <= position_radius_sq;
1408 if (!needs_normal && !needs_center) {
1409 continue;
1410 }
1411 const float3 &normal = orig_normals[i];
1412 const float distance = std::sqrt(distances_sq[i]);
1413 const int flip_index = math::dot(view_normal, normal) <= 0.0f;
1414 if (needs_center) {
1416 location, orig_positions[i], distance, position_radius_inv, flip_index, anctd);
1417 }
1418 if (needs_normal) {
1419 accumulate_area_normal(normal, distance, normal_radius_inv, flip_index, anctd);
1420 }
1421 }
1422 return;
1423 }
1424 }
1425
1426 tls.distances.reinitialize(verts.size());
1427 const MutableSpan<float> distances_sq = tls.distances;
1429 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances_sq);
1430
1431 for (const int i : verts.index_range()) {
1432 const int vert = verts[i];
1433 if (!hide_vert.is_empty() && hide_vert[vert]) {
1434 continue;
1435 }
1436 const bool needs_normal = bool(flag & AverageDataFlags::Normal) &&
1437 distances_sq[i] <= normal_radius_sq;
1438 const bool needs_center = bool(flag & AverageDataFlags::Position) &&
1439 distances_sq[i] <= position_radius_sq;
1440 if (!needs_normal && !needs_center) {
1441 continue;
1442 }
1443 const float3 &normal = vert_normals[vert];
1444 const float distance = std::sqrt(distances_sq[i]);
1445 const int flip_index = math::dot(view_normal, normal) <= 0.0f;
1446 if (needs_center) {
1448 location, vert_positions[vert], distance, position_radius_inv, flip_index, anctd);
1449 }
1450 if (needs_normal) {
1451 accumulate_area_normal(normal, distance, normal_radius_inv, flip_index, anctd);
1452 }
1453 }
1454}
1455
1457 const Brush &brush,
1458 const AverageDataFlags flag,
1459 const bke::pbvh::GridsNode &node,
1460 SampleLocalData &tls,
1461 AreaNormalCenterData &anctd)
1462{
1463 const SculptSession &ss = *object.sculpt;
1464 const float3 &location = ss.cache ? ss.cache->location_symm : ss.cursor_location;
1465 const float3 &view_normal = ss.cache ? ss.cache->view_normal_symm : ss.cursor_view_normal;
1466 const float position_radius = area_normal_and_center_get_position_radius(ss, brush);
1467 const float position_radius_sq = position_radius * position_radius;
1468 const float position_radius_inv = math::rcp(position_radius);
1469 const float normal_radius = area_normal_and_center_get_normal_radius(ss, brush);
1470 const float normal_radius_sq = normal_radius * normal_radius;
1471 const float normal_radius_inv = math::rcp(normal_radius);
1472
1473 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1475 const Span<float3> normals = subdiv_ccg.normals;
1476 const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
1477 const Span<int> grids = node.grids();
1478
1479 if (ss.cache && !ss.cache->accum) {
1480 if (const std::optional<OrigPositionData> orig_data = orig_position_data_lookup_grids(object,
1481 node))
1482 {
1483 const Span<float3> orig_positions = orig_data->positions;
1484 const Span<float3> orig_normals = orig_data->normals;
1485
1486 tls.distances.reinitialize(orig_positions.size());
1487 const MutableSpan<float> distances_sq = tls.distances;
1489 ss, orig_positions, eBrushFalloffShape(brush.falloff_shape), distances_sq);
1490
1491 for (const int i : grids.index_range()) {
1492 const IndexRange grid_range_node = bke::ccg::grid_range(key, i);
1493 const int grid = grids[i];
1494 for (const int offset : IndexRange(key.grid_area)) {
1495 if (!grid_hidden.is_empty() && grid_hidden[grid][offset]) {
1496 continue;
1497 }
1498 const int node_vert = grid_range_node[offset];
1499
1500 const bool needs_normal = bool(flag & AverageDataFlags::Normal) &&
1501 distances_sq[node_vert] <= normal_radius_sq;
1502 const bool needs_center = bool(flag & AverageDataFlags::Position) &&
1503 distances_sq[node_vert] <= position_radius_sq;
1504 if (!needs_normal && !needs_center) {
1505 continue;
1506 }
1507 const float3 &normal = orig_normals[node_vert];
1508 const float distance = std::sqrt(distances_sq[node_vert]);
1509 const int flip_index = math::dot(view_normal, normal) <= 0.0f;
1510 if (needs_center) {
1511 accumulate_area_center(location,
1512 orig_positions[node_vert],
1513 distance,
1514 position_radius_inv,
1515 flip_index,
1516 anctd);
1517 }
1518 if (needs_normal) {
1519 accumulate_area_normal(normal, distance, normal_radius_inv, flip_index, anctd);
1520 }
1521 }
1522 }
1523 return;
1524 }
1525 }
1526
1527 const Span<float3> positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
1528 tls.distances.reinitialize(positions.size());
1529 const MutableSpan<float> distances_sq = tls.distances;
1531 ss, positions, eBrushFalloffShape(brush.falloff_shape), distances_sq);
1532
1533 for (const int i : grids.index_range()) {
1534 const IndexRange grid_range_node = bke::ccg::grid_range(key, i);
1535 const int grid = grids[i];
1536 const IndexRange grid_range = bke::ccg::grid_range(key, grid);
1537 for (const int offset : IndexRange(key.grid_area)) {
1538 if (!grid_hidden.is_empty() && grid_hidden[grid][offset]) {
1539 continue;
1540 }
1541 const int node_vert = grid_range_node[offset];
1542 const int vert = grid_range[offset];
1543
1544 const bool needs_normal = uint8_t(flag & AverageDataFlags::Normal) != 0 &&
1545 distances_sq[node_vert] <= normal_radius_sq;
1546 const bool needs_center = uint8_t(flag & AverageDataFlags::Position) != 0 &&
1547 distances_sq[node_vert] <= position_radius_sq;
1548 if (!needs_normal && !needs_center) {
1549 continue;
1550 }
1551 const float3 &normal = normals[vert];
1552 const float distance = std::sqrt(distances_sq[node_vert]);
1553 const int flip_index = math::dot(view_normal, normal) <= 0.0f;
1554 if (needs_center) {
1556 location, positions[node_vert], distance, position_radius_inv, flip_index, anctd);
1557 }
1558 if (needs_normal) {
1559 accumulate_area_normal(normal, distance, normal_radius_inv, flip_index, anctd);
1560 }
1561 }
1562 }
1563}
1564
1566 const Brush &brush,
1567 const AverageDataFlags flag,
1568 const bool has_bm_orco,
1569 const bke::pbvh::BMeshNode &node,
1570 SampleLocalData &tls,
1571 AreaNormalCenterData &anctd)
1572{
1573 const SculptSession &ss = *object.sculpt;
1574 const float3 &location = ss.cache ? ss.cache->location_symm : ss.cursor_location;
1575 const float3 &view_normal = ss.cache ? ss.cache->view_normal_symm : ss.cursor_view_normal;
1576 const float position_radius = area_normal_and_center_get_position_radius(ss, brush);
1577 const float position_radius_sq = position_radius * position_radius;
1578 const float position_radius_inv = math::rcp(position_radius);
1579 const float normal_radius = area_normal_and_center_get_normal_radius(ss, brush);
1580 const float normal_radius_sq = normal_radius * normal_radius;
1581 const float normal_radius_inv = math::rcp(normal_radius);
1582
1583 bool use_original = false;
1584 if (ss.cache && !ss.cache->accum) {
1585 use_original = undo::has_bmesh_log_entry();
1586 }
1587
1588 /* When the mesh is edited we can't rely on original coords
1589 * (original mesh may not even have verts in brush radius). */
1590 if (use_original && has_bm_orco) {
1591 Span<float3> orig_positions;
1592 Span<int3> orig_tris;
1593 BKE_pbvh_node_get_bm_orco_data(node, orig_positions, orig_tris);
1594
1595 tls.positions.resize(orig_tris.size());
1596 const MutableSpan<float3> positions = tls.positions;
1597 for (const int i : orig_tris.index_range()) {
1598 const float *co_tri[3] = {
1599 orig_positions[orig_tris[i][0]],
1600 orig_positions[orig_tris[i][1]],
1601 orig_positions[orig_tris[i][2]],
1602 };
1603 closest_on_tri_to_point_v3(positions[i], location, UNPACK3(co_tri));
1604 }
1605
1606 tls.distances.reinitialize(positions.size());
1607 const MutableSpan<float> distances_sq = tls.distances;
1609 ss, positions, eBrushFalloffShape(brush.falloff_shape), distances_sq);
1610
1611 for (const int i : orig_tris.index_range()) {
1612 const bool needs_normal = bool(flag & AverageDataFlags::Normal) &&
1613 distances_sq[i] <= normal_radius_sq;
1614 const bool needs_center = bool(flag & AverageDataFlags::Position) &&
1615 distances_sq[i] <= position_radius_sq;
1616 if (!needs_normal && !needs_center) {
1617 continue;
1618 }
1619 const float3 normal = math::normal_tri(float3(orig_positions[orig_tris[i][0]]),
1620 float3(orig_positions[orig_tris[i][1]]),
1621 float3(orig_positions[orig_tris[i][2]]));
1622
1623 const float distance = std::sqrt(distances_sq[i]);
1624 const int flip_index = math::dot(view_normal, normal) <= 0.0f;
1625 if (needs_center) {
1627 location, positions[i], distance, position_radius_inv, flip_index, anctd);
1628 }
1629 if (needs_normal) {
1630 accumulate_area_normal(normal, distance, normal_radius_inv, flip_index, anctd);
1631 }
1632 }
1633 return;
1634 }
1635
1637 &const_cast<bke::pbvh::BMeshNode &>(node));
1638 if (use_original) {
1639 tls.positions.resize(verts.size());
1640 const MutableSpan<float3> positions = tls.positions;
1641 Array<float3> normals(verts.size());
1643
1644 tls.distances.reinitialize(positions.size());
1645 const MutableSpan<float> distances_sq = tls.distances;
1647 ss, positions, eBrushFalloffShape(brush.falloff_shape), distances_sq);
1648
1649 int i = 0;
1650 for (BMVert *vert : verts) {
1651 if (BM_elem_flag_test(vert, BM_ELEM_HIDDEN)) {
1652 i++;
1653 continue;
1654 }
1655 const bool needs_normal = bool(flag & AverageDataFlags::Normal) &&
1656 distances_sq[i] <= normal_radius_sq;
1657 const bool needs_center = bool(flag & AverageDataFlags::Position) &&
1658 distances_sq[i] <= position_radius_sq;
1659 if (!needs_normal && !needs_center) {
1660 i++;
1661 continue;
1662 }
1663 const float3 &normal = normals[i];
1664 const float distance = std::sqrt(distances_sq[i]);
1665 const int flip_index = math::dot(view_normal, normal) <= 0.0f;
1666 if (needs_center) {
1668 location, positions[i], distance, position_radius_inv, flip_index, anctd);
1669 }
1670 if (needs_normal) {
1671 accumulate_area_normal(normal, distance, normal_radius_inv, flip_index, anctd);
1672 }
1673 i++;
1674 }
1675 return;
1676 }
1677
1678 const Span<float3> positions = gather_bmesh_positions(verts, tls.positions);
1679
1680 tls.distances.reinitialize(positions.size());
1681 const MutableSpan<float> distances_sq = tls.distances;
1683 ss, positions, eBrushFalloffShape(brush.falloff_shape), distances_sq);
1684
1685 int i = 0;
1686 for (BMVert *vert : verts) {
1687 if (BM_elem_flag_test(vert, BM_ELEM_HIDDEN)) {
1688 i++;
1689 continue;
1690 }
1691 const bool needs_normal = bool(flag & AverageDataFlags::Normal) &&
1692 distances_sq[i] <= normal_radius_sq;
1693 const bool needs_center = bool(flag & AverageDataFlags::Position) &&
1694 distances_sq[i] <= position_radius_sq;
1695 if (!needs_normal && !needs_center) {
1696 i++;
1697 continue;
1698 }
1699 const float3 normal = vert->no;
1700 const float distance = std::sqrt(distances_sq[i]);
1701 const int flip_index = math::dot(view_normal, normal) <= 0.0f;
1702 if (needs_center) {
1704 location, positions[i], distance, position_radius_inv, flip_index, anctd);
1705 }
1706 if (needs_normal) {
1707 accumulate_area_normal(normal, distance, normal_radius_inv, flip_index, anctd);
1708 }
1709 i++;
1710 }
1711}
1712
1714 const AreaNormalCenterData &b)
1715{
1716 AreaNormalCenterData joined{};
1717
1718 joined.area_cos[0] = a.area_cos[0] + b.area_cos[0];
1719 joined.area_cos[1] = a.area_cos[1] + b.area_cos[1];
1720 joined.count_co[0] = a.count_co[0] + b.count_co[0];
1721 joined.count_co[1] = a.count_co[1] + b.count_co[1];
1722
1723 joined.area_nos[0] = a.area_nos[0] + b.area_nos[0];
1724 joined.area_nos[1] = a.area_nos[1] + b.area_nos[1];
1725 joined.count_no[0] = a.count_no[0] + b.count_no[0];
1726 joined.count_no[1] = a.count_no[1] + b.count_no[1];
1727
1728 return joined;
1729}
1730
1731void calc_area_center(const Depsgraph &depsgraph,
1732 const Brush &brush,
1733 const Object &ob,
1734 const IndexMask &node_mask,
1735 float r_area_co[3])
1736{
1737 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
1738 const SculptSession &ss = *ob.sculpt;
1739 int n;
1740
1743 switch (pbvh.type()) {
1744 case bke::pbvh::Type::Mesh: {
1745 const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
1746 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
1747 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, ob);
1748 const bke::AttributeAccessor attributes = mesh.attributes();
1749 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
1750
1753 node_mask.index_range(),
1754 1,
1756 [&](const IndexRange range, AreaNormalCenterData anctd) {
1757 SampleLocalData &tls = all_tls.local();
1758 node_mask.slice(range).foreach_index([&](const int i) {
1759 calc_area_normal_and_center_node_mesh(ob,
1760 vert_positions,
1761 vert_normals,
1762 hide_vert,
1763 brush,
1764 AverageDataFlags::Position,
1765 nodes[i],
1766 tls,
1767 anctd);
1768 });
1769 return anctd;
1770 },
1772 break;
1773 }
1775 const bool has_bm_orco = ss.bm && dyntopo::stroke_is_dyntopo(ob, brush);
1776
1779 node_mask.index_range(),
1780 1,
1782 [&](const IndexRange range, AreaNormalCenterData anctd) {
1783 SampleLocalData &tls = all_tls.local();
1784 node_mask.slice(range).foreach_index([&](const int i) {
1785 calc_area_normal_and_center_node_bmesh(
1786 ob, brush, AverageDataFlags::Position, has_bm_orco, nodes[i], tls, anctd);
1787 });
1788 return anctd;
1789 },
1791 break;
1792 }
1796 node_mask.index_range(),
1797 1,
1799 [&](const IndexRange range, AreaNormalCenterData anctd) {
1800 SampleLocalData &tls = all_tls.local();
1801 node_mask.slice(range).foreach_index([&](const int i) {
1802 calc_area_normal_and_center_node_grids(
1803 ob, brush, AverageDataFlags::Position, nodes[i], tls, anctd);
1804 });
1805 return anctd;
1806 },
1808 break;
1809 }
1810 }
1811
1812 /* For flatten center. */
1813 for (n = 0; n < anctd.area_cos.size(); n++) {
1814 if (anctd.count_co[n] == 0) {
1815 continue;
1816 }
1817
1818 mul_v3_v3fl(r_area_co, anctd.area_cos[n], 1.0f / anctd.count_co[n]);
1819 break;
1820 }
1821
1822 if (n == 2) {
1823 zero_v3(r_area_co);
1824 }
1825
1826 if (anctd.count_co[0] == 0 && anctd.count_co[1] == 0) {
1827 if (ss.cache) {
1828 copy_v3_v3(r_area_co, ss.cache->location_symm);
1829 }
1830 }
1831}
1832
1833std::optional<float3> calc_area_normal(const Depsgraph &depsgraph,
1834 const Brush &brush,
1835 const Object &ob,
1836 const IndexMask &node_mask)
1837{
1838 SculptSession &ss = *ob.sculpt;
1839 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
1840
1843 switch (pbvh.type()) {
1844 case bke::pbvh::Type::Mesh: {
1845 const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
1846 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
1847 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, ob);
1848 const bke::AttributeAccessor attributes = mesh.attributes();
1849 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
1850
1853 node_mask.index_range(),
1854 1,
1856 [&](const IndexRange range, AreaNormalCenterData anctd) {
1857 SampleLocalData &tls = all_tls.local();
1858 node_mask.slice(range).foreach_index([&](const int i) {
1859 calc_area_normal_and_center_node_mesh(ob,
1860 vert_positions,
1861 vert_normals,
1862 hide_vert,
1863 brush,
1864 AverageDataFlags::Normal,
1865 nodes[i],
1866 tls,
1867 anctd);
1868 });
1869 return anctd;
1870 },
1872 break;
1873 }
1875 const bool has_bm_orco = ss.bm && dyntopo::stroke_is_dyntopo(ob, brush);
1876
1879 node_mask.index_range(),
1880 1,
1882 [&](const IndexRange range, AreaNormalCenterData anctd) {
1883 SampleLocalData &tls = all_tls.local();
1884 node_mask.slice(range).foreach_index([&](const int i) {
1885 calc_area_normal_and_center_node_bmesh(
1886 ob,
1887 brush,
1888 AverageDataFlags::Normal,
1889 has_bm_orco,
1890 static_cast<const blender::bke::pbvh::BMeshNode &>(nodes[i]),
1891 tls,
1892 anctd);
1893 });
1894 return anctd;
1895 },
1897 break;
1898 }
1902 node_mask.index_range(),
1903 1,
1905 [&](const IndexRange range, AreaNormalCenterData anctd) {
1906 SampleLocalData &tls = all_tls.local();
1907 node_mask.slice(range).foreach_index([&](const int i) {
1908 calc_area_normal_and_center_node_grids(
1909 ob, brush, AverageDataFlags::Normal, nodes[i], tls, anctd);
1910 });
1911 return anctd;
1912 },
1914 break;
1915 }
1916 }
1917
1918 for (const int i : {0, 1}) {
1919 if (anctd.count_no[i] != 0) {
1920 if (!math::is_zero(anctd.area_nos[i])) {
1921 return math::normalize(anctd.area_nos[i]);
1922 }
1923 }
1924 }
1925 return std::nullopt;
1926}
1927
1928/*
1929 * Stabilizes the position (center) and orientation (normal) of the brush plane during a stroke.
1930 * Implements a smoothing mechanism based on a weighted moving average for both the plane normal
1931 * and the plane center.
1932 *
1933 * The stabilized normal (`r_stabilized_normal`) is computed as the average of the last
1934 * `max_normal_index` plane normals, where `max_normal_index` is determined by the
1935 * `stabilize_normal` parameter of the brush. Each new plane normal is interpolated with the
1936 * previous plane normal, with `stabilize_normal` controlling the interpolation factor.
1937 *
1938 * The stabilized center (`r_stabilized_center`) is computed based on the signed distances
1939 * of the stored plane centers from a reference plane defined by the current stroke step's center
1940 * and the stabilized normal. The signed distances are averaged, and this average is used to
1941 * adjust the position of the stabilized center such that it maintains the average offset of the
1942 * stored centers relative to the reference plane.
1943 */
1944static void calc_stabilized_plane(const Brush &brush,
1945 StrokeCache &cache,
1946 const float3 &plane_normal,
1947 const float3 &plane_center,
1948 float3 &r_stabilized_normal,
1949 float3 &r_stabilized_center)
1950{
1951 auto &plane_cache = cache.plane_brush;
1952
1953 const float normal_weight = brush.stabilize_normal;
1954 const float center_weight = brush.stabilize_plane;
1955
1956 float3 new_plane_normal;
1957 float3 new_plane_center;
1958
1959 if (plane_cache.first_time) {
1960 new_plane_normal = plane_normal;
1961 new_plane_center = plane_center;
1962
1963 const int max_normal_index = int(1 +
1964 normal_weight * (plane_brush_max_rolling_average_num - 1));
1965 const int max_center_index = int(1 +
1966 center_weight * (plane_brush_max_rolling_average_num - 1));
1967
1968 plane_cache.normals.reinitialize(max_normal_index);
1969 plane_cache.centers.reinitialize(max_center_index);
1970 plane_cache.normals.fill(plane_normal);
1971 plane_cache.centers.fill(plane_center);
1972
1973 plane_cache.normal_index = 0;
1974 plane_cache.center_index = 0;
1975 plane_cache.first_time = false;
1976 }
1977 else {
1978 const float3 last_normal = plane_cache.last_normal.value();
1979 const float3 last_center = plane_cache.last_center.value();
1980
1981 /* Interpolate between `plane_normal` and the last plane normal. */
1982 new_plane_normal = math::normalize(
1983 math::interpolate(plane_normal, last_normal, normal_weight));
1984
1985 float4 last_plane;
1986 plane_from_point_normal_v3(last_plane, last_center, last_normal);
1987
1988 /* Projection of `plane_center` on the last plane. */
1989 float3 projected_plane_center;
1990 closest_to_plane_normalized_v3(projected_plane_center, last_plane, plane_center);
1991
1992 new_plane_center = math::interpolate(plane_center, projected_plane_center, center_weight);
1993 }
1994
1995 plane_cache.normals[plane_cache.normal_index] = new_plane_normal;
1996 plane_cache.centers[plane_cache.center_index] = new_plane_center;
1997
1998 plane_cache.normal_index = (plane_cache.normal_index + 1) % plane_cache.normals.size();
1999 plane_cache.center_index = (plane_cache.center_index + 1) % plane_cache.centers.size();
2000
2001 r_stabilized_normal = float3(0.0f);
2002
2003 for (const int i : plane_cache.normals.index_range()) {
2004 r_stabilized_normal += plane_cache.normals[i];
2005 }
2006 r_stabilized_normal = math::normalize(r_stabilized_normal);
2007
2008 float4 reference_plane;
2009 plane_from_point_normal_v3(reference_plane, new_plane_center, r_stabilized_normal);
2010 float total_signed_distance = 0.0f;
2011
2012 for (const int i : plane_cache.centers.index_range()) {
2013 float signed_distance = math::dot(r_stabilized_normal, plane_cache.centers[i]) -
2014 reference_plane.w;
2015 total_signed_distance += signed_distance;
2016 }
2017
2018 const float avg_signed_distance = total_signed_distance / plane_cache.centers.size();
2019 const float new_center_signed_distance = math::dot(r_stabilized_normal, new_plane_center) -
2020 reference_plane.w;
2021 const float adjusted_distance = new_center_signed_distance - avg_signed_distance;
2022 r_stabilized_center = new_plane_center - r_stabilized_normal * adjusted_distance;
2023
2024 plane_cache.last_normal = r_stabilized_normal;
2025 plane_cache.last_center = r_stabilized_center;
2026}
2027
2029 const Brush &brush,
2030 const Object &ob,
2031 const IndexMask &node_mask,
2032 float r_area_no[3],
2033 float r_area_co[3])
2034{
2035 SculptSession &ss = *ob.sculpt;
2036 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
2037 int n;
2038
2041 switch (pbvh.type()) {
2042 case bke::pbvh::Type::Mesh: {
2043 const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
2044 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
2045 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, ob);
2046 const bke::AttributeAccessor attributes = mesh.attributes();
2047 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
2048
2051 node_mask.index_range(),
2052 1,
2054 [&](const IndexRange range, AreaNormalCenterData anctd) {
2055 SampleLocalData &tls = all_tls.local();
2056 node_mask.slice(range).foreach_index([&](const int i) {
2057 calc_area_normal_and_center_node_mesh(ob,
2058 vert_positions,
2059 vert_normals,
2060 hide_vert,
2061 brush,
2062 AverageDataFlags::All,
2063 nodes[i],
2064 tls,
2065 anctd);
2066 });
2067 return anctd;
2068 },
2070 break;
2071 }
2073 const bool has_bm_orco = ss.bm && dyntopo::stroke_is_dyntopo(ob, brush);
2074
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_bmesh(
2084 ob, brush, AverageDataFlags::All, has_bm_orco, nodes[i], tls, anctd);
2085 });
2086 return anctd;
2087 },
2089 break;
2090 }
2094 node_mask.index_range(),
2095 1,
2097 [&](const IndexRange range, AreaNormalCenterData anctd) {
2098 SampleLocalData &tls = all_tls.local();
2099 node_mask.slice(range).foreach_index([&](const int i) {
2100 calc_area_normal_and_center_node_grids(
2101 ob, brush, AverageDataFlags::All, nodes[i], tls, anctd);
2102 });
2103 return anctd;
2104 },
2106 break;
2107 }
2108 }
2109
2110 /* For flatten center. */
2111 for (n = 0; n < anctd.area_cos.size(); n++) {
2112 if (anctd.count_co[n] == 0) {
2113 continue;
2114 }
2115
2116 mul_v3_v3fl(r_area_co, anctd.area_cos[n], 1.0f / anctd.count_co[n]);
2117 break;
2118 }
2119
2120 if (n == 2) {
2121 zero_v3(r_area_co);
2122 }
2123
2124 if (anctd.count_co[0] == 0 && anctd.count_co[1] == 0) {
2125 if (ss.cache) {
2126 copy_v3_v3(r_area_co, ss.cache->location_symm);
2127 }
2128 }
2129
2130 /* For area normal. */
2131 for (n = 0; n < anctd.area_nos.size(); n++) {
2132 if (normalize_v3_v3(r_area_no, anctd.area_nos[n]) != 0.0f) {
2133 break;
2134 }
2135 }
2136
2137 if (brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_PLANE) {
2138 float3 stabilized_normal;
2139 float3 stabilized_center;
2140
2142 brush, *ss.cache, r_area_no, r_area_co, stabilized_normal, stabilized_center);
2143
2144 copy_v3_v3(r_area_no, stabilized_normal);
2145 copy_v3_v3(r_area_co, stabilized_center);
2146 }
2147}
2148
2149} // namespace blender::ed::sculpt_paint
2150
2152
2153/* -------------------------------------------------------------------- */
2156
2161static float brush_flip(const Brush &brush, const blender::ed::sculpt_paint::StrokeCache &cache)
2162{
2163 const float dir = (brush.flag & BRUSH_DIR_IN) ? -1.0f : 1.0f;
2164 const float pen_flip = cache.pen_flip ? -1.0f : 1.0f;
2165 const float invert = cache.invert ? -1.0f : 1.0f;
2166
2167 return dir * pen_flip * invert;
2168}
2169
2175static float brush_strength(const Sculpt &sd,
2177 const float feather,
2178 const PaintModeSettings & /*paint_mode_settings*/)
2179{
2180 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
2181 const blender::bke::PaintRuntime &paint_runtime = *sd.paint.runtime;
2182
2183 /* Primary strength input; square it to make lower values more sensitive. */
2184 const float root_alpha = BKE_brush_alpha_get(&sd.paint, &brush);
2185 const float alpha = root_alpha * root_alpha;
2186 const float pressure = BKE_brush_use_alpha_pressure(&brush) ?
2188 1.0f;
2189 float overlap = paint_runtime.overlap_factor;
2190 /* Spacing is integer percentage of radius, divide by 50 to get
2191 * normalized diameter. */
2192
2193 const float flip = brush_flip(brush, cache);
2194
2195 /* Pressure final value after being tweaked depending on the brush. */
2196 float final_pressure;
2197
2198 switch (brush.sculpt_brush_type) {
2200 final_pressure = pow4f(pressure);
2201 overlap = (1.0f + overlap) / 2.0f;
2202 return 0.25f * alpha * flip * final_pressure * overlap * feather;
2206 return alpha * flip * pressure * overlap * feather;
2208 return alpha * pressure * overlap * feather;
2211 /* Grab deform uses the same falloff as a regular grab brush. */
2212 return root_alpha * feather;
2213 }
2215 return root_alpha * feather * pressure * overlap;
2216 }
2217 else if (brush.cloth_deform_type == BRUSH_CLOTH_DEFORM_EXPAND) {
2218 /* Expand is more sensible to strength as it keeps expanding the cloth when sculpting over
2219 * the same vertices. */
2220 return 0.1f * alpha * flip * pressure * overlap * feather;
2221 }
2222 else {
2223 /* Multiply by 10 by default to get a larger range of strength depending on the size of the
2224 * brush and object. */
2225 return 10.0f * alpha * flip * pressure * overlap * feather;
2226 }
2228 return alpha * pressure * overlap * feather;
2230 return alpha * pressure * overlap * feather * 2.0f;
2232 final_pressure = pressure * pressure;
2233 return final_pressure * overlap * feather;
2236 return alpha * pressure * overlap * feather;
2238 /* Clay Strips needs less strength to compensate the curve. */
2239 final_pressure = powf(pressure, 1.5f);
2240 return alpha * flip * final_pressure * overlap * feather * 0.3f;
2242 final_pressure = pressure * pressure;
2243 return alpha * flip * final_pressure * overlap * feather * 1.3f;
2244
2246 overlap = (1.0f + overlap) / 2.0f;
2247 switch ((BrushMaskTool)brush.mask_tool) {
2248 case BRUSH_MASK_DRAW:
2249 return alpha * flip * pressure * overlap * feather;
2250 case BRUSH_MASK_SMOOTH:
2251 return alpha * pressure * feather;
2252 }
2253 break;
2256 return alpha * flip * pressure * overlap * feather;
2257
2259 if (flip > 0.0f) {
2260 return 0.250f * alpha * flip * pressure * overlap * feather;
2261 }
2262 else {
2263 return 0.125f * alpha * flip * pressure * overlap * feather;
2264 }
2265
2267 overlap = (1.0f + overlap) / 2.0f;
2268 return alpha * flip * pressure * overlap * feather;
2269
2271 if (flip > 0.0f || brush.plane_inversion_mode == BRUSH_PLANE_SWAP_HEIGHT_AND_DEPTH) {
2272 overlap = (1.0f + overlap) / 2.0f;
2273 return alpha * pressure * overlap * feather;
2274 }
2275 /* When the brush is inverted with the Invert Displacement mode (i.e. when the brush adds
2276 * contrast), use a different formula that results in a lower strength. This is done because,
2277 * from an artistic point of view, the contrast would otherwise generally be too strong. Note
2278 * that this behavior is coherent with the way Fill, Scrape and Flatten work. See #136211. */
2279 else {
2280 return 0.5f * alpha * pressure * overlap * feather;
2281 }
2283 return flip * alpha * pressure * feather;
2284
2286 if (flip > 0.0f) {
2287 return alpha * flip * pressure * overlap * feather;
2288 }
2289 else {
2290 return 0.25f * alpha * flip * pressure * overlap * feather;
2291 }
2292
2294 overlap = (1.0f + overlap) / 2.0f;
2295 return alpha * pressure * overlap * feather;
2296
2298 return alpha * pressure * feather;
2299
2301 return root_alpha * feather;
2302
2304 return root_alpha * feather;
2305
2307 return alpha * pressure * feather;
2308
2312 return root_alpha * feather;
2314 /* The Dyntopo Density brush does not use a normal brush workflow to calculate the effect,
2315 * and this strength value is unused. */
2316 return 0.0f;
2317 }
2319 return 0.0f;
2320}
2321
2323 const Brush &brush,
2324 const float brush_point[3],
2325 const int thread_id,
2326 float *r_value,
2327 float r_rgba[4])
2328{
2330 const MTex *mtex = BKE_brush_mask_texture_get(&brush, OB_MODE_SCULPT);
2331
2332 if (!mtex->tex) {
2333 *r_value = 1.0f;
2334 copy_v4_fl(r_rgba, 1.0f);
2335 return;
2336 }
2337
2338 float point[3];
2339 sub_v3_v3v3(point, brush_point, cache.plane_offset);
2340
2341 if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
2342 /* Get strength by feeding the vertex location directly into a texture. */
2343 *r_value = BKE_brush_sample_tex_3d(cache.paint, &brush, mtex, point, r_rgba, 0, ss.tex_pool);
2344 }
2345 else {
2346 /* If the active area is being applied for symmetry, flip it
2347 * across the symmetry axis and rotate it back to the original
2348 * position in order to project it. This insures that the
2349 * brush texture will be oriented correctly. */
2350 if (cache.radial_symmetry_pass) {
2351 mul_m4_v3(cache.symm_rot_mat_inv.ptr(), point);
2352 }
2354 cache.mirror_symmetry_pass);
2355
2356 /* Still no symmetry supported for other paint modes.
2357 * Sculpt does it DIY. */
2358 if (mtex->brush_map_mode == MTEX_MAP_MODE_AREA) {
2359 /* Similar to fixed mode, but projects from brush angle
2360 * rather than view direction. */
2361
2362 mul_m4_v3(cache.brush_local_mat.ptr(), symm_point);
2363
2364 float x = symm_point[0];
2365 float y = symm_point[1];
2366
2367 x *= mtex->size[0];
2368 y *= mtex->size[1];
2369
2370 x += mtex->ofs[0];
2371 y += mtex->ofs[1];
2372
2373 paint_get_tex_pixel(mtex, x, y, ss.tex_pool, thread_id, r_value, r_rgba);
2374
2375 add_v3_fl(r_rgba, brush.texture_sample_bias); // v3 -> Ignore alpha
2376 *r_value -= brush.texture_sample_bias;
2377 }
2378 else {
2380 cache.vc->region, symm_point, cache.projection_mat);
2381 const float point_3d[3] = {point_2d[0], point_2d[1], 0.0f};
2382 *r_value = BKE_brush_sample_tex_3d(
2383 cache.paint, &brush, mtex, point_3d, r_rgba, 0, ss.tex_pool);
2384 }
2385 }
2386}
2387
2389 const Brush &brush,
2390 float translation[3])
2391{
2392 mul_v3_fl(translation, ss.cache->bstrength);
2393 /* Handle brush inversion */
2394 if (ss.cache->bstrength < 0) {
2395 translation[0] *= -1;
2396 translation[1] *= -1;
2397 }
2398
2399 /* Apply texture size */
2400 for (int i = 0; i < 3; ++i) {
2401 translation[i] *= blender::math::safe_divide(1.0f, pow2f(brush.mtex.size[i]));
2402 }
2403
2404 /* Transform vector to object space */
2405 mul_mat3_m4_v3(ss.cache->brush_local_mat_inv.ptr(), translation);
2406
2407 /* Handle symmetry */
2408 if (ss.cache->radial_symmetry_pass) {
2409 mul_m4_v3(ss.cache->symm_rot_mat.ptr(), translation);
2410 }
2411 copy_v3_v3(
2412 translation,
2414}
2415
2416namespace blender::ed::sculpt_paint {
2417
2419{
2421 return true;
2422 }
2424 return true;
2425 }
2426 return false;
2427}
2428
2430 const float3 &location,
2431 const float radius_sq,
2432 const bool original)
2433{
2434 const Bounds<float3> &bounds = original ? node.bounds_orig() : node.bounds();
2435 const float3 nearest = math::clamp(location, bounds.min, bounds.max);
2436 return math::distance_squared(location, nearest) < radius_sq;
2437}
2438
2439bool node_in_cylinder(const DistRayAABB_Precalc &ray_dist_precalc,
2440 const bke::pbvh::Node &node,
2441 const float radius_sq,
2442 const bool original)
2443{
2444 const Bounds<float3> &bounds = original ? node.bounds_orig() : node.bounds();
2445
2446 float dummy_co[3], dummy_depth;
2447 const float dist_sq = dist_squared_ray_to_aabb_v3(
2448 &ray_dist_precalc, bounds.min, bounds.max, dummy_co, &dummy_depth);
2449
2450 /* TODO: Solve issues and enable distance check. */
2451 return dist_sq < radius_sq || true;
2452}
2453
2454static IndexMask pbvh_gather_cursor_update(Object &ob, bool use_original, IndexMaskMemory &memory)
2455{
2456 SculptSession &ss = *ob.sculpt;
2457 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
2458 const float3 center = ss.cache ? ss.cache->location_symm : ss.cursor_location;
2459 return bke::pbvh::search_nodes(pbvh, memory, [&](const bke::pbvh::Node &node) {
2460 return node_in_sphere(node, center, ss.cursor_radius, use_original);
2461 });
2462}
2463
2466 const Brush &brush,
2467 const bool use_original,
2468 const float radius_scale,
2469 IndexMaskMemory &memory)
2470{
2471 SculptSession &ss = *ob.sculpt;
2472 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
2473
2474 const float3 center = ss.cache->location_symm;
2475 const float radius_sq = math::square(ss.cache->radius * radius_scale);
2476 const bool ignore_ineffective = brush.sculpt_brush_type != SCULPT_BRUSH_TYPE_MASK;
2477 switch (brush.falloff_shape) {
2479 return bke::pbvh::search_nodes(pbvh, memory, [&](const bke::pbvh::Node &node) {
2480 if (ignore_ineffective && node_fully_masked_or_hidden(node)) {
2481 return false;
2482 }
2483 return node_in_sphere(node, center, radius_sq, use_original);
2484 });
2485 }
2486
2489 center, ss.cache->view_normal_symm);
2490 return bke::pbvh::search_nodes(pbvh, memory, [&](const bke::pbvh::Node &node) {
2491 if (ignore_ineffective && node_fully_masked_or_hidden(node)) {
2492 return false;
2493 }
2494 return node_in_cylinder(ray_dist_precalc, node, radius_sq, use_original);
2495 });
2496 }
2497 }
2498
2499 return {};
2500}
2501
2503 const eBrushFalloffShape falloff_shape,
2504 const bool use_original,
2505 const float3 &location,
2506 const float radius_sq,
2507 const std::optional<float3> &ray_direction,
2508 IndexMaskMemory &memory)
2509{
2510 switch (falloff_shape) {
2512 return bke::pbvh::search_nodes(pbvh, memory, [&](const bke::pbvh::Node &node) {
2513 if (node_fully_masked_or_hidden(node)) {
2514 return false;
2515 }
2516 return node_in_sphere(node, location, radius_sq, use_original);
2517 });
2518 }
2519
2521 BLI_assert(ray_direction);
2523 location, ray_direction.value_or(float3(0.0f)));
2524 return bke::pbvh::search_nodes(pbvh, memory, [&](const bke::pbvh::Node &node) {
2525 if (node_fully_masked_or_hidden(node)) {
2526 return false;
2527 }
2528 return node_in_cylinder(ray_dist_precalc, node, radius_sq, use_original);
2529 });
2530 }
2531 }
2533 return {};
2534}
2535
2537 const Brush &brush,
2538 const bool use_original,
2539 const float radius_scale,
2540 IndexMaskMemory &memory)
2541{
2542 return pbvh_gather_generic(ob, brush, use_original, radius_scale, memory);
2543}
2544
2545/* Calculate primary direction of movement for many brushes. */
2546static float3 calc_sculpt_normal(const Depsgraph &depsgraph,
2547 const Sculpt &sd,
2548 Object &ob,
2549 const IndexMask &node_mask)
2550{
2551 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
2552 const SculptSession &ss = *ob.sculpt;
2553 switch (brush.sculpt_plane) {
2555 return calc_area_normal(depsgraph, brush, ob, node_mask).value_or(float3(0));
2557 return ss.cache->view_normal;
2558 case SCULPT_DISP_DIR_X:
2559 return float3(1, 0, 0);
2560 case SCULPT_DISP_DIR_Y:
2561 return float3(0, 1, 0);
2562 case SCULPT_DISP_DIR_Z:
2563 return float3(0, 0, 1);
2564 }
2566 return {};
2567}
2568
2569static void update_sculpt_normal(const Depsgraph &depsgraph,
2570 const Sculpt &sd,
2571 Object &ob,
2572 const brushes::CursorSampleResult &cursor_sample_result)
2573{
2574 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
2575 StrokeCache &cache = *ob.sculpt->cache;
2576 /* Grab brush does not update the sculpt normal during a stroke. */
2577 const bool update_normal = !(brush.flag & BRUSH_ORIGINAL_NORMAL) &&
2580 !(brush.flag & BRUSH_ANCHORED)) &&
2583 cache.normal_weight > 0.0f);
2584
2585 if (cache.mirror_symmetry_pass == 0 && cache.radial_symmetry_pass == 0 &&
2587 {
2588 if (cursor_sample_result.plane_normal) {
2589 cache.sculpt_normal = *cursor_sample_result.plane_normal;
2590 }
2591 else {
2592 cache.sculpt_normal = calc_sculpt_normal(depsgraph, sd, ob, cursor_sample_result.node_mask);
2596 }
2597 }
2599 }
2600 else {
2603 }
2604}
2605
2607 const float center[3],
2608 const float screen_dir[2],
2609 float r_local_dir[3])
2610{
2611 Object &ob = *vc.obact;
2612 float loc[3];
2613
2614 mul_v3_m4v3(loc, ob.object_to_world().ptr(), center);
2615 const float zfac = ED_view3d_calc_zfac(vc.rv3d, loc);
2616
2617 ED_view3d_win_to_delta(vc.region, screen_dir, zfac, r_local_dir);
2618 normalize_v3(r_local_dir);
2619
2620 add_v3_v3(r_local_dir, ob.loc);
2621 mul_m4_v3(ob.world_to_object().ptr(), r_local_dir);
2622}
2623
2624static void calc_brush_local_mat(const float rotation,
2625 const Object &ob,
2626 float local_mat[4][4],
2627 float local_mat_inv[4][4])
2628{
2629 const StrokeCache *cache = ob.sculpt->cache;
2630 float tmat[4][4];
2631 float mat[4][4];
2632 float scale[4][4];
2633 float angle, v[3];
2634
2635 /* Ensure `ob.world_to_object` is up to date. */
2636 invert_m4_m4(ob.runtime->world_to_object.ptr(), ob.object_to_world().ptr());
2637
2638 /* Initialize last column of matrix. */
2639 mat[0][3] = 0.0f;
2640 mat[1][3] = 0.0f;
2641 mat[2][3] = 0.0f;
2642 mat[3][3] = 1.0f;
2643
2644 /* Read rotation (user angle, rake, etc.) to find the view's movement direction (negative X of
2645 * the brush). */
2646 angle = rotation + cache->special_rotation;
2647 /* By convention, motion direction points down the brush's Y axis, the angle represents the X
2648 * axis, normal is a 90 deg CCW rotation of the motion direction. */
2649 float motion_normal_screen[2];
2650 motion_normal_screen[0] = cosf(angle);
2651 motion_normal_screen[1] = sinf(angle);
2652 /* Convert view's brush transverse direction to object-space,
2653 * i.e. the normal of the plane described by the motion */
2654 float motion_normal_local[3];
2656 *cache->vc, cache->location_symm, motion_normal_screen, motion_normal_local);
2657
2658 /* Calculate the movement direction for the local matrix.
2659 * Note that there is a deliberate prioritization here: Our calculations are
2660 * designed such that the _motion vector_ gets projected into the tangent space;
2661 * in most cases this will be more intuitive than projecting the transverse
2662 * direction (which is orthogonal to the motion direction and therefore less
2663 * apparent to the user).
2664 * The Y-axis of the brush-local frame has to lie in the intersection of the tangent plane
2665 * and the motion plane. */
2666
2667 cross_v3_v3v3(v, cache->sculpt_normal, motion_normal_local);
2668 normalize_v3_v3(mat[1], v);
2669
2670 /* Get other axes. */
2671 cross_v3_v3v3(mat[0], mat[1], cache->sculpt_normal);
2672 copy_v3_v3(mat[2], cache->sculpt_normal);
2673
2674 /* Set location. */
2675 copy_v3_v3(mat[3], cache->location_symm);
2676
2677 /* Scale by brush radius. */
2678 float radius = cache->radius;
2679
2680 normalize_m4(mat);
2681 scale_m4_fl(scale, radius);
2682 mul_m4_m4m4(tmat, mat, scale);
2683
2684 /* Return tmat as is (for converting from local area coords to model-space coords). */
2685 copy_m4_m4(local_mat_inv, tmat);
2686 /* Return inverse (for converting from model-space coords to local area coords). */
2687 invert_m4_m4(local_mat, tmat);
2688}
2689
2691 const float4x4 &view_inverse,
2692 const float3 &normal,
2693 const float2 &tilt,
2694 const float tilt_strength)
2695{
2696 const float3 world_space = math::transform_direction(object.object_to_world(), normal);
2697
2698 /* Tweaked based on initial user feedback, with a value of 1.0, higher brush tilt strength
2699 * lead to the stroke surface direction becoming inverted due to extreme rotations. */
2700 constexpr float tilt_sensitivity = 0.7f;
2701 const float rot_max = M_PI_2 * tilt_strength * tilt_sensitivity;
2702 const float3 normal_tilt_y = math::rotate_direction_around_axis(
2703 world_space, view_inverse.x_axis(), tilt.y * rot_max);
2704 const float3 normal_tilt_xy = math::rotate_direction_around_axis(
2705 normal_tilt_y, view_inverse.y_axis(), tilt.x * rot_max);
2706
2707 return math::normalize(math::transform_direction(object.world_to_object(), normal_tilt_xy));
2708}
2709
2711 const StrokeCache &cache,
2712 const float tilt_strength)
2713{
2714 return tilt_apply_to_normal(
2715 *cache.vc->obact, float4x4(cache.vc->rv3d->viewinv), normal, cache.tilt, tilt_strength);
2716}
2717
2722
2723} // namespace blender::ed::sculpt_paint
2724
2725static void update_brush_local_mat(const Sculpt &sd, Object &ob)
2726{
2727 using namespace blender::ed::sculpt_paint;
2728 StrokeCache *cache = ob.sculpt->cache;
2729
2730 if (cache->mirror_symmetry_pass == 0 && cache->radial_symmetry_pass == 0) {
2731 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
2732 const MTex *mask_tex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT);
2734 mask_tex->rot, ob, cache->brush_local_mat.ptr(), cache->brush_local_mat_inv.ptr());
2735 }
2736}
2737
2739
2740/* -------------------------------------------------------------------- */
2743
2744static bool sculpt_needs_pbvh_pixels(PaintModeSettings &paint_mode_settings,
2745 const Brush &brush,
2746 Object &ob)
2747{
2749 USER_EXPERIMENTAL_TEST(&U, use_sculpt_texture_paint))
2750 {
2751 Image *image;
2752 ImageUser *image_user;
2753 return SCULPT_paint_image_canvas_get(paint_mode_settings, ob, &image, &image_user);
2754 }
2755
2756 return false;
2757}
2758
2759static void sculpt_pbvh_update_pixels(const Depsgraph &depsgraph,
2760 PaintModeSettings &paint_mode_settings,
2761 Object &ob)
2762{
2763 using namespace blender;
2764 BLI_assert(ob.type == OB_MESH);
2765
2766 Image *image;
2767 ImageUser *image_user;
2768 if (!SCULPT_paint_image_canvas_get(paint_mode_settings, ob, &image, &image_user)) {
2769 return;
2770 }
2771
2772 bke::pbvh::build_pixels(depsgraph, ob, *image, *image_user);
2773}
2774
2776
2777/* -------------------------------------------------------------------- */
2780namespace blender::ed::sculpt_paint {
2781
2805
2823} // namespace blender::ed::sculpt_paint
2824
2826{
2828 if (co[0] < 0.0f) {
2829 symm_area |= PAINT_SYMM_AREA_X;
2830 }
2831 if (co[1] < 0.0f) {
2832 symm_area |= PAINT_SYMM_AREA_Y;
2833 }
2834 if (co[2] < 0.0f) {
2835 symm_area |= PAINT_SYMM_AREA_Z;
2836 }
2837 return symm_area;
2838}
2839
2840static void flip_qt_qt(float out[4], const float in[4], const ePaintSymmetryFlags symm)
2841{
2842 float axis[3], angle;
2843
2844 quat_to_axis_angle(axis, &angle, in);
2845 normalize_v3(axis);
2846
2847 if (symm & PAINT_SYMM_X) {
2848 axis[0] *= -1.0f;
2849 angle *= -1.0f;
2850 }
2851 if (symm & PAINT_SYMM_Y) {
2852 axis[1] *= -1.0f;
2853 angle *= -1.0f;
2854 }
2855 if (symm & PAINT_SYMM_Z) {
2856 axis[2] *= -1.0f;
2857 angle *= -1.0f;
2858 }
2859
2861}
2862
2863static void flip_qt(float quat[4], const ePaintSymmetryFlags symm)
2864{
2865 flip_qt_qt(quat, quat, symm);
2866}
2867
2869 const ePaintSymmetryFlags symm,
2870 const ePaintSymmetryAreas symmarea,
2871 const float3 &pivot)
2872{
2874 for (int i = 0; i < 3; i++) {
2876 if (!(symm & symm_it)) {
2877 continue;
2878 }
2879 if (symmarea & symm_it) {
2881 }
2882 if (pivot[i] < 0.0f) {
2884 }
2885 }
2886 return result;
2887}
2888
2890 const ePaintSymmetryFlags symm,
2891 const ePaintSymmetryAreas symmarea,
2892 const float pivot[3])
2893{
2894 for (int i = 0; i < 3; i++) {
2896 if (!(symm & symm_it)) {
2897 continue;
2898 }
2899 if (symmarea & symm_it) {
2900 flip_qt(quat, symm_it);
2901 }
2902 if (pivot[i] < 0.0f) {
2903 flip_qt(quat, symm_it);
2904 }
2905 }
2906}
2907
2908namespace blender::ed::sculpt_paint {
2909
2910void calc_brush_plane(const Depsgraph &depsgraph,
2911 const Brush &brush,
2912 Object &ob,
2913 const IndexMask &node_mask,
2914 float3 &r_area_no,
2915 float3 &r_area_co)
2916{
2917 const SculptSession &ss = *ob.sculpt;
2918
2919 r_area_no = float3(0.0f);
2920 r_area_co = float3(0.0f);
2921
2922 const bool use_original_plane = (brush.flag & BRUSH_ORIGINAL_PLANE) &&
2924 const bool use_original_normal = (brush.flag & BRUSH_ORIGINAL_NORMAL) &&
2926
2927 const bool needs_recalculation = SCULPT_stroke_is_first_brush_step_of_symmetry_pass(*ss.cache) ||
2928 !use_original_plane || !use_original_normal;
2929
2930 if (SCULPT_stroke_is_main_symmetry_pass(*ss.cache) && needs_recalculation) {
2931 switch (brush.sculpt_plane) {
2933 r_area_no = ss.cache->view_normal;
2934 break;
2935
2936 case SCULPT_DISP_DIR_X:
2937 r_area_no = float3(1.0f, 0.0f, 0.0f);
2938 break;
2939
2940 case SCULPT_DISP_DIR_Y:
2941 r_area_no = float3(0.0f, 1.0f, 0.0f);
2942 break;
2943
2944 case SCULPT_DISP_DIR_Z:
2945 r_area_no = float3(0.0f, 0.0f, 1.0f);
2946 break;
2947
2949 calc_area_normal_and_center(depsgraph, brush, ob, node_mask, r_area_no, r_area_co);
2951 project_plane_v3_v3v3(r_area_no, r_area_no, ss.cache->view_normal_symm);
2952 r_area_no = math::normalize(r_area_no);
2953 }
2954 break;
2955 }
2956
2957 /* Flatten center has not been calculated yet if we are not using the area normal. */
2958 if (brush.sculpt_plane != SCULPT_DISP_DIR_AREA) {
2959 BLI_assert(math::is_zero(r_area_co));
2960 calc_area_center(depsgraph, brush, ob, node_mask, r_area_co);
2961 }
2962
2963 if (!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(*ss.cache) && use_original_normal) {
2964 r_area_no = ss.cache->sculpt_normal;
2965 }
2966 else {
2967 ss.cache->sculpt_normal = r_area_no;
2968 }
2969
2970 if (!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(*ss.cache) && use_original_plane) {
2971 r_area_co = ss.cache->last_center;
2972 }
2973 else {
2974 ss.cache->last_center = r_area_co;
2975 }
2976 }
2977 else {
2979
2980 r_area_no = ss.cache->sculpt_normal;
2981 r_area_no = symmetry_flip(r_area_no, ss.cache->mirror_symmetry_pass);
2982 r_area_no = math::transform_direction(ss.cache->symm_rot_mat, r_area_no);
2983
2984 r_area_co = ss.cache->last_center;
2985 r_area_co = symmetry_flip(r_area_co, ss.cache->mirror_symmetry_pass);
2986 r_area_co = math::transform_point(ss.cache->symm_rot_mat, r_area_co);
2987
2988 /* Shift the plane for the current tile. */
2989 r_area_co += ss.cache->plane_offset;
2990 }
2991}
2992
2993float brush_plane_offset_get(const Brush &brush, const SculptSession &ss)
2994{
2995 return brush.flag & BRUSH_OFFSET_PRESSURE ? brush.plane_offset * ss.cache->pressure :
2996 brush.plane_offset;
2997}
2998
2999} // namespace blender::ed::sculpt_paint
3000
3002
3003/* -------------------------------------------------------------------- */
3006
3007namespace blender::ed::sculpt_paint {
3008
3009static void dynamic_topology_update(const Depsgraph &depsgraph,
3010 const Scene & /*scene*/,
3011 Sculpt &sd,
3012 Object &ob,
3013 const Brush &brush,
3014 PaintModeSettings & /*paint_mode_settings*/)
3015{
3016 SculptSession &ss = *ob.sculpt;
3018
3019 /* Build a list of all nodes that are potentially within the brush's area of influence. */
3020 const bool use_original = brush_type_needs_original(brush.sculpt_brush_type) ? true :
3021 !ss.cache->accum;
3022 constexpr float radius_scale = 1.25f;
3023
3024 IndexMaskMemory memory;
3025 const IndexMask node_mask = pbvh_gather_generic(ob, brush, use_original, radius_scale, memory);
3026 if (node_mask.is_empty()) {
3027 return;
3028 }
3029
3031
3032 /* Free index based vertex info as it will become invalid after modifying the topology during the
3033 * stroke. */
3035
3037
3038 if (!(sd.flags & SCULPT_DYNTOPO_DETAIL_MANUAL)) {
3040 mode |= PBVH_Subdivide;
3041 }
3042
3043 if ((sd.flags & SCULPT_DYNTOPO_COLLAPSE) ||
3045 {
3046 mode |= PBVH_Collapse;
3047 }
3048 }
3049
3052 }
3053 else {
3055 }
3056 pbvh.tag_positions_changed(node_mask);
3057 pbvh.tag_topology_changed(node_mask);
3058 node_mask.foreach_index([&](const int i) { BKE_pbvh_node_mark_topology_update(nodes[i]); });
3059 node_mask.foreach_index(GrainSize(1), [&](const int i) {
3060 BKE_pbvh_bmesh_node_save_orig(ss.bm, ss.bm_log, &nodes[i], false);
3061 });
3062
3063 float max_edge_len;
3066 }
3067 else if (sd.flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
3069 }
3070 else {
3072 sd.detail_size, ss.cache->radius, ss.cache->dyntopo_pixel_radius, U.pixelsize);
3073 }
3074 const float min_edge_len = max_edge_len * dyntopo::detail_size::EDGE_LENGTH_MIN_FACTOR;
3075
3077 pbvh,
3078 *ss.bm_log,
3079 mode,
3080 min_edge_len,
3081 max_edge_len,
3082 ss.cache->location_symm,
3084 ss.cache->radius,
3085 (brush.flag & BRUSH_FRONTFACE) != 0,
3087}
3088
3090{
3092 /* Elastic deformations in any brush need all nodes to avoid artifacts as the effect
3093 * of the Kelvinlet is not constrained by the radius. */
3094 return true;
3095 }
3096
3098 /* Pose needs all nodes because it applies all symmetry iterations at the same time
3099 * and the IK chain can grow to any area of the model. */
3100 /* TODO: This can be optimized by filtering the nodes after calculating the chain. */
3101 return true;
3102 }
3103
3105 /* Boundary needs all nodes because it is not possible to know where the boundary
3106 * deformation is going to be propagated before calculating it. */
3107 /* TODO: after calculating the boundary info in the first iteration, it should be
3108 * possible to get the nodes that have vertices included in any boundary deformation
3109 * and cache them. */
3110 return true;
3111 }
3112
3115 {
3116 /* Snake hook in elastic deform type has same requirements as the elastic deform brush. */
3117 return true;
3118 }
3119 return false;
3120}
3121
3124 Object &ob,
3125 const Brush &brush,
3126 IndexMaskMemory &memory)
3127{
3128 const SculptSession &ss = *ob.sculpt;
3129 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
3130
3131 const bool use_original = brush_type_needs_original(brush.sculpt_brush_type) ? true :
3132 !ss.cache->accum;
3133 /* Build a list of all nodes that are potentially within the brush's area of influence */
3134
3136 /* These brushes need to update all nodes as they are not constrained by the brush radius */
3137 return {all_leaf_nodes(pbvh, memory), std::nullopt, std::nullopt};
3138 }
3140 return brushes::plane::calc_node_mask(depsgraph, ob, brush, memory);
3141 }
3143 return brushes::clay_strips::calc_node_mask(depsgraph, ob, brush, memory);
3144 }
3146 return {cloth::brush_affected_nodes_gather(ob, brush, memory), std::nullopt, std::nullopt};
3147 }
3148
3149 float radius_scale = 1.0f;
3150 /* Corners of square brushes can go outside the brush radius. */
3152 radius_scale = M_SQRT2;
3153 }
3154
3155 /* With these options enabled not all required nodes are inside the original brush radius, so
3156 * the brush can produce artifacts in some situations. */
3158 radius_scale = 2.0f;
3159 }
3160 return {pbvh_gather_generic(ob, brush, use_original, radius_scale, memory),
3161 std::nullopt,
3162 std::nullopt};
3163}
3164
3165static void push_undo_nodes(const Depsgraph &depsgraph,
3166 Object &ob,
3167 const Brush &brush,
3168 const IndexMask &node_mask)
3169{
3170 SculptSession &ss = *ob.sculpt;
3171 bool need_coords = ss.cache->supports_gravity;
3172
3174 /* Draw face sets in smooth mode moves the vertices. */
3175 if (ss.cache->alt_smooth) {
3176 need_coords = true;
3177 }
3178 else {
3180 }
3181 }
3182 else if (brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_MASK) {
3184 }
3185 else if (brush_type_is_paint(brush.sculpt_brush_type)) {
3187 }
3188 else {
3189 need_coords = true;
3190 }
3191
3192 if (need_coords) {
3194 }
3195}
3196
3197static void do_brush_action(const Depsgraph &depsgraph,
3198 const Scene & /*scene*/,
3199 Sculpt &sd,
3200 Object &ob,
3201 const Brush &brush,
3202 PaintModeSettings &paint_mode_settings)
3203{
3204 SculptSession &ss = *ob.sculpt;
3205 IndexMaskMemory memory;
3206 IndexMask texnode_mask;
3207
3208 const bool use_original = brush_type_needs_original(brush.sculpt_brush_type) ? true :
3209 !ss.cache->accum;
3210 const bool use_pixels = sculpt_needs_pbvh_pixels(paint_mode_settings, brush, ob);
3211
3212 if (sculpt_needs_pbvh_pixels(paint_mode_settings, brush, ob)) {
3213 sculpt_pbvh_update_pixels(depsgraph, paint_mode_settings, ob);
3214
3215 texnode_mask = pbvh_gather_texpaint(ob, brush, use_original, 1.0f, memory);
3216
3217 if (texnode_mask.is_empty()) {
3218 return;
3219 }
3220 }
3221
3222 const brushes::CursorSampleResult cursor_sample_result = calc_brush_node_mask(
3223 depsgraph, ob, brush, memory);
3224 const IndexMask node_mask = cursor_sample_result.node_mask;
3225
3226 /* Only act if some verts are inside the brush area. */
3227 if (node_mask.is_empty()) {
3228 return;
3229 }
3230
3231 if (auto_mask::is_enabled(sd, ob, &brush)) {
3234 cache.calc_cavity_factor(depsgraph, ob, node_mask);
3235 }
3236 }
3237
3238 if (!use_pixels) {
3239 push_undo_nodes(depsgraph, ob, brush, node_mask);
3240 }
3241
3242 /* There are issues with the underlying normals cache / mesh data that can cause the data to
3243 * become out of date.
3244 *
3245 * For EEVEE and Workbench, this is partially mitigated by the fact that the Paint BVH is used
3246 * to signal this update when drawing.
3247 *
3248 * TODO: See #141417
3249 */
3250 const bool external_engine = ss.rv3d && ss.rv3d->view_render != nullptr;
3251 if (external_engine) {
3254 }
3255 if (sculpt_brush_needs_normal(ss, brush)) {
3256 update_sculpt_normal(depsgraph, sd, ob, cursor_sample_result);
3257 }
3258
3259 update_brush_local_mat(sd, ob);
3260
3262 if (!ss.cache->cloth_sim) {
3264 depsgraph, ob, 1.0f, 0.0f, 0.0f, false, true);
3265 }
3268 ob,
3269 node_mask,
3270 *ss.cache->cloth_sim,
3271 ss.cache->location_symm,
3272 std::numeric_limits<float>::max());
3273 }
3274
3275 bool invert = ss.cache->pen_flip || ss.cache->invert;
3276 if (brush.flag & BRUSH_DIR_IN) {
3277 invert = !invert;
3278 }
3279
3280 /* Apply one type of brush action. */
3281 switch (brush.sculpt_brush_type) {
3283 if (brush_uses_vector_displacement(brush)) {
3285 }
3286 else {
3287 brushes::do_draw_brush(depsgraph, sd, ob, node_mask);
3288 }
3289 break;
3290 }
3293 /* NOTE: The enhance brush needs to initialize its state on the first brush step. The
3294 * stroke strength can become 0 during the stroke, but it can not change sign (the sign is
3295 * determined in the beginning of the stroke. So here it is important to not switch to
3296 * enhance brush in the middle of the stroke. */
3298 /* Invert mode, intensify details. */
3299 brushes::do_enhance_details_brush(depsgraph, sd, ob, node_mask);
3300 }
3301 else {
3303 depsgraph, sd, ob, node_mask, std::clamp(ss.cache->bstrength, 0.0f, 1.0f));
3304 }
3305 }
3307 brushes::do_surface_smooth_brush(depsgraph, sd, ob, node_mask);
3308 }
3309 break;
3311 brushes::do_crease_brush(depsgraph, sd, ob, node_mask);
3312 break;
3314 brushes::do_blob_brush(depsgraph, sd, ob, node_mask);
3315 break;
3317 brushes::do_pinch_brush(depsgraph, sd, ob, node_mask);
3318 break;
3320 brushes::do_inflate_brush(depsgraph, sd, ob, node_mask);
3321 break;
3323 brushes::do_grab_brush(depsgraph, sd, ob, node_mask);
3324 break;
3326 brushes::do_rotate_brush(depsgraph, sd, ob, node_mask);
3327 break;
3329 brushes::do_snake_hook_brush(depsgraph, sd, ob, node_mask);
3330 break;
3332 brushes::do_nudge_brush(depsgraph, sd, ob, node_mask);
3333 break;
3335 brushes::do_thumb_brush(depsgraph, sd, ob, node_mask);
3336 break;
3338 brushes::do_layer_brush(depsgraph, sd, ob, node_mask);
3339 break;
3341 brushes::do_clay_brush(depsgraph, sd, ob, node_mask);
3342 break;
3344 BLI_assert(cursor_sample_result.plane_normal && cursor_sample_result.plane_center);
3346 sd,
3347 ob,
3348 node_mask,
3349 *cursor_sample_result.plane_normal,
3350 *cursor_sample_result.plane_center);
3351 break;
3354 break;
3356 brushes::do_clay_thumb_brush(depsgraph, sd, ob, node_mask);
3357 break;
3359 switch ((BrushMaskTool)brush.mask_tool) {
3360 case BRUSH_MASK_DRAW:
3361 brushes::do_mask_brush(depsgraph, sd, ob, node_mask);
3362 break;
3363 case BRUSH_MASK_SMOOTH:
3364 brushes::do_smooth_mask_brush(depsgraph, sd, ob, node_mask, ss.cache->bstrength);
3365 break;
3366 }
3367 break;
3369 pose::do_pose_brush(depsgraph, sd, ob, node_mask);
3370 break;
3372 brushes::do_draw_sharp_brush(depsgraph, sd, ob, node_mask);
3373 break;
3375 brushes::do_elastic_deform_brush(depsgraph, sd, ob, node_mask);
3376 break;
3378 if (ss.cache->alt_smooth) {
3379 brushes::do_topology_relax_brush(depsgraph, sd, ob, node_mask);
3380 }
3381 else {
3382 brushes::do_topology_slide_brush(depsgraph, sd, ob, node_mask);
3383 }
3384 break;
3386 boundary::do_boundary_brush(depsgraph, sd, ob, node_mask);
3387 break;
3389 cloth::do_cloth_brush(depsgraph, sd, ob, node_mask);
3390 break;
3392 if (!ss.cache->alt_smooth) {
3393 brushes::do_draw_face_sets_brush(depsgraph, sd, ob, node_mask);
3394 }
3395 else {
3396 brushes::do_relax_face_sets_brush(depsgraph, sd, ob, node_mask);
3397 }
3398 break;
3401 break;
3404 break;
3406 color::do_paint_brush(depsgraph, paint_mode_settings, sd, ob, node_mask, texnode_mask);
3407 break;
3409 color::do_smear_brush(depsgraph, sd, ob, node_mask);
3410 break;
3412 BLI_assert(cursor_sample_result.plane_normal && cursor_sample_result.plane_center);
3414 sd,
3415 ob,
3416 node_mask,
3417 *cursor_sample_result.plane_normal,
3418 *cursor_sample_result.plane_center);
3419 break;
3420 }
3421
3423 brush.autosmooth_factor > 0)
3424 {
3427 {
3429 depsgraph, sd, ob, node_mask, brush.autosmooth_factor * (1.0f - ss.cache->pressure));
3430 }
3431 else {
3432 brushes::do_smooth_brush(depsgraph, sd, ob, node_mask, brush.autosmooth_factor);
3433 }
3434 }
3435
3436 if (brush_uses_topology_rake(ss, brush)) {
3438 depsgraph, sd, ob, node_mask, brush.topology_rake_factor);
3439 }
3440
3441 /* The cloth brush adds the gravity as a regular force and it is processed in the solver. */
3443 brushes::do_gravity_brush(depsgraph, sd, ob, node_mask);
3444 }
3445
3448 cloth::sim_activate_nodes(ob, *ss.cache->cloth_sim, node_mask);
3449 cloth::do_simulation_step(depsgraph, sd, ob, *ss.cache->cloth_sim, node_mask);
3450 }
3451 }
3452
3453 /* Update average stroke position. */
3454 const float3 world_location = math::project_point(ob.object_to_world(), ss.cache->location);
3455
3456 bke::PaintRuntime &paint_runtime = *sd.paint.runtime;
3457 add_v3_v3(paint_runtime.average_stroke_accum, world_location);
3458 paint_runtime.average_stroke_counter++;
3459 /* Update last stroke position. */
3460 paint_runtime.last_stroke_valid = true;
3461}
3462
3463} // namespace blender::ed::sculpt_paint
3464
3466 const ePaintSymmetryFlags symm,
3467 const char axis,
3468 const float angle)
3469{
3470 using namespace blender;
3475
3478
3479 /* XXX This reduces the length of the grab delta if it approaches the line of symmetry
3480 * XXX However, a different approach appears to be needed. */
3481#if 0
3482 if (sd->paint.symmetry_flags & PAINT_SYMMETRY_FEATHER) {
3483 float frac = 1.0f / max_overlap_count(sd);
3484 float reduce = (feather - frac) / (1.0f - frac);
3485
3486 printf("feather: %f frac: %f reduce: %f\n", feather, frac, reduce);
3487
3488 if (frac < 1.0f) {
3489 mul_v3_fl(cache.grab_delta_symmetry, reduce);
3490 }
3491 }
3492#endif
3493
3496 zero_v3(cache.plane_offset);
3497
3498 /* Expects XYZ. */
3499 if (axis) {
3500 rotate_m4(cache.symm_rot_mat.ptr(), axis, angle);
3501 rotate_m4(cache.symm_rot_mat_inv.ptr(), axis, -angle);
3502 }
3503
3504 mul_m4_v3(cache.symm_rot_mat.ptr(), cache.location_symm);
3505 mul_m4_v3(cache.symm_rot_mat.ptr(), cache.grab_delta_symm);
3506
3507 if (cache.supports_gravity) {
3510 }
3511
3512 if (cache.rake_rotation) {
3513 float4 new_quat;
3514 float4 existing(cache.rake_rotation->w,
3515 cache.rake_rotation->x,
3516 cache.rake_rotation->y,
3517 cache.rake_rotation->z);
3518 flip_qt_qt(new_quat, existing, symm);
3519 cache.rake_rotation_symm = math::Quaternion(new_quat);
3520 }
3521}
3522
3523namespace blender::ed::sculpt_paint {
3524
3525using BrushActionFunc = void (*)(const Depsgraph &depsgraph,
3526 const Scene &scene,
3527 Sculpt &sd,
3528 Object &ob,
3529 const Brush &brush,
3530 PaintModeSettings &paint_mode_settings);
3531
3532static void do_tiled(const Depsgraph &depsgraph,
3533 const Scene &scene,
3534 Sculpt &sd,
3535 Object &ob,
3536 const Brush &brush,
3537 PaintModeSettings &paint_mode_settings,
3538 const BrushActionFunc action)
3539{
3540 SculptSession &ss = *ob.sculpt;
3541 StrokeCache *cache = ss.cache;
3542 const float radius = cache->radius;
3543 const Bounds<float3> bb = *BKE_object_boundbox_get(&ob);
3544 const float *bbMin = bb.min;
3545 const float *bbMax = bb.max;
3546 const float *step = sd.paint.tile_offset;
3547
3548 /* These are integer locations, for real location: multiply with step and add orgLoc.
3549 * So 0,0,0 is at orgLoc. */
3550 int start[3];
3551 int end[3];
3552 int cur[3];
3553
3554 /* Position of the "prototype" stroke for tiling. */
3555 float orgLoc[3];
3556 float original_initial_location[3];
3557 copy_v3_v3(orgLoc, cache->location_symm);
3558 copy_v3_v3(original_initial_location, cache->initial_location_symm);
3559
3560 for (int dim = 0; dim < 3; dim++) {
3561 if ((sd.paint.symmetry_flags & (PAINT_TILE_X << dim)) && step[dim] > 0) {
3562 start[dim] = (bbMin[dim] - orgLoc[dim] - radius) / step[dim];
3563 end[dim] = (bbMax[dim] - orgLoc[dim] + radius) / step[dim];
3564 }
3565 else {
3566 start[dim] = end[dim] = 0;
3567 }
3568 }
3569
3570 /* First do the "un-tiled" position to initialize the stroke for this location. */
3571 cache->tile_pass = 0;
3572 action(depsgraph, scene, sd, ob, brush, paint_mode_settings);
3573
3574 /* Now do it for all the tiles. */
3575 copy_v3_v3_int(cur, start);
3576 for (cur[0] = start[0]; cur[0] <= end[0]; cur[0]++) {
3577 for (cur[1] = start[1]; cur[1] <= end[1]; cur[1]++) {
3578 for (cur[2] = start[2]; cur[2] <= end[2]; cur[2]++) {
3579 if (!cur[0] && !cur[1] && !cur[2]) {
3580 /* Skip tile at orgLoc, this was already handled before all others. */
3581 continue;
3582 }
3583
3584 ++cache->tile_pass;
3585
3586 for (int dim = 0; dim < 3; dim++) {
3587 cache->location_symm[dim] = cur[dim] * step[dim] + orgLoc[dim];
3588 cache->plane_offset[dim] = cur[dim] * step[dim];
3589 cache->initial_location_symm[dim] = cur[dim] * step[dim] +
3590 original_initial_location[dim];
3591 }
3592 action(depsgraph, scene, sd, ob, brush, paint_mode_settings);
3593 }
3594 }
3595 }
3596}
3597
3598static void do_radial_symmetry(const Depsgraph &depsgraph,
3599 const Scene &scene,
3600 Sculpt &sd,
3601 Object &ob,
3602 const Brush &brush,
3603 PaintModeSettings &paint_mode_settings,
3604 const BrushActionFunc action,
3605 const ePaintSymmetryFlags symm,
3606 const int axis,
3607 const float /*feather*/)
3608{
3609 SculptSession &ss = *ob.sculpt;
3610 const Mesh &mesh = *static_cast<Mesh *>(ob.data);
3611
3612 for (int i = 1; i < mesh.radial_symmetry[axis - 'X']; i++) {
3613 const float angle = 2.0f * M_PI * i / mesh.radial_symmetry[axis - 'X'];
3616 do_tiled(depsgraph, scene, sd, ob, brush, paint_mode_settings, action);
3617 }
3618}
3619
3624static void sculpt_fix_noise_tear(const Sculpt &sd, Object &ob)
3625{
3626 SculptSession &ss = *ob.sculpt;
3627 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
3628 const MTex *mtex = BKE_brush_mask_texture_get(&brush, OB_MODE_SCULPT);
3629
3630 if (ss.multires.active && mtex->tex && mtex->tex->type == TEX_NOISE) {
3632 }
3633}
3634
3635static void do_symmetrical_brush_actions(const Depsgraph &depsgraph,
3636 const Scene &scene,
3637 Sculpt &sd,
3638 Object &ob,
3639 const BrushActionFunc action,
3640 PaintModeSettings &paint_mode_settings)
3641{
3642 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
3643 const Mesh &mesh = *static_cast<Mesh *>(ob.data);
3644 SculptSession &ss = *ob.sculpt;
3645 StrokeCache &cache = *ss.cache;
3646 const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
3647
3648 float feather = calc_symmetry_feather(sd, mesh, *ss.cache);
3649
3650 cache.bstrength = brush_strength(sd, cache, feather, paint_mode_settings);
3651 cache.symmetry = symm;
3652
3653 /* `symm` is a bit combination of XYZ -
3654 * 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
3655 for (int i = 0; i <= symm; i++) {
3656 if (!is_symmetry_iteration_valid(i, symm)) {
3657 continue;
3658 }
3660 cache.mirror_symmetry_pass = symm;
3661 cache.radial_symmetry_pass = 0;
3662
3663 SCULPT_cache_calc_brushdata_symm(cache, symm, 0, 0);
3664 do_tiled(depsgraph, scene, sd, ob, brush, paint_mode_settings, action);
3665
3667 depsgraph, scene, sd, ob, brush, paint_mode_settings, action, symm, 'X', feather);
3669 depsgraph, scene, sd, ob, brush, paint_mode_settings, action, symm, 'Y', feather);
3671 depsgraph, scene, sd, ob, brush, paint_mode_settings, action, symm, 'Z', feather);
3672 }
3673}
3674
3675} // namespace blender::ed::sculpt_paint
3676
3678{
3680 return ob && ob->mode & OB_MODE_SCULPT;
3681}
3682
3684{
3685 using namespace blender::ed::sculpt_paint;
3687}
3688
3694
3703{
3706 ScrArea *area = CTX_wm_area(C);
3707 ARegion *region = CTX_wm_region(C);
3708
3709 if (paint && ob && BKE_paint_brush(paint) &&
3710 (area && ELEM(area->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) &&
3711 (region && region->regiontype == RGN_TYPE_WINDOW))
3712 {
3713 bToolRef *tref = area->runtime.tool;
3714 if (tref && tref->runtime && tref->runtime->keymap[0]) {
3715 std::array<wmOperatorType *, 7> trim_operators = {
3716 WM_operatortype_find("SCULPT_OT_trim_box_gesture", false),
3717 WM_operatortype_find("SCULPT_OT_trim_lasso_gesture", false),
3718 WM_operatortype_find("SCULPT_OT_trim_line_gesture", false),
3719 WM_operatortype_find("SCULPT_OT_trim_polyline_gesture", false),
3720 WM_operatortype_find("SCULPT_OT_mesh_filter", false),
3721 WM_operatortype_find("SCULPT_OT_cloth_filter", false),
3722 WM_operatortype_find("SCULPT_OT_color_filter", false),
3723 };
3724
3725 return std::any_of(trim_operators.begin(), trim_operators.end(), [tref](wmOperatorType *ot) {
3726 PointerRNA ptr;
3727 return WM_toolsystem_ref_properties_get_from_operator(tref, ot, &ptr);
3728 });
3729 }
3730 }
3731 return false;
3732}
3733
3739
3740static const char *sculpt_brush_type_name(const Sculpt &sd)
3741{
3742 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
3743
3744 switch (eBrushSculptType(brush.sculpt_brush_type)) {
3746 return "Draw Brush";
3748 return "Smooth Brush";
3750 return "Crease Brush";
3752 return "Blob Brush";
3754 return "Pinch Brush";
3756 return "Inflate Brush";
3758 return "Grab Brush";
3760 return "Nudge Brush";
3762 return "Thumb Brush";
3764 return "Layer Brush";
3766 return "Clay Brush";
3768 return "Clay Strips Brush";
3770 return "Clay Thumb Brush";
3772 return "Snake Hook Brush";
3774 return "Rotate Brush";
3776 return "Mask Brush";
3778 return "Simplify Brush";
3780 return "Draw Sharp Brush";
3782 return "Elastic Deform Brush";
3784 return "Pose Brush";
3786 return "Multi-plane Scrape Brush";
3788 return "Slide/Relax Brush";
3790 return "Boundary Brush";
3792 return "Cloth Brush";
3794 return "Draw Face Sets";
3796 return "Multires Displacement Eraser";
3798 return "Multires Displacement Smear";
3800 return "Paint Brush";
3802 return "Smear Brush";
3804 return "Plane Brush";
3805 }
3806
3807 return "Sculpting";
3808}
3809
3810namespace blender::ed::sculpt_paint {
3811
3812StrokeCache::StrokeCache() = default;
3813
3815{
3816 if (this->dial) {
3817 BLI_dial_free(this->dial);
3818 }
3819}
3820
3821} // namespace blender::ed::sculpt_paint
3822
3823enum class StrokeFlags : uint8_t {
3827};
3828
3829namespace blender::ed::sculpt_paint {
3830
3831/* Initialize mirror modifier clipping. */
3832static void sculpt_init_mirror_clipping(const Object &ob, const SculptSession &ss)
3833{
3835
3837 if (!(md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime))) {
3838 continue;
3839 }
3841
3842 if (!(mmd->flag & MOD_MIR_CLIPPING)) {
3843 continue;
3844 }
3845 /* Check each axis for mirroring. */
3846 for (int i = 0; i < 3; i++) {
3847 if (!(mmd->flag & (MOD_MIR_AXIS_X << i))) {
3848 continue;
3849 }
3850 /* Enable sculpt clipping. */
3852
3853 /* Update the clip tolerance. */
3854 ss.cache->mirror_modifier_clip.tolerance[i] = std::max(
3856
3857 /* Store matrix for mirror object clipping. */
3858 if (mmd->mirror_ob) {
3859 const float4x4 mirror_ob_inv = math::invert(mmd->mirror_ob->object_to_world());
3861 mirror_ob_inv.ptr(),
3862 ob.object_to_world().ptr());
3863 }
3864 }
3865 }
3867}
3868
3870{
3871 Main *bmain = CTX_data_main(C);
3872 Brush *cur_brush = BKE_paint_brush(paint);
3873
3874 if (cur_brush->sculpt_brush_type == SCULPT_BRUSH_TYPE_MASK) {
3875 cache->saved_mask_brush_tool = cur_brush->mask_tool;
3876 cur_brush->mask_tool = BRUSH_MASK_SMOOTH;
3877 return;
3878 }
3879
3880 if (ELEM(cur_brush->sculpt_brush_type,
3885 {
3886 /* Do nothing, this brush has its own smooth mode. */
3887 return;
3888 }
3889
3890 /* Switch to the smooth brush if possible. */
3891 BKE_paint_brush_set_essentials(bmain, paint, "Smooth");
3892 Brush *smooth_brush = BKE_paint_brush(paint);
3893
3894 if (!smooth_brush) {
3895 BKE_paint_brush_set(paint, cur_brush);
3896 CLOG_WARN(&LOG, "Switching to the smooth brush not possible, corresponding brush not");
3897 cache->saved_active_brush = nullptr;
3898 return;
3899 }
3900
3901 int cur_brush_size = BKE_brush_size_get(paint, cur_brush);
3902
3903 cache->saved_active_brush = cur_brush;
3904
3905 cache->saved_smooth_size = BKE_brush_size_get(paint, smooth_brush);
3906 BKE_brush_size_set(paint, smooth_brush, cur_brush_size);
3908}
3909
3911{
3912 Brush &brush = *BKE_paint_brush(paint);
3913
3915 brush.mask_tool = cache->saved_mask_brush_tool;
3916 return;
3917 }
3918
3919 if (ELEM(brush.sculpt_brush_type,
3924 {
3925 /* Do nothing. */
3926 return;
3927 }
3928
3929 /* If saved_active_brush is not set, brush was not switched/affected in
3930 * smooth_brush_toggle_on(). */
3931 if (cache->saved_active_brush) {
3934 cache->saved_active_brush = nullptr;
3935 }
3936}
3937
3938/* Initialize the stroke cache invariants from operator properties. */
3940 bContext *C, Sculpt &sd, SculptSession &ss, const wmOperator &op, const float mval[2])
3941{
3942 StrokeCache *cache = MEM_new<StrokeCache>(__func__);
3943 bke::PaintRuntime *paint_runtime = sd.paint.runtime;
3944 ToolSettings *tool_settings = CTX_data_tool_settings(C);
3945 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
3948
3949 ss.cache = cache;
3950
3951 /* Set scaling adjustment. */
3952 float max_scale = 0.0f;
3953 for (int i = 0; i < 3; i++) {
3954 max_scale = max_ff(max_scale, fabsf(ob.scale[i]));
3955 }
3956 cache->scale[0] = max_scale / ob.scale[0];
3957 cache->scale[1] = max_scale / ob.scale[1];
3958 cache->scale[2] = max_scale / ob.scale[2];
3959
3960 cache->plane_trim_squared = brush->plane_trim * brush->plane_trim;
3961
3962 cache->mirror_modifier_clip.flag = 0;
3963
3965
3966 /* Initial mouse location. */
3967 cache->initial_mouse = mval ? float2(mval) : float2(0.0f);
3968
3971
3973 cache->initial_normal = ss.cursor_sampled_normal.value_or(ss.cursor_normal);
3974
3975 const int mode = RNA_enum_get(op.ptr, "mode");
3976 cache->pen_flip = RNA_boolean_get(op.ptr, "pen_flip");
3977 cache->invert = mode == BRUSH_STROKE_INVERT;
3978 cache->alt_smooth = mode == BRUSH_STROKE_SMOOTH;
3979
3980 cache->normal_weight = brush->normal_weight;
3981
3982 /* Interpret invert as following normal, for grab brushes. */
3984 if (cache->invert) {
3985 cache->invert = false;
3986 cache->normal_weight = (cache->normal_weight == 0.0f);
3987 }
3988 }
3989
3990 /* Not very nice, but with current events system implementation
3991 * we can't handle brush appearance inversion hotkey separately (sergey). */
3992 if (cache->invert) {
3993 paint_runtime->draw_inverted = true;
3994 }
3995 else {
3996 paint_runtime->draw_inverted = false;
3997 }
3998
3999 /* Alt-Smooth. */
4000 if (cache->alt_smooth) {
4001 smooth_brush_toggle_on(C, &sd.paint, cache);
4002 /* Refresh the brush pointer in case we switched brush in the toggle function. */
4003 brush = BKE_paint_brush(&sd.paint);
4004 }
4005
4006 cache->mouse = cache->initial_mouse;
4007 cache->mouse_event = cache->initial_mouse;
4008 copy_v2_v2(paint_runtime->tex_mouse, cache->initial_mouse);
4009
4010 cache->initial_direction_flipped = brush_flip(*brush, *cache) < 0.0f;
4011
4012 /* Truly temporary data that isn't stored in properties. */
4013 cache->vc = vc;
4014 cache->brush = brush;
4015 cache->paint = &sd.paint;
4016
4017 /* Cache projection matrix. */
4018 cache->projection_mat = ED_view3d_ob_project_mat_get(cache->vc->rv3d, &ob);
4019
4020 const float3 z_axis(0.0f, 0.0f, 1.0f);
4021 ob.runtime->world_to_object = math::invert(ob.object_to_world());
4023 ob.world_to_object() * float4x4(cache->vc->rv3d->viewinv), z_axis));
4024
4025 cache->supports_gravity = bke::brush::supports_gravity(*brush) && sd.gravity_factor > 0.0f;
4026 /* Get gravity vector in world space. */
4027 if (cache->supports_gravity) {
4028 if (sd.gravity_object) {
4029 const Object *gravity_object = sd.gravity_object;
4030 cache->gravity_direction = gravity_object->object_to_world().z_axis();
4031 }
4032 else {
4033 cache->gravity_direction = {0.0f, 0.0f, 1.0f};
4034 }
4035
4036 /* Transform to sculpted object space. */
4038 math::transform_direction(ob.world_to_object(), cache->gravity_direction));
4039 }
4040
4041 cache->accum = true;
4042
4043 /* Make copies of the mesh vertex locations and normals for some brushes. */
4044 if (brush->flag & BRUSH_ANCHORED) {
4045 cache->accum = false;
4046 }
4047
4048 /* Draw sharp does not need the original coordinates to produce the accumulate effect, so it
4049 * should work the opposite way. */
4051 cache->accum = false;
4052 }
4053
4054 if (bke::brush::supports_accumulate(*brush)) {
4055 if (!(brush->flag & BRUSH_ACCUMULATE)) {
4056 cache->accum = false;
4058 cache->accum = true;
4059 }
4060 }
4061 }
4062
4063 /* Original coordinates require the sculpt undo system, which isn't used
4064 * for image brushes. It's also not necessary, just disable it. */
4065 if (brush && brush->sculpt_brush_type == SCULPT_BRUSH_TYPE_PAINT &&
4066 SCULPT_use_image_paint_brush(tool_settings->paint_mode, ob))
4067 {
4068 cache->accum = true;
4069 }
4070
4073 }
4074 cache->first_time = true;
4075 cache->plane_brush.first_time = true;
4076
4078 constexpr int pixel_input_threshold = 5;
4079 cache->dial = BLI_dial_init(cache->initial_mouse, pixel_input_threshold);
4080 }
4081}
4082
4083static float brush_dynamic_size_get(const Brush &brush,
4084 const StrokeCache &cache,
4085 float initial_size)
4086{
4087 const float pressure_eval = BKE_curvemapping_evaluateF(brush.curve_size, 0, cache.pressure);
4088 switch (brush.sculpt_brush_type) {
4090 return max_ff(initial_size * 0.20f, initial_size * pow3f(pressure_eval));
4092 return max_ff(initial_size * 0.30f, initial_size * powf(pressure_eval, 1.5f));
4094 float clay_stabilized_pressure = brushes::clay_thumb_get_stabilized_pressure(cache);
4095 return initial_size *
4096 BKE_curvemapping_evaluateF(brush.curve_size, 0, clay_stabilized_pressure);
4097 }
4098 default:
4099 return initial_size * pressure_eval;
4100 }
4101}
4102
4103/* In these brushes the grab delta is calculated always from the initial stroke location, which is
4104 * generally used to create grab deformations. */
4106{
4108 return true;
4109 }
4110
4111 if (ELEM(brush.sculpt_brush_type,
4117 {
4118 return true;
4119 }
4122 {
4123 return true;
4124 }
4125 return false;
4126}
4127
4128/* In these brushes the grab delta is calculated from the previous stroke location, which is used
4129 * to calculate to orientate the brush tip and deformation towards the stroke direction. */
4143
4144static void brush_delta_update(const Depsgraph &depsgraph,
4145 Paint &paint,
4146 const Object &ob,
4147 const Brush &brush)
4148{
4149 bke::PaintRuntime &paint_runtime = *paint.runtime;
4150 SculptSession &ss = *ob.sculpt;
4151 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
4152 StrokeCache *cache = ss.cache;
4153 const float mval[2] = {
4154 cache->mouse_event[0],
4155 cache->mouse_event[1],
4156 };
4157 int brush_type = brush.sculpt_brush_type;
4158
4159 if (!ELEM(brush_type,
4175 !brush_uses_topology_rake(ss, brush))
4176 {
4177 return;
4178 }
4179 float grab_location[3], imat[4][4], delta[3], loc[3];
4180
4182 if (brush_type == SCULPT_BRUSH_TYPE_GRAB && brush.flag & BRUSH_GRAB_ACTIVE_VERTEX) {
4183 if (pbvh.type() == bke::pbvh::Type::Mesh) {
4185 cache->orig_grab_location = positions[std::get<int>(ss.active_vert())];
4186 }
4187 else {
4189 }
4190 }
4191 else {
4192 copy_v3_v3(cache->orig_grab_location, cache->location);
4193 }
4194 }
4195 else if (brush_type == SCULPT_BRUSH_TYPE_SNAKE_HOOK ||
4196 (brush_type == SCULPT_BRUSH_TYPE_CLOTH &&
4198 {
4199 add_v3_v3(cache->location, cache->grab_delta);
4200 }
4201
4202 /* Compute 3d coordinate at same z from original location + mval. */
4203 mul_v3_m4v3(loc, ob.object_to_world().ptr(), cache->orig_grab_location);
4204 ED_view3d_win_to_3d(cache->vc->v3d, cache->vc->region, loc, mval, grab_location);
4205
4206 /* Compute delta to move verts by. */
4209 sub_v3_v3v3(delta, grab_location, cache->old_grab_location);
4210 invert_m4_m4(imat, ob.object_to_world().ptr());
4211 mul_mat3_m4_v3(imat, delta);
4212 add_v3_v3(cache->grab_delta, delta);
4213 }
4214 else if (need_delta_for_tip_orientation(brush)) {
4215 if (brush.flag & BRUSH_ANCHORED) {
4216 float orig[3];
4217 mul_v3_m4v3(orig, ob.object_to_world().ptr(), cache->orig_grab_location);
4218 sub_v3_v3v3(cache->grab_delta, grab_location, orig);
4219 }
4220 else {
4221 sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
4222 }
4223 invert_m4_m4(imat, ob.object_to_world().ptr());
4224 mul_mat3_m4_v3(imat, cache->grab_delta);
4225 }
4226 else {
4227 /* Use for 'Brush.topology_rake_factor'. */
4228 sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
4229 }
4230 }
4231 else {
4232 zero_v3(cache->grab_delta);
4233 }
4234
4237 }
4238
4239 copy_v3_v3(cache->old_grab_location, grab_location);
4240
4242 /* Location stays the same for finding vertices in brush radius. */
4243 copy_v3_v3(cache->location, cache->orig_grab_location);
4244
4245 paint_runtime.draw_anchored = true;
4246 copy_v2_v2(paint_runtime.anchored_initial_mouse, cache->initial_mouse);
4247 paint_runtime.anchored_size = paint_runtime.pixel_radius;
4248 }
4249
4250 /* Handle 'rake' */
4251 cache->rake_rotation = std::nullopt;
4252 cache->rake_rotation_symm = std::nullopt;
4253 invert_m4_m4(imat, ob.object_to_world().ptr());
4254 mul_mat3_m4_v3(imat, grab_location);
4255
4257 copy_v3_v3(cache->rake_data.follow_co, grab_location);
4258 }
4259
4260 if (!brush_needs_rake_rotation(brush)) {
4261 return;
4262 }
4264
4265 if (!is_zero_v3(cache->grab_delta)) {
4266 const float eps = 0.00001f;
4267
4268 float v1[3], v2[3];
4269
4270 copy_v3_v3(v1, cache->rake_data.follow_co);
4272 sub_v3_v3(v2, cache->grab_delta);
4273
4274 sub_v3_v3(v1, grab_location);
4275 sub_v3_v3(v2, grab_location);
4276
4277 if ((normalize_v3(v2) > eps) && (normalize_v3(v1) > eps) && (len_squared_v3v3(v1, v2) > eps)) {
4278 const float rake_dist_sq = len_squared_v3v3(cache->rake_data.follow_co, grab_location);
4279 const float rake_fade = (rake_dist_sq > square_f(cache->rake_data.follow_dist)) ?
4280 1.0f :
4281 sqrtf(rake_dist_sq) / cache->rake_data.follow_dist;
4282
4283 const math::AxisAngle between_vecs(v1, v2);
4284 const math::AxisAngle rotated(between_vecs.axis(),
4285 between_vecs.angle() * brush.rake_factor * rake_fade);
4286 cache->rake_rotation = math::to_quaternion(rotated);
4287 }
4288 }
4289 rake_data_update(&cache->rake_data, grab_location);
4290}
4291
4292static void cache_paint_invariants_update(StrokeCache &cache, const Brush &brush)
4293{
4294 cache.hardness = brush.hardness;
4297 {
4299 1.0f - cache.pressure :
4300 cache.pressure;
4301 }
4302
4303 cache.paint_brush.flow = brush.flow;
4306 1.0f - cache.pressure :
4307 cache.pressure;
4308 }
4309
4310 cache.paint_brush.wet_mix = brush.wet_mix;
4313 1.0f - cache.pressure :
4314 cache.pressure;
4315
4316 /* This makes wet mix more sensible in higher values, which allows to create brushes that have
4317 * a wider pressure range were they only blend colors without applying too much of the brush
4318 * color. */
4319 cache.paint_brush.wet_mix = 1.0f - pow2f(1.0f - cache.paint_brush.wet_mix);
4320 }
4321
4326 1.0f - cache.pressure :
4327 cache.pressure;
4328 }
4329
4330 cache.paint_brush.density = brush.density;
4333 1.0f - cache.pressure :
4334 cache.pressure;
4335 }
4336}
4337
4338/* Initialize the stroke cache variants from operator properties. */
4340{
4341 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
4343 bke::PaintRuntime &paint_runtime = *paint.runtime;
4344 SculptSession &ss = *ob.sculpt;
4345 StrokeCache &cache = *ss.cache;
4346 Brush &brush = *BKE_paint_brush(&sd.paint);
4347
4349 !((brush.flag & BRUSH_ANCHORED) ||
4353 {
4354 RNA_float_get_array(ptr, "location", cache.location);
4355 }
4356
4357 RNA_float_get_array(ptr, "mouse", cache.mouse);
4358 RNA_float_get_array(ptr, "mouse_event", cache.mouse_event);
4359
4360 /* XXX: Use pressure value from first brush step for brushes which don't support strokes (grab,
4361 * thumb). They depends on initial state and brush coord/pressure/etc.
4362 * It's more an events design issue, which doesn't split coordinate/pressure/angle changing
4363 * events. We should avoid this after events system re-design. */
4365 cache.pressure = RNA_float_get(ptr, "pressure");
4366 }
4367
4368 cache.tilt = {RNA_float_get(ptr, "x_tilt"), RNA_float_get(ptr, "y_tilt")};
4369
4370 /* Truly temporary data that isn't stored in properties. */
4372 cache.initial_radius = object_space_radius_get(*cache.vc, paint, brush, cache.location);
4373
4374 if (!BKE_brush_use_locked_size(&paint, &brush)) {
4375 BKE_brush_unprojected_size_set(&paint, &brush, cache.initial_radius * 2.0f);
4376 }
4377 }
4378
4379 /* Clay stabilized pressure. */
4384 }
4385 else {
4387 cache.pressure;
4391 {
4393 }
4394 }
4395 }
4396
4398 {
4399 cache.radius = brush_dynamic_size_get(brush, cache, cache.initial_radius);
4401 brush, cache, paint_runtime.initial_pixel_radius);
4402 }
4403 else {
4404 cache.radius = cache.initial_radius;
4405 cache.dyntopo_pixel_radius = paint_runtime.initial_pixel_radius;
4406 }
4407
4408 cache_paint_invariants_update(cache, brush);
4409
4410 cache.radius_squared = cache.radius * cache.radius;
4411
4412 if (brush.flag & BRUSH_ANCHORED) {
4413 /* True location has been calculated as part of the stroke system already here. */
4414 if (brush.flag & BRUSH_EDGE_TO_EDGE) {
4415 RNA_float_get_array(ptr, "location", cache.location);
4416 }
4417
4419 *cache.vc, cache.location, paint_runtime.pixel_radius);
4420 cache.radius_squared = cache.radius * cache.radius;
4421 }
4422
4423 brush_delta_update(depsgraph, paint, ob, brush);
4424
4426 cache.vertex_rotation = -BLI_dial_angle(cache.dial, cache.mouse) * cache.bstrength;
4427
4428 paint_runtime.draw_anchored = true;
4429 copy_v2_v2(paint_runtime.anchored_initial_mouse, cache.initial_mouse);
4430 paint_runtime.anchored_size = paint_runtime.pixel_radius;
4431 }
4432
4433 cache.special_rotation = paint_runtime.brush_rotation;
4434
4435 cache.iteration_count++;
4436}
4437
4438/* Returns true if any of the smoothing modes are active (currently
4439 * one of smooth brush, autosmooth, mask smooth, or shift-key
4440 * smooth). */
4442 const Brush &brush,
4443 const Object &object,
4444 int stroke_mode)
4445{
4446 SculptSession &ss = *object.sculpt;
4447 const bke::pbvh::Tree *pbvh = bke::object::pbvh_get(object);
4448 if (pbvh && auto_mask::is_enabled(sd, object, &brush)) {
4449 return true;
4450 }
4451 return ((stroke_mode == BRUSH_STROKE_SMOOTH) || (ss.cache && ss.cache->alt_smooth) ||
4454 (brush.mask_tool == BRUSH_MASK_SMOOTH)) ||
4464}
4465
4466} // namespace blender::ed::sculpt_paint
4467
4468void SCULPT_stroke_modifiers_check(const bContext *C, Object &ob, const Brush &brush)
4469{
4470 using namespace blender::ed::sculpt_paint;
4471 SculptSession &ss = *ob.sculpt;
4473 const Sculpt &sd = *CTX_data_tool_settings(C)->sculpt;
4474
4475 bool need_pmap = sculpt_needs_connectivity_info(sd, brush, ob, 0);
4477 (!BKE_sculptsession_use_pbvh_draw(&ob, rv3d) && need_pmap))
4478 {
4482 }
4483}
4484
4485namespace blender::ed::sculpt_paint {
4486static void sculpt_raycast_cb(bke::pbvh::Node &node, RaycastData &rd, float *tmin)
4487{
4488 if (BKE_pbvh_node_get_tmin(&node) >= *tmin) {
4489 return;
4490 }
4491
4493 bool use_origco = false;
4494 Span<float3> origco;
4495 if (rd.use_original && rd.is_mid_stroke) {
4496 switch (pbvh.type()) {
4498 if (const std::optional<OrigPositionData> orig_data =
4500 *rd.object, static_cast<const bke::pbvh::MeshNode &>(node)))
4501 {
4502 use_origco = true;
4503 origco = orig_data->positions;
4504 }
4505 break;
4507 if (const std::optional<OrigPositionData> orig_data = orig_position_data_lookup_grids(
4508 *rd.object, static_cast<const bke::pbvh::GridsNode &>(node)))
4509 {
4510 use_origco = true;
4511 origco = orig_data->positions;
4512 }
4513 break;
4515 use_origco = true;
4516 break;
4517 }
4518 }
4519
4521 return;
4522 }
4523
4524 bool hit = false;
4525 switch (pbvh.type()) {
4526 case bke::pbvh::Type::Mesh: {
4527 int mesh_active_vert;
4528 hit = bke::pbvh::node_raycast_mesh(static_cast<bke::pbvh::MeshNode &>(node),
4529 origco,
4530 rd.vert_positions,
4531 rd.faces,
4532 rd.corner_verts,
4533 rd.corner_tris,
4534 rd.hide_poly,
4535 rd.ray_start,
4536 rd.ray_normal,
4537 &rd.isect_precalc,
4538 &rd.depth,
4539 mesh_active_vert,
4541 rd.face_normal);
4542 if (hit) {
4543 rd.active_vertex = mesh_active_vert;
4544 }
4545 break;
4546 }
4548 SubdivCCGCoord grids_active_vert;
4550 static_cast<bke::pbvh::GridsNode &>(node),
4551 origco,
4552 rd.ray_start,
4553 rd.ray_normal,
4554 &rd.isect_precalc,
4555 &rd.depth,
4556 grids_active_vert,
4558 rd.face_normal);
4559 if (hit) {
4560 rd.active_vertex = grids_active_vert.to_index(
4562 }
4563 break;
4564 }
4566 BMVert *bmesh_active_vert;
4567 hit = bke::pbvh::node_raycast_bmesh(static_cast<bke::pbvh::BMeshNode &>(node),
4568 rd.ray_start,
4569 rd.ray_normal,
4570 &rd.isect_precalc,
4571 &rd.depth,
4572 use_origco,
4573 &bmesh_active_vert,
4574 rd.face_normal);
4575 if (hit) {
4576 rd.active_vertex = bmesh_active_vert;
4577 }
4578 break;
4579 }
4580 }
4581
4582 if (hit) {
4583 rd.hit = true;
4584 *tmin = rd.depth;
4585 }
4586}
4587
4589 FindNearestToRayData &fntrd,
4590 float *tmin)
4591{
4592 if (BKE_pbvh_node_get_tmin(&node) >= *tmin) {
4593 return;
4594 }
4596 bool use_origco = false;
4597 Span<float3> origco;
4598 if (fntrd.use_original && fntrd.is_mid_stroke) {
4599 switch (pbvh.type()) {
4601 if (const std::optional<OrigPositionData> orig_data =
4603 *fntrd.object, static_cast<const bke::pbvh::MeshNode &>(node)))
4604 {
4605 use_origco = true;
4606 origco = orig_data->positions;
4607 }
4608 break;
4610 if (const std::optional<OrigPositionData> orig_data = orig_position_data_lookup_grids(
4611 *fntrd.object, static_cast<const bke::pbvh::GridsNode &>(node)))
4612 {
4613 use_origco = true;
4614 origco = orig_data->positions;
4615 }
4616
4617 break;
4619 use_origco = true;
4620 break;
4621 }
4622 }
4623
4625 node,
4626 origco,
4627 use_origco,
4628 fntrd.vert_positions,
4629 fntrd.faces,
4630 fntrd.corner_verts,
4631 fntrd.corner_tris,
4632 fntrd.hide_poly,
4633 fntrd.subdiv_ccg,
4634 fntrd.ray_start,
4635 fntrd.ray_normal,
4636 &fntrd.depth,
4637 &fntrd.dist_sq_to_ray))
4638 {
4639 fntrd.hit = true;
4640 *tmin = fntrd.dist_sq_to_ray;
4641 }
4642}
4643
4645 const float2 &mval,
4646 float3 &r_ray_start,
4647 float3 &r_ray_end,
4648 float3 &r_ray_normal,
4649 bool original)
4650{
4651 Object &ob = *vc->obact;
4652 RegionView3D *rv3d = vc->rv3d;
4653 View3D *v3d = vc->v3d;
4654
4655 /* TODO: what if the segment is totally clipped? (return == 0). */
4657 vc->depsgraph, vc->region, vc->v3d, mval, r_ray_start, r_ray_end, true);
4658
4659 const float4x4 &world_to_object = ob.world_to_object();
4660 r_ray_start = math::transform_point(world_to_object, r_ray_start);
4661 r_ray_end = math::transform_point(world_to_object, r_ray_end);
4662
4663 float dist;
4664 r_ray_normal = math::normalize_and_get_length(r_ray_end - r_ray_start, dist);
4665
4666 if (rv3d->is_persp || RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
4667 return dist;
4668 }
4669
4670 /* Get the view origin without the addition
4671 * of -ray_normal * clip_start that
4672 * ED_view3d_win_to_segment_clipped gave us.
4673 * This is necessary to avoid floating point overflow.
4674 */
4675 float3 view_origin;
4676 ED_view3d_win_to_origin(vc->region, mval, view_origin);
4677 r_ray_start = math::transform_point(world_to_object, view_origin);
4678
4680 bke::pbvh::clip_ray_ortho(pbvh, original, r_ray_start, r_ray_end, r_ray_normal);
4681
4682 return math::distance(r_ray_start, r_ray_end);
4683}
4684
4687 const float2 &mval,
4688 const bool use_sampled_normal)
4689{
4692 const Brush &brush = *BKE_paint_brush_for_read(paint);
4693 bool original = false;
4694
4696
4697 Object &ob = *vc.obact;
4698 SculptSession &ss = *ob.sculpt;
4699
4700 const View3D *v3d = CTX_wm_view3d(C);
4701 const Base *base = CTX_data_active_base(C);
4702
4704
4705 if (!pbvh || !vc.rv3d || !BKE_base_is_visible(v3d, base)) {
4706 out->location = float3(0.0f);
4707 out->normal = float3(0.0f);
4708 ss.clear_active_elements(false);
4709 return false;
4710 }
4711
4712 /* bke::pbvh::Tree raycast to get active vertex and face normal. */
4713 float3 ray_start;
4714 float3 ray_end;
4715 float3 ray_normal;
4716 float depth = raycast_init(&vc, mval, ray_start, ray_end, ray_normal, original);
4717 SCULPT_stroke_modifiers_check(C, ob, brush);
4718
4719 RaycastData srd{};
4720 srd.use_original = original;
4721 srd.object = &ob;
4722 srd.is_mid_stroke = ob.sculpt->cache != nullptr;
4723 srd.hit = false;
4724 if (pbvh->type() == bke::pbvh::Type::Mesh) {
4725 const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
4727 srd.faces = mesh.faces();
4728 srd.corner_verts = mesh.corner_verts();
4729 srd.corner_tris = mesh.corner_tris();
4730 const bke::AttributeAccessor attributes = mesh.attributes();
4731 srd.hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
4732 }
4733 else if (pbvh->type() == bke::pbvh::Type::Grids) {
4734 srd.subdiv_ccg = ss.subdiv_ccg;
4735 }
4737 srd.ray_start = ray_start;
4738 srd.ray_normal = ray_normal;
4739 srd.depth = depth;
4740
4743 *pbvh,
4744 [&](bke::pbvh::Node &node, float *tmin) { sculpt_raycast_cb(node, srd, tmin); },
4745 ray_start,
4746 ray_normal,
4747 srd.use_original);
4748
4749 /* Cursor is not over the mesh, return default values. */
4750 if (!srd.hit) {
4751 out->location = float3(0.0f);
4752 out->normal = float3(0.0f);
4753 ss.clear_active_elements(true);
4754 return false;
4755 }
4756
4757 /* Update the active vertex of the SculptSession. */
4759
4760 switch (pbvh->type()) {
4763 ss.active_grid_index = std::nullopt;
4764 break;
4766 ss.active_face_index = std::nullopt;
4768 break;
4770 ss.active_face_index = std::nullopt;
4771 ss.active_grid_index = std::nullopt;
4772 break;
4773 }
4774
4775 out->location = ray_start + ray_normal * srd.depth;
4776
4777 /* Option to return the face normal directly for performance o accuracy reasons. */
4778 if (!use_sampled_normal) {
4779 out->normal = srd.face_normal;
4780 return srd.hit;
4781 }
4782
4783 /* Sampled normal calculation. */
4784
4785 /* Update cursor data in SculptSession. */
4786 const float3 z_axis = {0.0f, 0.0f, 1.0f};
4787 ob.runtime->world_to_object = math::invert(ob.object_to_world());
4789 math::transform_direction(ob.world_to_object() * float4x4(vc.rv3d->viewinv), z_axis));
4790 ss.cursor_normal = srd.face_normal;
4791 ss.cursor_location = out->location;
4792 ss.rv3d = vc.rv3d;
4793 ss.v3d = vc.v3d;
4794
4795 ss.cursor_radius = object_space_radius_get(vc, *paint, brush, out->location);
4796
4797 IndexMaskMemory memory;
4798 const IndexMask node_mask = pbvh_gather_cursor_update(ob, original, memory);
4799
4800 /* In case there are no nodes under the cursor, return the face normal. */
4801 if (node_mask.is_empty()) {
4802 out->normal = srd.face_normal;
4803 return true;
4804 }
4805
4807
4808 /* Calculate the sampled normal. */
4809 if (const std::optional<float3> sampled_normal = calc_area_normal(
4810 *depsgraph, brush, ob, node_mask))
4811 {
4812 out->normal = *sampled_normal;
4813 ss.cursor_sampled_normal = *sampled_normal;
4814 }
4815 else {
4816 /* Use face normal when there are no vertices to sample inside the cursor radius. */
4817 out->normal = srd.face_normal;
4818 }
4819 return true;
4820}
4821
4828 float3 &out,
4829 const float2 &mval,
4830 const bool force_original,
4831 const bool check_closest,
4832 const bool limit_closest_radius)
4833{
4835
4837
4838 Object &ob = *vc.obact;
4839
4840 SculptSession &ss = *ob.sculpt;
4841 StrokeCache *cache = ss.cache;
4842 const bool original = force_original || ((cache) ? !cache->accum : false);
4844 const Brush &brush = *BKE_paint_brush(paint);
4845
4846 SCULPT_stroke_modifiers_check(C, ob, brush);
4847
4848 float3 ray_start;
4849 float3 ray_end;
4850 float3 ray_normal;
4851 const float depth = raycast_init(&vc, mval, ray_start, ray_end, ray_normal, original);
4852
4854
4855 bool hit = false;
4856 {
4857 RaycastData rd;
4858 rd.object = &ob;
4859 rd.is_mid_stroke = ob.sculpt->cache != nullptr;
4860 rd.ray_start = ray_start;
4861 rd.ray_normal = ray_normal;
4862 rd.hit = false;
4863 if (pbvh.type() == bke::pbvh::Type::Mesh) {
4864 const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
4866 rd.faces = mesh.faces();
4867 rd.corner_verts = mesh.corner_verts();
4868 rd.corner_tris = mesh.corner_tris();
4869 const bke::AttributeAccessor attributes = mesh.attributes();
4870 rd.hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
4871 }
4872 else if (pbvh.type() == bke::pbvh::Type::Grids) {
4873 rd.subdiv_ccg = ss.subdiv_ccg;
4874 }
4876 rd.depth = depth;
4877 rd.use_original = original;
4879
4881 pbvh,
4882 [&](bke::pbvh::Node &node, float *tmin) { sculpt_raycast_cb(node, rd, tmin); },
4883 ray_start,
4884 ray_normal,
4885 rd.use_original);
4886 if (rd.hit) {
4887 hit = true;
4888 out = ray_start + ray_normal * rd.depth;
4889 }
4890 }
4891
4892 if (hit || !check_closest) {
4893 return hit;
4894 }
4895
4896 FindNearestToRayData fntrd{};
4897 fntrd.use_original = original;
4898 fntrd.object = &ob;
4899 fntrd.is_mid_stroke = ss.cache != nullptr;
4900 fntrd.hit = false;
4901 if (pbvh.type() == bke::pbvh::Type::Mesh) {
4902 const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
4904 fntrd.faces = mesh.faces();
4905 fntrd.corner_verts = mesh.corner_verts();
4906 fntrd.corner_tris = mesh.corner_tris();
4907 const bke::AttributeAccessor attributes = mesh.attributes();
4908 fntrd.hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
4909 }
4910 else if (pbvh.type() == bke::pbvh::Type::Grids) {
4911 fntrd.subdiv_ccg = ss.subdiv_ccg;
4912 }
4913 fntrd.ray_start = ray_start;
4914 fntrd.ray_normal = ray_normal;
4915 fntrd.depth = std::numeric_limits<float>::max();
4916 fntrd.dist_sq_to_ray = std::numeric_limits<float>::max();
4917
4919 pbvh,
4920 [&](bke::pbvh::Node &node, float *tmin) {
4921 sculpt_find_nearest_to_ray_cb(node, fntrd, tmin);
4922 },
4923 ray_start,
4924 ray_normal,
4925 fntrd.use_original);
4926 if (fntrd.hit && fntrd.dist_sq_to_ray) {
4927 hit = true;
4928 out = ray_start + ray_normal * fntrd.depth;
4929 }
4930
4931 float closest_radius_sq = std::numeric_limits<float>::max();
4932 if (limit_closest_radius) {
4933 closest_radius_sq = object_space_radius_get(vc, *paint, brush, out);
4934 closest_radius_sq *= closest_radius_sq;
4935 }
4936
4937 return hit && fntrd.dist_sq_to_ray < closest_radius_sq;
4938}
4939
4941 float out[3],
4942 const float mval[2],
4943 const bool force_original)
4944{
4946 const bool check_closest = brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE;
4947
4948 float3 location;
4950 C, location, mval, force_original, check_closest, true);
4951 if (result) {
4952 copy_v3_v3(out, location);
4953 }
4954 return result;
4955}
4956} // namespace blender::ed::sculpt_paint
4957
4958static void brush_init_tex(const Sculpt &sd, SculptSession &ss)
4959{
4960 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
4961 const MTex *mask_tex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT);
4962
4963 /* Init mtex nodes. */
4964 if (mask_tex->tex && mask_tex->tex->nodetree) {
4965 /* Has internal flag to detect it only does it once. */
4967 }
4968
4969 if (ss.tex_pool == nullptr) {
4971 }
4972}
4973
4975{
4977 ToolSettings *tool_settings = CTX_data_tool_settings(C);
4978 const Sculpt &sd = *tool_settings->sculpt;
4980 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
4981
4982 if (!G.background) {
4984 }
4985 brush_init_tex(sd, ss);
4986
4987 const bool needs_colors = blender::ed::sculpt_paint::brush_type_is_paint(
4988 brush->sculpt_brush_type) &&
4989 !SCULPT_use_image_paint_brush(tool_settings->paint_mode, ob);
4990
4991 if (needs_colors) {
4993 }
4994
4995 /* CTX_data_ensure_evaluated_depsgraph should be used at the end to include the updates of
4996 * earlier steps modifying the data. */
5000
5002}
5003
5005 const Sculpt &sd,
5006 Object &ob)
5007{
5008 using namespace blender::ed::sculpt_paint;
5009 SculptSession &ss = *ob.sculpt;
5010 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
5011
5012 /* Brushes that use original coordinates and need a "restore" step. This has to happen separately
5013 * rather than in the brush deformation calculation because that is called once for each symmetry
5014 * pass, potentially within the same BVH node.
5015 *
5016 * NOTE: Despite the Cloth and Boundary brush using original coordinates, the brushes do not
5017 * expect this restoration to happen on every stroke step. Performing this restoration causes
5018 * issues with the cloth simulation mode for those brushes.
5019 */
5020 if (ELEM(brush->sculpt_brush_type,
5025 {
5027 return;
5028 }
5029
5030 /* For the cloth brush it makes more sense to not restore the mesh state to keep running the
5031 * simulation from the previous state. */
5033 return;
5034 }
5035
5036 /* Restore the mesh before continuing with anchored stroke. */
5037 if (brush->flag & BRUSH_ANCHORED || brush->flag & BRUSH_DRAG_DOT) {
5038
5040
5041 if (ss.cache) {
5042 /* Temporary data within the StrokeCache that is usually cleared at the end of the stroke
5043 * needs to be invalidated here so that the brushes do not accumulate and apply extra data.
5044 * See #129069. */
5046 ss.cache->paint_brush.mix_colors = {};
5047 }
5048 }
5049}
5050
5051namespace blender::ed::sculpt_paint {
5052
5053static void tag_mesh_positions_changed(Object &object, const bool use_pbvh_draw)
5054{
5055 Mesh &mesh = *static_cast<Mesh *>(object.data);
5056
5057 /* Various operations inside sculpt mode can cause either the #MeshRuntimeData or the entire
5058 * Mesh to be changed (e.g. Undoing the very first operation after opening a file, performing
5059 * remesh, etc).
5060 *
5061 * This isn't an ideal fix for the core issue here, but to mitigate the drastic performance
5062 * falloff, we refreeze the cache before we do any operation that would tag this runtime
5063 * cache as dirty.
5064 *
5065 * See #130636. */
5066 if (!mesh.runtime->corner_tris_cache.frozen) {
5067 mesh.runtime->corner_tris_cache.freeze();
5068 }
5069
5070 /* Updating mesh positions without marking caches dirty is generally not good, but since
5071 * sculpt mode has special requirements and is expected to have sole ownership of the mesh it
5072 * modifies, it's generally okay. */
5073 if (use_pbvh_draw) {
5074 /* When drawing from bke::pbvh::Tree is used, vertex and face normals are updated
5075 * later in #bke::pbvh::update_normals. However, we update the mesh's bounds eagerly here
5076 * since they are trivial to access from the bke::pbvh::Tree. Updating the
5077 * object's evaluated geometry bounding box is necessary because sculpt strokes don't cause
5078 * an object reevaluation. */
5079 mesh.tag_positions_changed_no_normals();
5080 /* Sculpt mode does not use or recalculate face corner normals, so they are cleared. */
5081 mesh.runtime->corner_normals_cache.tag_dirty();
5082 }
5083 else {
5084 /* Drawing happens from the modifier stack evaluation result.
5085 * Tag both coordinates and normals as modified, as both needed for proper drawing and the
5086 * modifier stack is not guaranteed to tag normals for update. */
5087 mesh.tag_positions_changed();
5088 }
5089
5090 if (const bke::pbvh::Tree *pbvh = bke::object::pbvh_get(object)) {
5091 mesh.bounds_set_eager(bke::pbvh::bounds_get(*pbvh));
5092 if (object.runtime->bounds_eval) {
5093 object.runtime->bounds_eval = mesh.bounds_min_max();
5094 }
5095 }
5096}
5097
5098void flush_update_step(const bContext *C, const UpdateType update_type)
5099{
5102
5103 if (rv3d) {
5104 /* Mark for faster 3D viewport redraws. */
5105 rv3d->rflag |= RV3D_PAINTING;
5106 }
5107
5108 const SculptSession &ss = *ob.sculpt;
5109 const MultiresModifierData *mmd = ss.multires.modifier;
5110 if (mmd != nullptr) {
5111 Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
5113 }
5114
5115 ARegion &region = *CTX_wm_region(C);
5116 if (update_type == UpdateType::Image) {
5117 ED_region_tag_redraw(&region);
5118 if (update_type == UpdateType::Image) {
5119 /* Early exit when only need to update the images. We don't want to tag any geometry updates
5120 * that would rebuild the bke::pbvh::Tree. */
5121 return;
5122 }
5123 }
5124
5126
5127 const bool use_pbvh_draw = BKE_sculptsession_use_pbvh_draw(&ob, rv3d);
5128 /* Only current viewport matters, slower update for all viewports will
5129 * be done in sculpt_flush_update_done. */
5130 if (!use_pbvh_draw) {
5131 /* Slow update with full dependency graph update and all that comes with it.
5132 * Needed when there are modifiers or full shading in the 3D viewport. */
5134 }
5135
5136 ED_region_tag_redraw(&region);
5137
5139 if (update_type == UpdateType::Position && !ss.shapekey_active) {
5140 if (pbvh.type() == bke::pbvh::Type::Mesh) {
5141 tag_mesh_positions_changed(ob, use_pbvh_draw);
5142 }
5143 }
5144}
5145
5146void flush_update_done(const bContext *C, Object &ob, const UpdateType update_type)
5147{
5148 /* After we are done drawing the stroke, check if we need to do a more
5149 * expensive depsgraph tag to update geometry. */
5150 const Mesh &mesh = *static_cast<Mesh *>(ob.data);
5151
5152 /* Always needed for linked duplicates. */
5153 bool need_tag = ID_REAL_USERS(&mesh.id) > 1;
5154
5155 RegionView3D *current_rv3d = CTX_wm_region_view3d(C);
5156 if (current_rv3d) {
5157 current_rv3d->rflag &= ~RV3D_PAINTING;
5158 }
5159
5161 LISTBASE_FOREACH (wmWindow *, win, &wm.windows) {
5162 const bScreen &screen = *WM_window_get_active_screen(win);
5163 LISTBASE_FOREACH (ScrArea *, area, &screen.areabase) {
5164 const SpaceLink &sl = *static_cast<SpaceLink *>(area->spacedata.first);
5165 if (sl.spacetype != SPACE_VIEW3D) {
5166 continue;
5167 }
5168
5169 /* Tag all 3D viewports for redraw now that we are done. Other
5170 * viewports did not get a full redraw, and anti-aliasing for the
5171 * current viewport was deactivated. */
5172 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
5173 if (region->regiontype == RGN_TYPE_WINDOW) {
5174 const RegionView3D *other_rv3d = static_cast<RegionView3D *>(region->regiondata);
5175 if (other_rv3d != current_rv3d) {
5176 need_tag |= !BKE_sculptsession_use_pbvh_draw(&ob, other_rv3d);
5177 }
5178
5179 ED_region_tag_redraw(region);
5180 }
5181 }
5182 }
5183
5184 if (update_type == UpdateType::Image) {
5185 LISTBASE_FOREACH (ScrArea *, area, &screen.areabase) {
5186 const SpaceLink &sl = *static_cast<SpaceLink *>(area->spacedata.first);
5187 if (sl.spacetype != SPACE_IMAGE) {
5188 continue;
5189 }
5191 }
5192 }
5193 }
5194
5196
5197 if (update_type == UpdateType::Position) {
5199
5200 /* Coordinates were modified, so fake neighbors are not longer valid. */
5202 }
5203
5204 if (update_type == UpdateType::Position) {
5205 if (pbvh.type() == bke::pbvh::Type::BMesh) {
5206 SculptSession &ss = *ob.sculpt;
5208 }
5209 }
5210
5211 if (need_tag) {
5213 }
5214}
5215
5216/* Replace an entire attribute using implicit sharing to avoid copies when possible. */
5217static void replace_attribute(const bke::AttributeAccessor src_attributes,
5218 const StringRef name,
5219 const bke::AttrDomain domain,
5220 const bke::AttrType data_type,
5221 bke::MutableAttributeAccessor dst_attributes)
5222{
5223 dst_attributes.remove(name);
5224 bke::GAttributeReader src = src_attributes.lookup(name, domain, data_type);
5225 if (!src) {
5226 return;
5227 }
5228 if (src.sharing_info && src.varray.is_span()) {
5230 dst_attributes.add(name, domain, data_type, init);
5231 }
5232 else {
5233 const bke::AttributeInitVArray init(*src);
5234 dst_attributes.add(name, domain, data_type, init);
5235 }
5236}
5237
5240 const StringRef name)
5241{
5242 const bke::GAttributeReader a_attr = a.lookup(name);
5243 const bke::GAttributeReader b_attr = b.lookup(name);
5244 if (!a_attr.sharing_info || !b_attr.sharing_info) {
5245 return false;
5246 }
5247 return a_attr.sharing_info == b_attr.sharing_info;
5248}
5249
5250static bool topology_matches(const Mesh &a, const Mesh &b)
5251{
5252 if (a.verts_num != b.verts_num || a.edges_num != b.edges_num || a.faces_num != b.faces_num ||
5253 a.corners_num != b.corners_num)
5254 {
5255 return false;
5256 }
5257 if (a.runtime->face_offsets_sharing_info != b.runtime->face_offsets_sharing_info) {
5258 return false;
5259 }
5260 const bke::AttributeAccessor a_attributes = a.attributes();
5261 const bke::AttributeAccessor b_attributes = b.attributes();
5262 if (!attribute_matches(a_attributes, b_attributes, ".edge_verts") ||
5263 !attribute_matches(a_attributes, b_attributes, ".corner_vert") ||
5264 !attribute_matches(a_attributes, b_attributes, ".corner_edge"))
5265 {
5266 return false;
5267 }
5268 return true;
5269}
5270
5272 const Scene &scene,
5273 Object &object,
5274 Mesh *new_mesh)
5275{
5276 Mesh &mesh = *static_cast<Mesh *>(object.data);
5277 sculpt_paint::undo::geometry_begin(scene, object, &op);
5278 BKE_mesh_nomain_to_mesh(new_mesh, &mesh, &object, false);
5281}
5282
5284{
5285 const int layer_index = CustomData_get_layer_index(&mesh.vert_data, CD_MDEFORMVERT);
5286 if (layer_index == -1) {
5287 return nullptr;
5288 }
5289 return mesh.vert_data.layers[layer_index].sharing_info;
5290}
5291
5293 const Scene &scene,
5294 const Depsgraph &depsgraph,
5295 const RegionView3D *rv3d,
5296 Object &object,
5297 Mesh *new_mesh)
5298{
5299 Mesh &mesh = *static_cast<Mesh *>(object.data);
5300 const bool changed_topology = !topology_matches(mesh, *new_mesh);
5301 const bool use_pbvh_draw = BKE_sculptsession_use_pbvh_draw(&object, rv3d);
5302 bool entire_mesh_changed = false;
5303
5304 if (changed_topology) {
5305 store_sculpt_entire_mesh(op, scene, object, new_mesh);
5306 entire_mesh_changed = true;
5307 }
5308 else {
5309 /* Detect attributes present in the new mesh which no longer match the original. */
5310 VectorSet<StringRef> vertex_group_names;
5311 LISTBASE_FOREACH (const bDeformGroup *, vertex_group, &mesh.vertex_group_names) {
5312 vertex_group_names.add(vertex_group->name);
5313 }
5314
5315 VectorSet<StringRef> changed_attributes;
5316 new_mesh->attributes().foreach_attribute([&](const bke::AttributeIter &iter) {
5317 if (ELEM(iter.name, ".edge_verts", ".corner_vert", ".corner_edge")) {
5318 return;
5319 }
5320 if (vertex_group_names.contains(iter.name)) {
5321 /* Vertex group changes are handled separately. */
5322 return;
5323 }
5324 const bke::GAttributeReader attribute = iter.get();
5325 if (attribute_matches(new_mesh->attributes(), mesh.attributes(), iter.name)) {
5326 return;
5327 }
5328 changed_attributes.add(iter.name);
5329 });
5330 /* Detect attributes that were removed in the new mesh. */
5331 mesh.attributes().foreach_attribute([&](const bke::AttributeIter &iter) {
5332 if (!new_mesh->attributes().contains(iter.name)) {
5333 changed_attributes.add(iter.name);
5334 }
5335 });
5336
5337 /* Vertex groups aren't handled fully by the attribute system, we need to use CustomData. */
5338 const bool vertex_groups_changed = get_vertex_group_sharing_info(mesh) !=
5340
5341 if (vertex_groups_changed) {
5342 changed_attributes.add_multiple(vertex_group_names);
5343 }
5344
5345 /* Try to use the few specialized sculpt undo types that result in better performance, mainly
5346 * because redo avoids clearing the BVH, but also because some other updates can be skipped. */
5347 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
5348 IndexMaskMemory memory;
5349 const IndexMask leaf_nodes = bke::pbvh::all_leaf_nodes(pbvh, memory);
5350 if (changed_attributes.as_span() == Span<StringRef>{"position"}) {
5351 undo::push_begin(scene, object, &op);
5352 undo::push_nodes(depsgraph, object, leaf_nodes, undo::Type::Position);
5353 undo::push_end(object);
5354 CustomData_free_layer_named(&mesh.vert_data, "position");
5355 mesh.attributes_for_write().remove("position");
5356 const bke::AttributeReader position = new_mesh->attributes().lookup<float3>("position");
5357 if (position.sharing_info) {
5358 /* Use lower level API to add the position attribute to avoid copying the array and to
5359 * allow using #tag_positions_changed_no_normals instead of #tag_positions_changed (which
5360 * would be called by the attribute API). */
5362 &mesh.vert_data,
5364 const_cast<float3 *>(position.varray.get_internal_span().data()),
5365 mesh.verts_num,
5366 "position",
5367 position.sharing_info);
5368 }
5369 else {
5370 mesh.vert_positions_for_write().copy_from(VArraySpan(*position));
5371 }
5372
5373 pbvh.tag_positions_changed(leaf_nodes);
5374 pbvh.update_bounds(depsgraph, object);
5375 tag_mesh_positions_changed(object, use_pbvh_draw);
5376 BKE_mesh_copy_parameters(&mesh, new_mesh);
5377 BKE_id_free(nullptr, new_mesh);
5378 }
5379 else if (changed_attributes.as_span() == Span<StringRef>{".sculpt_mask"}) {
5380 undo::push_begin(scene, object, &op);
5381 undo::push_nodes(depsgraph, object, leaf_nodes, undo::Type::Mask);
5382 undo::push_end(object);
5383 replace_attribute(new_mesh->attributes(),
5384 ".sculpt_mask",
5387 mesh.attributes_for_write());
5388 pbvh.tag_masks_changed(leaf_nodes);
5389 BKE_mesh_copy_parameters(&mesh, new_mesh);
5390 BKE_id_free(nullptr, new_mesh);
5391 }
5392 else if (changed_attributes.as_span() == Span<StringRef>{".sculpt_face_set"}) {
5393 undo::push_begin(scene, object, &op);
5394 undo::push_nodes(depsgraph, object, leaf_nodes, undo::Type::FaceSet);
5395 undo::push_end(object);
5396 replace_attribute(new_mesh->attributes(),
5397 ".sculpt_face_set",
5400 mesh.attributes_for_write());
5401 pbvh.tag_face_sets_changed(leaf_nodes);
5402 BKE_mesh_copy_parameters(&mesh, new_mesh);
5403 BKE_id_free(nullptr, new_mesh);
5404 }
5405 else {
5406 /* Non-geometry-type sculpt undo steps can only handle a single change at a time. When
5407 * multiple attributes or attributes that don't have their own undo type are changed, we're
5408 * forced to fall back to the slower geometry undo type. */
5409 store_sculpt_entire_mesh(op, scene, object, new_mesh);
5410 entire_mesh_changed = true;
5411 }
5412 }
5414 if (!use_pbvh_draw || entire_mesh_changed) {
5416 }
5417}
5418
5419} // namespace blender::ed::sculpt_paint
5420
5421/* Returns whether the mouse/stylus is over the mesh (1)
5422 * or over the background (0). */
5423static bool over_mesh(bContext *C, wmOperator * /*op*/, const float mval[2])
5424{
5425 float3 co_dummy;
5427 Brush *brush = BKE_paint_brush(&sd->paint);
5428
5429 const bool check_closest = brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE;
5430
5432 C, co_dummy, mval, false, check_closest, true);
5433}
5434
5435static void stroke_undo_begin(const bContext *C, wmOperator *op)
5436{
5437 using namespace blender::ed::sculpt_paint;
5438 const Scene &scene = *CTX_data_scene(C);
5440 const Sculpt &sd = *CTX_data_tool_settings(C)->sculpt;
5441 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
5442 ToolSettings *tool_settings = CTX_data_tool_settings(C);
5443
5444 /* Setup the correct undo system. Image painting and sculpting are mutual exclusive.
5445 * Color attributes are part of the sculpting undo system. */
5446 if (brush && brush->sculpt_brush_type == SCULPT_BRUSH_TYPE_PAINT &&
5447 SCULPT_use_image_paint_brush(tool_settings->paint_mode, ob))
5448 {
5450 }
5451 else {
5453 }
5454}
5455
5456static void stroke_undo_end(const bContext *C, Brush *brush)
5457{
5458 using namespace blender::ed::sculpt_paint;
5460 ToolSettings *tool_settings = CTX_data_tool_settings(C);
5461
5462 if (brush && brush->sculpt_brush_type == SCULPT_BRUSH_TYPE_PAINT &&
5463 SCULPT_use_image_paint_brush(tool_settings->paint_mode, ob))
5464 {
5466 }
5467 else {
5468 undo::push_end(ob);
5469 }
5470}
5471
5472namespace blender::ed::sculpt_paint {
5473
5474bool color_supported_check(const Scene &scene, Object &object, ReportList *reports)
5475{
5476 if (const SculptSession &ss = *object.sculpt; ss.bm) {
5477 BKE_report(reports, RPT_ERROR, "Not supported in dynamic topology mode");
5478 return false;
5479 }
5480 if (BKE_sculpt_multires_active(&scene, &object)) {
5481 BKE_report(reports, RPT_ERROR, "Not supported in multiresolution mode");
5482 return false;
5483 }
5484
5485 return true;
5486}
5487
5488static bool stroke_test_start(bContext *C, wmOperator *op, const float mval[2])
5489{
5490 /* Don't start the stroke until `mval` goes over the mesh.
5491 * NOTE: `mval` will only be null when re-executing the saved stroke.
5492 * We have exception for 'exec' strokes since they may not set `mval`,
5493 * only 'location', see: #52195. */
5494 if (((op->flag & OP_IS_INVOKE) == 0) || (mval == nullptr) || over_mesh(C, op, mval)) {
5496 SculptSession &ss = *ob.sculpt;
5498 Brush *brush = BKE_paint_brush(&sd.paint);
5499 ToolSettings *tool_settings = CTX_data_tool_settings(C);
5500
5501 /* NOTE: This should be removed when paint mode is available. Paint mode can force based on the
5502 * canvas it is painting on. (ref. use_sculpt_texture_paint). */
5503 if (brush && brush_type_is_paint(brush->sculpt_brush_type) &&
5504 !SCULPT_use_image_paint_brush(tool_settings->paint_mode, ob))
5505 {
5506 View3D *v3d = CTX_wm_view3d(C);
5507 if (v3d->shading.type == OB_SOLID) {
5509 }
5510 }
5511
5513
5514 sculpt_update_cache_invariants(C, sd, ss, *op, mval);
5515
5517 cursor_geometry_info_update(C, &cgi, mval, false);
5518
5519 stroke_undo_begin(C, op);
5520
5521 return true;
5522 }
5523 return false;
5524}
5525
5527 wmOperator * /*op*/,
5528 PaintStroke *stroke,
5529 PointerRNA *itemptr)
5530{
5531 const Scene &scene = *CTX_data_scene(C);
5532 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
5535 SculptSession &ss = *ob.sculpt;
5536 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
5537 ToolSettings &tool_settings = *CTX_data_tool_settings(C);
5538 StrokeCache *cache = ss.cache;
5540
5541 SCULPT_stroke_modifiers_check(C, ob, brush);
5542 sculpt_update_cache_variants(C, sd, ob, itemptr);
5544
5545 if (dyntopo::stroke_is_dyntopo(ob, brush)) {
5547 depsgraph, scene, sd, ob, dynamic_topology_update, tool_settings.paint_mode);
5548 }
5549
5551 depsgraph, scene, sd, ob, do_brush_action, tool_settings.paint_mode);
5552
5553 /* Hack to fix noise texture tearing mesh. */
5554 sculpt_fix_noise_tear(sd, ob);
5555
5556 ss.cache->first_time = false;
5558
5559 /* Cleanup. */
5562 }
5563 else if (brush_type_is_paint(brush.sculpt_brush_type)) {
5564 if (SCULPT_use_image_paint_brush(tool_settings.paint_mode, ob)) {
5566 }
5567 else {
5569 }
5570 }
5571 else {
5573 }
5574}
5575
5576static void brush_exit_tex(Sculpt &sd)
5577{
5578 Brush *brush = BKE_paint_brush(&sd.paint);
5579 const MTex *mask_tex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT);
5580
5581 if (mask_tex->tex && mask_tex->tex->nodetree) {
5582 ntreeTexEndExecTree(mask_tex->tex->nodetree->runtime->execdata);
5583 }
5584}
5585
5586static void stroke_done(const bContext *C, PaintStroke * /*stroke*/)
5587{
5589 SculptSession &ss = *ob.sculpt;
5591 ToolSettings *tool_settings = CTX_data_tool_settings(C);
5592
5593 /* Finished. */
5594 if (!ss.cache) {
5595 brush_exit_tex(sd);
5596 return;
5597 }
5598 bke::PaintRuntime *paint_runtime = sd.paint.runtime;
5599 Brush *brush = BKE_paint_brush(&sd.paint);
5600 BLI_assert(brush == ss.cache->brush); /* const, so we shouldn't change. */
5601 paint_runtime->draw_inverted = false;
5602
5603 SCULPT_stroke_modifiers_check(C, ob, *brush);
5604
5605 /* Alt-Smooth. */
5606 if (ss.cache->alt_smooth) {
5608 /* Refresh the brush pointer in case we switched brush in the toggle function. */
5609 brush = BKE_paint_brush(&sd.paint);
5610 }
5611
5612 MEM_delete(ss.cache);
5613 ss.cache = nullptr;
5614
5615 stroke_undo_end(C, brush);
5616
5619 }
5620 else if (brush->sculpt_brush_type == SCULPT_BRUSH_TYPE_PAINT) {
5621 if (SCULPT_use_image_paint_brush(tool_settings->paint_mode, ob)) {
5623 }
5624 else {
5626 }
5627 }
5628 else {
5630 }
5631
5633 brush_exit_tex(sd);
5634}
5635
5637 wmOperator *op,
5638 const wmEvent *event)
5639{
5640 PaintStroke *stroke;
5641 int ignore_background_click;
5643 Scene &scene = *CTX_data_scene(C);
5644 const View3D *v3d = CTX_wm_view3d(C);
5645 const Base *base = CTX_data_active_base(C);
5646 /* Test that ob is visible; otherwise we won't be able to get evaluated data
5647 * from the depsgraph. We do this here instead of SCULPT_mode_poll
5648 * to avoid falling through to the translate operator in the
5649 * global view3d keymap. */
5650 if (!BKE_base_is_visible(v3d, base)) {
5651 return OPERATOR_CANCELLED;
5652 }
5653
5655
5657 Brush &brush = *BKE_paint_brush(&sd.paint);
5658
5660 !color_supported_check(scene, ob, op->reports))
5661 {
5662 return OPERATOR_CANCELLED;
5663 }
5667 }
5670 {
5671 return OPERATOR_CANCELLED;
5672 }
5673 if (ELEM(brush.sculpt_brush_type,
5676 {
5678 if (!pbvh || pbvh->type() != bke::pbvh::Type::Grids) {
5679 BKE_report(op->reports, RPT_ERROR, "Only supported in multiresolution mode");
5680 return OPERATOR_CANCELLED;
5681 }
5682 }
5683
5684 stroke = paint_stroke_new(C,
5685 op,
5689 nullptr,
5691 event->type);
5692
5693 op->customdata = stroke;
5694
5695 /* For tablet rotation. */
5696 ignore_background_click = RNA_boolean_get(op->ptr, "ignore_background_click");
5697 const float mval[2] = {float(event->mval[0]), float(event->mval[1])};
5698 if (ignore_background_click && !over_mesh(C, op, mval)) {
5699 paint_stroke_free(C, op, static_cast<PaintStroke *>(op->customdata));
5700 return OPERATOR_PASS_THROUGH;
5701 }
5702
5703 const wmOperatorStatus retval = op->type->modal(C, op, event);
5704 OPERATOR_RETVAL_CHECK(retval);
5705
5707 paint_stroke_free(C, op, static_cast<PaintStroke *>(op->customdata));
5708 return retval;
5709 }
5710 /* Add modal handler. */
5712
5714
5716}
5717
5719{
5721
5723 op,
5727 nullptr,
5729 0);
5730
5731 /* Frees op->customdata. */
5732 paint_stroke_exec(C, op, static_cast<PaintStroke *>(op->customdata));
5733
5734 return OPERATOR_FINISHED;
5735}
5736
5738{
5739 using namespace blender::ed::sculpt_paint;
5740 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
5742 SculptSession &ss = *ob.sculpt;
5744 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
5745
5746 /* XXX Canceling strokes that way does not work with dynamic topology,
5747 * user will have to do real undo for now. See #46456. */
5748 if (ss.cache && !dyntopo::stroke_is_dyntopo(ob, brush)) {
5750 }
5751
5752 paint_stroke_cancel(C, op, static_cast<PaintStroke *>(op->customdata));
5753
5754 MEM_delete(ss.cache);
5755 ss.cache = nullptr;
5756
5757 brush_exit_tex(sd);
5758}
5759
5761{
5762 return paint_stroke_modal(C, op, event, (PaintStroke **)&op->customdata);
5763}
5764
5765static void redo_empty_ui(bContext * /*C*/, wmOperator * /*op*/) {}
5766
5768{
5769 /* Identifiers. */
5770 ot->name = "Sculpt";
5771 ot->idname = "SCULPT_OT_brush_stroke";
5772 ot->description = "Sculpt a stroke into the geometry";
5773
5774 /* API callbacks. */
5776 ot->modal = brush_stroke_modal;
5778 ot->poll = SCULPT_poll;
5780 ot->ui = redo_empty_ui;
5781
5782 /* Flags (sculpt does its own undo? (ton)). */
5783 ot->flag = OPTYPE_BLOCKING;
5784
5785 /* Properties. */
5786
5788
5790 ot->srna,
5791 "override_location",
5792 false,
5793 "Override Location",
5794 "Override the given \"location\" array by recalculating object space positions from the "
5795 "provided \"mouse_event\" positions");
5797
5798 RNA_def_boolean(ot->srna,
5799 "ignore_background_click",
5800 false,
5801 "Ignore Background Click",
5802 "Clicks on the background do not start the stroke");
5803}
5804
5805/* Fake Neighbors. */
5806
5807static void fake_neighbor_init(Object &object, const float max_dist)
5808{
5809 SculptSession &ss = *object.sculpt;
5810 const int totvert = SCULPT_vertex_count_get(object);
5813}
5814
5819
5821 int vert = -1;
5822 float distance_sq = std::numeric_limits<float>::max();
5823
5825 {
5826 NearestVertData joined = a;
5827 if (joined.vert == -1) {
5828 joined.vert = b.vert;
5829 joined.distance_sq = b.distance_sq;
5830 }
5831 else if (b.distance_sq < joined.distance_sq) {
5832 joined.vert = b.vert;
5833 joined.distance_sq = b.distance_sq;
5834 }
5835 return joined;
5836 }
5837};
5838
5840 const Span<float3> vert_positions,
5841 const Span<bool> hide_vert,
5842 const float3 &location,
5843 const float max_distance_sq,
5844 const int island_id,
5845 const bke::pbvh::MeshNode &node,
5846 NearestVertData &nvtd)
5847{
5848 for (const int vert : node.verts()) {
5849 if (!hide_vert.is_empty() && hide_vert[vert]) {
5850 continue;
5851 }
5853 continue;
5854 }
5855 if (islands::vert_id_get(ss, vert) == island_id) {
5856 continue;
5857 }
5858 const float distance_sq = math::distance_squared(vert_positions[vert], location);
5859 if (distance_sq < max_distance_sq && distance_sq < nvtd.distance_sq) {
5860 nvtd.vert = vert;
5861 nvtd.distance_sq = distance_sq;
5862 }
5863 }
5864}
5865
5867 const CCGKey &key,
5868 const Span<float3> positions,
5869 const BitGroupVector<> &grid_hidden,
5870 const float3 &location,
5871 const float max_distance_sq,
5872 const int island_id,
5873 const bke::pbvh::GridsNode &node,
5874 NearestVertData &nvtd)
5875{
5876 for (const int grid : node.grids()) {
5877 const IndexRange grid_range = bke::ccg::grid_range(key, grid);
5878 BKE_subdiv_ccg_foreach_visible_grid_vert(key, grid_hidden, grid, [&](const int offset) {
5879 const int vert = grid_range[offset];
5881 return;
5882 }
5883 if (islands::vert_id_get(ss, vert) == island_id) {
5884 return;
5885 }
5886 const float distance_sq = math::distance_squared(positions[vert], location);
5887 if (distance_sq < max_distance_sq && distance_sq < nvtd.distance_sq) {
5888 nvtd.vert = vert;
5889 nvtd.distance_sq = distance_sq;
5890 }
5891 });
5892 }
5893}
5894
5896 const float3 &location,
5897 const float max_distance_sq,
5898 const int island_id,
5899 const bke::pbvh::BMeshNode &node,
5900 NearestVertData &nvtd)
5901{
5902 for (const BMVert *bm_vert :
5904 {
5905 if (BM_elem_flag_test(bm_vert, BM_ELEM_HIDDEN)) {
5906 continue;
5907 }
5908 const int vert = BM_elem_index_get(bm_vert);
5910 continue;
5911 }
5912 if (islands::vert_id_get(ss, vert) == island_id) {
5913 continue;
5914 }
5915 const float distance_sq = math::distance_squared(float3(bm_vert->co), location);
5916 if (distance_sq < max_distance_sq && distance_sq < nvtd.distance_sq) {
5917 nvtd.vert = vert;
5918 nvtd.distance_sq = distance_sq;
5919 }
5920 }
5921}
5922
5923static void fake_neighbor_search(const Depsgraph &depsgraph,
5924 const Object &ob,
5925 const float max_distance_sq,
5926 MutableSpan<int> fake_neighbors)
5927{
5928 /* NOTE: This algorithm is extremely slow, it has O(n^2) runtime for the entire mesh. This looks
5929 * like the "closest pair of points" problem which should have far better solutions. */
5930 SculptSession &ss = *ob.sculpt;
5931 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
5932
5933 switch (pbvh.type()) {
5934 case bke::pbvh::Type::Mesh: {
5935 const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
5936 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
5937 const bke::AttributeAccessor attributes = mesh.attributes();
5938 const VArraySpan<bool> hide_vert = *attributes.lookup<bool>(".hide_vert",
5940 for (const int vert : vert_positions.index_range()) {
5941 if (fake_neighbors[vert] != FAKE_NEIGHBOR_NONE) {
5942 continue;
5943 }
5944 const int island_id = islands::vert_id_get(ss, vert);
5945 const float3 &location = vert_positions[vert];
5946
5947 IndexMaskMemory memory;
5948 const IndexMask nodes_in_sphere = bke::pbvh::search_nodes(
5949 pbvh, memory, [&](const bke::pbvh::Node &node) {
5950 return node_in_sphere(node, location, max_distance_sq, false);
5951 });
5952 if (nodes_in_sphere.is_empty()) {
5953 continue;
5954 }
5957 nodes_in_sphere.index_range(),
5958 1,
5960 [&](const IndexRange range, NearestVertData nvtd) {
5961 nodes_in_sphere.slice(range).foreach_index([&](const int i) {
5963 vert_positions,
5964 hide_vert,
5965 location,
5966 max_distance_sq,
5967 island_id,
5968 nodes[i],
5969 nvtd);
5970 });
5971 return nvtd;
5972 },
5974 if (nvtd.vert == -1) {
5975 continue;
5976 }
5977 fake_neighbors[vert] = nvtd.vert;
5978 fake_neighbors[nvtd.vert] = vert;
5979 }
5980 break;
5981 }
5983 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
5984 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
5985 const Span<float3> positions = subdiv_ccg.positions;
5986 const BitGroupVector<> grid_hidden = subdiv_ccg.grid_hidden;
5987 for (const int vert : positions.index_range()) {
5988 if (fake_neighbors[vert] != FAKE_NEIGHBOR_NONE) {
5989 continue;
5990 }
5991 const int island_id = islands::vert_id_get(ss, vert);
5992 const float3 &location = positions[vert];
5993 IndexMaskMemory memory;
5994 const IndexMask nodes_in_sphere = bke::pbvh::search_nodes(
5995 pbvh, memory, [&](const bke::pbvh::Node &node) {
5996 return node_in_sphere(node, location, max_distance_sq, false);
5997 });
5998 if (nodes_in_sphere.is_empty()) {
5999 continue;
6000 }
6003 nodes_in_sphere.index_range(),
6004 1,
6006 [&](const IndexRange range, NearestVertData nvtd) {
6007 nodes_in_sphere.slice(range).foreach_index([&](const int i) {
6009 key,
6010 positions,
6011 grid_hidden,
6012 location,
6013 max_distance_sq,
6014 island_id,
6015 nodes[i],
6016 nvtd);
6017 });
6018 return nvtd;
6019 },
6021 if (nvtd.vert == -1) {
6022 continue;
6023 }
6024 fake_neighbors[vert] = nvtd.vert;
6025 fake_neighbors[nvtd.vert] = vert;
6026 }
6027 break;
6028 }
6030 const BMesh &bm = *ss.bm;
6031 for (const int vert : IndexRange(bm.totvert)) {
6032 if (fake_neighbors[vert] != FAKE_NEIGHBOR_NONE) {
6033 continue;
6034 }
6035 const int island_id = islands::vert_id_get(ss, vert);
6036 const float3 location = BM_vert_at_index(&const_cast<BMesh &>(bm), vert)->co;
6037 IndexMaskMemory memory;
6038 const IndexMask nodes_in_sphere = bke::pbvh::search_nodes(
6039 pbvh, memory, [&](const bke::pbvh::Node &node) {
6040 return node_in_sphere(node, location, max_distance_sq, false);
6041 });
6042 if (nodes_in_sphere.is_empty()) {
6043 continue;
6044 }
6047 nodes_in_sphere.index_range(),
6048 1,
6050 [&](const IndexRange range, NearestVertData nvtd) {
6051 nodes_in_sphere.slice(range).foreach_index([&](const int i) {
6053 ss, location, max_distance_sq, island_id, nodes[i], nvtd);
6054 });
6055 return nvtd;
6056 },
6058 if (nvtd.vert == -1) {
6059 continue;
6060 }
6061 fake_neighbors[vert] = nvtd.vert;
6062 fake_neighbors[nvtd.vert] = vert;
6063 }
6064 break;
6065 }
6066 }
6067}
6068
6069} // namespace blender::ed::sculpt_paint
6070
6072
6074{
6075 SculptSession &ss = *object.sculpt;
6076 if (!ss.vertex_info.boundary.is_empty()) {
6077 return;
6078 }
6079
6080 Mesh *base_mesh = BKE_mesh_from_object(&object);
6081
6082 ss.vertex_info.boundary.resize(base_mesh->verts_num);
6083 Array<int> adjacent_faces_edge_count(base_mesh->edges_num, 0);
6084 array_utils::count_indices(base_mesh->corner_edges(), adjacent_faces_edge_count);
6085
6086 const Span<int2> edges = base_mesh->edges();
6087 for (const int e : edges.index_range()) {
6088 if (adjacent_faces_edge_count[e] < 2) {
6089 const int2 &edge = edges[e];
6090 ss.vertex_info.boundary[edge[0]].set();
6091 ss.vertex_info.boundary[edge[1]].set();
6092 }
6093 }
6094}
6095
6096} // namespace blender::ed::sculpt_paint::boundary
6097
6099 Object &ob,
6100 const float max_dist)
6101{
6102 using namespace blender::ed::sculpt_paint;
6103 SculptSession &ss = *ob.sculpt;
6104
6105 /* Fake neighbors were already initialized with the same distance, so no need to be
6106 * recalculated. */
6108 ss.fake_neighbors.current_max_distance == max_dist)
6109 {
6111 }
6112
6114 fake_neighbor_init(ob, max_dist);
6116
6118}
6119
6121{
6122 using namespace blender::ed::sculpt_paint;
6123 SculptSession &ss = *ob.sculpt;
6125}
6126
6127namespace blender::ed::sculpt_paint {
6128bool vertex_is_occluded(const Depsgraph &depsgraph,
6129 const Object &object,
6130 const float3 &position,
6131 bool original)
6132{
6133 SculptSession &ss = *object.sculpt;
6134
6135 ViewContext *vc = ss.cache ? ss.cache->vc : &ss.filter_cache->vc;
6136
6138 vc->region, position, ss.cache ? ss.cache->projection_mat : ss.filter_cache->viewmat);
6139
6140 float3 ray_start;
6141 float3 ray_end;
6142 float3 ray_normal;
6143 float depth = raycast_init(vc, mouse, ray_end, ray_start, ray_normal, original);
6144
6145 ray_normal = ray_normal * -1.0f;
6146 ray_start = position + ray_normal * 0.002f;
6147
6148 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(const_cast<Object &>(object));
6149
6150 RaycastData srd = {nullptr};
6151 srd.use_original = original;
6152 srd.object = &const_cast<Object &>(object);
6153 srd.is_mid_stroke = ss.cache != nullptr;
6154 srd.hit = false;
6155 srd.ray_start = ray_start;
6156 srd.ray_normal = ray_normal;
6157 srd.depth = depth;
6158 if (pbvh.type() == bke::pbvh::Type::Mesh) {
6159 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
6161 srd.faces = mesh.faces();
6162 srd.corner_verts = mesh.corner_verts();
6163 srd.corner_tris = mesh.corner_tris();
6164 }
6165 else if (pbvh.type() == bke::pbvh::Type::Grids) {
6166 srd.subdiv_ccg = ss.subdiv_ccg;
6167 }
6168 vert_random_access_ensure(const_cast<Object &>(object));
6169
6172 pbvh,
6173 [&](bke::pbvh::Node &node, float *tmin) { sculpt_raycast_cb(node, srd, tmin); },
6174 ray_start,
6175 ray_normal,
6176 srd.use_original);
6177
6178 return srd.hit;
6179}
6180} // namespace blender::ed::sculpt_paint
6181
6183
6184int vert_id_get(const SculptSession &ss, const int vert)
6185{
6187 if (!ss.topology_island_cache) {
6188 /* The cache should be calculated whenever it's necessary.
6189 * Still avoid crashing in release builds though. */
6190 return 0;
6191 }
6193 if (!cache.vert_island_ids.is_empty()) {
6194 return cache.vert_island_ids[vert];
6195 }
6196 return 0;
6197}
6198
6200{
6201 ss.topology_island_cache.reset();
6202}
6203
6205 const int verts_num)
6206{
6207 Array<int> island_indices(verts_num);
6208 const int islands_num = vert_sets.calc_reduced_ids(island_indices);
6209 if (islands_num == 1) {
6210 return {};
6211 }
6212
6213 Array<uint8_t> island_ids(island_indices.size());
6214 threading::parallel_for(island_ids.index_range(), 4096, [&](const IndexRange range) {
6215 for (const int i : range) {
6216 island_ids[i] = uint8_t(island_indices[i]);
6217 }
6218 });
6219
6221 cache.vert_island_ids = std::move(island_ids);
6222 return cache;
6223}
6224
6226{
6227 const OffsetIndices<int> faces = mesh.faces();
6228 const Span<int> corner_verts = mesh.corner_verts();
6229 const bke::AttributeAccessor attributes = mesh.attributes();
6230 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
6231 IndexMaskMemory memory;
6232 const IndexMask visible_faces = hide_poly.is_empty() ?
6233 IndexMask(faces.size()) :
6235 faces.index_range(), hide_poly, memory);
6236
6237 AtomicDisjointSet disjoint_set(mesh.verts_num);
6238 visible_faces.foreach_index(GrainSize(1024), [&](const int face) {
6239 const Span<int> face_verts = corner_verts.slice(faces[face]);
6240 for (const int i : face_verts.index_range().drop_front(1)) {
6241 disjoint_set.join(face_verts.first(), face_verts[i]);
6242 }
6243 });
6244 return vert_disjoint_set_to_islands(disjoint_set, mesh.verts_num);
6245}
6246
6251{
6252 const SculptSession &ss = *object.sculpt;
6253 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
6254 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
6255 AtomicDisjointSet disjoint_set(subdiv_ccg.positions.size());
6256 threading::parallel_for(IndexRange(subdiv_ccg.grids_num), 512, [&](const IndexRange range) {
6257 for (const int grid : range) {
6258 SubdivCCGNeighbors neighbors;
6259 for (const short y : IndexRange(key.grid_size)) {
6260 for (const short x : IndexRange(key.grid_size)) {
6261 const SubdivCCGCoord coord{grid, x, y};
6262 SubdivCCGNeighbors neighbors;
6263 BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, coord, true, neighbors);
6264 for (const SubdivCCGCoord neighbor : neighbors.coords) {
6265 disjoint_set.join(coord.to_index(key), neighbor.to_index(key));
6266 }
6267 }
6268 }
6269 }
6270 });
6271
6272 return vert_disjoint_set_to_islands(disjoint_set, subdiv_ccg.positions.size());
6273}
6274
6276{
6277 const SculptSession &ss = *object.sculpt;
6278 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
6280 BMesh &bm = *ss.bm;
6281 vert_random_access_ensure(const_cast<Object &>(object));
6282
6283 IndexMaskMemory memory;
6284 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
6285 AtomicDisjointSet disjoint_set(bm.totvert);
6286 node_mask.foreach_index(GrainSize(1), [&](const int i) {
6287 for (const BMFace *face :
6289 {
6290 if (BM_elem_flag_test(face, BM_ELEM_HIDDEN)) {
6291 continue;
6292 }
6293 disjoint_set.join(BM_elem_index_get(face->l_first->v),
6294 BM_elem_index_get(face->l_first->next->v));
6295 disjoint_set.join(BM_elem_index_get(face->l_first->v),
6296 BM_elem_index_get(face->l_first->next->next->v));
6297 }
6298 });
6299
6300 return vert_disjoint_set_to_islands(disjoint_set, bm.totvert);
6301}
6302
6304{
6305 switch (bke::object::pbvh_get(object)->type()) {
6307 return calc_topology_islands_mesh(*static_cast<const Mesh *>(object.data));
6309 return calc_topology_islands_grids(object);
6311 return calc_topology_islands_bmesh(object);
6312 }
6314 return {};
6315}
6316
6318{
6319 SculptSession &ss = *object.sculpt;
6320 if (ss.topology_island_cache) {
6321 return;
6322 }
6323 ss.topology_island_cache = std::make_unique<SculptTopologyIslandCache>(calculate_cache(object));
6324}
6325
6326} // namespace blender::ed::sculpt_paint::islands
6327
6328void SCULPT_cube_tip_init(const Sculpt & /*sd*/,
6329 const Object &ob,
6330 const Brush &brush,
6331 float mat[4][4])
6332{
6333 using namespace blender::ed::sculpt_paint;
6334 SculptSession &ss = *ob.sculpt;
6335 float scale[4][4];
6336 float tmat[4][4];
6337 float unused[4][4];
6338
6339 zero_m4(mat);
6340 calc_brush_local_mat(0.0, ob, unused, mat);
6341
6342 /* NOTE: we ignore the radius scaling done inside of calc_brush_local_mat to
6343 * duplicate prior behavior.
6344 *
6345 * TODO: try disabling this and check that all edge cases work properly.
6346 */
6347 normalize_m4(mat);
6348
6349 scale_m4_fl(scale, ss.cache->radius);
6350 mul_m4_m4m4(tmat, mat, scale);
6351 mul_v3_fl(tmat[1], brush.tip_scale_x);
6352 invert_m4_m4(mat, tmat);
6353}
6354
6355
6356namespace blender::ed::sculpt_paint {
6357
6359{
6360 const bke::AttributeAccessor attributes = mesh.attributes();
6361 this->mask = *attributes.lookup<float>(".sculpt_mask", bke::AttrDomain::Point);
6362 this->hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
6363 this->hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
6364 this->face_sets = *attributes.lookup<int>(".sculpt_face_set", bke::AttrDomain::Face);
6365}
6366
6368{
6369 BLI_assert(verts.size() == positions.size());
6370
6371 int i = 0;
6372 for (const BMVert *vert : verts) {
6373 positions[i] = vert->co;
6374 i++;
6375 }
6376}
6377
6378void gather_grids_normals(const SubdivCCG &subdiv_ccg,
6379 const Span<int> grids,
6381{
6382 gather_data_grids(subdiv_ccg, subdiv_ccg.normals.as_span(), grids, normals);
6383}
6384
6386{
6387 int i = 0;
6388 for (const BMVert *vert : verts) {
6389 normals[i] = vert->no;
6390 i++;
6391 }
6392}
6393
6394template<typename T>
6396{
6397 BLI_assert(indices.size() == dst.size());
6398
6399 for (const int i : indices.index_range()) {
6400 dst[i] = src[indices[i]];
6401 }
6402}
6403
6404template<typename T>
6405void gather_data_grids(const SubdivCCG &subdiv_ccg,
6406 const Span<T> src,
6407 const Span<int> grids,
6408 const MutableSpan<T> node_data)
6409{
6410 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
6411 BLI_assert(grids.size() * key.grid_area == node_data.size());
6412
6413 for (const int i : grids.index_range()) {
6414 const IndexRange grids_range = bke::ccg::grid_range(key, grids[i]);
6415 const IndexRange node_range = bke::ccg::grid_range(key, i);
6416 node_data.slice(node_range).copy_from(src.slice(grids_range));
6417 }
6418}
6419
6420template<typename T>
6422 const Set<BMVert *, 0> &verts,
6423 const MutableSpan<T> node_data)
6424{
6425 BLI_assert(verts.size() == node_data.size());
6426
6427 int i = 0;
6428 for (const BMVert *vert : verts) {
6429 node_data[i] = src[BM_elem_index_get(vert)];
6430 i++;
6431 }
6432}
6433
6434template<typename T>
6436{
6437 BLI_assert(indices.size() == src.size());
6438
6439 for (const int i : indices.index_range()) {
6440 dst[indices[i]] = src[i];
6441 }
6442}
6443
6444template<typename T>
6445void scatter_data_grids(const SubdivCCG &subdiv_ccg,
6446 const Span<T> node_data,
6447 const Span<int> grids,
6448 const MutableSpan<T> dst)
6449{
6450 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
6451 BLI_assert(grids.size() * key.grid_area == node_data.size());
6452
6453 for (const int i : grids.index_range()) {
6454 const IndexRange grids_range = bke::ccg::grid_range(key, grids[i]);
6455 const IndexRange node_range = bke::ccg::grid_range(key, i);
6456 dst.slice(grids_range).copy_from(node_data.slice(node_range));
6457 }
6458}
6459
6460template<typename T>
6461void scatter_data_bmesh(const Span<T> node_data,
6462 const Set<BMVert *, 0> &verts,
6463 const MutableSpan<T> dst)
6464{
6465 BLI_assert(verts.size() == node_data.size());
6466
6467 int i = 0;
6468 for (const BMVert *vert : verts) {
6469 dst[BM_elem_index_get(vert)] = node_data[i];
6470 i++;
6471 }
6472}
6473
6482 Span<int>,
6486 Span<int>,
6491 const Set<BMVert *, 0> &,
6493
6501 Span<int>,
6505 Span<int>,
6509 const Set<BMVert *, 0> &,
6511
6513 const Brush &brush,
6514 const Object &object,
6515 const MeshAttributeData &attribute_data,
6516 const Span<float3> vert_positions,
6517 const Span<float3> vert_normals,
6518 const bke::pbvh::MeshNode &node,
6519 Vector<float> &r_factors,
6520 Vector<float> &r_distances)
6521{
6522 const Span<int> verts = node.verts();
6523 r_factors.resize(verts.size());
6524 r_distances.resize(verts.size());
6525
6527 brush,
6528 object,
6529 attribute_data,
6530 vert_positions,
6531 vert_normals,
6532 node,
6533 r_factors.as_mutable_span(),
6534 r_distances.as_mutable_span());
6535}
6537 const Brush &brush,
6538 const Object &object,
6539 const MeshAttributeData &attribute_data,
6540 const Span<float3> vert_positions,
6541 const Span<float3> vert_normals,
6542 const bke::pbvh::MeshNode &node,
6543 const MutableSpan<float> factors,
6544 const MutableSpan<float> distances)
6545{
6546 const SculptSession &ss = *object.sculpt;
6547 const StrokeCache &cache = *ss.cache;
6548
6549 const Span<int> verts = node.verts();
6550
6551 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
6552 filter_region_clip_factors(ss, vert_positions, verts, factors);
6553 if (brush.flag & BRUSH_FRONTFACE) {
6554 calc_front_face(cache.view_normal_symm, vert_normals, verts, factors);
6555 }
6556
6558 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
6559 filter_distances_with_radius(cache.radius, distances, factors);
6560 apply_hardness_to_distances(cache, distances);
6561 calc_brush_strength_factors(cache, brush, distances, factors);
6562
6563 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
6564
6565 calc_brush_texture_factors(ss, brush, vert_positions, verts, factors);
6566}
6567
6569 const Brush &brush,
6570 const Object &object,
6571 const MeshAttributeData &attribute_data,
6572 const Span<float3> positions,
6573 const Span<float3> vert_normals,
6574 const bke::pbvh::MeshNode &node,
6575 Vector<float> &r_factors,
6576 Vector<float> &r_distances)
6577{
6578 const SculptSession &ss = *object.sculpt;
6579 const StrokeCache &cache = *ss.cache;
6580
6581 const Span<int> verts = node.verts();
6582
6583 r_factors.resize(verts.size());
6584 const MutableSpan<float> factors = r_factors;
6585 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
6586 filter_region_clip_factors(ss, positions, factors);
6587 if (brush.flag & BRUSH_FRONTFACE) {
6588 calc_front_face(cache.view_normal_symm, vert_normals, verts, factors);
6589 }
6590
6591 r_distances.resize(verts.size());
6592 const MutableSpan<float> distances = r_distances;
6593 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
6594 filter_distances_with_radius(cache.radius, distances, factors);
6595 apply_hardness_to_distances(cache, distances);
6596 calc_brush_strength_factors(cache, brush, distances, factors);
6597
6598 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
6599
6600 calc_brush_texture_factors(ss, brush, positions, factors);
6601}
6602
6604 const Brush &brush,
6605 const Object &object,
6606 const Span<float3> positions,
6607 const bke::pbvh::GridsNode &node,
6608 Vector<float> &r_factors,
6609 Vector<float> &r_distances)
6610{
6611 const SculptSession &ss = *object.sculpt;
6612 const StrokeCache &cache = *ss.cache;
6613 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
6614
6615 const Span<int> grids = node.grids();
6616
6617 r_factors.resize(positions.size());
6618 const MutableSpan<float> factors = r_factors;
6619 fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
6620 filter_region_clip_factors(ss, positions, factors);
6621 if (brush.flag & BRUSH_FRONTFACE) {
6622 calc_front_face(cache.view_normal_symm, subdiv_ccg, grids, factors);
6623 }
6624
6625 r_distances.resize(positions.size());
6626 const MutableSpan<float> distances = r_distances;
6627 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
6628 filter_distances_with_radius(cache.radius, distances, factors);
6629 apply_hardness_to_distances(cache, distances);
6630 calc_brush_strength_factors(cache, brush, distances, factors);
6631
6632 auto_mask::calc_grids_factors(depsgraph, object, cache.automasking.get(), node, grids, factors);
6633
6634 calc_brush_texture_factors(ss, brush, positions, factors);
6635}
6636
6638 const Brush &brush,
6639 const Object &object,
6640 const Span<float3> positions,
6642 Vector<float> &r_factors,
6643 Vector<float> &r_distances)
6644{
6645 const SculptSession &ss = *object.sculpt;
6646 const StrokeCache &cache = *ss.cache;
6647
6649
6650 r_factors.resize(verts.size());
6651 const MutableSpan<float> factors = r_factors;
6653 filter_region_clip_factors(ss, positions, factors);
6654 if (brush.flag & BRUSH_FRONTFACE) {
6655 calc_front_face(cache.view_normal_symm, verts, factors);
6656 }
6657
6658 r_distances.resize(verts.size());
6659 const MutableSpan<float> distances = r_distances;
6660 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
6661 filter_distances_with_radius(cache.radius, distances, factors);
6662 apply_hardness_to_distances(cache, distances);
6663 calc_brush_strength_factors(cache, brush, distances, factors);
6664
6665 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
6666
6667 calc_brush_texture_factors(ss, brush, positions, factors);
6668}
6669
6671 const Brush &brush,
6672 const Object &object,
6673 const MeshAttributeData &attribute_data,
6674 const Span<float3> positions,
6675 const Span<float3> normals,
6676 const bke::pbvh::MeshNode &node,
6677 Vector<float> &r_factors,
6678 Vector<float> &r_distances)
6679{
6680 const SculptSession &ss = *object.sculpt;
6681 const StrokeCache &cache = *ss.cache;
6682
6683 const Span<int> verts = node.verts();
6684
6685 r_factors.resize(verts.size());
6686 const MutableSpan<float> factors = r_factors;
6687 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
6688 filter_region_clip_factors(ss, positions, factors);
6689
6690 if (brush.flag & BRUSH_FRONTFACE) {
6691 calc_front_face(cache.view_normal_symm, normals, factors);
6692 }
6693
6694 r_distances.resize(verts.size());
6695 const MutableSpan<float> distances = r_distances;
6696 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
6697 filter_distances_with_radius(cache.radius, distances, factors);
6698 apply_hardness_to_distances(cache, distances);
6699 calc_brush_strength_factors(cache, brush, distances, factors);
6700
6701 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
6702
6703 calc_brush_texture_factors(ss, brush, positions, factors);
6704}
6705
6707 const Brush &brush,
6708 const Object &object,
6709 const Span<float3> positions,
6710 const Span<float3> normals,
6711 const bke::pbvh::GridsNode &node,
6712 Vector<float> &r_factors,
6713 Vector<float> &r_distances)
6714{
6715 SculptSession &ss = *object.sculpt;
6716 const StrokeCache &cache = *ss.cache;
6717 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
6718
6719 const Span<int> grids = node.grids();
6720
6721 r_factors.resize(positions.size());
6722 const MutableSpan<float> factors = r_factors;
6723 fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
6724 filter_region_clip_factors(ss, positions, factors);
6725 if (brush.flag & BRUSH_FRONTFACE) {
6726 calc_front_face(cache.view_normal_symm, normals, factors);
6727 }
6728
6729 r_distances.resize(positions.size());
6730 const MutableSpan<float> distances = r_distances;
6731 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
6732 filter_distances_with_radius(cache.radius, distances, factors);
6733 apply_hardness_to_distances(cache, distances);
6734 calc_brush_strength_factors(cache, brush, distances, factors);
6735
6736 auto_mask::calc_grids_factors(depsgraph, object, cache.automasking.get(), node, grids, factors);
6737
6738 calc_brush_texture_factors(ss, brush, positions, factors);
6739}
6740
6742 const Brush &brush,
6743 const Object &object,
6744 const Span<float3> positions,
6745 const Span<float3> normals,
6747 Vector<float> &r_factors,
6748 Vector<float> &r_distances)
6749{
6750 SculptSession &ss = *object.sculpt;
6751 const StrokeCache &cache = *ss.cache;
6752
6754
6755 r_factors.resize(verts.size());
6756 const MutableSpan<float> factors = r_factors;
6758 filter_region_clip_factors(ss, positions, factors);
6759 if (brush.flag & BRUSH_FRONTFACE) {
6760 calc_front_face(cache.view_normal_symm, normals, factors);
6761 }
6762
6763 r_distances.resize(verts.size());
6764 const MutableSpan<float> distances = r_distances;
6765 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
6766 filter_distances_with_radius(cache.radius, distances, factors);
6767 apply_hardness_to_distances(cache, distances);
6768 calc_brush_strength_factors(cache, brush, distances, factors);
6769
6770 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
6771
6772 calc_brush_texture_factors(ss, brush, positions, factors);
6773}
6774
6776 const Span<int> verts,
6777 const MutableSpan<float> r_factors)
6778{
6779 BLI_assert(verts.size() == r_factors.size());
6780
6781 if (!hide_vert.is_empty()) {
6782 for (const int i : verts.index_range()) {
6783 r_factors[i] = hide_vert[verts[i]] ? 0.0f : 1.0f;
6784 }
6785 }
6786 else {
6787 r_factors.fill(1.0f);
6788 }
6789}
6790
6791void fill_factor_from_hide(const SubdivCCG &subdiv_ccg,
6792 const Span<int> grids,
6793 const MutableSpan<float> r_factors)
6794{
6795 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
6796 BLI_assert(grids.size() * key.grid_area == r_factors.size());
6797
6798 const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
6799 if (grid_hidden.is_empty()) {
6800 r_factors.fill(1.0f);
6801 return;
6802 }
6803 for (const int i : grids.index_range()) {
6804 const BitSpan hidden = grid_hidden[grids[i]];
6805 const int start = i * key.grid_area;
6806 for (const int offset : IndexRange(key.grid_area)) {
6807 r_factors[start + offset] = hidden[offset] ? 0.0f : 1.0f;
6808 }
6809 }
6810}
6811
6813{
6814 BLI_assert(verts.size() == r_factors.size());
6815
6816 int i = 0;
6817 for (const BMVert *vert : verts) {
6818 r_factors[i] = BM_elem_flag_test_bool(vert, BM_ELEM_HIDDEN) ? 0.0f : 1.0f;
6819 i++;
6820 }
6821}
6822
6824 const Span<float> mask,
6825 const Span<int> verts,
6826 const MutableSpan<float> r_factors)
6827{
6828 BLI_assert(verts.size() == r_factors.size());
6829
6830 if (!mask.is_empty()) {
6831 for (const int i : verts.index_range()) {
6832 r_factors[i] = 1.0f - mask[verts[i]];
6833 }
6834 }
6835 else {
6836 r_factors.fill(1.0f);
6837 }
6838
6839 if (!hide_vert.is_empty()) {
6840 for (const int i : verts.index_range()) {
6841 if (hide_vert[verts[i]]) {
6842 r_factors[i] = 0.0f;
6843 }
6844 }
6845 }
6846}
6847
6849 const Set<BMVert *, 0> &verts,
6850 const MutableSpan<float> r_factors)
6851{
6852 BLI_assert(verts.size() == r_factors.size());
6853
6854 /* TODO: Avoid overhead of accessing attributes for every bke::pbvh::Tree node. */
6855 const int mask_offset = CustomData_get_offset_named(&bm.vdata, CD_PROP_FLOAT, ".sculpt_mask");
6856 int i = 0;
6857 for (const BMVert *vert : verts) {
6858 r_factors[i] = (mask_offset == -1) ? 1.0f : 1.0f - BM_ELEM_CD_GET_FLOAT(vert, mask_offset);
6859 if (BM_elem_flag_test(vert, BM_ELEM_HIDDEN)) {
6860 r_factors[i] = 0.0f;
6861 }
6862 i++;
6863 }
6864}
6865
6867 const Span<int> grids,
6868 const MutableSpan<float> r_factors)
6869{
6870 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
6871 BLI_assert(grids.size() * key.grid_area == r_factors.size());
6872
6873 if (!subdiv_ccg.masks.is_empty()) {
6874 const Span<float> masks = subdiv_ccg.masks;
6875 for (const int i : grids.index_range()) {
6876 const Span src = masks.slice(bke::ccg::grid_range(key, grids[i]));
6877 MutableSpan dst = r_factors.slice(bke::ccg::grid_range(key, i));
6878 for (const int offset : dst.index_range()) {
6879 dst[offset] = 1.0f - src[offset];
6880 }
6881 }
6882 }
6883 else {
6884 r_factors.fill(1.0f);
6885 }
6886
6887 const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
6888 if (!grid_hidden.is_empty()) {
6889 for (const int i : grids.index_range()) {
6890 const BitSpan hidden = grid_hidden[grids[i]];
6891 const int start = i * key.grid_area;
6892 for (const int offset : IndexRange(key.grid_area)) {
6893 if (hidden[offset]) {
6894 r_factors[start + offset] = 0.0f;
6895 }
6896 }
6897 }
6898 }
6899}
6900
6901void calc_front_face(const float3 &view_normal,
6902 const Span<float3> vert_normals,
6903 const Span<int> verts,
6904 const MutableSpan<float> factors)
6905{
6906 BLI_assert(verts.size() == factors.size());
6907
6908 for (const int i : verts.index_range()) {
6909 const float dot = math::dot(view_normal, vert_normals[verts[i]]);
6910 factors[i] *= std::max(dot, 0.0f);
6911 }
6912}
6913
6914void calc_front_face(const float3 &view_normal,
6915 const Span<float3> normals,
6916 const MutableSpan<float> factors)
6917{
6918 BLI_assert(normals.size() == factors.size());
6919
6920 for (const int i : normals.index_range()) {
6921 const float dot = math::dot(view_normal, normals[i]);
6922 factors[i] *= std::max(dot, 0.0f);
6923 }
6924}
6925void calc_front_face(const float3 &view_normal,
6926 const SubdivCCG &subdiv_ccg,
6927 const Span<int> grids,
6928 const MutableSpan<float> factors)
6929{
6930 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
6931 const Span<float3> normals = subdiv_ccg.normals;
6932 BLI_assert(grids.size() * key.grid_area == factors.size());
6933
6934 for (const int i : grids.index_range()) {
6935 const Span<float3> grid_normals = normals.slice(bke::ccg::grid_range(key, grids[i]));
6936 MutableSpan<float> grid_factors = factors.slice(bke::ccg::grid_range(key, i));
6937 for (const int offset : grid_factors.index_range()) {
6938 const float dot = math::dot(view_normal, grid_normals[offset]);
6939 grid_factors[offset] *= std::max(dot, 0.0f);
6940 }
6941 }
6942}
6943
6944void calc_front_face(const float3 &view_normal,
6945 const Set<BMVert *, 0> &verts,
6946 const MutableSpan<float> factors)
6947{
6948 BLI_assert(verts.size() == factors.size());
6949
6950 int i = 0;
6951 for (const BMVert *vert : verts) {
6952 const float dot = math::dot(view_normal, float3(vert->no));
6953 factors[i] *= std::max(dot, 0.0f);
6954 i++;
6955 }
6956}
6957
6958void calc_front_face(const float3 &view_normal,
6959 const Set<BMFace *, 0> &faces,
6960 const MutableSpan<float> factors)
6961{
6962 BLI_assert(faces.size() == factors.size());
6963
6964 int i = 0;
6965 for (const BMFace *face : faces) {
6966 const float dot = math::dot(view_normal, float3(face->no));
6967 factors[i] *= std::max(dot, 0.0f);
6968 i++;
6969 }
6970}
6971
6973 const Span<float3> positions,
6974 const Span<int> verts,
6975 const MutableSpan<float> factors)
6976{
6977 BLI_assert(verts.size() == factors.size());
6978
6979 const RegionView3D *rv3d = ss.cache ? ss.cache->vc->rv3d : ss.rv3d;
6980 const View3D *v3d = ss.cache ? ss.cache->vc->v3d : ss.v3d;
6981 if (!RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
6982 return;
6983 }
6984
6985 const ePaintSymmetryFlags mirror_symmetry_pass = ss.cache ? ss.cache->mirror_symmetry_pass :
6987 const int radial_symmetry_pass = ss.cache ? ss.cache->radial_symmetry_pass : 0;
6988 const float4x4 symm_rot_mat_inv = ss.cache ? ss.cache->symm_rot_mat_inv : float4x4::identity();
6989 for (const int i : verts.index_range()) {
6990 float3 symm_co = symmetry_flip(positions[verts[i]], mirror_symmetry_pass);
6991 if (radial_symmetry_pass) {
6992 symm_co = math::transform_point(symm_rot_mat_inv, symm_co);
6993 }
6994 if (ED_view3d_clipping_test(rv3d, symm_co, true)) {
6995 factors[i] = 0.0f;
6996 }
6997 }
6998}
6999
7001 const Span<float3> positions,
7002 const MutableSpan<float> factors)
7003{
7004 BLI_assert(positions.size() == factors.size());
7005
7006 const RegionView3D *rv3d = ss.cache ? ss.cache->vc->rv3d : ss.rv3d;
7007 const View3D *v3d = ss.cache ? ss.cache->vc->v3d : ss.v3d;
7008 if (!RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
7009 return;
7010 }
7011
7012 const ePaintSymmetryFlags mirror_symmetry_pass = ss.cache ? ss.cache->mirror_symmetry_pass :
7014 const int radial_symmetry_pass = ss.cache ? ss.cache->radial_symmetry_pass : 0;
7015 const float4x4 symm_rot_mat_inv = ss.cache ? ss.cache->symm_rot_mat_inv : float4x4::identity();
7016 for (const int i : positions.index_range()) {
7017 float3 symm_co = symmetry_flip(positions[i], mirror_symmetry_pass);
7018 if (radial_symmetry_pass) {
7019 symm_co = math::transform_point(symm_rot_mat_inv, symm_co);
7020 }
7021 if (ED_view3d_clipping_test(rv3d, symm_co, true)) {
7022 factors[i] = 0.0f;
7023 }
7024 }
7025}
7026
7028 const Span<float3> positions,
7029 const Span<int> verts,
7030 const eBrushFalloffShape falloff_shape,
7031 const MutableSpan<float> r_distances)
7032{
7033 BLI_assert(verts.size() == r_distances.size());
7034
7035 const float3 &test_location = ss.cache ? ss.cache->location_symm : ss.cursor_location;
7036 if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE && (ss.cache || ss.filter_cache)) {
7037 /* The tube falloff shape requires the cached view normal. */
7038 const float3 &view_normal = ss.cache ? ss.cache->view_normal_symm :
7040 float4 test_plane;
7041 plane_from_point_normal_v3(test_plane, test_location, view_normal);
7042 for (const int i : verts.index_range()) {
7043 float3 projected;
7044 closest_to_plane_normalized_v3(projected, test_plane, positions[verts[i]]);
7045 r_distances[i] = math::distance_squared(projected, test_location);
7046 }
7047 }
7048 else {
7049 for (const int i : verts.index_range()) {
7050 r_distances[i] = math::distance_squared(test_location, positions[verts[i]]);
7051 }
7052 }
7053}
7054
7056 const Span<float3> positions,
7057 const Span<int> verts,
7058 const eBrushFalloffShape falloff_shape,
7059 const MutableSpan<float> r_distances)
7060{
7061 calc_brush_distances_squared(ss, positions, verts, falloff_shape, r_distances);
7062 for (float &value : r_distances) {
7063 value = std::sqrt(value);
7064 }
7065}
7066
7068 const Span<float3> positions,
7069 const eBrushFalloffShape falloff_shape,
7070 const MutableSpan<float> r_distances)
7071{
7072 BLI_assert(positions.size() == r_distances.size());
7073
7074 const float3 &test_location = ss.cache ? ss.cache->location_symm : ss.cursor_location;
7075 if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE && (ss.cache || ss.filter_cache)) {
7076 /* The tube falloff shape requires the cached view normal. */
7077 const float3 &view_normal = ss.cache ? ss.cache->view_normal_symm :
7079 float4 test_plane;
7080 plane_from_point_normal_v3(test_plane, test_location, view_normal);
7081 for (const int i : positions.index_range()) {
7082 float3 projected;
7083 closest_to_plane_normalized_v3(projected, test_plane, positions[i]);
7084 r_distances[i] = math::distance_squared(projected, test_location);
7085 }
7086 }
7087 else {
7088 for (const int i : positions.index_range()) {
7089 r_distances[i] = math::distance_squared(test_location, positions[i]);
7090 }
7091 }
7092}
7093
7095 const Span<float3> positions,
7096 const eBrushFalloffShape falloff_shape,
7097 const MutableSpan<float> r_distances)
7098{
7099 calc_brush_distances_squared(ss, positions, falloff_shape, r_distances);
7100 for (float &value : r_distances) {
7101 value = std::sqrt(value);
7102 }
7103}
7104
7105void filter_distances_with_radius(const float radius,
7106 const Span<float> distances,
7107 const MutableSpan<float> factors)
7108{
7109 for (const int i : distances.index_range()) {
7110 if (distances[i] >= radius) {
7111 factors[i] = 0.0f;
7112 }
7113 }
7114}
7115
7116template<typename T>
7118 const Span<T> positions,
7119 const MutableSpan<float> r_distances)
7120{
7121 BLI_assert(r_distances.size() == positions.size());
7122
7123 const float roundness = brush.tip_roundness;
7124 const float roundness_rcp = math::safe_rcp(roundness);
7125 const float hardness = 1.0f - roundness;
7126
7127 for (const int i : positions.index_range()) {
7128 const T local = math::abs(positions[i]);
7129
7130 if (math::reduce_max(local) > 1.0f) {
7131 r_distances[i] = 1.0f;
7132 continue;
7133 }
7134 if (std::min(local.x, local.y) > hardness) {
7135 /* Corner, distance to the center of the corner circle. */
7136 r_distances[i] = math::distance(float2(hardness), float2(local)) * roundness_rcp;
7137 continue;
7138 }
7139 if (std::max(local.x, local.y) > hardness) {
7140 /* Side, distance to the square XY axis. */
7141 r_distances[i] = (std::max(local.x, local.y) - hardness) * roundness_rcp;
7142 continue;
7143 }
7144
7145 /* Inside the square, constant distance. */
7146 r_distances[i] = 0.0f;
7147 }
7148}
7149template void calc_brush_cube_distances<float2>(const Brush &brush,
7150 const Span<float2> positions,
7151 MutableSpan<float> r_distances);
7152template void calc_brush_cube_distances<float3>(const Brush &brush,
7153 const Span<float3> positions,
7154 MutableSpan<float> r_distances);
7155
7156void apply_hardness_to_distances(const float radius,
7157 const float hardness,
7158 const MutableSpan<float> distances)
7159{
7160 if (hardness == 0.0f) {
7161 return;
7162 }
7163 const float threshold = hardness * radius;
7164 if (hardness == 1.0f) {
7165 for (const int i : distances.index_range()) {
7166 distances[i] = distances[i] < threshold ? 0.0f : radius;
7167 }
7168 return;
7169 }
7170 const float radius_inv = math::rcp(radius);
7171 const float hardness_inv_rcp = math::rcp(1.0f - hardness);
7172 for (const int i : distances.index_range()) {
7173 if (distances[i] < threshold) {
7174 distances[i] = 0.0f;
7175 }
7176 else {
7177 const float radius_factor = (distances[i] * radius_inv - hardness) * hardness_inv_rcp;
7178 distances[i] = radius_factor * radius;
7179 }
7180 }
7181}
7182
7184 const Brush &brush,
7185 const Span<float> distances,
7186 const MutableSpan<float> factors)
7187{
7190 distances,
7191 cache.radius,
7192 factors);
7193}
7194
7196 const Brush &brush,
7197 const Span<float3> vert_positions,
7198 const Span<int> verts,
7199 const MutableSpan<float> factors)
7200{
7201 BLI_assert(verts.size() == factors.size());
7202
7203 const int thread_id = BLI_task_parallel_thread_id(nullptr);
7204 const MTex *mtex = BKE_brush_mask_texture_get(&brush, OB_MODE_SCULPT);
7205 if (!mtex->tex) {
7206 return;
7207 }
7208
7209 for (const int i : verts.index_range()) {
7210 if (factors[i] == 0.0f) {
7211 continue;
7212 }
7213 float texture_value;
7214 float4 texture_rgba;
7215 /* NOTE: This is not a thread-safe call. */
7217 ss, brush, vert_positions[verts[i]], thread_id, &texture_value, texture_rgba);
7218
7219 factors[i] *= texture_value;
7220 }
7221}
7222
7224 const Brush &brush,
7225 const Span<float3> positions,
7226 const MutableSpan<float> factors)
7227{
7228 BLI_assert(positions.size() == factors.size());
7229
7230 const int thread_id = BLI_task_parallel_thread_id(nullptr);
7231 const MTex *mtex = BKE_brush_mask_texture_get(&brush, OB_MODE_SCULPT);
7232 if (!mtex->tex) {
7233 return;
7234 }
7235
7236 for (const int i : positions.index_range()) {
7237 if (factors[i] == 0.0f) {
7238 continue;
7239 }
7240 float texture_value;
7241 float4 texture_rgba;
7242 /* NOTE: This is not a thread-safe call. */
7243 sculpt_apply_texture(ss, brush, positions[i], thread_id, &texture_value, texture_rgba);
7244
7245 factors[i] *= texture_value;
7246 }
7247}
7248
7250 const Span<float3> positions,
7251 const Span<float3> orig_positions)
7252{
7253 BLI_assert(translations.size() == orig_positions.size());
7254 BLI_assert(translations.size() == positions.size());
7255 for (const int i : translations.index_range()) {
7256 const float3 prev_translation = positions[i] - orig_positions[i];
7257 translations[i] -= prev_translation;
7258 }
7259}
7260
7261#ifndef NDEBUG
7262static bool contains_nan(const Span<float> values)
7263{
7264 return std::any_of(values.begin(), values.end(), [&](const float v) { return std::isnan(v); });
7265}
7266#endif
7267
7268void apply_translations(const Span<float3> translations,
7269 const Span<int> verts,
7270 const MutableSpan<float3> positions)
7271{
7272 BLI_assert(verts.size() == translations.size());
7273 BLI_assert(!contains_nan(translations.cast<float>()));
7274
7275 for (const int i : verts.index_range()) {
7276 const int vert = verts[i];
7277 positions[vert] += translations[i];
7278 }
7279}
7280
7281void apply_translations(const Span<float3> translations,
7282 const Span<int> grids,
7283 SubdivCCG &subdiv_ccg)
7284{
7285 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
7286 MutableSpan<float3> positions = subdiv_ccg.positions;
7287 BLI_assert(grids.size() * key.grid_area == translations.size());
7288 BLI_assert(!contains_nan(translations.cast<float>()));
7289
7290 for (const int i : grids.index_range()) {
7291 const Span<float3> grid_translations = translations.slice(bke::ccg::grid_range(key, i));
7292 MutableSpan<float3> grid_positions = positions.slice(bke::ccg::grid_range(key, grids[i]));
7293 for (const int offset : grid_positions.index_range()) {
7294 grid_positions[offset] += grid_translations[offset];
7295 }
7296 }
7297}
7298
7300{
7301 BLI_assert(verts.size() == translations.size());
7302 BLI_assert(!contains_nan(translations.cast<float>()));
7303
7304 int i = 0;
7305 for (BMVert *vert : verts) {
7306 add_v3_v3(vert->co, translations[i]);
7307 i++;
7308 }
7309}
7310
7311void project_translations(const MutableSpan<float3> translations, const float3 &plane)
7312{
7313 /* Equivalent to #project_plane_v3_v3v3. */
7314 const float len_sq = math::length_squared(plane);
7315 if (len_sq < std::numeric_limits<float>::epsilon()) {
7316 return;
7317 }
7318 const float dot_factor = -math::rcp(len_sq);
7319 for (const int i : translations.index_range()) {
7320 translations[i] += plane * math::dot(translations[i], plane) * dot_factor;
7321 }
7322}
7323
7325 const Span<int> verts,
7326 const MutableSpan<float3> translations)
7327{
7328 BLI_assert(verts.size() == translations.size());
7329
7330 for (const int i : verts.index_range()) {
7331 translations[i] = math::transform_point(deform_imats[verts[i]], translations[i]);
7332 }
7333}
7334
7336 const SculptSession &ss,
7337 const Span<float3> positions,
7338 const Span<int> verts,
7339 const MutableSpan<float3> translations)
7340{
7341 BLI_assert(verts.size() == translations.size());
7342
7343 const StrokeCache *cache = ss.cache;
7344 if (!cache) {
7345 return;
7346 }
7347 for (const int axis : IndexRange(3)) {
7348 if (sd.flags & (SCULPT_LOCK_X << axis)) {
7349 for (float3 &translation : translations) {
7350 translation[axis] = 0.0f;
7351 }
7352 continue;
7353 }
7354
7355 if (!(cache->mirror_modifier_clip.flag & (uint8_t(StrokeFlags::ClipX) << axis))) {
7356 continue;
7357 }
7358
7359 const float4x4 mirror(cache->mirror_modifier_clip.mat);
7360 const float4x4 mirror_inverse(cache->mirror_modifier_clip.mat_inv);
7361 for (const int i : verts.index_range()) {
7362 const int vert = verts[i];
7363
7364 /* Transform into the space of the mirror plane, check translations, then transform back. */
7365 float3 co_mirror = math::transform_point(mirror, positions[vert]);
7366 if (math::abs(co_mirror[axis]) > cache->mirror_modifier_clip.tolerance[axis]) {
7367 continue;
7368 }
7369 /* Clear the translation in the local space of the mirror object. */
7370 co_mirror[axis] = 0.0f;
7371 const float3 co_local = math::transform_point(mirror_inverse, co_mirror);
7372 translations[i][axis] = co_local[axis] - positions[vert][axis];
7373 }
7374 }
7375}
7376
7378 const SculptSession &ss,
7379 const Span<float3> positions,
7380 const MutableSpan<float3> translations)
7381{
7382 BLI_assert(positions.size() == translations.size());
7383
7384 const StrokeCache *cache = ss.cache;
7385 if (!cache) {
7386 return;
7387 }
7388 for (const int axis : IndexRange(3)) {
7389 if (sd.flags & (SCULPT_LOCK_X << axis)) {
7390 for (float3 &translation : translations) {
7391 translation[axis] = 0.0f;
7392 }
7393 continue;
7394 }
7395
7396 if (!(cache->mirror_modifier_clip.flag & (uint8_t(StrokeFlags::ClipX) << axis))) {
7397 continue;
7398 }
7399
7400 const float4x4 mirror(cache->mirror_modifier_clip.mat);
7401 const float4x4 mirror_inverse(cache->mirror_modifier_clip.mat_inv);
7402 for (const int i : positions.index_range()) {
7403 /* Transform into the space of the mirror plane, check translations, then transform back. */
7404 float3 co_mirror = math::transform_point(mirror, positions[i]);
7405 if (math::abs(co_mirror[axis]) > cache->mirror_modifier_clip.tolerance[axis]) {
7406 continue;
7407 }
7408 /* Clear the translation in the local space of the mirror object. */
7409 co_mirror[axis] = 0.0f;
7410 const float3 co_local = math::transform_point(mirror_inverse, co_mirror);
7411 translations[i][axis] = co_local[axis] - positions[i][axis];
7412 }
7413 }
7414}
7415
7416std::optional<ShapeKeyData> ShapeKeyData::from_object(Object &object)
7417{
7418 Mesh &mesh = *static_cast<Mesh *>(object.data);
7419 Key *keys = mesh.key;
7420 if (!keys) {
7421 return std::nullopt;
7422 }
7423 const int active_index = object.shapenr - 1;
7424 const KeyBlock *active_key = BKE_keyblock_find_by_index(keys, active_index);
7425 if (!active_key) {
7426 return std::nullopt;
7427 }
7429 data.active_key_data = {static_cast<float3 *>(active_key->data), active_key->totelem};
7430 data.basis_key_active = active_key == keys->refkey;
7431 if (const std::optional<Array<bool>> dependent = BKE_keyblock_get_dependent_keys(keys,
7432 active_index))
7433 {
7434 int i;
7435 LISTBASE_FOREACH_INDEX (KeyBlock *, other_key, &keys->block, i) {
7436 if ((other_key != active_key) && (*dependent)[i]) {
7437 data.dependent_keys.append({static_cast<float3 *>(other_key->data), other_key->totelem});
7438 }
7439 }
7440 }
7441 return data;
7442}
7443
7445{
7446 Mesh &mesh = *static_cast<Mesh *>(object_orig.data);
7447 this->eval = bke::pbvh::vert_positions_eval(depsgraph, object_orig);
7448
7449 if (!object_orig.sculpt->deform_imats.is_empty()) {
7450 deform_imats_ = object_orig.sculpt->deform_imats;
7451 }
7452 orig_ = mesh.vert_positions_for_write();
7453
7455 if (eval_mut.data() != orig_.data()) {
7456 eval_mut_ = eval_mut;
7457 }
7458
7459 shape_key_data_ = ShapeKeyData::from_object(object_orig);
7460}
7461
7463{
7464 if (eval_mut_) {
7465 /* Apply translations to the evaluated mesh. This is necessary because multiple brush
7466 * evaluations can happen in between object reevaluations (otherwise just deforming the
7467 * original positions would be enough). */
7468 apply_translations(translations, verts, *eval_mut_);
7469 }
7470
7471 if (deform_imats_) {
7472 /* Apply the reverse procedural deformation, since subsequent translation happens to the state
7473 * from "before" deforming modifiers. */
7474 apply_crazyspace_to_translations(*deform_imats_, verts, translations);
7475 }
7476
7477 if (shape_key_data_) {
7478 if (!shape_key_data_->dependent_keys.is_empty()) {
7479 for (MutableSpan<float3> data : shape_key_data_->dependent_keys) {
7480 apply_translations(translations, verts, data);
7481 }
7482 }
7483
7484 if (shape_key_data_->basis_key_active) {
7485 /* The basis key positions and the mesh positions are always kept in sync. */
7486 apply_translations(translations, verts, orig_);
7487 }
7488 apply_translations(translations, verts, shape_key_data_->active_key_data);
7489 }
7490 else {
7491 apply_translations(translations, verts, orig_);
7492 }
7493}
7494
7495void scale_translations(const MutableSpan<float3> translations, const Span<float> factors)
7496{
7497 for (const int i : translations.index_range()) {
7498 translations[i] *= factors[i];
7499 }
7500}
7501
7502void scale_translations(const MutableSpan<float3> translations, const float factor)
7503{
7504 if (factor == 1.0f) {
7505 return;
7506 }
7507 for (const int i : translations.index_range()) {
7508 translations[i] *= factor;
7509 }
7510}
7511
7512void scale_factors(const MutableSpan<float> factors, const float strength)
7513{
7514 if (strength == 1.0f) {
7515 return;
7516 }
7517 for (float &factor : factors) {
7518 factor *= strength;
7519 }
7520}
7521
7522void scale_factors(const MutableSpan<float> factors, const Span<float> strengths)
7523{
7524 BLI_assert(factors.size() == strengths.size());
7525
7526 for (const int i : factors.index_range()) {
7527 factors[i] *= strengths[i];
7528 }
7529}
7530
7532 const Span<float> factors,
7533 const MutableSpan<float3> r_translations)
7534{
7535 BLI_assert(r_translations.size() == factors.size());
7536
7537 for (const int i : factors.index_range()) {
7538 r_translations[i] = offset * factors[i];
7539 }
7540}
7541
7543 const Span<int> verts,
7544 const Span<float3> old_positions,
7545 const MutableSpan<float3> translations)
7546{
7547 BLI_assert(new_positions.size() == verts.size());
7548 for (const int i : verts.index_range()) {
7549 translations[i] = new_positions[i] - old_positions[verts[i]];
7550 }
7551}
7552
7554 const Span<float3> old_positions,
7555 const MutableSpan<float3> translations)
7556{
7557 BLI_assert(new_positions.size() == old_positions.size());
7558 for (const int i : new_positions.index_range()) {
7559 translations[i] = new_positions[i] - old_positions[i];
7560 }
7561}
7562
7564 const IndexMask &node_mask,
7565 Array<int> &node_data)
7566{
7567 node_data.reinitialize(node_mask.size() + 1);
7568 node_mask.foreach_index(
7569 [&](const int i, const int pos) { node_data[pos] = nodes[i].verts().size(); });
7571}
7572
7575 const IndexMask &node_mask,
7576 Array<int> &node_data)
7577{
7578 node_data.reinitialize(node_mask.size() + 1);
7579 node_mask.foreach_index([&](const int i, const int pos) {
7580 node_data[pos] = nodes[i].grids().size() * key.grid_area;
7581 });
7583}
7584
7586 const IndexMask &node_mask,
7587 Array<int> &node_data)
7588{
7589 node_data.reinitialize(node_mask.size() + 1);
7590 node_mask.foreach_index([&](const int i, const int pos) {
7591 node_data[pos] =
7593 });
7595}
7596
7598 const Span<int> corner_verts,
7599 const GroupedSpan<int> vert_to_face,
7600 const Span<bool> hide_poly,
7601 const Span<int> verts,
7602 Vector<int> &r_offset_data,
7603 Vector<int> &r_data)
7604{
7605 BLI_assert(corner_verts.size() == faces.total_size());
7606 r_offset_data.resize(verts.size() + 1);
7607 r_data.clear();
7608 for (const int i : verts.index_range()) {
7609 r_offset_data[i] = r_data.size();
7610 append_neighbors_to_vector(faces, corner_verts, vert_to_face, hide_poly, verts[i], r_data);
7611 }
7612 r_offset_data.last() = r_data.size();
7613 return GroupedSpan<int>(r_offset_data.as_span(), r_data.as_span());
7614}
7615
7617 const Span<int> grids,
7618 Vector<int> &r_offset_data,
7619 Vector<int> &r_data)
7620{
7621 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
7622 SubdivCCGNeighbors neighbors;
7623
7624 r_offset_data.resize(key.grid_area * grids.size() + 1);
7625 r_data.clear();
7626
7627 for (const int i : grids.index_range()) {
7628 const int grid = grids[i];
7629 const int node_verts_start = i * key.grid_area;
7630
7631 for (const short y : IndexRange(key.grid_size)) {
7632 for (const short x : IndexRange(key.grid_size)) {
7633 const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
7634 r_offset_data[node_verts_start + offset] = r_data.size();
7635
7636 SubdivCCGCoord coord{};
7637 coord.grid_index = grid;
7638 coord.x = x;
7639 coord.y = y;
7640 BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, coord, false, neighbors);
7641 for (const SubdivCCGCoord neighbor : neighbors.coords) {
7642 r_data.append(neighbor.to_index(key));
7643 }
7644 }
7645 }
7646 }
7647 r_offset_data.last() = r_data.size();
7648 return GroupedSpan<int>(r_offset_data.as_span(), r_data.as_span());
7649}
7650
7652 Vector<int> &r_offset_data,
7653 Vector<BMVert *> &r_data)
7654{
7655 r_offset_data.resize(verts.size() + 1);
7656 r_data.clear();
7657
7658 BMeshNeighborVerts neighbor_data;
7659 int i = 0;
7660 for (BMVert *vert : verts) {
7661 r_offset_data[i] = r_data.size();
7662 r_data.extend(vert_neighbors_get_bmesh(*vert, neighbor_data));
7663 i++;
7664 }
7665 r_offset_data.last() = r_data.size();
7666 return GroupedSpan<BMVert *>(r_offset_data.as_span(), r_data.as_span());
7667}
7668
7669template<bool use_factors>
7671 const Span<int> corner_verts,
7672 const GroupedSpan<int> vert_to_face,
7673 const BitSpan boundary_verts,
7674 const Span<bool> hide_poly,
7675 const Span<int> verts,
7676 const Span<float> factors,
7677 Vector<int> &r_offset_data,
7678 Vector<int> &r_data)
7679{
7680 BLI_assert(corner_verts.size() == faces.total_size());
7681 if constexpr (use_factors) {
7682 BLI_assert(verts.size() == factors.size());
7683 }
7684
7685 r_offset_data.resize(verts.size() + 1);
7686 r_data.clear();
7687
7688 for (const int i : verts.index_range()) {
7689 const int vert = verts[i];
7690 const int vert_start = r_data.size();
7691 r_offset_data[i] = vert_start;
7692 if constexpr (use_factors) {
7693 if (factors[i] == 0.0f) {
7694 continue;
7695 }
7696 }
7697 append_neighbors_to_vector(faces, corner_verts, vert_to_face, hide_poly, vert, r_data);
7698
7699 if (boundary_verts[vert]) {
7700 /* Do not include neighbors of corner vertices. */
7701 if (r_data.size() == vert_start + 2) {
7702 r_data.resize(vert_start);
7703 }
7704 else {
7705 /* Only include other boundary vertices as neighbors of boundary vertices. */
7706 for (int neighbor_i = r_data.size() - 1; neighbor_i >= vert_start; neighbor_i--) {
7707 if (!boundary_verts[r_data[neighbor_i]]) {
7708 r_data.remove_and_reorder(neighbor_i);
7709 }
7710 }
7711 }
7712 }
7713 }
7714 r_offset_data.last() = r_data.size();
7715 return GroupedSpan<int>(r_offset_data.as_span(), r_data.as_span());
7716}
7717
7719 const Span<int> corner_verts,
7720 const GroupedSpan<int> vert_to_face,
7721 const BitSpan boundary_verts,
7722 const Span<bool> hide_poly,
7723 const Span<int> verts,
7724 const Span<float> factors,
7725 Vector<int> &r_offset_data,
7726 Vector<int> &r_data)
7727{
7729 corner_verts,
7730 vert_to_face,
7731 boundary_verts,
7732 hide_poly,
7733 verts,
7734 factors,
7735 r_offset_data,
7736 r_data);
7737}
7738
7740 const Span<int> corner_verts,
7741 const GroupedSpan<int> vert_to_face,
7742 const BitSpan boundary_verts,
7743 const Span<bool> hide_poly,
7744 const Span<int> verts,
7745 Vector<int> &r_offset_data,
7746 Vector<int> &r_data)
7747{
7749 corner_verts,
7750 vert_to_face,
7751 boundary_verts,
7752 hide_poly,
7753 verts,
7754 {},
7755 r_offset_data,
7756 r_data);
7757}
7758
7760 const Span<int> corner_verts,
7761 const BitSpan boundary_verts,
7762 const SubdivCCG &subdiv_ccg,
7763 const Span<int> grids,
7765{
7766 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
7767
7768 BLI_assert(grids.size() * key.grid_area == result.size());
7769
7770 for (const int i : grids.index_range()) {
7771 const int grid = grids[i];
7772 const int node_verts_start = i * key.grid_area;
7773
7774 /* TODO: This loop could be optimized in the future by skipping unnecessary logic for
7775 * non-boundary grid vertices. */
7776 for (const int y : IndexRange(key.grid_size)) {
7777 for (const int x : IndexRange(key.grid_size)) {
7778 const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
7779 const int node_vert_index = node_verts_start + offset;
7780
7781 SubdivCCGCoord coord{};
7782 coord.grid_index = grid;
7783 coord.x = x;
7784 coord.y = y;
7785
7786 SubdivCCGNeighbors neighbors;
7787 BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, coord, false, neighbors);
7788
7790 faces, corner_verts, boundary_verts, subdiv_ccg, coord))
7791 {
7792 if (neighbors.coords.size() == 2) {
7793 /* Do not include neighbors of corner vertices. */
7794 neighbors.coords.clear();
7795 }
7796 else {
7797 /* Only include other boundary vertices as neighbors of boundary vertices. */
7798 neighbors.coords.remove_if([&](const SubdivCCGCoord coord) {
7800 faces, corner_verts, boundary_verts, subdiv_ccg, coord);
7801 });
7802 }
7803 }
7804 result[node_vert_index] = neighbors.coords;
7805 }
7806 }
7807 }
7808}
7809
7812{
7813 BLI_assert(verts.size() == result.size());
7814 BMeshNeighborVerts neighbor_data;
7815
7816 int i = 0;
7817 for (BMVert *vert : verts) {
7818 vert_neighbors_get_interior_bmesh(*vert, neighbor_data);
7819 result[i] = neighbor_data;
7820 i++;
7821 }
7822}
7823
7825 const Span<int> verts,
7826 const float4 &plane,
7827 const MutableSpan<float3> translations)
7828{
7829 for (const int i : verts.index_range()) {
7830 const float3 &position = vert_positions[verts[i]];
7832 closest_to_plane_normalized_v3(closest, plane, position);
7833 translations[i] = closest - position;
7834 }
7835}
7836
7838 const float4 &plane,
7839 const MutableSpan<float3> translations)
7840{
7841 for (const int i : positions.index_range()) {
7842 const float3 &position = positions[i];
7844 closest_to_plane_normalized_v3(closest, plane, position);
7845 translations[i] = closest - position;
7846 }
7847}
7848
7850 const float3 &pivot,
7851 const ePaintSymmetryFlags symm,
7852 const MutableSpan<float> factors)
7853{
7854 BLI_assert(positions.size() == factors.size());
7855
7856 for (const int i : positions.index_range()) {
7857 if (!SCULPT_check_vertex_pivot_symmetry(positions[i], pivot, symm)) {
7858 factors[i] = 0.0f;
7859 }
7860 }
7861}
7862
7864 const StrokeCache &cache,
7865 const Span<float3> translations,
7866 const MutableSpan<float> factors)
7867{
7868 if (!(brush.flag & BRUSH_PLANE_TRIM)) {
7869 return;
7870 }
7871 const float threshold = cache.radius_squared * cache.plane_trim_squared;
7872 for (const int i : translations.index_range()) {
7873 if (math::length_squared(translations[i]) > threshold) {
7874 factors[i] = 0.0f;
7875 }
7876 }
7877}
7878
7880 const Span<int> verts,
7881 const float4 &plane,
7882 const MutableSpan<float> factors)
7883{
7884 for (const int i : verts.index_range()) {
7885 if (plane_point_side_v3(plane, vert_positions[verts[i]]) <= 0.0f) {
7886 factors[i] = 0.0f;
7887 }
7888 }
7889}
7890
7892 const float4 &plane,
7893 const MutableSpan<float> factors)
7894{
7895 for (const int i : positions.index_range()) {
7896 if (plane_point_side_v3(plane, positions[i]) <= 0.0f) {
7897 factors[i] = 0.0f;
7898 }
7899 }
7900}
7901
7903 const Span<int> verts,
7904 const float4 &plane,
7905 const MutableSpan<float> factors)
7906{
7907 for (const int i : verts.index_range()) {
7908 if (plane_point_side_v3(plane, vert_positions[verts[i]]) > 0.0f) {
7909 factors[i] = 0.0f;
7910 }
7911 }
7912}
7913
7915 const float4 &plane,
7916 const MutableSpan<float> factors)
7917{
7918 for (const int i : positions.index_range()) {
7919 if (plane_point_side_v3(plane, positions[i]) > 0.0f) {
7920 factors[i] = 0.0f;
7921 }
7922 }
7923}
7924
7925} // namespace blender::ed::sculpt_paint
bool BKE_brush_use_alpha_pressure(const Brush *brush)
Definition brush.cc:1290
float BKE_brush_alpha_get(const Paint *paint, const Brush *brush)
Definition brush.cc:1357
float BKE_brush_sample_tex_3d(const Paint *paint, const Brush *br, const MTex *mtex, const float point[3], float rgba[4], int thread, ImagePool *pool)
Definition brush.cc:920
bool BKE_brush_use_locked_size(const Paint *paint, const Brush *brush)
Definition brush.cc:1277
std::optional< BrushColorJitterSettings > BKE_brush_color_jitter_get_settings(const Paint *paint, const Brush *brush)
Definition brush.cc:1170
bool BKE_brush_use_size_pressure(const Brush *brush)
Definition brush.cc:1285
float BKE_brush_radius_get(const Paint *paint, const Brush *brush)
Definition brush.cc:1272
bool BKE_brush_has_cube_tip(const Brush *brush, PaintMode paint_mode)
Definition brush.cc:1707
float BKE_brush_unprojected_radius_get(const Paint *paint, const Brush *brush)
Definition brush.cc:1315
void BKE_brush_size_set(Paint *paint, Brush *brush, int size)
Definition brush.cc:1248
void BKE_brush_unprojected_size_set(Paint *paint, Brush *brush, float unprojected_size)
Definition brush.cc:1295
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:1448
int BKE_brush_size_get(const Paint *paint, const Brush *brush)
Definition brush.cc:1264
const MTex * BKE_brush_mask_texture_get(const Brush *brush, eObjectMode object_mode)
Definition brush.cc:904
int CCG_grid_xy_to_index(const int grid_size, const int x, const int y)
Definition BKE_ccg.hh:73
float BKE_curvemapping_evaluateF(const CurveMapping *cumap, int cur, float value)
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:1907
std::optional< blender::Array< bool > > BKE_keyblock_get_dependent_keys(const Key *key, int index)
Definition key.cc:2371
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, bool process_shape_keys=true)
void BKE_mesh_copy_parameters(Mesh *me_dst, const Mesh *me_src)
Mesh * BKE_mesh_from_object(Object *ob)
@ MULTIRES_COORDS_MODIFIED
void multires_stitch_grids(Object *)
Definition multires.cc:549
void multires_mark_as_modified(Depsgraph *depsgraph, Object *object, MultiresModifiedFlags flags)
Definition multires.cc:247
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:1105
std::variant< std::monostate, int, BMVert * > ActiveVert
Definition BKE_paint.hh:360
#define PAINT_SYMM_AREA_DEFAULT
Definition BKE_paint.hh:106
bool BKE_paint_brush_set(Paint *paint, Brush *brush)
Definition paint.cc:710
bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const RegionView3D *rv3d)
Definition paint.cc:3068
ePaintSymmetryAreas
Definition BKE_paint.hh:108
@ PAINT_SYMM_AREA_Z
Definition BKE_paint.hh:111
@ PAINT_SYMM_AREA_X
Definition BKE_paint.hh:109
@ PAINT_SYMM_AREA_Y
Definition BKE_paint.hh:110
blender::float3 seed_hsv_jitter()
#define SCULPT_FACE_SET_NONE
Definition BKE_paint.hh:324
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:650
MultiresModifierData * BKE_sculpt_multires_active(const Scene *scene, Object *ob)
Definition paint.cc:2513
void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph, Object *ob_orig, bool is_paint_tool)
Definition paint.cc:2797
void BKE_sculpt_color_layer_create_if_needed(Object *object)
Definition paint.cc:2773
Paint * BKE_paint_get_active_from_context(const bContext *C)
Definition paint.cc:476
void BKE_sculptsession_free_pbvh(Object &object)
Definition paint.cc:2286
Brush * BKE_paint_brush(Paint *paint)
Definition paint.cc:645
void BKE_sculpt_mask_layers_ensure(Depsgraph *depsgraph, Main *bmain, Object *ob, MultiresModifierData *mmd)
Definition paint.cc:2806
A BVH for high poly meshes.
bool BKE_pbvh_node_fully_hidden_get(const blender::bke::pbvh::Node &node)
Definition pbvh.cc:1723
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:1675
float BKE_pbvh_node_get_tmin(const blender::bke::pbvh::Node *node)
Definition pbvh.cc:849
bool BKE_pbvh_node_fully_masked_get(const blender::bke::pbvh::Node &node)
Definition pbvh.cc:1741
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:1786
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
@ RPT_ERROR
Definition BKE_report.hh:39
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
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)
SubdivCCGAdjacencyType
CCGKey BKE_subdiv_ccg_key_top_level(const SubdivCCG &subdiv_ccg)
void BKE_subdiv_ccg_foreach_visible_grid_vert(const CCGKey &key, const blender::BitGroupVector<> &grid_hidden, const int grid, const Fn &fn)
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)
#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 ENUM_OPERATORS(_type, _max)
#define UNPACK3(a)
#define ELEM(...)
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:189
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_SHADING
Definition DNA_ID.h:1094
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
#define ID_REAL_USERS(id)
Definition DNA_ID.h:676
@ 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
@ KEYBLOCK_LOCKED_SHAPE
@ eModifierMode_Realtime
@ eModifierType_Mirror
@ MOD_MIR_CLIPPING
@ MOD_MIR_AXIS_X
@ 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
@ TEX_NOISE
@ MTEX_MAP_MODE_AREA
@ MTEX_MAP_MODE_3D
#define USER_EXPERIMENTAL_TEST(userdef, member)
@ V3D_SHADING_VERTEX_COLOR
@ RV3D_PAINTING
#define RV3D_CLIPPING_ENABLED(v3d, rv3d)
@ 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:711
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:618
blender::float2 ED_view3d_project_float_v2_m4(const ARegion *region, const float co[3], const blender::float4x4 &mat)
void ED_view3d_win_to_delta(const ARegion *region, const float xy_delta[2], float zfac, float r_out[3], bool precise=false)
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)
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:344
@ PROP_HIDDEN
Definition RNA_types.hh:338
#define C
Definition RandGen.cpp:29
#define ND_DRAW
Definition WM_types.hh:461
@ OPTYPE_BLOCKING
Definition WM_types.hh:184
#define NC_OBJECT
Definition WM_types.hh:379
#define U
#define BM_ELEM_CD_SET_FLOAT(ele, offset, f)
#define BM_ELEM_CD_GET_FLOAT(ele, offset)
#define BM_ELEM_CD_GET_INT(ele, offset)
@ BM_ELEM_HIDDEN
#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:795
const float * BM_log_find_original_vert_co(BMLog *log, BMVert *v)
Definition bmesh_log.cc:784
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:264
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:256
IndexRange index_range() const
Definition BLI_array.hh:360
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:419
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
bool add(const StringRef attribute_id, const AttrDomain domain, const AttrType data_type, const AttributeInit &initializer)
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, AttrType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
bool remove(const StringRef attribute_id)
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:676
void tag_positions_changed(const IndexMask &node_mask)
Definition pbvh.cc:635
Span< NodeT > nodes() const
void update_bounds(const Depsgraph &depsgraph, const Object &object)
Definition pbvh.cc:1386
void tag_face_sets_changed(const IndexMask &node_mask)
Definition pbvh.cc:662
void tag_masks_changed(const IndexMask &node_mask)
Definition pbvh.cc:669
void tag_topology_changed(const IndexMask &node_mask)
Definition pbvh.cc:655
void deform(MutableSpan< float3 > translations, Span< int > verts) const
Definition sculpt.cc:7462
PositionDeformData(const Depsgraph &depsgraph, Object &object_orig)
Definition sculpt.cc:7444
IndexMask slice(IndexRange range) const
void foreach_index(Fn &&fn) const
nullptr float
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 powf(x, y)
static ushort indices[]
static float verts[][3]
static float normals[][3]
uint pos
#define in
#define out
#define printf(...)
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
float distance(VecOp< float, D >, VecOp< float, D >) RET
VecBase< float, 2 > float2
CCL_NAMESPACE_BEGIN ccl_device float invert(const float color, const float factor)
Definition invert.h:11
#define LOG(level)
Definition log.h:97
#define T
static char faces[256]
#define G(x, y, z)
void count_indices(Span< int > indices, MutableSpan< int > counts)
bool supports_auto_smooth_pressure(const Brush &brush)
Definition brush.cc:1929
bool supports_rake_factor(const Brush &brush)
Definition brush.cc:1823
bool supports_accumulate(const Brush &brush)
Definition brush.cc:1760
bool supports_gravity(const Brush &brush)
Definition brush.cc:1954
bool supports_hardness_pressure(const Brush &brush)
Definition brush.cc:1933
bool supports_dyntopo(const Brush &brush)
Definition brush.cc:1736
bool supports_topology_rake(const Brush &brush)
Definition brush.cc:1775
bool supports_normal_weight(const Brush &brush)
Definition brush.cc:1816
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:338
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:3052
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:2663
void update_normals(const Depsgraph &depsgraph, Object &object_orig, Tree &pbvh)
Definition pbvh.cc:1257
IndexMask all_leaf_nodes(const Tree &pbvh, IndexMaskMemory &memory)
Definition pbvh.cc:2628
void clip_ray_ortho(Tree &pbvh, bool original, float ray_start[3], float ray_end[3], float ray_normal[3])
Definition pbvh.cc:2182
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:1976
void node_update_mask_bmesh(int mask_offset, BMeshNode &node)
Definition pbvh.cc:1479
void node_update_mask_mesh(Span< float > mask, MeshNode &node)
Definition pbvh.cc:1421
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:1449
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:2092
Bounds< float3 > bounds_get(const Tree &pbvh)
Definition pbvh.cc:1661
Span< float3 > vert_normals_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:1059
MutableSpan< float3 > vert_positions_eval_for_write(const Depsgraph &depsgraph, Object &object_orig)
Definition pbvh.cc:1053
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:2432
void store_bounds_orig(Tree &pbvh)
Definition pbvh.cc:1408
Span< int > node_face_indices_calc_grids(const SubdivCCG &subdiv_ccg, const GridsNode &node, Vector< int > &faces)
Definition pbvh.cc:1767
Span< float3 > vert_positions_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:1040
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:2294
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:483
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:6073
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_blob_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob, const IndexMask &node_mask)
Definition crease.cc:273
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 Sculpt &sd, Object &ob, const IndexMask &node_mask)
Definition crease.cc:265
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_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 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:850
int vert_face_set_get(const GroupedSpan< int > vert_to_face_map, const Span< int > face_sets, const int vert)
Definition sculpt.cc:230
bool vert_has_unique_face_set(const GroupedSpan< int > vert_to_face_map, const Span< int > face_sets, int vert)
Definition sculpt.cc:292
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:252
bke::SpanAttributeWriter< int > ensure_face_sets_mesh(Mesh &mesh)
int active_face_set_get(const Object &object)
Definition sculpt.cc:196
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:318
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:6317
static SculptTopologyIslandCache calc_topology_islands_grids(const Object &object)
Definition sculpt.cc:6250
static SculptTopologyIslandCache vert_disjoint_set_to_islands(const AtomicDisjointSet &vert_sets, const int verts_num)
Definition sculpt.cc:6204
static SculptTopologyIslandCache calc_topology_islands_mesh(const Mesh &mesh)
Definition sculpt.cc:6225
static SculptTopologyIslandCache calculate_cache(const Object &object)
Definition sculpt.cc:6303
static SculptTopologyIslandCache calc_topology_islands_bmesh(const Object &object)
Definition sculpt.cc:6275
int vert_id_get(const SculptSession &ss, const int vert)
Definition sculpt.cc:6184
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:1147
static void restore_color_from_undo_step(Object &object)
Definition sculpt.cc:946
static void restore_face_set_from_undo_step(Object &object)
Definition sculpt.cc:979
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:1031
void geometry_begin(const Scene &scene, Object &ob, const wmOperator *op)
static void restore_mask_from_undo_step(Object &object)
Definition sculpt.cc:871
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:4940
void fill_factor_from_hide_and_mask(Span< bool > hide_vert, Span< float > mask, Span< int > verts, MutableSpan< float > r_factors)
Definition sculpt.cc:6823
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:2606
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:3123
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:829
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:4083
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:5839
static bool attribute_matches(const bke::AttributeAccessor a, const bke::AttributeAccessor b, const StringRef name)
Definition sculpt.cc:5238
bool node_in_sphere(const bke::pbvh::Node &node, const float3 &location, const float radius_sq, const bool original)
Definition sculpt.cc:2429
void scatter_data_bmesh(Span< T > node_data, const Set< BMVert *, 0 > &verts, MutableSpan< T > dst)
Definition sculpt.cc:6461
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:2439
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:6706
void gather_bmesh_positions(const Set< BMVert *, 0 > &verts, MutableSpan< float3 > positions)
Definition sculpt.cc:6367
static void smooth_brush_toggle_off(Paint *paint, StrokeCache *cache)
Definition sculpt.cc:3910
static void tag_mesh_positions_changed(Object &object, const bool use_pbvh_draw)
Definition sculpt.cc:5053
void calc_brush_strength_factors(const StrokeCache &cache, const Brush &brush, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:7183
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:6405
static void redo_empty_ui(bContext *, wmOperator *)
Definition sculpt.cc:5765
void vert_random_access_ensure(Object &object)
Definition sculpt.cc:141
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:592
void filter_below_plane_factors(Span< float3 > vert_positions, Span< int > verts, const float4 &plane, MutableSpan< float > factors)
Definition sculpt.cc:7879
wmOperatorStatus paint_stroke_exec(bContext *C, wmOperator *op, PaintStroke *stroke)
static void stroke_update_step(bContext *C, wmOperator *op, PaintStroke *, PointerRNA *stroke_element)
static void do_radial_symmetry(const Depsgraph &depsgraph, const Scene &scene, Sculpt &sd, Object &ob, const Brush &brush, PaintModeSettings &paint_mode_settings, const BrushActionFunc action, const ePaintSymmetryFlags symm, const int axis, const float)
Definition sculpt.cc:3598
void apply_hardness_to_distances(float radius, float hardness, MutableSpan< float > distances)
Definition sculpt.cc:7156
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:6603
GroupedSpan< int > calc_vert_neighbors(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face, Span< bool > hide_poly, Span< int > verts, Vector< int > &r_offset_data, Vector< int > &r_data)
Definition sculpt.cc:7597
void gather_bmesh_normals(const Set< BMVert *, 0 > &verts, MutableSpan< float3 > normals)
Definition sculpt.cc:6385
static void pose_fake_neighbors_free(SculptSession &ss)
Definition sculpt.cc:5815
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:7670
bool node_fully_masked_or_hidden(const bke::pbvh::Node &node)
Definition sculpt.cc:2418
float3 tilt_effective_normal_get(const SculptSession &ss, const Brush &brush)
Definition sculpt.cc:2718
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:6512
void filter_distances_with_radius(float radius, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:7105
std::optional< OrigPositionData > orig_position_data_lookup_grids(const Object &object, const bke::pbvh::GridsNode &node)
static const ImplicitSharingInfo * get_vertex_group_sharing_info(const Mesh &mesh)
Definition sculpt.cc:5283
static void cache_paint_invariants_update(StrokeCache &cache, const Brush &brush)
Definition sculpt.cc:4292
void filter_region_clip_factors(const SculptSession &ss, Span< float3 > vert_positions, Span< int > verts, MutableSpan< float > factors)
Definition sculpt.cc:6972
void gather_data_bmesh(Span< T > src, const Set< BMVert *, 0 > &verts, MutableSpan< T > node_data)
Definition sculpt.cc:6421
static void fake_neighbor_init(Object &object, const float max_dist)
Definition sculpt.cc:5807
void reset_translations_to_original(MutableSpan< float3 > translations, Span< float3 > positions, Span< float3 > orig_positions)
Definition sculpt.cc:7249
float3 symmetry_flip(const float3 &src, const ePaintSymmetryFlags symm)
static int sculpt_brush_needs_normal(const SculptSession &ss, const Brush &brush)
Definition sculpt.cc:809
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:7495
void paint_stroke_cancel(bContext *C, wmOperator *op, PaintStroke *stroke)
static bool brush_type_needs_original(const char sculpt_brush_type)
Definition sculpt.cc:786
bool paint_supports_dynamic_size(const Brush &br, PaintMode mode)
static void sculpt_init_mirror_clipping(const Object &ob, const SculptSession &ss)
Definition sculpt.cc:3832
static IndexMask pbvh_gather_texpaint(Object &ob, const Brush &brush, const bool use_original, const float radius_scale, IndexMaskMemory &memory)
Definition sculpt.cc:2536
static void stroke_done(const bContext *C, PaintStroke *stroke)
static void brush_exit_tex(Sculpt &sd)
Definition sculpt.cc:5576
bool color_supported_check(const Scene &scene, Object &object, ReportList *reports)
Definition sculpt.cc:5474
static bool need_delta_from_anchored_origin(const Brush &brush)
Definition sculpt.cc:4105
static void calc_area_normal_and_center_node_grids(const Object &object, const Brush &brush, const AverageDataFlags flag, const bke::pbvh::GridsNode &node, SampleLocalData &tls, AreaNormalCenterData &anctd)
Definition sculpt.cc:1456
static wmOperatorStatus brush_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition sculpt.cc:5760
static bool sculpt_needs_connectivity_info(const Sculpt &sd, const Brush &brush, const Object &object, int stroke_mode)
Definition sculpt.cc:4441
bool report_if_shape_key_is_locked(const Object &ob, ReportList *reports)
Definition sculpt.cc:127
static void store_sculpt_entire_mesh(const wmOperator &op, const Scene &scene, Object &object, Mesh *new_mesh)
Definition sculpt.cc:5271
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:4644
static bool brush_type_needs_all_pbvh_nodes(const Brush &brush)
Definition sculpt.cc:3089
void filter_verts_outside_symmetry_area(Span< float3 > positions, const float3 &pivot, ePaintSymmetryFlags symm, MutableSpan< float > factors)
Definition sculpt.cc:7849
static void do_brush_action(const Depsgraph &depsgraph, const Scene &, Sculpt &sd, Object &ob, const Brush &brush, PaintModeSettings &paint_mode_settings)
Definition sculpt.cc:3197
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:836
void calc_translations_to_plane(Span< float3 > vert_positions, Span< int > verts, const float4 &plane, MutableSpan< float3 > translations)
Definition sculpt.cc:7824
void scale_factors(MutableSpan< float > factors, float strength)
Definition sculpt.cc:7512
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:6670
static void do_symmetrical_brush_actions(const Depsgraph &depsgraph, const Scene &scene, Sculpt &sd, Object &ob, const BrushActionFunc action, PaintModeSettings &paint_mode_settings)
Definition sculpt.cc:3635
static void brush_delta_update(const Depsgraph &depsgraph, Paint &paint, const Object &ob, const Brush &brush)
Definition sculpt.cc:4144
static void smooth_brush_toggle_on(const bContext *C, Paint *paint, StrokeCache *cache)
Definition sculpt.cc:3869
static float3 calc_sculpt_normal(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob, const IndexMask &node_mask)
Definition sculpt.cc:2546
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:7542
static bool need_delta_for_tip_orientation(const Brush &brush)
Definition sculpt.cc:4130
void clip_and_lock_translations(const Sculpt &sd, const SculptSession &ss, Span< float3 > positions, Span< int > verts, MutableSpan< float3 > translations)
Definition sculpt.cc:7335
bool cursor_geometry_info_update(bContext *C, CursorGeometryInfo *out, const float2 &mval, const bool use_sampled_normal)
Definition sculpt.cc:4685
static void sculpt_brush_stroke_cancel(bContext *C, wmOperator *op)
Definition sculpt.cc:5737
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:2502
static void push_undo_nodes(const Depsgraph &depsgraph, Object &ob, const Brush &brush, const IndexMask &node_mask)
Definition sculpt.cc:3165
void flush_update_done(const bContext *C, Object &ob, const UpdateType update_type)
Definition sculpt.cc:5146
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:6435
static bool contains_nan(const Span< float > values)
Definition sculpt.cc:7262
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:7055
void SCULPT_OT_brush_stroke(wmOperatorType *ot)
Definition sculpt.cc:5767
void project_translations(MutableSpan< float3 > translations, const float3 &plane)
Definition sculpt.cc:7311
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:2910
Span< BMVert * > vert_neighbors_get_interior_bmesh(BMVert &vert, BMeshNeighborVerts &r_neighbors)
Definition sculpt.cc:402
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:2624
void(*)(const Depsgraph &depsgraph, const Scene &scene, Sculpt &sd, Object &ob, const Brush &brush, PaintModeSettings &paint_mode_settings) BrushActionFunc
Definition sculpt.cc:3525
std::optional< float3 > calc_area_normal(const Depsgraph &depsgraph, const Brush &brush, const Object &ob, const IndexMask &node_mask)
Definition sculpt.cc:1833
void filter_plane_trim_limit_factors(const Brush &brush, const StrokeCache &cache, Span< float3 > translations, MutableSpan< float > factors)
Definition sculpt.cc:7863
OffsetIndices< int > create_node_vert_offsets(Span< bke::pbvh::MeshNode > nodes, const IndexMask &node_mask, Array< int > &node_data)
Definition sculpt.cc:7563
Span< BMVert * > vert_neighbors_get_bmesh(BMVert &vert, BMeshNeighborVerts &r_neighbors)
Definition sculpt.cc:387
void apply_translations(Span< float3 > translations, Span< int > verts, MutableSpan< float3 > positions)
Definition sculpt.cc:7268
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:6568
bool vertex_is_occluded(const Depsgraph &depsgraph, const Object &object, const float3 &position, bool original)
Definition sculpt.cc:6128
ViewContext * paint_stroke_view_context(PaintStroke *stroke)
void gather_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6395
void calc_brush_texture_factors(const SculptSession &ss, const Brush &brush, Span< float3 > vert_positions, Span< int > vert, MutableSpan< float > factors)
Definition sculpt.cc:7195
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:5895
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 AverageDataFlags flag, const bke::pbvh::MeshNode &node, SampleLocalData &tls, AreaNormalCenterData &anctd)
Definition sculpt.cc:1365
bool paint_brush_cursor_poll(bContext *C)
static void sculpt_fix_noise_tear(const Sculpt &sd, Object &ob)
Definition sculpt.cc:3624
static AreaNormalCenterData calc_area_normal_and_center_reduce(const AreaNormalCenterData &a, const AreaNormalCenterData &b)
Definition sculpt.cc:1713
void filter_above_plane_factors(Span< float3 > vert_positions, Span< int > verts, const float4 &plane, MutableSpan< float > factors)
Definition sculpt.cc:7902
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:1731
float object_space_radius_get(const ViewContext &vc, const Paint &paint, const Brush &brush, const float3 &location, const float scale_factor)
Definition sculpt.cc:114
void flush_update_step(const bContext *C, const UpdateType update_type)
Definition sculpt.cc:5098
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:4339
static constexpr int plane_brush_max_rolling_average_num
float brush_plane_offset_get(const Brush &brush, const SculptSession &ss)
Definition sculpt.cc:2993
static wmOperatorStatus sculpt_brush_stroke_exec(bContext *C, wmOperator *op)
Definition sculpt.cc:5718
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:1944
void apply_crazyspace_to_translations(Span< float3x3 > deform_imats, Span< int > verts, MutableSpan< float3 > translations)
Definition sculpt.cc:7324
static void sculpt_find_nearest_to_ray_cb(bke::pbvh::Node &node, FindNearestToRayData &fntrd, float *tmin)
Definition sculpt.cc:4588
static bool topology_matches(const Mesh &a, const Mesh &b)
Definition sculpt.cc:5250
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:693
static void sculpt_raycast_cb(bke::pbvh::Node &node, RaycastData &rd, float *tmin)
Definition sculpt.cc:4486
static void fake_neighbor_search(const Depsgraph &depsgraph, const Object &ob, const float max_distance_sq, MutableSpan< int > fake_neighbors)
Definition sculpt.cc:5923
static wmOperatorStatus sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition sculpt.cc:5636
void calc_front_face(const float3 &view_normal, Span< float3 > normals, MutableSpan< float > factors)
Definition sculpt.cc:6914
float paint_stroke_distance_get(PaintStroke *stroke)
static void replace_attribute(const bke::AttributeAccessor src_attributes, const StringRef name, const bke::AttrDomain domain, const bke::AttrType data_type, bke::MutableAttributeAccessor dst_attributes)
Definition sculpt.cc:5217
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:5866
std::optional< Span< float > > orig_mask_data_lookup_mesh(const Object &object, const bke::pbvh::MeshNode &node)
static void calc_area_normal_and_center_node_bmesh(const Object &object, const Brush &brush, const AverageDataFlags flag, const bool has_bm_orco, const bke::pbvh::BMeshNode &node, SampleLocalData &tls, AreaNormalCenterData &anctd)
Definition sculpt.cc:1565
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:639
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:2454
static bool brush_uses_topology_rake(const SculptSession &ss, const Brush &brush)
Definition sculpt.cc:800
void calc_brush_distances_squared(const SculptSession &ss, Span< float3 > positions, Span< int > verts, eBrushFalloffShape falloff_shape, MutableSpan< float > r_distances)
Definition sculpt.cc:7027
void gather_grids_normals(const SubdivCCG &subdiv_ccg, Span< int > grids, MutableSpan< float3 > normals)
Definition sculpt.cc:6378
static void sculpt_update_cache_invariants(bContext *C, Sculpt &sd, SculptSession &ss, const wmOperator &op, const float mval[2])
Definition sculpt.cc:3939
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:2028
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:7531
void calc_brush_cube_distances(const Brush &brush, const Span< T > positions, const MutableSpan< float > r_distances)
Definition sculpt.cc:7117
static float area_normal_and_center_get_normal_radius(const SculptSession &ss, const Brush &brush)
Definition sculpt.cc:1281
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:5292
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:450
std::optional< Span< int > > orig_face_set_data_lookup_grids(const Object &object, const bke::pbvh::GridsNode &node)
static void dynamic_topology_update(const Depsgraph &depsgraph, const Scene &, Sculpt &sd, Object &ob, const Brush &brush, PaintModeSettings &)
Definition sculpt.cc:3009
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:429
void fill_factor_from_hide(Span< bool > hide_vert, Span< int > verts, MutableSpan< float > r_factors)
Definition sculpt.cc:6775
void scatter_data_grids(const SubdivCCG &subdiv_ccg, Span< T > node_data, Span< int > grids, MutableSpan< T > dst)
Definition sculpt.cc:6445
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:7585
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:6637
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:7739
static void update_sculpt_normal(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob, const brushes::CursorSampleResult &cursor_sample_result)
Definition sculpt.cc:2569
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)
static void do_tiled(const Depsgraph &depsgraph, const Scene &scene, Sculpt &sd, Object &ob, const Brush &brush, PaintModeSettings &paint_mode_settings, const BrushActionFunc action)
Definition sculpt.cc:3532
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:6741
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:4827
Span< float3 > vert_positions_for_grab_active_get(const Depsgraph &depsgraph, const Object &object)
Definition sculpt.cc:169
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:2690
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:2465
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
const char * name
#define fabsf
#define sqrtf
#define sinf
#define cosf
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:5456
bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(const blender::ed::sculpt_paint::StrokeCache &cache)
Definition sculpt.cc:542
bool SCULPT_brush_cursor_poll(bContext *C)
Definition sculpt.cc:3734
ePaintSymmetryFlags SCULPT_mesh_symmetry_xyz_get(const Object &object)
Definition sculpt.cc:184
static void restore_from_undo_step_if_necessary(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob)
Definition sculpt.cc:5004
StrokeFlags
Definition sculpt.cc:3823
static void brush_stroke_init(bContext *C)
Definition sculpt.cc:4974
const float * SCULPT_brush_frontface_normal_from_falloff_shape(const SculptSession &ss, char falloff_shape)
Definition sculpt.cc:1180
Span< int > SCULPT_fake_neighbors_ensure(const Depsgraph &depsgraph, Object &ob, const float max_dist)
Definition sculpt.cc:6098
static void brush_init_tex(const Sculpt &sd, SculptSession &ss)
Definition sculpt.cc:4958
static bool sculpt_needs_pbvh_pixels(PaintModeSettings &paint_mode_settings, const Brush &brush, Object &ob)
Definition sculpt.cc:2744
static bool over_mesh(bContext *C, wmOperator *, const float mval[2])
Definition sculpt.cc:5423
void SCULPT_stroke_modifiers_check(const bContext *C, Object &ob, const Brush &brush)
Definition sculpt.cc:4468
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:2322
static float calc_symmetry_feather(const Sculpt &sd, const Mesh &mesh, const blender::ed::sculpt_paint::StrokeCache &cache)
Definition sculpt.cc:1229
static void sculpt_pbvh_update_pixels(const Depsgraph &depsgraph, PaintModeSettings &paint_mode_settings, Object &ob)
Definition sculpt.cc:2759
static const char * sculpt_brush_type_name(const Sculpt &sd)
Definition sculpt.cc:3740
void SCULPT_cache_calc_brushdata_symm(blender::ed::sculpt_paint::StrokeCache &cache, const ePaintSymmetryFlags symm, const char axis, const float angle)
Definition sculpt.cc:3465
bool SCULPT_mode_poll_view3d(bContext *C)
Definition sculpt.cc:3683
static float brush_flip(const Brush &brush, const blender::ed::sculpt_paint::StrokeCache &cache)
Definition sculpt.cc:2161
float3 SCULPT_flip_v3_by_symm_area(const float3 &vector, const ePaintSymmetryFlags symm, const ePaintSymmetryAreas symmarea, const float3 &pivot)
Definition sculpt.cc:2868
bool SCULPT_mode_poll(bContext *C)
Definition sculpt.cc:3677
static void stroke_undo_begin(const bContext *C, wmOperator *op)
Definition sculpt.cc:5435
static float calc_radial_symmetry_feather(const Mesh &mesh, const blender::ed::sculpt_paint::StrokeCache &cache, const ePaintSymmetryFlags symm, const char axis)
Definition sculpt.cc:1214
void SCULPT_calc_vertex_displacement(const SculptSession &ss, const Brush &brush, float translation[3])
Definition sculpt.cc:2388
static bool is_brush_related_tool(bContext *C)
Definition sculpt.cc:3702
bool SCULPT_stroke_is_main_symmetry_pass(const blender::ed::sculpt_paint::StrokeCache &cache)
Definition sculpt.cc:530
static void flip_qt(float quat[4], const ePaintSymmetryFlags symm)
Definition sculpt.cc:2863
static void flip_qt_qt(float out[4], const float in[4], const ePaintSymmetryFlags symm)
Definition sculpt.cc:2840
int SCULPT_vertex_count_get(const Object &object)
Definition sculpt.cc:151
void sculpt_project_v3_normal_align(const SculptSession &ss, const float normal_weight, float grab_delta[3])
Definition sculpt.cc:567
static void update_brush_local_mat(const Sculpt &sd, Object &ob)
Definition sculpt.cc:2725
void SCULPT_cube_tip_init(const Sculpt &, const Object &ob, const Brush &brush, float mat[4][4])
Definition sculpt.cc:6328
void SCULPT_fake_neighbors_free(Object &ob)
Definition sculpt.cc:6120
bool SCULPT_is_vertex_inside_brush_radius_symm(const float vertex[3], const float br_co[3], float radius, char symm)
Definition sculpt.cc:742
bool SCULPT_check_vertex_pivot_symmetry(const float vco[3], const float pco[3], const char symm)
Definition sculpt.cc:548
static float brush_strength(const Sculpt &sd, const blender::ed::sculpt_paint::StrokeCache &cache, const float feather, const PaintModeSettings &)
Definition sculpt.cc:2175
bool SCULPT_poll(bContext *C)
Definition sculpt.cc:3689
ePaintSymmetryAreas SCULPT_get_vertex_symm_area(const float co[3])
Definition sculpt.cc:2825
static float calc_overlap(const blender::ed::sculpt_paint::StrokeCache &cache, const ePaintSymmetryFlags symm, const char axis, const float angle)
Definition sculpt.cc:1193
void SCULPT_flip_quat_by_symm_area(float quat[4], const ePaintSymmetryFlags symm, const ePaintSymmetryAreas symmarea, const float pivot[3])
Definition sculpt.cc:2889
bool SCULPT_stroke_is_first_brush_step(const blender::ed::sculpt_paint::StrokeCache &cache)
Definition sculpt.cc:536
void SCULPT_tag_update_overlays(bContext *C)
Definition sculpt.cc:759
#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
float tip_scale_x
float texture_sample_bias
float stabilize_plane
float plane_trim
char falloff_shape
float tilt_strength_factor
struct CurveMapping * curve_distance_falloff
float hardness
char mask_tool
int smooth_deform_type
float wet_mix
float wet_persistence
int deform_target
float plane_offset
int curve_distance_falloff_preset
float tip_roundness
float autosmooth_factor
int paint_flags
struct CurveMapping * curve_size
struct CurveMapping * curve_strength
int grid_size
Definition BKE_ccg.hh:33
int grid_area
Definition BKE_ccg.hh:35
char name[258]
Definition DNA_ID.h:432
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
PaintRuntimeHandle * runtime
struct ViewRender * view_render
float viewinv[4][4]
struct bToolRef * tool
ScrArea_Runtime runtime
blender::Array< int > fake_neighbor_index
Definition BKE_paint.hh:349
blender::float3 follow_co
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:417
BMLog * bm_log
Definition BKE_paint.hh:392
std::optional< int > active_grid_index
Definition BKE_paint.hh:423
RegionView3D * rv3d
Definition BKE_paint.hh:436
blender::ed::sculpt_paint::filter::Cache * filter_cache
Definition BKE_paint.hh:418
std::optional< int > active_face_index
Definition BKE_paint.hh:422
KeyBlock * shapekey_active
Definition BKE_paint.hh:377
blender::float3 cursor_normal
Definition BKE_paint.hh:431
SculptVertexInfo vertex_info
Definition BKE_paint.hh:462
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:395
blender::float3 cursor_view_normal
Definition BKE_paint.hh:433
float cursor_radius
Definition BKE_paint.hh:429
ActiveVert active_vert() const
Definition paint.cc:2367
blender::float3 cursor_location
Definition BKE_paint.hh:430
blender::float3 active_vert_position(const Depsgraph &depsgraph, const Object &object) const
Definition paint.cc:2403
ImagePool * tex_pool
Definition BKE_paint.hh:415
struct SculptSession::@300305335361021334214041350300054316061376210174 multires
std::unique_ptr< SculptTopologyIslandCache > topology_island_cache
Definition BKE_paint.hh:517
View3D * v3d
Definition BKE_paint.hh:437
std::optional< blender::float3 > cursor_sampled_normal
Definition BKE_paint.hh:432
blender::Array< blender::float3x3, 0 > deform_imats
Definition BKE_paint.hh:405
MultiresModifierData * modifier
Definition BKE_paint.hh:373
SculptFakeNeighbors fake_neighbors
Definition BKE_paint.hh:463
bool deform_modifiers_active
Definition BKE_paint.hh:401
void set_active_vert(ActiveVert vert)
Definition paint.cc:2437
void clear_active_elements(bool persist_last_active)
Definition paint.cc:2422
blender::Array< uint8_t > vert_island_ids
Definition BKE_paint.hh:357
blender::BitVector boundary
Definition BKE_paint.hh:334
struct Object * gravity_object
float detail_percent
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
View3DShading shading
RegionView3D * rv3d
Definition ED_view3d.hh:80
ARegion * region
Definition ED_view3d.hh:77
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
blender::float2 anchored_initial_mouse
blender::float3 average_stroke_accum
static NearestVertData join(const NearestVertData &a, const NearestVertData &b)
Definition sculpt.cc:5824
static std::optional< ShapeKeyData > from_object(Object &object)
Definition sculpt.cc:7416
std::optional< math::Quaternion > rake_rotation
struct blender::ed::sculpt_paint::StrokeCache::@216032235377206062040134367360200004271263147147 paint_brush
struct blender::ed::sculpt_paint::StrokeCache::@177302106234056170131152043023217207016132071266 clay_thumb_brush
std::unique_ptr< auto_mask::Cache > automasking
struct blender::ed::sculpt_paint::StrokeCache::@341056124057116163146344066210332230262122242125 plane_brush
struct blender::ed::sculpt_paint::StrokeCache::@120056277040371114166010206352311170205127263324 mirror_modifier_clip
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:757
int mval[2]
Definition WM_types.hh:763
const char * name
Definition WM_types.hh:1033
wmOperatorStatus(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1081
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:4238
wmOperatorType * ot
Definition wm_files.cc:4237
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
bScreen * WM_window_get_active_screen(const wmWindow *win)
uint8_t flag
Definition wm_window.cc:145