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