Blender V4.3
sculpt_undo.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
30#include "sculpt_undo.hh"
31
32#include <mutex>
33
34#include "MEM_guardedalloc.h"
35
36#include "BLI_array.hh"
39#include "BLI_listbase.h"
40#include "BLI_map.hh"
41#include "BLI_string.h"
42#include "BLI_utildefines.h"
43#include "BLI_vector.hh"
44
45#include "DNA_key_types.h"
46#include "DNA_object_types.h"
47#include "DNA_scene_types.h"
48#include "DNA_screen_types.h"
49
50#include "BKE_attribute.hh"
51#include "BKE_ccg.hh"
52#include "BKE_context.hh"
53#include "BKE_customdata.hh"
54#include "BKE_global.hh"
55#include "BKE_key.hh"
56#include "BKE_layer.hh"
57#include "BKE_main.hh"
58#include "BKE_mesh.hh"
59#include "BKE_multires.hh"
60#include "BKE_object.hh"
61#include "BKE_paint.hh"
62#include "BKE_scene.hh"
63#include "BKE_subdiv_ccg.hh"
64#include "BKE_subsurf.hh"
65#include "BKE_undo_system.hh"
66
67/* TODO(sergey): Ideally should be no direct call to such low level things. */
68#include "BKE_subdiv_eval.hh"
69
70#include "DEG_depsgraph.hh"
71
72#include "WM_api.hh"
73#include "WM_types.hh"
74
75#include "ED_geometry.hh"
76#include "ED_object.hh"
77#include "ED_sculpt.hh"
78#include "ED_undo.hh"
79
80#include "bmesh.hh"
81#include "mesh_brush_common.hh"
82#include "paint_hide.hh"
83#include "paint_intern.hh"
84#include "sculpt_automask.hh"
85#include "sculpt_color.hh"
86#include "sculpt_dyntopo.hh"
87#include "sculpt_face_set.hh"
88#include "sculpt_intern.hh"
89
91
92/* Implementation of undo system for objects in sculpt mode.
93 *
94 * Each undo step in sculpt mode consists of list of nodes, each node contains a flat array of data
95 * related to the step type.
96 *
97 * Node type used for undo depends on specific operation and active sculpt mode ("regular" or
98 * dynamic topology).
99 *
100 * Regular sculpt brushes will use Position, HideVert, HideFace, Mask, Face Set * nodes. These
101 * nodes are created for every BVH node which is affected by the brush. The undo push for the node
102 * happens BEFORE modifications. This makes the operation undo to work in the following way: for
103 * every node in the undo step swap happens between node in the undo stack and the corresponding
104 * value in the BVH. This is how redo is possible after undo.
105 *
106 * The COORDS, HIDDEN or MASK type of nodes contains arrays of the corresponding values.
107 *
108 * Operations like Symmetrize are using GEOMETRY type of nodes which pushes the entire state of the
109 * mesh to the undo stack. This node contains all CustomData layers.
110 *
111 * The tricky aspect of this undo node type is that it stores mesh before and after modification.
112 * This allows the undo system to both undo and redo the symmetrize operation within the
113 * pre-modified-push of other node type behavior, but it uses more memory that it seems it should
114 * be.
115 *
116 * The dynamic topology undo nodes are handled somewhat separately from all other ones and the idea
117 * there is to store log of operations: which vertices and faces have been added or removed.
118 *
119 * Begin of dynamic topology sculpting mode have own node type. It contains an entire copy of mesh
120 * since just enabling the dynamic topology mode already does modifications on it.
121 *
122 * End of dynamic topology and symmetrize in this mode are handled in a special manner as well. */
123
124#define NO_ACTIVE_LAYER bke::AttrDomain::Auto
125
159
166
167/* Storage of geometry for the undo node.
168 * Is used as a storage for either original or modified geometry. */
170 /* Is used for sanity check, helping with ensuring that two and only two
171 * geometry pushes happened in the undo stack. */
173
184};
185
186struct Node;
187
188struct StepData {
194
196 std::string object_name;
197
200
201 /* The number of vertices in the entire mesh. */
203 /* The number of face corners in the entire mesh. */
205
210
213
214 /* Geometry modification operations.
215 *
216 * Original geometry is stored before some modification is run and is used to restore state of
217 * the object when undoing the operation
218 *
219 * Modified geometry is stored after the modification and is used to redo the modification. */
223
224 /* bmesh */
226
227 /* Geometry at the bmesh enter moment. */
229
231
232 std::mutex nodes_mutex;
233
244
247
248 size_t undo_size;
249};
250
253 /* NOTE: will split out into list for multi-object-sculpt-mode. */
255
256 /* Active color attribute at the start of this undo step. */
258
259 /* Active color attribute at the end of this undo step. */
261};
262
264{
265 UndoStack *ustack = ED_undo_stack_get();
267 return reinterpret_cast<SculptUndoStep *>(us);
268}
269
271{
272 if (SculptUndoStep *us = get_active_step()) {
273 return &us->data;
274 }
275 return nullptr;
276}
277
278static bool use_multires_undo(const StepData &step_data, const SculptSession &ss)
279{
280 return step_data.mesh_grids_num != 0 && ss.subdiv_ccg != nullptr;
281}
282
283static bool topology_matches(const StepData &step_data, const Object &object)
284{
285 const SculptSession &ss = *object.sculpt;
286 if (use_multires_undo(step_data, ss)) {
287 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
288 return subdiv_ccg.grids_num == step_data.mesh_grids_num &&
289 subdiv_ccg.grid_size == step_data.grid_size;
290 }
291 Mesh &mesh = *static_cast<Mesh *>(object.data);
292 return mesh.verts_num == step_data.mesh_verts_num;
293}
294
295static bool indices_contain_true(const Span<bool> data, const Span<int> indices)
296{
297 return std::any_of(indices.begin(), indices.end(), [&](const int i) { return data[i]; });
298}
299
301 Depsgraph &depsgraph,
302 const StepData &step_data,
303 Object &object)
304{
305 SculptSession &ss = *object.sculpt;
306 if (ss.shapekey_active && ss.shapekey_active->name != step_data.active_shape_key_name) {
307 /* Shape key has been changed before calling undo operator. */
308
309 Key *key = BKE_key_from_object(&object);
310 KeyBlock *kb = key ? BKE_keyblock_find_name(key, step_data.active_shape_key_name.c_str()) :
311 nullptr;
312
313 if (kb) {
314 object.shapenr = BLI_findindex(&key->block, kb) + 1;
315
318 }
319 else {
320 /* Key has been removed -- skip this undo node. */
321 return false;
322 }
323 }
324 return true;
325}
326
327static void update_shapekeys(const Object &ob, KeyBlock *kb, const Span<float3> new_positions)
328{
329 const Mesh &mesh = *static_cast<Mesh *>(ob.data);
330 const int kb_act_idx = ob.shapenr - 1;
331
332 /* For relative keys editing of base should update other keys. */
333 if (std::optional<Array<bool>> dependent = BKE_keyblock_get_dependent_keys(mesh.key, kb_act_idx))
334 {
335 float(*offsets)[3] = BKE_keyblock_convert_to_vertcos(&ob, kb);
336
337 /* Calculate key coord offsets (from previous location). */
338 for (int i = 0; i < mesh.verts_num; i++) {
339 sub_v3_v3v3(offsets[i], new_positions[i], offsets[i]);
340 }
341
342 int currkey_i;
343 /* Apply offsets on other keys. */
344 LISTBASE_FOREACH_INDEX (KeyBlock *, currkey, &mesh.key->block, currkey_i) {
345 if ((currkey != kb) && (*dependent)[currkey_i]) {
346 BKE_keyblock_update_from_offset(&ob, currkey, offsets);
347 }
348 }
349
350 MEM_freeN(offsets);
351 }
352
353 /* Apply new coords on active key block, no need to re-allocate kb->data here! */
355 &ob, kb, reinterpret_cast<const float(*)[3]>(new_positions.data()));
356}
357
358static void restore_position_mesh(const Depsgraph &depsgraph,
359 Object &object,
360 const Span<std::unique_ptr<Node>> unodes,
361 MutableSpan<bool> modified_verts)
362{
363 Mesh &mesh = *static_cast<Mesh *>(object.data);
364 const SculptSession &ss = *object.sculpt;
365
366 /* Ideally, we would use the #PositionDeformData::deform method to perform the reverse
367 * deformation based on the evaluated positions, however this causes odd behavior.
368 * For now, this is a modified version of older code that depends on an extra `orig_position`
369 * array stored inside the #Node to perform swaps correctly.
370 *
371 * See #128859 for more detail.
372 */
375 MutableSpan orig_positions = mesh.vert_positions_for_write();
376 if (ss.shapekey_active) {
377 threading::parallel_for(unodes.index_range(), 1, [&](const IndexRange range) {
378 for (const int node_i : range) {
379 Node &unode = *unodes[node_i];
380 const Span<int> verts = unode.vert_indices.as_span().take_front(unode.unique_verts_num);
381 for (const int i : verts.index_range()) {
382 std::swap(unode.position[i], eval_mut[verts[i]]);
383 }
384
385 modified_verts.fill_indices(verts, true);
386 }
387 });
388
389 float(*vertCos)[3] = BKE_keyblock_convert_to_vertcos(&object, ss.shapekey_active);
390 MutableSpan key_positions(reinterpret_cast<float3 *>(vertCos), ss.shapekey_active->totelem);
391
392 threading::parallel_for(unodes.index_range(), 1, [&](const IndexRange range) {
393 for (const int node_i : range) {
394 Node &unode = *unodes[node_i];
395 const Span<int> verts = unode.vert_indices.as_span().take_front(unode.unique_verts_num);
396 for (const int i : verts.index_range()) {
397 std::swap(unode.orig_position[i], key_positions[verts[i]]);
398 }
399 }
400 });
401
402 update_shapekeys(object, ss.shapekey_active, key_positions);
403
404 if (ss.shapekey_active == mesh.key->refkey) {
405 mesh.vert_positions_for_write().copy_from(key_positions);
406 }
407
408 MEM_freeN(vertCos);
409 }
410 else {
411 threading::parallel_for(unodes.index_range(), 1, [&](const IndexRange range) {
412 for (const int node_i : range) {
413 Node &unode = *unodes[node_i];
414 const Span<int> verts = unode.vert_indices.as_span().take_front(unode.unique_verts_num);
415 for (const int i : verts.index_range()) {
416 std::swap(unode.position[i], eval_mut[verts[i]]);
417 }
418
419 modified_verts.fill_indices(verts, true);
420 }
421 });
422
423 if (orig_positions.data() != eval_mut.data()) {
424 threading::parallel_for(unodes.index_range(), 1, [&](const IndexRange range) {
425 for (const int node_i : range) {
426 Node &unode = *unodes[node_i];
427 const Span<int> verts = unode.vert_indices.as_span().take_front(
428 unode.unique_verts_num);
429 for (const int i : verts.index_range()) {
430 std::swap(unode.orig_position[i], orig_positions[verts[i]]);
431 }
432 }
433 });
434 }
435 }
436 }
437 else {
438 PositionDeformData position_data(depsgraph, object);
439 threading::EnumerableThreadSpecific<Vector<float3>> all_tls;
440 threading::parallel_for(unodes.index_range(), 1, [&](const IndexRange range) {
441 Vector<float3> &translations = all_tls.local();
442 for (const int i : range) {
443 Node &unode = *unodes[i];
444 const Span<int> verts = unode.vert_indices.as_span().take_front(unode.unique_verts_num);
445 translations.resize(verts.size());
446 translations_from_new_positions(
447 unode.position.as_span().take_front(unode.unique_verts_num),
448 verts,
449 position_data.eval,
450 translations);
451
452 gather_data_mesh(position_data.eval,
453 verts,
454 unode.position.as_mutable_span().take_front(unode.unique_verts_num));
455
456 position_data.deform(translations, verts);
457
458 modified_verts.fill_indices(verts, true);
459 }
460 });
461 }
462}
463
465 const CCGKey &key,
466 Node &unode,
467 MutableSpan<bool> modified_grids)
468{
469 const Span<int> grids = unode.grids;
470 MutableSpan<float3> undo_position = unode.position;
471
472 for (const int i : grids.index_range()) {
473 MutableSpan data = positions.slice(bke::ccg::grid_range(key, grids[i]));
474 MutableSpan undo_data = undo_position.slice(bke::ccg::grid_range(key, i));
475 for (const int offset : data.index_range()) {
476 std::swap(data[offset], undo_data[offset]);
477 }
478 }
479
480 modified_grids.fill_indices(grids, true);
481}
482
484 Node &unode,
485 MutableSpan<bool> modified_vertices)
486{
487 Mesh &mesh = *static_cast<Mesh *>(object.data);
488 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
489 bke::SpanAttributeWriter<bool> hide_vert = attributes.lookup_or_add_for_write_span<bool>(
490 ".hide_vert", bke::AttrDomain::Point);
491 for (const int i : unode.vert_indices.index_range().take_front(unode.unique_verts_num)) {
492 const int vert = unode.vert_indices[i];
493 if (unode.vert_hidden[i].test() != hide_vert.span[vert]) {
494 unode.vert_hidden[i].set(!unode.vert_hidden[i].test());
495 hide_vert.span[vert] = !hide_vert.span[vert];
496 modified_vertices[vert] = true;
497 }
498 }
499 hide_vert.finish();
500}
501
503 Node &unode,
504 MutableSpan<bool> modified_grids)
505{
506 if (unode.grid_hidden.is_empty()) {
508 return;
509 }
510
511 BitGroupVector<> &grid_hidden = BKE_subdiv_ccg_grid_hidden_ensure(subdiv_ccg);
512 const Span<int> grids = unode.grids;
513 for (const int i : grids.index_range()) {
514 /* Swap the two bit spans. */
516 MutableBoundedBitSpan b = grid_hidden[grids[i]];
517 for (const int j : a.index_range()) {
518 const bool value_a = a[j];
519 const bool value_b = b[j];
520 a[j].set(value_b);
521 b[j].set(value_a);
522 }
523 }
524
525 modified_grids.fill_indices(grids, true);
526}
527
528static void restore_hidden_face(Object &object, Node &unode, MutableSpan<bool> modified_faces)
529{
530 Mesh &mesh = *static_cast<Mesh *>(object.data);
531 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
532 bke::SpanAttributeWriter hide_poly = attributes.lookup_or_add_for_write_span<bool>(
533 ".hide_poly", bke::AttrDomain::Face);
534
535 const Span<int> face_indices = unode.face_indices;
536
537 for (const int i : face_indices.index_range()) {
538 const int face = face_indices[i];
539 if (unode.face_hidden[i].test() != hide_poly.span[face]) {
540 unode.face_hidden[i].set(!unode.face_hidden[i].test());
541 hide_poly.span[face] = !hide_poly.span[face];
542 modified_faces[face] = true;
543 }
544 }
545 hide_poly.finish();
546}
547
548static void restore_color(Object &object, StepData &step_data, MutableSpan<bool> modified_vertices)
549{
550 Mesh &mesh = *static_cast<Mesh *>(object.data);
551 bke::GSpanAttributeWriter color_attribute = color::active_color_attribute_for_write(mesh);
552
553 for (std::unique_ptr<Node> &unode : step_data.nodes) {
554 if (color_attribute.domain == bke::AttrDomain::Point && !unode->col.is_empty()) {
555 color::swap_gathered_colors(
556 unode->vert_indices.as_span().take_front(unode->unique_verts_num),
557 color_attribute.span,
558 unode->col);
559 }
560 else if (color_attribute.domain == bke::AttrDomain::Corner && !unode->loop_col.is_empty()) {
561 color::swap_gathered_colors(unode->corner_indices, color_attribute.span, unode->loop_col);
562 }
563
564 modified_vertices.fill_indices(unode->vert_indices.as_span(), true);
565 }
566
567 color_attribute.finish();
568}
569
570static void restore_mask_mesh(Object &object, Node &unode, MutableSpan<bool> modified_vertices)
571{
572 Mesh *mesh = BKE_object_get_original_mesh(&object);
573
574 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
575 bke::SpanAttributeWriter<float> mask = attributes.lookup_or_add_for_write_span<float>(
576 ".sculpt_mask", bke::AttrDomain::Point);
577
578 const Span<int> index = unode.vert_indices.as_span().take_front(unode.unique_verts_num);
579
580 for (const int i : index.index_range()) {
581 const int vert = index[i];
582 if (mask.span[vert] != unode.mask[i]) {
583 std::swap(mask.span[vert], unode.mask[i]);
584 modified_vertices[vert] = true;
585 }
586 }
587
588 mask.finish();
589}
590
591static void restore_mask_grids(Object &object, Node &unode, MutableSpan<bool> modified_grids)
592{
593 SculptSession &ss = *object.sculpt;
594 SubdivCCG *subdiv_ccg = ss.subdiv_ccg;
595 MutableSpan<float> masks = subdiv_ccg->masks;
596
597 const CCGKey key = BKE_subdiv_ccg_key_top_level(*subdiv_ccg);
598
599 const Span<int> grids = unode.grids;
600 MutableSpan<float> undo_mask = unode.mask;
601
602 for (const int i : grids.index_range()) {
603 MutableSpan data = masks.slice(bke::ccg::grid_range(key, grids[i]));
604 MutableSpan undo_data = undo_mask.slice(bke::ccg::grid_range(key, i));
605 for (const int offset : data.index_range()) {
606 std::swap(data[offset], undo_data[offset]);
607 }
608 }
609
610 modified_grids.fill_indices(unode.grids.as_span(), true);
611}
612
613static bool restore_face_sets(Object &object,
614 Node &unode,
615 MutableSpan<bool> modified_face_set_faces)
616{
617 const Span<int> face_indices = unode.face_indices;
618
619 bke::SpanAttributeWriter<int> face_sets = face_set::ensure_face_sets_mesh(
620 *static_cast<Mesh *>(object.data));
621 bool modified = false;
622 for (const int i : face_indices.index_range()) {
623 const int face = face_indices[i];
624 if (unode.face_sets[i] == face_sets.span[face]) {
625 continue;
626 }
627 std::swap(unode.face_sets[i], face_sets.span[face]);
628 modified_face_set_faces[face] = true;
629 modified = true;
630 }
631 face_sets.finish();
632 return modified;
633}
634
635static void bmesh_restore_generic(StepData &step_data, Object &object, SculptSession &ss)
636{
637 if (step_data.applied) {
638 BM_log_undo(ss.bm, ss.bm_log);
639 step_data.applied = false;
640 }
641 else {
642 BM_log_redo(ss.bm, ss.bm_log);
643 step_data.applied = true;
644 }
645
646 if (step_data.type == Type::Mask) {
647 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
648 IndexMaskMemory memory;
649 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
650 pbvh.tag_masks_changed(node_mask);
651 }
652 else {
656 }
657}
658
659/* Create empty sculpt BMesh and enable logging. */
660static void bmesh_enable(Object &object, StepData &step_data)
661{
662 SculptSession &ss = *object.sculpt;
663 Mesh *mesh = static_cast<Mesh *>(object.data);
664
667
668 /* Create empty BMesh and enable logging. */
669 BMeshCreateParams bmesh_create_params{};
670 bmesh_create_params.use_toolflags = false;
671
672 ss.bm = BM_mesh_create(&bm_mesh_allocsize_default, &bmesh_create_params);
673 BM_data_layer_add_named(ss.bm, &ss.bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
674
675 mesh->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
676
677 /* Restore the BMLog using saved entries. */
679}
680
682 StepData &step_data,
683 Object &object,
684 SculptSession &ss)
685{
686 if (step_data.applied) {
687 dyntopo::disable(C, &step_data);
688 step_data.applied = false;
689 }
690 else {
691 bmesh_enable(object, step_data);
692
693 /* Restore the mesh from the first log entry. */
694 BM_log_redo(ss.bm, ss.bm_log);
695
696 step_data.applied = true;
697 }
698}
699
700static void bmesh_restore_end(bContext *C, StepData &step_data, Object &object, SculptSession &ss)
701{
702 if (step_data.applied) {
703 bmesh_enable(object, step_data);
704
705 /* Restore the mesh from the last log entry. */
706 BM_log_undo(ss.bm, ss.bm_log);
707
708 step_data.applied = false;
709 }
710 else {
711 /* Disable dynamic topology sculpting. */
712 dyntopo::disable(C, nullptr);
713 step_data.applied = true;
714 }
715}
716
717static void store_geometry_data(NodeGeometry *geometry, const Object &object)
718{
719 const Mesh *mesh = static_cast<const Mesh *>(object.data);
720
721 BLI_assert(!geometry->is_initialized);
722 geometry->is_initialized = true;
723
725 &mesh->vert_data, &geometry->vert_data, CD_MASK_MESH.vmask, mesh->verts_num);
727 &mesh->edge_data, &geometry->edge_data, CD_MASK_MESH.emask, mesh->edges_num);
729 &mesh->corner_data, &geometry->corner_data, CD_MASK_MESH.lmask, mesh->corners_num);
731 &mesh->face_data, &geometry->face_data, CD_MASK_MESH.pmask, mesh->faces_num);
732 implicit_sharing::copy_shared_pointer(mesh->face_offset_indices,
733 mesh->runtime->face_offsets_sharing_info,
734 &geometry->face_offset_indices,
735 &geometry->face_offsets_sharing_info);
736
737 geometry->totvert = mesh->verts_num;
738 geometry->totedge = mesh->edges_num;
739 geometry->totloop = mesh->corners_num;
740 geometry->faces_num = mesh->faces_num;
741}
742
743static void restore_geometry_data(const NodeGeometry *geometry, Mesh *mesh)
744{
745 BLI_assert(geometry->is_initialized);
746
748
749 mesh->verts_num = geometry->totvert;
750 mesh->edges_num = geometry->totedge;
751 mesh->corners_num = geometry->totloop;
752 mesh->faces_num = geometry->faces_num;
753 mesh->totface_legacy = 0;
754
756 &geometry->vert_data, &mesh->vert_data, CD_MASK_MESH.vmask, geometry->totvert);
758 &geometry->edge_data, &mesh->edge_data, CD_MASK_MESH.emask, geometry->totedge);
760 &geometry->corner_data, &mesh->corner_data, CD_MASK_MESH.lmask, geometry->totloop);
762 &geometry->face_data, &mesh->face_data, CD_MASK_MESH.pmask, geometry->faces_num);
763 implicit_sharing::copy_shared_pointer(geometry->face_offset_indices,
764 geometry->face_offsets_sharing_info,
765 &mesh->face_offset_indices,
766 &mesh->runtime->face_offsets_sharing_info);
767}
768
769static void geometry_free_data(NodeGeometry *geometry)
770{
771 CustomData_free(&geometry->vert_data, geometry->totvert);
772 CustomData_free(&geometry->edge_data, geometry->totedge);
773 CustomData_free(&geometry->corner_data, geometry->totloop);
774 CustomData_free(&geometry->face_data, geometry->faces_num);
775 implicit_sharing::free_shared_data(&geometry->face_offset_indices,
776 &geometry->face_offsets_sharing_info);
777}
778
779static void restore_geometry(StepData &step_data, Object &object)
780{
781 if (step_data.geometry_clear_pbvh) {
784 }
785
786 Mesh *mesh = static_cast<Mesh *>(object.data);
787
788 if (step_data.applied) {
790 step_data.applied = false;
791 }
792 else {
794 step_data.applied = true;
795 }
796}
797
798/* Handle all dynamic-topology updates
799 *
800 * Returns true if this was a dynamic-topology undo step, otherwise
801 * returns false to indicate the non-dyntopo code should run. */
802static int bmesh_restore(
803 bContext *C, Depsgraph &depsgraph, StepData &step_data, Object &object, SculptSession &ss)
804{
805 switch (step_data.type) {
806 case Type::DyntopoBegin:
808 bmesh_restore_begin(C, step_data, object, ss);
809 return true;
810
811 case Type::DyntopoEnd:
813 bmesh_restore_end(C, step_data, object, ss);
814 return true;
815 default:
816 if (ss.bm_log) {
818 bmesh_restore_generic(step_data, object, ss);
819 return true;
820 }
821 break;
822 }
823
824 return false;
825}
826
828{
830}
831
836
837/* Geometry updates (such as Apply Base, for example) will re-evaluate the object and refine its
838 * Subdiv descriptor. Upon undo it is required that mesh, grids, and subdiv all stay consistent
839 * with each other. This means that when geometry coordinate changes the undo should refine the
840 * subdiv to the new coarse mesh coordinates. Tricky part is: this needs to happen without using
841 * dependency graph tag: tagging object for geometry update will either loose sculpted data from
842 * the sculpt grids, or will wrongly "commit" them to the CD_MDISPS.
843 *
844 * So what we do instead is do minimum object evaluation to get base mesh coordinates for the
845 * multires modifier input. While this is expensive, it is less expensive than dependency graph
846 * evaluation and is only happening when geometry coordinates changes on undo.
847 *
848 * Note that the dependency graph is ensured to be evaluated prior to the undo step is decoded,
849 * so if the object's modifier stack references other object it is all fine. */
850static void refine_subdiv(Depsgraph *depsgraph,
851 SculptSession &ss,
852 Object &object,
853 bke::subdiv::Subdiv *subdiv)
854{
856 depsgraph, &object, ss.multires.modifier);
857
858 bke::subdiv::eval_refine_from_mesh(
859 subdiv, static_cast<const Mesh *>(object.data), deformed_verts);
860}
861
862static void restore_list(bContext *C, Depsgraph *depsgraph, StepData &step_data)
863{
864 Scene *scene = CTX_data_scene(C);
865 ViewLayer *view_layer = CTX_data_view_layer(C);
867 BKE_view_layer_synced_ensure(scene, view_layer);
868 Object &object = *BKE_view_layer_active_object_get(view_layer);
869 if (step_data.object_name != object.id.name) {
870 return;
871 }
872 SculptSession &ss = *object.sculpt;
873 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
874
875 /* Restore pivot. */
876 ss.pivot_pos = step_data.pivot_pos;
877 ss.pivot_rot = step_data.pivot_rot;
878
879 if (bmesh_restore(C, *depsgraph, step_data, object, ss)) {
880 return;
881 }
882
883 /* Switching to sculpt mode does not push a particular type.
884 * See #124484. */
885 if (step_data.type == Type::None && step_data.nodes.is_empty()) {
886 return;
887 }
888
889 const bool tag_update = ID_REAL_USERS(object.data) > 1 ||
890 !BKE_sculptsession_use_pbvh_draw(&object, rv3d) || ss.shapekey_active ||
892
893 switch (step_data.type) {
894 case Type::None: {
896 break;
897 }
898 case Type::Position: {
899 IndexMaskMemory memory;
900 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
901
903 if (!topology_matches(step_data, object)) {
904 return;
905 }
906
907 if (use_multires_undo(step_data, ss)) {
909 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
910 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
911
912 Array<bool> modified_grids(subdiv_ccg.grids_num, false);
913 for (std::unique_ptr<Node> &unode : step_data.nodes) {
914 restore_position_grids(subdiv_ccg.positions, key, *unode, modified_grids);
915 }
916 const IndexMask changed_nodes = IndexMask::from_predicate(
917 node_mask, GrainSize(1), memory, [&](const int i) {
918 return indices_contain_true(modified_grids, nodes[i].grids());
919 });
920 pbvh.tag_positions_changed(changed_nodes);
922 }
923 else {
925 if (!restore_active_shape_key(*C, *depsgraph, step_data, object)) {
926 return;
927 }
928 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
929 Array<bool> modified_verts(mesh.verts_num, false);
930 restore_position_mesh(*depsgraph, object, step_data.nodes, modified_verts);
931
932 const IndexMask changed_nodes = IndexMask::from_predicate(
933 node_mask, GrainSize(1), memory, [&](const int i) {
934 return indices_contain_true(modified_verts, nodes[i].all_verts());
935 });
936 pbvh.tag_positions_changed(changed_nodes);
937 }
938
939 if (tag_update) {
940 Mesh &mesh = *static_cast<Mesh *>(object.data);
941 mesh.tag_positions_changed();
943 }
944 else {
945 Mesh &mesh = *static_cast<Mesh *>(object.data);
946 /* The BVH normals recalculation that will happen later (caused by
947 * `pbvh.tag_positions_changed`) won't recalculate the face corner normals.
948 * We need to manually clear that cache. */
949 mesh.runtime->corner_normals_cache.tag_dirty();
950 }
951 bke::pbvh::update_bounds(*depsgraph, object, pbvh);
952 bke::pbvh::store_bounds_orig(pbvh);
953 break;
954 }
955 case Type::HideVert: {
956 IndexMaskMemory memory;
957 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
958
960 if (!topology_matches(step_data, object)) {
961 return;
962 }
963
964 if (use_multires_undo(step_data, ss)) {
966 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
967 Array<bool> modified_grids(subdiv_ccg.grids_num, false);
968 for (std::unique_ptr<Node> &unode : step_data.nodes) {
969 restore_vert_visibility_grids(subdiv_ccg, *unode, modified_grids);
970 }
971 const IndexMask changed_nodes = IndexMask::from_predicate(
972 node_mask, GrainSize(1), memory, [&](const int i) {
973 return indices_contain_true(modified_grids, nodes[i].grids());
974 });
975 pbvh.tag_visibility_changed(changed_nodes);
976 }
977 else {
979 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
980 Array<bool> modified_verts(mesh.verts_num, false);
981 for (std::unique_ptr<Node> &unode : step_data.nodes) {
982 restore_vert_visibility_mesh(object, *unode, modified_verts);
983 }
984 const IndexMask changed_nodes = IndexMask::from_predicate(
985 node_mask, GrainSize(1), memory, [&](const int i) {
986 return indices_contain_true(modified_verts, nodes[i].all_verts());
987 });
988 pbvh.tag_visibility_changed(changed_nodes);
989 }
990
992 bke::pbvh::update_visibility(object, pbvh);
993 if (BKE_sculpt_multires_active(scene, &object)) {
995 }
996 break;
997 }
998 case Type::HideFace: {
999 IndexMaskMemory memory;
1000 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1001
1003 if (!topology_matches(step_data, object)) {
1004 return;
1005 }
1006
1007 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
1008 Array<bool> modified_faces(mesh.faces_num, false);
1009 for (std::unique_ptr<Node> &unode : step_data.nodes) {
1010 restore_hidden_face(object, *unode, modified_faces);
1011 }
1012
1013 if (use_multires_undo(step_data, ss)) {
1015 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1016 const IndexMask changed_nodes = IndexMask::from_predicate(
1017 node_mask, GrainSize(1), memory, [&](const int i) {
1018 Vector<int> faces_vector;
1019 const Span<int> faces = bke::pbvh::node_face_indices_calc_grids(
1020 subdiv_ccg, nodes[i], faces_vector);
1021 return indices_contain_true(modified_faces, faces);
1022 });
1023 pbvh.tag_visibility_changed(changed_nodes);
1024 }
1025 else {
1027 const IndexMask changed_nodes = IndexMask::from_predicate(
1028 node_mask, GrainSize(1), memory, [&](const int i) {
1029 return indices_contain_true(modified_faces, nodes[i].faces());
1030 });
1031 pbvh.tag_visibility_changed(changed_nodes);
1032 }
1033
1034 hide::sync_all_from_faces(object);
1035 bke::pbvh::update_visibility(object, pbvh);
1036 break;
1037 }
1038 case Type::Mask: {
1039 IndexMaskMemory memory;
1040 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1041
1043 if (!topology_matches(step_data, object)) {
1044 return;
1045 }
1046
1047 if (use_multires_undo(step_data, ss)) {
1049 Array<bool> modified_grids(ss.subdiv_ccg->grids_num, false);
1050 for (std::unique_ptr<Node> &unode : step_data.nodes) {
1051 restore_mask_grids(object, *unode, modified_grids);
1052 }
1053 const IndexMask changed_nodes = IndexMask::from_predicate(
1054 node_mask, GrainSize(1), memory, [&](const int i) {
1055 return indices_contain_true(modified_grids, nodes[i].grids());
1056 });
1057 bke::pbvh::update_mask_grids(*ss.subdiv_ccg, changed_nodes, pbvh);
1058 pbvh.tag_masks_changed(changed_nodes);
1059 }
1060 else {
1062 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
1063 Array<bool> modified_verts(mesh.verts_num, false);
1064 for (std::unique_ptr<Node> &unode : step_data.nodes) {
1065 restore_mask_mesh(object, *unode, modified_verts);
1066 }
1067 const IndexMask changed_nodes = IndexMask::from_predicate(
1068 node_mask, GrainSize(1), memory, [&](const int i) {
1069 return indices_contain_true(modified_verts, nodes[i].all_verts());
1070 });
1071 bke::pbvh::update_mask_mesh(mesh, changed_nodes, pbvh);
1072 pbvh.tag_masks_changed(changed_nodes);
1073 }
1074 break;
1075 }
1076 case Type::FaceSet: {
1077 IndexMaskMemory memory;
1078 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1079
1081 if (!topology_matches(step_data, object)) {
1082 return;
1083 }
1084
1085 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
1086 Array<bool> modified_faces(mesh.faces_num, false);
1087 for (std::unique_ptr<Node> &unode : step_data.nodes) {
1088 restore_face_sets(object, *unode, modified_faces);
1089 }
1090 if (use_multires_undo(step_data, ss)) {
1092 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1093 const IndexMask changed_nodes = IndexMask::from_predicate(
1094 node_mask, GrainSize(1), memory, [&](const int i) {
1095 Vector<int> faces_vector;
1096 const Span<int> faces = bke::pbvh::node_face_indices_calc_grids(
1097 subdiv_ccg, nodes[i], faces_vector);
1098 return indices_contain_true(modified_faces, faces);
1099 });
1100 pbvh.tag_face_sets_changed(changed_nodes);
1101 }
1102 else {
1104 const IndexMask changed_nodes = IndexMask::from_predicate(
1105 node_mask, GrainSize(1), memory, [&](const int i) {
1106 return indices_contain_true(modified_faces, nodes[i].faces());
1107 });
1108 pbvh.tag_face_sets_changed(changed_nodes);
1109 }
1110 break;
1111 }
1112 case Type::Color: {
1113 IndexMaskMemory memory;
1114 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1115
1117 if (!topology_matches(step_data, object)) {
1118 return;
1119 }
1120
1122
1123 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
1124 Array<bool> modified_verts(mesh.verts_num, false);
1125 restore_color(object, step_data, modified_verts);
1126 const IndexMask changed_nodes = IndexMask::from_predicate(
1127 node_mask, GrainSize(1), memory, [&](const int i) {
1128 return indices_contain_true(modified_verts, nodes[i].all_verts());
1129 });
1130 pbvh.tag_attribute_changed(changed_nodes, mesh.active_color_attribute);
1131 break;
1132 }
1133 case Type::Geometry: {
1134 BLI_assert(!ss.bm);
1135
1136 restore_geometry(step_data, object);
1138 if (SubdivCCG *subdiv_ccg = ss.subdiv_ccg) {
1139 refine_subdiv(depsgraph, ss, object, subdiv_ccg->subdiv);
1140 }
1141 break;
1142 }
1143 case Type::DyntopoBegin:
1144 case Type::DyntopoEnd:
1145 /* Handled elsewhere. */
1147 break;
1148 }
1149
1151 if (tag_update) {
1153 }
1154}
1155
1156static void free_step_data(StepData &step_data)
1157{
1161 if (step_data.bm_entry) {
1162 BM_log_entry_drop(step_data.bm_entry);
1163 }
1164 step_data.~StepData();
1165}
1166
1173static const Node *get_node(const bke::pbvh::Node *node, const Type type)
1174{
1175 StepData *step_data = get_step_data();
1176 if (!step_data) {
1177 return nullptr;
1178 }
1179 if (step_data->type != type) {
1180 return nullptr;
1181 }
1182 /* This access does not need to be locked because this function is not expected to be called
1183 * while the per-node undo data is being pushed. In other words, this must not be called
1184 * concurrently with #push_node.*/
1185 std::unique_ptr<Node> *node_ptr = step_data->undo_nodes_by_pbvh_node.lookup_ptr(node);
1186 if (!node_ptr) {
1187 return nullptr;
1188 }
1189 return node_ptr->get();
1190}
1191
1192static void store_vert_visibility_grids(const SubdivCCG &subdiv_ccg,
1193 const bke::pbvh::GridsNode &node,
1194 Node &unode)
1195{
1196 const BitGroupVector<> grid_hidden = subdiv_ccg.grid_hidden;
1197 if (grid_hidden.is_empty()) {
1198 return;
1199 }
1200
1201 const Span<int> grid_indices = node.grids();
1202 unode.grid_hidden = BitGroupVector<0>(grid_indices.size(), grid_hidden.group_size());
1203 for (const int i : grid_indices.index_range()) {
1204 unode.grid_hidden[i].copy_from(grid_hidden[grid_indices[i]]);
1205 }
1206}
1207
1208static void store_positions_mesh(const Depsgraph &depsgraph, const Object &object, Node &unode)
1209{
1210 const SculptSession &ss = *object.sculpt;
1211 gather_data_mesh(bke::pbvh::vert_positions_eval(depsgraph, object),
1212 unode.vert_indices.as_span(),
1213 unode.position.as_mutable_span());
1214 gather_data_mesh(bke::pbvh::vert_normals_eval(depsgraph, object),
1215 unode.vert_indices.as_span(),
1216 unode.normal.as_mutable_span());
1217
1218 if (ss.deform_modifiers_active) {
1219 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
1220 const Span<float3> orig_positions = ss.shapekey_active ? Span(static_cast<const float3 *>(
1221 ss.shapekey_active->data),
1222 mesh.verts_num) :
1223 mesh.vert_positions();
1224
1226 orig_positions, unode.vert_indices.as_span(), unode.orig_position.as_mutable_span());
1227 }
1228}
1229
1230static void store_positions_grids(const SubdivCCG &subdiv_ccg, Node &unode)
1231{
1233 subdiv_ccg, subdiv_ccg.positions.as_span(), unode.grids, unode.position.as_mutable_span());
1235 subdiv_ccg, subdiv_ccg.normals.as_span(), unode.grids, unode.normal.as_mutable_span());
1236}
1237
1238static void store_vert_visibility_mesh(const Mesh &mesh, const bke::pbvh::Node &node, Node &unode)
1239{
1240 const bke::AttributeAccessor attributes = mesh.attributes();
1241 const VArraySpan<bool> hide_vert = *attributes.lookup<bool>(".hide_vert",
1242 bke::AttrDomain::Point);
1243 if (hide_vert.is_empty()) {
1244 return;
1245 }
1246
1247 const Span<int> verts = static_cast<const bke::pbvh::MeshNode &>(node).all_verts();
1248 for (const int i : verts.index_range()) {
1249 unode.vert_hidden[i].set(hide_vert[verts[i]]);
1250 }
1251}
1252
1253static void store_face_visibility(const Mesh &mesh, Node &unode)
1254{
1255 const bke::AttributeAccessor attributes = mesh.attributes();
1256 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
1257 if (hide_poly.is_empty()) {
1258 unode.face_hidden.fill(false);
1259 return;
1260 }
1261 const Span<int> faces = unode.face_indices;
1262 for (const int i : faces.index_range()) {
1263 unode.face_hidden[i].set(hide_poly[faces[i]]);
1264 }
1265}
1266
1267static void store_mask_mesh(const Mesh &mesh, Node &unode)
1268{
1269 const bke::AttributeAccessor attributes = mesh.attributes();
1270 const VArraySpan mask = *attributes.lookup<float>(".sculpt_mask", bke::AttrDomain::Point);
1271 if (mask.is_empty()) {
1272 unode.mask.fill(0.0f);
1273 }
1274 else {
1276 }
1277}
1278
1279static void store_mask_grids(const SubdivCCG &subdiv_ccg, Node &unode)
1280{
1281 if (!subdiv_ccg.masks.is_empty()) {
1283 subdiv_ccg, subdiv_ccg.masks.as_span(), unode.grids, unode.mask.as_mutable_span());
1284 }
1285 else {
1286 unode.mask.fill(0.0f);
1287 }
1288}
1289
1290static void store_color(const Mesh &mesh, const bke::pbvh::MeshNode &node, Node &unode)
1291{
1292 const OffsetIndices<int> faces = mesh.faces();
1293 const Span<int> corner_verts = mesh.corner_verts();
1294 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
1295 const bke::GAttributeReader color_attribute = color::active_color_attribute(mesh);
1296 const GVArraySpan colors(*color_attribute);
1297
1298 /* NOTE: even with loop colors we still store (derived)
1299 * vertex colors for original data lookup. */
1300 const Span<int> verts = node.verts();
1301 unode.col.reinitialize(verts.size());
1302 color::gather_colors_vert(
1303 faces, corner_verts, vert_to_face_map, colors, color_attribute.domain, verts, unode.col);
1304
1305 if (color_attribute.domain == bke::AttrDomain::Corner) {
1306 for (const int face : node.faces()) {
1307 for (const int corner : faces[face]) {
1308 unode.corner_indices.append(corner);
1309 }
1310 }
1311 unode.loop_col.reinitialize(unode.corner_indices.size());
1312 color::gather_colors(colors, unode.corner_indices, unode.loop_col);
1313 }
1314}
1315
1317{
1318 if (!step_data.geometry_original.is_initialized) {
1319 return &step_data.geometry_original;
1320 }
1321
1323
1324 return &step_data.geometry_modified;
1325}
1326
1327static void geometry_push(const Object &object)
1328{
1329 StepData *step_data = get_step_data();
1330
1331 step_data->type = Type::Geometry;
1332
1333 step_data->applied = false;
1334 step_data->geometry_clear_pbvh = true;
1335
1336 NodeGeometry *geometry = geometry_get(*step_data);
1337 store_geometry_data(geometry, object);
1338}
1339
1340static void store_face_sets(const Mesh &mesh, Node &unode)
1341{
1342 const bke::AttributeAccessor attributes = mesh.attributes();
1343 const VArraySpan face_sets = *attributes.lookup<int>(".sculpt_face_set", bke::AttrDomain::Face);
1344 if (face_sets.is_empty()) {
1345 unode.face_sets.fill(1);
1346 }
1347 else {
1348 gather_data_mesh(face_sets, unode.face_indices.as_span(), unode.face_sets.as_mutable_span());
1349 }
1350}
1351
1352static void fill_node_data_mesh(const Depsgraph &depsgraph,
1353 const Object &object,
1354 const bke::pbvh::MeshNode &node,
1355 const Type type,
1356 Node &unode)
1357{
1358 const SculptSession &ss = *object.sculpt;
1359 const Mesh &mesh = *static_cast<Mesh *>(object.data);
1360
1361 unode.vert_indices = node.all_verts();
1362 unode.unique_verts_num = node.verts().size();
1363
1364 const int verts_num = unode.vert_indices.size();
1365
1366 const bool need_faces = ELEM(type, Type::FaceSet, Type::HideFace);
1367 if (need_faces) {
1368 unode.face_indices = node.faces();
1369 }
1370
1371 switch (type) {
1372 case Type::None:
1374 break;
1375 case Type::Position: {
1376 unode.position.reinitialize(verts_num);
1377 /* Needed for original data lookup. */
1378 unode.normal.reinitialize(verts_num);
1379 if (ss.deform_modifiers_active) {
1380 unode.orig_position.reinitialize(verts_num);
1381 }
1382 store_positions_mesh(depsgraph, object, unode);
1383 break;
1384 }
1385 case Type::HideVert: {
1386 unode.vert_hidden.resize(unode.vert_indices.size());
1387 store_vert_visibility_mesh(mesh, node, unode);
1388 break;
1389 }
1390 case Type::HideFace: {
1391 unode.face_hidden.resize(unode.face_indices.size());
1392 store_face_visibility(mesh, unode);
1393 break;
1394 }
1395 case Type::Mask: {
1396 unode.mask.reinitialize(verts_num);
1397 store_mask_mesh(mesh, unode);
1398 break;
1399 }
1400 case Type::Color: {
1401 store_color(mesh, node, unode);
1402 break;
1403 }
1404 case Type::DyntopoBegin:
1405 case Type::DyntopoEnd:
1406 /* Dyntopo should be handled elsewhere. */
1408 break;
1409 case Type::Geometry:
1410 /* See #geometry_push. */
1412 break;
1413 case Type::FaceSet: {
1414 unode.face_sets.reinitialize(unode.face_indices.size());
1415 store_face_sets(mesh, unode);
1416 break;
1417 }
1418 }
1419}
1420
1421static void fill_node_data_grids(const Object &object,
1422 const bke::pbvh::GridsNode &node,
1423 const Type type,
1424 Node &unode)
1425{
1426 const SculptSession &ss = *object.sculpt;
1427 const Mesh &base_mesh = *static_cast<const Mesh *>(object.data);
1428 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1429
1430 unode.grids = node.grids();
1431
1432 const int grid_area = subdiv_ccg.grid_size * subdiv_ccg.grid_size;
1433 const int verts_num = unode.grids.size() * grid_area;
1434
1435 const bool need_faces = ELEM(type, Type::FaceSet, Type::HideFace);
1436 if (need_faces) {
1437 bke::pbvh::node_face_indices_calc_grids(subdiv_ccg, node, unode.face_indices);
1438 }
1439
1440 switch (type) {
1441 case Type::None:
1443 break;
1444 case Type::Position: {
1445 unode.position.reinitialize(verts_num);
1446 /* Needed for original data lookup. */
1447 unode.normal.reinitialize(verts_num);
1448 store_positions_grids(subdiv_ccg, unode);
1449 break;
1450 }
1451 case Type::HideVert: {
1452 store_vert_visibility_grids(subdiv_ccg, node, unode);
1453 break;
1454 }
1455 case Type::HideFace: {
1456 unode.face_hidden.resize(unode.face_indices.size());
1457 store_face_visibility(base_mesh, unode);
1458 break;
1459 }
1460 case Type::Mask: {
1461 unode.mask.reinitialize(verts_num);
1462 store_mask_grids(subdiv_ccg, unode);
1463 break;
1464 }
1465 case Type::Color: {
1467 break;
1468 }
1469 case Type::DyntopoBegin:
1470 case Type::DyntopoEnd:
1471 /* Dyntopo should be handled elsewhere. */
1473 break;
1474 case Type::Geometry:
1475 /* See #geometry_push. */
1477 break;
1478 case Type::FaceSet: {
1479 unode.face_sets.reinitialize(unode.face_indices.size());
1480 store_face_sets(base_mesh, unode);
1481 break;
1482 }
1483 }
1484}
1485
1490BLI_NOINLINE static void bmesh_push(const Object &object,
1491 const bke::pbvh::BMeshNode *node,
1492 Type type)
1493{
1494 StepData *step_data = get_step_data();
1495 const SculptSession &ss = *object.sculpt;
1496
1497 std::scoped_lock lock(step_data->nodes_mutex);
1498
1499 Node *unode = step_data->nodes.is_empty() ? nullptr : step_data->nodes.first().get();
1500
1501 if (unode == nullptr) {
1502 step_data->nodes.append(std::make_unique<Node>());
1503 unode = step_data->nodes.last().get();
1504
1505 step_data->type = type;
1506 step_data->applied = true;
1507
1508 if (type == Type::DyntopoEnd) {
1509 step_data->bm_entry = BM_log_entry_add(ss.bm_log);
1511 }
1512 else if (type == Type::DyntopoBegin) {
1513 /* Store a copy of the mesh's current vertices, loops, and
1514 * faces. A full copy like this is needed because entering
1515 * dynamic-topology immediately does topological edits
1516 * (converting faces to triangles) that the BMLog can't
1517 * fully restore from. */
1518 NodeGeometry *geometry = &step_data->geometry_bmesh_enter;
1519 store_geometry_data(geometry, object);
1520
1521 step_data->bm_entry = BM_log_entry_add(ss.bm_log);
1522 BM_log_all_added(ss.bm, ss.bm_log);
1523 }
1524 else {
1525 step_data->bm_entry = BM_log_entry_add(ss.bm_log);
1526 }
1527 }
1528
1529 if (node) {
1530 const int cd_vert_mask_offset = CustomData_get_offset_named(
1531 &ss.bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
1532
1533 /* The vertices and node aren't changed, though pointers to them are stored in the log. */
1534 bke::pbvh::BMeshNode *node_mut = const_cast<bke::pbvh::BMeshNode *>(node);
1535
1536 switch (type) {
1537 case Type::None:
1539 break;
1540 case Type::Position:
1541 case Type::Mask:
1542 /* Before any vertex values get modified, ensure their
1543 * original positions are logged. */
1544 for (BMVert *vert : BKE_pbvh_bmesh_node_unique_verts(node_mut)) {
1545 BM_log_vert_before_modified(ss.bm_log, vert, cd_vert_mask_offset);
1546 }
1547 for (BMVert *vert : BKE_pbvh_bmesh_node_other_verts(node_mut)) {
1548 BM_log_vert_before_modified(ss.bm_log, vert, cd_vert_mask_offset);
1549 }
1550 break;
1551
1552 case Type::HideFace:
1553 case Type::HideVert: {
1554 for (BMVert *vert : BKE_pbvh_bmesh_node_unique_verts(node_mut)) {
1555 BM_log_vert_before_modified(ss.bm_log, vert, cd_vert_mask_offset);
1556 }
1557 for (BMVert *vert : BKE_pbvh_bmesh_node_other_verts(node_mut)) {
1558 BM_log_vert_before_modified(ss.bm_log, vert, cd_vert_mask_offset);
1559 }
1560
1561 for (BMFace *f : BKE_pbvh_bmesh_node_faces(node_mut)) {
1563 }
1564 break;
1565 }
1566
1567 case Type::DyntopoBegin:
1568 case Type::DyntopoEnd:
1569 case Type::Geometry:
1570 case Type::FaceSet:
1571 case Type::Color:
1572 break;
1573 }
1574 }
1575}
1576
1581static Node *ensure_node(StepData &step_data, const bke::pbvh::Node &node, bool &r_new)
1582{
1583 std::scoped_lock lock(step_data.nodes_mutex);
1584 r_new = false;
1585 std::unique_ptr<Node> &unode = step_data.undo_nodes_by_pbvh_node.lookup_or_add_cb(&node, [&]() {
1586 std::unique_ptr<Node> unode = std::make_unique<Node>();
1587 r_new = true;
1588 return unode;
1589 });
1590 return unode.get();
1591}
1592
1593void push_node(const Depsgraph &depsgraph,
1594 const Object &object,
1595 const bke::pbvh::Node *node,
1596 Type type)
1597{
1598 SculptSession &ss = *object.sculpt;
1599 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1600 if (ss.bm || ELEM(type, Type::DyntopoBegin, Type::DyntopoEnd)) {
1601 bmesh_push(object, static_cast<const bke::pbvh::BMeshNode *>(node), type);
1602 return;
1603 }
1604
1605 StepData *step_data = get_step_data();
1606 BLI_assert(ELEM(step_data->type, Type::None, type));
1607 step_data->type = type;
1608
1609 bool newly_added;
1610 Node *unode = ensure_node(*step_data, *node, newly_added);
1611 if (!newly_added) {
1612 /* The node was already filled with data for this undo step. */
1613 return;
1614 }
1615
1616 ss.needs_flush_to_id = 1;
1617
1618 switch (pbvh.type()) {
1619 case bke::pbvh::Type::Mesh:
1621 depsgraph, object, static_cast<const bke::pbvh::MeshNode &>(*node), type, *unode);
1622 break;
1623 case bke::pbvh::Type::Grids:
1624 fill_node_data_grids(object, static_cast<const bke::pbvh::GridsNode &>(*node), type, *unode);
1625 break;
1626 case bke::pbvh::Type::BMesh:
1628 break;
1629 }
1630}
1631
1632void push_nodes(const Depsgraph &depsgraph,
1633 Object &object,
1634 const IndexMask &node_mask,
1635 const Type type)
1636{
1637 SculptSession &ss = *object.sculpt;
1638
1639 ss.needs_flush_to_id = 1;
1640
1641 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1642 if (ss.bm || ELEM(type, Type::DyntopoBegin, Type::DyntopoEnd)) {
1644 node_mask.foreach_index([&](const int i) { bmesh_push(object, &nodes[i], type); });
1645 return;
1646 }
1647
1648 StepData *step_data = get_step_data();
1649 BLI_assert(ELEM(step_data->type, Type::None, type));
1650 step_data->type = type;
1651
1652 switch (pbvh.type()) {
1653 case bke::pbvh::Type::Mesh: {
1656 node_mask.foreach_index([&](const int i) {
1657 bool newly_added;
1658 Node *unode = ensure_node(*step_data, nodes[i], newly_added);
1659 if (newly_added) {
1660 nodes_to_fill.append({&nodes[i], unode});
1661 }
1662 });
1663 threading::parallel_for(nodes_to_fill.index_range(), 1, [&](const IndexRange range) {
1664 for (const auto &[node, unode] : nodes_to_fill.as_span().slice(range)) {
1665 fill_node_data_mesh(depsgraph, object, *node, type, *unode);
1666 }
1667 });
1668 break;
1669 }
1670 case bke::pbvh::Type::Grids: {
1673 node_mask.foreach_index([&](const int i) {
1674 bool newly_added;
1675 Node *unode = ensure_node(*step_data, nodes[i], newly_added);
1676 if (newly_added) {
1677 nodes_to_fill.append({&nodes[i], unode});
1678 }
1679 });
1680 threading::parallel_for(nodes_to_fill.index_range(), 1, [&](const IndexRange range) {
1681 for (const auto &[node, unode] : nodes_to_fill.as_span().slice(range)) {
1682 fill_node_data_grids(object, *node, type, *unode);
1683 }
1684 });
1685 break;
1686 }
1687 case bke::pbvh::Type::BMesh: {
1689 break;
1690 }
1691 }
1692}
1693
1694static void save_active_attribute(Object &object, SculptAttrRef *attr)
1695{
1696 Mesh *mesh = BKE_object_get_original_mesh(&object);
1697 attr->was_set = true;
1698 attr->domain = NO_ACTIVE_LAYER;
1699 attr->name[0] = 0;
1700 if (!mesh) {
1701 return;
1702 }
1703 const char *name = mesh->active_color_attribute;
1704 const bke::AttributeAccessor attributes = mesh->attributes();
1705 const std::optional<bke::AttributeMetaData> meta_data = attributes.lookup_meta_data(name);
1706 if (!meta_data) {
1707 return;
1708 }
1709 if (!(ATTR_DOMAIN_AS_MASK(meta_data->domain) & ATTR_DOMAIN_MASK_COLOR) ||
1710 !(CD_TYPE_AS_MASK(meta_data->data_type) & CD_MASK_COLOR_ALL))
1711 {
1712 return;
1713 }
1714 attr->domain = meta_data->domain;
1715 STRNCPY(attr->name, name);
1716 attr->type = meta_data->data_type;
1717}
1718
1719void push_begin_ex(const Scene & /*scene*/, Object &ob, const char *name)
1720{
1721 UndoStack *ustack = ED_undo_stack_get();
1722
1723 /* If possible, we need to tag the object and its geometry data as 'changed in the future' in
1724 * the previous undo step if it's a memfile one. */
1726 ED_undosys_stack_memfile_id_changed_tag(ustack, static_cast<ID *>(ob.data));
1727
1728 /* Special case, we never read from this. */
1729 bContext *C = nullptr;
1730
1732 ustack, C, name, BKE_UNDOSYS_TYPE_SCULPT);
1733 us->data.object_name = ob.id.name;
1734
1735 if (!us->active_color_start.was_set) {
1737 }
1738
1739 /* Set end attribute in case push_end is not called,
1740 * so we don't end up with corrupted state.
1741 */
1742 if (!us->active_color_end.was_set) {
1744 us->active_color_end.was_set = false;
1745 }
1746
1747 const SculptSession &ss = *ob.sculpt;
1748 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
1749
1750 switch (pbvh.type()) {
1751 case bke::pbvh::Type::Mesh: {
1752 const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
1753 us->data.mesh_verts_num = mesh.verts_num;
1754 us->data.mesh_corners_num = mesh.corners_num;
1755 break;
1756 }
1757 case bke::pbvh::Type::Grids: {
1760 break;
1761 }
1762 case bke::pbvh::Type::BMesh: {
1763 break;
1764 }
1765 }
1766
1767 /* Store sculpt pivot. */
1768 us->data.pivot_pos = ss.pivot_pos;
1769 us->data.pivot_rot = ss.pivot_rot;
1770
1771 if (const KeyBlock *key = BKE_keyblock_from_object(&ob)) {
1772 us->data.active_shape_key_name = key->name;
1773 }
1774}
1775
1776void push_begin(const Scene &scene, Object &ob, const wmOperator *op)
1777{
1778 push_begin_ex(scene, ob, op->type->name);
1779}
1780
1781static size_t node_size_in_bytes(const Node &node)
1782{
1783 size_t size = sizeof(Node);
1784 size += node.position.as_span().size_in_bytes();
1785 size += node.orig_position.as_span().size_in_bytes();
1786 size += node.normal.as_span().size_in_bytes();
1787 size += node.col.as_span().size_in_bytes();
1788 size += node.mask.as_span().size_in_bytes();
1789 size += node.loop_col.as_span().size_in_bytes();
1790 size += node.vert_indices.as_span().size_in_bytes();
1791 size += node.corner_indices.as_span().size_in_bytes();
1792 size += node.vert_hidden.size() / 8;
1793 size += node.face_hidden.size() / 8;
1794 size += node.grids.as_span().size_in_bytes();
1795 size += node.grid_hidden.all_bits().size() / 8;
1796 size += node.face_sets.as_span().size_in_bytes();
1797 size += node.face_indices.as_span().size_in_bytes();
1798 return size;
1799}
1800
1801void push_end_ex(Object &ob, const bool use_nested_undo)
1802{
1803 StepData *step_data = get_step_data();
1804
1805 /* Move undo node storage from map to vector. */
1806 step_data->nodes.reserve(step_data->undo_nodes_by_pbvh_node.size());
1807 for (std::unique_ptr<Node> &node : step_data->undo_nodes_by_pbvh_node.values()) {
1808 step_data->nodes.append(std::move(node));
1809 }
1810 step_data->undo_nodes_by_pbvh_node.clear_and_shrink();
1811
1812 /* We don't need normals in the undo stack. */
1813 for (std::unique_ptr<Node> &unode : step_data->nodes) {
1814 unode->normal = {};
1815 }
1816
1817 step_data->undo_size = threading::parallel_reduce(
1818 step_data->nodes.index_range(),
1819 16,
1820 0,
1821 [&](const IndexRange range, size_t size) {
1822 for (const int i : range) {
1823 size += node_size_in_bytes(*step_data->nodes[i]);
1824 }
1825 return size;
1826 },
1827 std::plus<size_t>());
1828
1829 /* We could remove this and enforce all callers run in an operator using 'OPTYPE_UNDO'. */
1830 wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first);
1831 if (wm->op_undo_depth == 0 || use_nested_undo) {
1832 UndoStack *ustack = ED_undo_stack_get();
1833 BKE_undosys_step_push(ustack, nullptr, nullptr);
1834 if (wm->op_undo_depth == 0) {
1836 }
1838 }
1839
1840 UndoStack *ustack = ED_undo_stack_get();
1841 SculptUndoStep *us = (SculptUndoStep *)BKE_undosys_stack_init_or_active_with_type(
1842 ustack, BKE_UNDOSYS_TYPE_SCULPT);
1843
1844 save_active_attribute(ob, &us->active_color_end);
1845}
1846
1848{
1849 push_end_ex(ob, false);
1850}
1851
1852/* -------------------------------------------------------------------- */
1857{
1858 if (attr->domain == bke::AttrDomain::Auto) {
1859 return;
1860 }
1861
1864
1865 SculptAttrRef existing;
1866 save_active_attribute(*ob, &existing);
1867
1868 AttributeOwner owner = AttributeOwner::from_id(&mesh->id);
1869 CustomDataLayer *layer = BKE_attribute_find(owner, attr->name, attr->type, attr->domain);
1870
1871 /* Temporary fix for #97408. This is a fundamental
1872 * bug in the undo stack; the operator code needs to push
1873 * an extra undo step before running an operator if a
1874 * non-memfile undo system is active.
1875 *
1876 * For now, detect if the layer does exist but with a different
1877 * domain and just unconvert it.
1878 */
1879 if (!layer) {
1882 if (layer) {
1884 mesh, attr->name, eCustomDataType(attr->type), attr->domain, nullptr))
1885 {
1886 layer = BKE_attribute_find(owner, attr->name, attr->type, attr->domain);
1887 }
1888 }
1889 }
1890
1891 if (!layer) {
1892 /* Memfile undo killed the layer; re-create it. */
1893 mesh->attributes_for_write().add(
1894 attr->name, attr->domain, attr->type, bke::AttributeInitDefaultValue());
1895 layer = BKE_attribute_find(owner, attr->name, attr->type, attr->domain);
1897 }
1898
1899 if (layer) {
1900 BKE_id_attributes_active_color_set(&mesh->id, layer->name);
1901 }
1902}
1903
1904static void step_encode_init(bContext * /*C*/, UndoStep *us_p)
1905{
1906 SculptUndoStep *us = (SculptUndoStep *)us_p;
1907 new (&us->data) StepData();
1908}
1909
1910static bool step_encode(bContext * /*C*/, Main *bmain, UndoStep *us_p)
1911{
1912 /* Dummy, encoding is done along the way by adding tiles
1913 * to the current 'SculptUndoStep' added by encode_init. */
1914 SculptUndoStep *us = (SculptUndoStep *)us_p;
1915 us->step.data_size = us->data.undo_size;
1916
1917 Node *unode = us->data.nodes.is_empty() ? nullptr : us->data.nodes.last().get();
1918 if (unode && us->data.type == Type::DyntopoEnd) {
1919 us->step.use_memfile_step = true;
1920 }
1921 us->step.is_applied = true;
1922
1923 if (!us->data.nodes.is_empty()) {
1924 bmain->is_memfile_undo_flush_needed = true;
1925 }
1926
1927 return true;
1928}
1929
1931{
1932 BLI_assert(us->step.is_applied == true);
1933
1934 restore_list(C, depsgraph, us->data);
1935 us->step.is_applied = false;
1936}
1937
1939{
1940 BLI_assert(us->step.is_applied == false);
1941
1942 restore_list(C, depsgraph, us->data);
1943 us->step.is_applied = true;
1944}
1945
1947 Depsgraph *depsgraph,
1948 SculptUndoStep *us,
1949 const bool is_final)
1950{
1951 /* Walk forward over any applied steps of same type,
1952 * then walk back in the next loop, un-applying them. */
1953 SculptUndoStep *us_iter = us;
1954 while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) {
1955 if (us_iter->step.next->is_applied == false) {
1956 break;
1957 }
1958 us_iter = (SculptUndoStep *)us_iter->step.next;
1959 }
1960
1961 while ((us_iter != us) || (!is_final && us_iter == us)) {
1962 BLI_assert(us_iter->step.type == us->step.type); /* Previous loop ensures this. */
1963
1964 set_active_layer(C, &((SculptUndoStep *)us_iter)->active_color_start);
1965 step_decode_undo_impl(C, depsgraph, us_iter);
1966
1967 if (us_iter == us) {
1968 if (us_iter->step.prev && us_iter->step.prev->type == BKE_UNDOSYS_TYPE_SCULPT) {
1969 set_active_layer(C, &((SculptUndoStep *)us_iter->step.prev)->active_color_end);
1970 }
1971 break;
1972 }
1973
1974 us_iter = (SculptUndoStep *)us_iter->step.prev;
1975 }
1976}
1977
1978static void step_decode_redo(bContext *C, Depsgraph *depsgraph, SculptUndoStep *us)
1979{
1980 SculptUndoStep *us_iter = us;
1981 while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) {
1982 if (us_iter->step.prev->is_applied == true) {
1983 break;
1984 }
1985 us_iter = (SculptUndoStep *)us_iter->step.prev;
1986 }
1987 while (us_iter && (us_iter->step.is_applied == false)) {
1988 set_active_layer(C, &((SculptUndoStep *)us_iter)->active_color_end);
1989 step_decode_redo_impl(C, depsgraph, us_iter);
1990
1991 if (us_iter == us) {
1992 set_active_layer(C, &((SculptUndoStep *)us_iter)->active_color_start);
1993 break;
1994 }
1995 us_iter = (SculptUndoStep *)us_iter->step.next;
1996 }
1997}
1998
1999static void step_decode(
2000 bContext *C, Main *bmain, UndoStep *us_p, const eUndoStepDir dir, bool is_final)
2001{
2002 /* NOTE: behavior for undo/redo closely matches image undo. */
2003 BLI_assert(dir != STEP_INVALID);
2004
2006
2007 /* Ensure sculpt mode. */
2008 {
2009 Scene *scene = CTX_data_scene(C);
2010 ViewLayer *view_layer = CTX_data_view_layer(C);
2011 BKE_view_layer_synced_ensure(scene, view_layer);
2012 Object *ob = BKE_view_layer_active_object_get(view_layer);
2013 if (ob && (ob->type == OB_MESH)) {
2015 /* Pass. */
2016 }
2017 else {
2018 object::mode_generic_exit(bmain, depsgraph, scene, ob);
2019
2020 /* Sculpt needs evaluated state.
2021 * NOTE: needs to be done here, as #object::mode_generic_exit will usually invalidate
2022 * (some) evaluated data. */
2024
2025 Mesh *mesh = static_cast<Mesh *>(ob->data);
2026 /* Don't add sculpt topology undo steps when reading back undo state.
2027 * The undo steps must enter/exit for us. */
2028 mesh->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
2029 object_sculpt_mode_enter(*bmain, *depsgraph, *scene, *ob, true, nullptr);
2030 }
2031
2032 if (ob->sculpt) {
2033 ob->sculpt->needs_flush_to_id = 1;
2034 }
2035 bmain->is_memfile_undo_flush_needed = true;
2036 }
2037 else {
2038 BLI_assert(0);
2039 return;
2040 }
2041 }
2042
2043 SculptUndoStep *us = (SculptUndoStep *)us_p;
2044 if (dir == STEP_UNDO) {
2045 step_decode_undo(C, depsgraph, us, is_final);
2046 }
2047 else if (dir == STEP_REDO) {
2049 }
2050}
2051
2052static void step_free(UndoStep *us_p)
2053{
2054 SculptUndoStep *us = (SculptUndoStep *)us_p;
2055 free_step_data(us->data);
2056}
2057
2058void geometry_begin(const Scene &scene, Object &ob, const wmOperator *op)
2059{
2060 push_begin(scene, ob, op);
2061 geometry_push(ob);
2062}
2063
2064void geometry_begin_ex(const Scene &scene, Object &ob, const char *name)
2065{
2066 push_begin_ex(scene, ob, name);
2067 geometry_push(ob);
2068}
2069
2071{
2072 geometry_push(ob);
2073 push_end(ob);
2074}
2075
2077{
2078 ut->name = "Sculpt";
2079 ut->poll = nullptr; /* No poll from context for now. */
2083 ut->step_free = step_free;
2084
2086
2087 ut->step_size = sizeof(SculptUndoStep);
2088}
2089
2092/* -------------------------------------------------------------------- */
2115{
2117 return false;
2118 }
2119
2120 Object *object = CTX_data_active_object(C);
2121 SculptSession *sculpt_session = object->sculpt;
2122
2123 return sculpt_session->multires.active;
2124}
2125
2126static void push_all_grids(const Depsgraph &depsgraph, Object *object)
2127{
2128 /* It is possible that undo push is done from an object state where there is no tree. This
2129 * happens, for example, when an operation which tagged for geometry update was performed prior
2130 * to the current operation without making any stroke in between.
2131 *
2132 * Skip pushing nodes based on the following logic: on redo Type::Position will
2133 * ensure pbvh::Tree for the new base geometry, which will have same coordinates as if we create
2134 * pbvh::Tree here.
2135 */
2136 const bke::pbvh::Tree *pbvh = bke::object::pbvh_get(*object);
2137 if (pbvh == nullptr) {
2138 return;
2139 }
2140
2141 IndexMaskMemory memory;
2142 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(*pbvh, memory);
2143 push_nodes(depsgraph, *object, node_mask, Type::Position);
2144}
2145
2147{
2148 if (!use_multires_mesh(C)) {
2149 return;
2150 }
2151
2152 const Scene &scene = *CTX_data_scene(C);
2153 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
2154 Object *object = CTX_data_active_object(C);
2155
2156 push_begin_ex(scene, *object, str);
2157
2158 geometry_push(*object);
2160
2161 push_all_grids(depsgraph, object);
2162}
2163
2165{
2166 if (!use_multires_mesh(C)) {
2167 ED_undo_push(C, str);
2168 return;
2169 }
2170
2171 Object *object = CTX_data_active_object(C);
2172
2173 geometry_push(*object);
2175
2176 push_end(*object);
2177}
2178
2181} // namespace blender::ed::sculpt_paint::undo
2182
2183namespace blender::ed::sculpt_paint {
2184
2185std::optional<OrigPositionData> orig_position_data_lookup_mesh_all_verts(
2186 const Object & /*object*/, const bke::pbvh::MeshNode &node)
2187{
2188 const undo::Node *unode = undo::get_node(&node, undo::Type::Position);
2189 if (!unode) {
2190 return std::nullopt;
2191 }
2192 return OrigPositionData{unode->position.as_span(), unode->normal.as_span()};
2193}
2194
2195std::optional<OrigPositionData> orig_position_data_lookup_mesh(const Object &object,
2196 const bke::pbvh::MeshNode &node)
2197{
2198 std::optional<OrigPositionData> result = orig_position_data_lookup_mesh_all_verts(object, node);
2199 if (!result) {
2200 return std::nullopt;
2201 }
2202 return OrigPositionData{result->positions.take_front(node.verts().size()),
2203 result->normals.take_front(node.verts().size())};
2204}
2205
2206std::optional<OrigPositionData> orig_position_data_lookup_grids(const Object & /*object*/,
2207 const bke::pbvh::GridsNode &node)
2208{
2209 const undo::Node *unode = undo::get_node(&node, undo::Type::Position);
2210 if (!unode) {
2211 return std::nullopt;
2212 }
2213 return OrigPositionData{unode->position.as_span(), unode->normal.as_span()};
2214}
2215
2217 const Set<BMVert *, 0> &verts,
2218 const MutableSpan<float3> positions,
2219 const MutableSpan<float3> normals)
2220{
2221 int i = 0;
2222 for (const BMVert *vert : verts) {
2223 const float *co;
2224 const float *no;
2225 BM_log_original_vert_data(&const_cast<BMLog &>(bm_log), const_cast<BMVert *>(vert), &co, &no);
2226 if (!positions.is_empty()) {
2227 positions[i] = co;
2228 }
2229 if (!normals.is_empty()) {
2230 normals[i] = no;
2231 }
2232 i++;
2233 }
2234}
2235
2236std::optional<Span<float4>> orig_color_data_lookup_mesh(const Object & /*object*/,
2237 const bke::pbvh::MeshNode &node)
2238{
2239 const undo::Node *unode = undo::get_node(&node, undo::Type::Color);
2240 if (!unode) {
2241 return std::nullopt;
2242 }
2243 return unode->col.as_span();
2244}
2245
2246std::optional<Span<int>> orig_face_set_data_lookup_mesh(const Object & /*object*/,
2247 const bke::pbvh::MeshNode &node)
2248{
2249 const undo::Node *unode = undo::get_node(&node, undo::Type::FaceSet);
2250 if (!unode) {
2251 return std::nullopt;
2252 }
2253 return unode->face_sets.as_span();
2254}
2255
2256std::optional<Span<int>> orig_face_set_data_lookup_grids(const Object & /*object*/,
2257 const bke::pbvh::GridsNode &node)
2258{
2259 const undo::Node *unode = undo::get_node(&node, undo::Type::FaceSet);
2260 if (!unode) {
2261 return std::nullopt;
2262 }
2263 return unode->face_sets.as_span();
2264}
2265
2266std::optional<Span<float>> orig_mask_data_lookup_mesh(const Object & /*object*/,
2267 const bke::pbvh::MeshNode &node)
2268{
2269 const undo::Node *unode = undo::get_node(&node, undo::Type::Mask);
2270 if (!unode) {
2271 return std::nullopt;
2272 }
2273 return unode->mask.as_span();
2274}
2275
2276std::optional<Span<float>> orig_mask_data_lookup_grids(const Object & /*object*/,
2277 const bke::pbvh::GridsNode &node)
2278{
2279 const undo::Node *unode = undo::get_node(&node, undo::Type::Mask);
2280 if (!unode) {
2281 return std::nullopt;
2282 }
2283 return unode->mask.as_span();
2284}
2285
2286} // namespace blender::ed::sculpt_paint
struct CustomDataLayer * BKE_attribute_search_for_write(AttributeOwner &owner, const char *name, eCustomDataMask type, AttrDomainMask domain_mask)
Definition attribute.cc:669
void BKE_id_attributes_active_color_set(struct ID *id, const char *name)
Definition attribute.cc:965
@ ATTR_DOMAIN_MASK_ALL
struct CustomDataLayer * BKE_attribute_find(const AttributeOwner &owner, const char *name, eCustomDataType type, blender::bke::AttrDomain domain)
#define ATTR_DOMAIN_MASK_COLOR
#define ATTR_DOMAIN_AS_MASK(domain)
Depsgraph * CTX_data_ensure_evaluated_depsgraph(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)
RegionView3D * CTX_wm_region_view3d(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_offset_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
void CustomData_init_from(const CustomData *source, CustomData *dest, eCustomDataMask mask, int totelem)
void CustomData_free(CustomData *data, int totelem)
#define CD_TYPE_AS_MASK(_type)
const CustomData_MeshMasks CD_MASK_MESH
#define G_MAIN
KeyBlock * BKE_keyblock_from_object(Object *ob)
Definition key.cc:1905
void BKE_keyblock_update_from_offset(const Object *ob, KeyBlock *kb, const float(*ofs)[3])
Definition key.cc:2447
KeyBlock * BKE_keyblock_find_name(Key *key, const char name[])
Definition key.cc:1932
std::optional< blender::Array< bool > > BKE_keyblock_get_dependent_keys(const Key *key, int index)
Definition key.cc:2578
void BKE_keyblock_update_from_vertcos(const Object *ob, KeyBlock *kb, const float(*vertCos)[3])
Definition key.cc:2297
Key * BKE_key_from_object(Object *ob)
Definition key.cc:1820
float(* BKE_keyblock_convert_to_vertcos(const Object *ob, const KeyBlock *kb))[3]
Definition key.cc:2389
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
Object * BKE_view_layer_active_object_get(const ViewLayer *view_layer)
void BKE_mesh_clear_geometry(Mesh *mesh)
blender::Array< blender::float3 > BKE_multires_create_deformed_base_mesh_vert_coords(Depsgraph *depsgraph, Object *object, MultiresModifierData *mmd)
Definition multires.cc:244
void multires_mark_as_modified(Depsgraph *depsgraph, Object *object, MultiresModifiedFlags flags)
Definition multires.cc:373
General operations, lookup, etc. for blender objects.
Mesh * BKE_object_get_original_mesh(const Object *object)
bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const RegionView3D *rv3d)
Definition paint.cc:2862
void BKE_sculptsession_free_deformMats(SculptSession *ss)
Definition paint.cc:2049
MultiresModifierData * BKE_sculpt_multires_active(const Scene *scene, Object *ob)
Definition paint.cc:2316
void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph, Object *ob_orig, bool is_paint_tool)
Definition paint.cc:2601
void BKE_sculptsession_free_pbvh(Object &object)
Definition paint.cc:2099
PaintMode BKE_paintmode_get_active_from_context(const bContext *C)
Definition paint.cc:506
const blender::Set< BMFace *, 0 > & BKE_pbvh_bmesh_node_faces(blender::bke::pbvh::BMeshNode *node)
const blender::Set< BMVert *, 0 > & BKE_pbvh_bmesh_node_unique_verts(blender::bke::pbvh::BMeshNode *node)
const blender::Set< BMVert *, 0 > & BKE_pbvh_bmesh_node_other_verts(blender::bke::pbvh::BMeshNode *node)
void BKE_pbvh_sync_visibility_from_verts(Object &object)
Definition pbvh.cc:2530
void BKE_scene_graph_evaluated_ensure(Depsgraph *depsgraph, Main *bmain)
Definition scene.cc:2573
CCGKey BKE_subdiv_ccg_key_top_level(const SubdivCCG &subdiv_ccg)
blender::BitGroupVector & BKE_subdiv_ccg_grid_hidden_ensure(SubdivCCG &subdiv_ccg)
void BKE_subdiv_ccg_grid_hidden_free(SubdivCCG &subdiv_ccg)
@ MULTIRES_HIDDEN_MODIFIED
@ MULTIRES_COORDS_MODIFIED
@ UNDOTYPE_FLAG_DECODE_ACTIVE_STEP
const UndoType * BKE_UNDOSYS_TYPE_SCULPT
eUndoPushReturn BKE_undosys_step_push(UndoStack *ustack, bContext *C, const char *name)
eUndoStepDir
@ STEP_INVALID
@ STEP_UNDO
@ STEP_REDO
UndoStep * BKE_undosys_step_push_init_with_type(UndoStack *ustack, bContext *C, const char *name, const UndoType *ut)
#define BKE_undosys_stack_limit_steps_and_memory_defaults(ustack)
UndoStep * BKE_undosys_stack_init_or_active_with_type(UndoStack *ustack, const UndoType *ut)
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_NOINLINE
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define ELEM(...)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_SHADING
Definition DNA_ID.h:1061
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
#define ID_REAL_USERS(id)
Definition DNA_ID.h:637
#define MAX_CUSTOMDATA_LAYER_NAME
#define CD_MASK_PROP_ALL
#define CD_MASK_COLOR_ALL
@ CD_PROP_FLOAT
@ ME_SCULPT_DYNAMIC_TOPOLOGY
@ OB_MODE_SCULPT
@ OB_MODE_VERTEX_PAINT
Object is a sort of wrapper for general info.
@ OB_MESH
void ED_undo_push(bContext *C, const char *str)
Definition ed_undo.cc:104
UndoStack * ED_undo_stack_get()
Definition ed_undo.cc:455
void ED_undosys_stack_memfile_id_changed_tag(UndoStack *ustack, ID *id)
Read Guarded memory(de)allocation.
#define ND_DATA
Definition WM_types.hh:475
#define NC_OBJECT
Definition WM_types.hh:346
volatile int lock
void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char *name)
void BM_log_all_added(BMesh *bm, BMLog *log)
Definition bmesh_log.cc:874
void BM_log_original_vert_data(BMLog *log, BMVert *v, const float **r_co, const float **r_no)
Definition bmesh_log.cc:988
void BM_log_face_modified(BMLog *log, BMFace *f)
Definition bmesh_log.cc:801
void BM_log_redo(BMesh *bm, BMLog *log)
Definition bmesh_log.cc:738
void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
Definition bmesh_log.cc:772
void BM_log_entry_drop(BMLogEntry *entry)
Definition bmesh_log.cc:651
BMLog * BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry)
Definition bmesh_log.cc:504
void BM_log_undo(BMesh *bm, BMLog *log)
Definition bmesh_log.cc:717
void BM_log_before_all_removed(BMesh *bm, BMLog *log)
Definition bmesh_log.cc:902
BMLogEntry * BM_log_entry_add(BMLog *log)
Definition bmesh_log.cc:624
const BMAllocTemplate bm_mesh_allocsize_default
Definition bmesh_mesh.cc:29
BMesh * BM_mesh_create(const BMAllocTemplate *allocsize, const BMeshCreateParams *params)
BMesh Make Mesh.
void BM_mesh_normals_update(BMesh *bm)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static AttributeOwner from_id(ID *id)
Definition attribute.cc:43
int64_t size() const
Definition BLI_array.hh:245
Span< T > as_span() const
Definition BLI_array.hh:232
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:237
IndexRange index_range() const
Definition BLI_array.hh:349
void fill(const T &value) const
Definition BLI_array.hh:261
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:388
bool is_empty() const
Definition BLI_array.hh:253
constexpr IndexRange take_front(int64_t n) const
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:574
constexpr void fill_indices(Span< IndexT > indices, const T &value) const
Definition BLI_span.hh:527
constexpr const T * data() const
Definition BLI_span.hh:216
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
constexpr Span take_front(int64_t n) const
Definition BLI_span.hh:194
constexpr bool is_empty() const
Definition BLI_span.hh:261
int64_t size() const
void append(const T &value)
Span< T > as_span() const
std::optional< AttributeMetaData > lookup_meta_data(const StringRef attribute_id) const
void tag_attribute_changed(const IndexMask &node_mask, StringRef attribute_name)
Definition pbvh.cc:593
void tag_positions_changed(const IndexMask &node_mask)
Definition pbvh.cc:549
Span< NodeT > nodes() const
void tag_face_sets_changed(const IndexMask &node_mask)
Definition pbvh.cc:579
void tag_masks_changed(const IndexMask &node_mask)
Definition pbvh.cc:586
void tag_visibility_changed(const IndexMask &node_mask)
Definition pbvh.cc:562
void foreach_index(Fn &&fn) const
local_group_size(16, 16) .push_constant(Type b
OperationNode * node
const Depsgraph * depsgraph
draw_view in_light_buf[] float
#define str(s)
static float verts[][3]
bool ED_geometry_attribute_convert(Mesh *mesh, const char *name, const eCustomDataType dst_type, const blender::bke::AttrDomain dst_domain, ReportList *reports)
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
static char faces[256]
MutableSpan< float3 > vert_positions_eval_for_write(const Depsgraph &depsgraph, Object &object_orig)
Definition pbvh.cc:2496
static void save_active_attribute(Object &object, SculptAttrRef *attr)
void push_nodes(const Depsgraph &depsgraph, Object &object, const IndexMask &node_mask, const Type type)
static void store_vert_visibility_grids(const SubdivCCG &subdiv_ccg, const bke::pbvh::GridsNode &node, Node &unode)
static bool use_multires_mesh(bContext *C)
static void geometry_push(const Object &object)
static void store_positions_grids(const SubdivCCG &subdiv_ccg, Node &unode)
static BLI_NOINLINE void bmesh_push(const Object &object, const bke::pbvh::BMeshNode *node, Type type)
static void free_step_data(StepData &step_data)
void push_multires_mesh_begin(bContext *C, const char *str)
void push_multires_mesh_end(bContext *C, const char *str)
static void fill_node_data_mesh(const Depsgraph &depsgraph, const Object &object, const bke::pbvh::MeshNode &node, const Type type, Node &unode)
static size_t node_size_in_bytes(const Node &node)
static bool topology_matches(const StepData &step_data, const Object &object)
static SculptUndoStep * get_active_step()
static void store_face_visibility(const Mesh &mesh, Node &unode)
static void step_encode_init(bContext *, UndoStep *us_p)
static void restore_mask_grids(Object &object, Node &unode, MutableSpan< bool > modified_grids)
void push_node(const Depsgraph &depsgraph, const Object &object, const bke::pbvh::Node *node, Type type)
static bool use_multires_undo(const StepData &step_data, const SculptSession &ss)
void push_begin_ex(const Scene &, Object &ob, const char *name)
static void step_decode_redo_impl(bContext *C, Depsgraph *depsgraph, SculptUndoStep *us)
static void restore_geometry_data(const NodeGeometry *geometry, Mesh *mesh)
static void restore_vert_visibility_grids(SubdivCCG &subdiv_ccg, Node &unode, MutableSpan< bool > modified_grids)
static StepData * get_step_data()
static void store_vert_visibility_mesh(const Mesh &mesh, const bke::pbvh::Node &node, Node &unode)
static void restore_mask_mesh(Object &object, Node &unode, MutableSpan< bool > modified_vertices)
static void store_mask_grids(const SubdivCCG &subdiv_ccg, Node &unode)
static NodeGeometry * geometry_get(StepData &step_data)
static void store_positions_mesh(const Depsgraph &depsgraph, const Object &object, Node &unode)
static void fill_node_data_grids(const Object &object, const bke::pbvh::GridsNode &node, const Type type, Node &unode)
static void geometry_free_data(NodeGeometry *geometry)
static void step_decode_undo(bContext *C, Depsgraph *depsgraph, SculptUndoStep *us, const bool is_final)
void geometry_begin_ex(const Scene &scene, Object &ob, const char *name)
static void step_free(UndoStep *us_p)
static int bmesh_restore(bContext *C, Depsgraph &depsgraph, StepData &step_data, Object &object, SculptSession &ss)
static const Node * get_node(const bke::pbvh::Node *node, const Type type)
static bool step_encode(bContext *, Main *bmain, UndoStep *us_p)
static bool indices_contain_true(const Span< bool > data, const Span< int > indices)
static Node * ensure_node(StepData &step_data, const bke::pbvh::Node &node, bool &r_new)
void geometry_begin(const Scene &scene, Object &ob, const wmOperator *op)
static void restore_position_grids(MutableSpan< float3 > positions, const CCGKey &key, Node &unode, MutableSpan< bool > modified_grids)
static void step_decode_undo_impl(bContext *C, Depsgraph *depsgraph, SculptUndoStep *us)
static void restore_list(bContext *C, Depsgraph *depsgraph, StepData &step_data)
static void restore_hidden_face(Object &object, Node &unode, MutableSpan< bool > modified_faces)
static void step_decode_redo(bContext *C, Depsgraph *depsgraph, SculptUndoStep *us)
static void store_geometry_data(NodeGeometry *geometry, const Object &object)
static void store_mask_mesh(const Mesh &mesh, Node &unode)
static void bmesh_restore_generic(StepData &step_data, Object &object, SculptSession &ss)
static void restore_position_mesh(const Depsgraph &depsgraph, Object &object, const Span< std::unique_ptr< Node > > unodes, MutableSpan< bool > modified_verts)
static bool restore_active_shape_key(bContext &C, Depsgraph &depsgraph, const StepData &step_data, Object &object)
static void refine_subdiv(Depsgraph *depsgraph, SculptSession &ss, Object &object, bke::subdiv::Subdiv *subdiv)
static void store_color(const Mesh &mesh, const bke::pbvh::MeshNode &node, Node &unode)
static void update_shapekeys(const Object &ob, KeyBlock *kb, const Span< float3 > new_positions)
static void restore_vert_visibility_mesh(Object &object, Node &unode, MutableSpan< bool > modified_vertices)
void push_begin(const Scene &scene, Object &ob, const wmOperator *op)
static void bmesh_enable(Object &object, StepData &step_data)
static void bmesh_restore_end(bContext *C, StepData &step_data, Object &object, SculptSession &ss)
void restore_from_bmesh_enter_geometry(const StepData &step_data, Mesh &mesh)
static void store_face_sets(const Mesh &mesh, Node &unode)
static void step_decode(bContext *C, Main *bmain, UndoStep *us_p, const eUndoStepDir dir, bool is_final)
static void restore_color(Object &object, StepData &step_data, MutableSpan< bool > modified_vertices)
static bool restore_face_sets(Object &object, Node &unode, MutableSpan< bool > modified_face_set_faces)
static void push_all_grids(const Depsgraph &depsgraph, Object *object)
void push_end_ex(Object &ob, const bool use_nested_undo)
static void restore_geometry(StepData &step_data, Object &object)
static void bmesh_restore_begin(bContext *C, StepData &step_data, Object &object, SculptSession &ss)
static void set_active_layer(bContext *C, SculptAttrRef *attr)
void object_sculpt_mode_enter(Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob, bool force_dyntopo, ReportList *reports)
std::optional< Span< float > > orig_mask_data_lookup_grids(const Object &object, const bke::pbvh::GridsNode &node)
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:6092
std::optional< OrigPositionData > orig_position_data_lookup_grids(const Object &object, const bke::pbvh::GridsNode &node)
void orig_position_data_gather_bmesh(const BMLog &bm_log, const Set< BMVert *, 0 > &verts, MutableSpan< float3 > positions, MutableSpan< float3 > normals)
std::optional< Span< float4 > > orig_color_data_lookup_mesh(const Object &object, const bke::pbvh::MeshNode &node)
void gather_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6082
std::optional< Span< float > > orig_mask_data_lookup_mesh(const Object &object, const bke::pbvh::MeshNode &node)
std::optional< OrigPositionData > orig_position_data_lookup_mesh_all_verts(const Object &object, const bke::pbvh::MeshNode &node)
std::optional< OrigPositionData > orig_position_data_lookup_mesh(const Object &object, const bke::pbvh::MeshNode &node)
std::optional< Span< int > > orig_face_set_data_lookup_grids(const Object &object, const bke::pbvh::GridsNode &node)
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:95
#define NO_ACTIVE_LAYER
CustomData vdata
Definition DNA_ID.h:413
char name[66]
Definition DNA_ID.h:425
char name[64]
void * data
ListBase block
bool is_memfile_undo_flush_needed
Definition BKE_main.hh:165
MeshRuntimeHandle * runtime
uint16_t flag
int verts_num
struct SculptSession * sculpt
BMLog * bm_log
Definition BKE_paint.hh:402
KeyBlock * shapekey_active
Definition BKE_paint.hh:387
blender::float4 pivot_rot
Definition BKE_paint.hh:463
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:405
blender::float3 pivot_pos
Definition BKE_paint.hh:462
char needs_flush_to_id
Definition BKE_paint.hh:497
struct SculptSession::@48 multires
MultiresModifierData * modifier
Definition BKE_paint.hh:383
bool deform_modifiers_active
Definition BKE_paint.hh:411
blender::Array< blender::float3 > normals
blender::BitGroupVector grid_hidden
blender::Array< float > masks
blender::Array< blender::float3 > positions
size_t data_size
UndoStep * prev
UndoStep * next
const UndoType * type
bool use_memfile_step
void(* step_encode_init)(bContext *C, UndoStep *us)
const char * name
void(* step_free)(UndoStep *us)
bool(* poll)(struct bContext *C)
void(* step_decode)(bContext *C, Main *bmain, UndoStep *us, eUndoStepDir dir, bool is_final)
bool(* step_encode)(bContext *C, Main *bmain, UndoStep *us)
const ImplicitSharingInfo * face_offsets_sharing_info
char name[MAX_CUSTOMDATA_LAYER_NAME]
Vector< std::unique_ptr< Node > > nodes
Map< const bke::pbvh::Node *, std::unique_ptr< Node > > undo_nodes_by_pbvh_node
const char * name
Definition WM_types.hh:990
struct wmOperatorType * type
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void WM_file_tag_modified()
Definition wm_files.cc:171