Blender V4.5
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
25#include "sculpt_undo.hh"
26
27#include <mutex>
28
29#include "CLG_log.h"
30
31#include "BLI_array.hh"
33#include "BLI_listbase.h"
34#include "BLI_map.hh"
35#include "BLI_memory_counter.hh"
36#include "BLI_string.h"
37#include "BLI_utildefines.h"
38#include "BLI_vector.hh"
39
40#include "DNA_key_types.h"
41#include "DNA_object_types.h"
42#include "DNA_scene_types.h"
43#include "DNA_screen_types.h"
44
45#include "BKE_attribute.hh"
46#include "BKE_ccg.hh"
47#include "BKE_context.hh"
48#include "BKE_customdata.hh"
49#include "BKE_global.hh"
50#include "BKE_key.hh"
51#include "BKE_layer.hh"
52#include "BKE_main.hh"
53#include "BKE_mesh.hh"
54#include "BKE_multires.hh"
55#include "BKE_object.hh"
56#include "BKE_paint.hh"
57#include "BKE_scene.hh"
58#include "BKE_subdiv_ccg.hh"
59#include "BKE_subsurf.hh"
60#include "BKE_undo_system.hh"
61
62/* TODO(sergey): Ideally should be no direct call to such low level things. */
63#include "BKE_subdiv_eval.hh"
64
65#include "DEG_depsgraph.hh"
66
67#include "WM_api.hh"
68#include "WM_types.hh"
69
70#include "ED_geometry.hh"
71#include "ED_object.hh"
72#include "ED_sculpt.hh"
73#include "ED_undo.hh"
74
75#include "bmesh.hh"
76#include "mesh_brush_common.hh"
77#include "paint_hide.hh"
78#include "paint_intern.hh"
79#include "sculpt_automask.hh"
80#include "sculpt_color.hh"
81#include "sculpt_dyntopo.hh"
82#include "sculpt_face_set.hh"
83#include "sculpt_intern.hh"
84
85static CLG_LogRef LOG = {"ed.sculpt.undo"};
86
88
89/* Implementation of undo system for objects in sculpt mode.
90 *
91 * Each undo step in sculpt mode consists of list of nodes, each node contains a flat array of data
92 * related to the step type.
93 *
94 * Node type used for undo depends on specific operation and active sculpt mode ("regular" or
95 * dynamic topology).
96 *
97 * Regular sculpt brushes will use Position, HideVert, HideFace, Mask, Face Set * nodes. These
98 * nodes are created for every BVH node which is affected by the brush. The undo push for the node
99 * happens BEFORE modifications. This makes the operation undo to work in the following way: for
100 * every node in the undo step swap happens between node in the undo stack and the corresponding
101 * value in the BVH. This is how redo is possible after undo.
102 *
103 * The COORDS, HIDDEN or MASK type of nodes contains arrays of the corresponding values.
104 *
105 * Operations like Symmetrize are using GEOMETRY type of nodes which pushes the entire state of the
106 * mesh to the undo stack. This node contains all CustomData layers.
107 *
108 * The tricky aspect of this undo node type is that it stores mesh before and after modification.
109 * This allows the undo system to both undo and redo the symmetrize operation within the
110 * pre-modified-push of other node type behavior, but it uses more memory that it seems it should
111 * be.
112 *
113 * The dynamic topology undo nodes are handled somewhat separately from all other ones and the idea
114 * there is to store log of operations: which vertices and faces have been added or removed.
115 *
116 * Begin of dynamic topology sculpting mode have own node type. It contains an entire copy of mesh
117 * since just enabling the dynamic topology mode already does modifications on it.
118 *
119 * End of dynamic topology and symmetrize in this mode are handled in a special manner as well. */
120
121#define NO_ACTIVE_LAYER bke::AttrDomain::Auto
122
156
163
164/* Storage of geometry for the undo node.
165 * Is used as a storage for either original or modified geometry. */
167 /* Is used for sanity check, helping with ensuring that two and only two
168 * geometry pushes happened in the undo stack. */
170
181};
182
183struct Node;
184
185struct StepData {
186 private:
187 bool applied_ = true;
188
189 public:
195
197 std::string object_name;
198
201
202 /* TODO: Combine the three structs into a variant, since they specify data that is only valid
203 * within a single mode. */
204 struct {
205 /* The number of vertices in the entire mesh. */
207 /* The number of face corners in the entire mesh. */
210
211 struct {
217
218 struct {
230
231 /* Geometry at the bmesh enter moment. */
234
237
238 /* Geometry modification operations. */
239 /* Original geometry is stored before the modification and is restored from when undoing. */
241 /* Modified geometry is stored after the modification and is restored from when redoing. */
243
245
256
259
260 size_t undo_size;
261
263 bool needs_undo() const
264 {
265 return applied_;
266 }
267
269 {
270 applied_ = true;
271 }
272
274 {
275 applied_ = false;
276 }
277};
278
281 /* NOTE: will split out into list for multi-object-sculpt-mode. */
283
284 /* Active color attribute at the start of this undo step. */
286
287 /* Active color attribute at the end of this undo step. */
289};
290
292{
293 UndoStack *ustack = ED_undo_stack_get();
295 return reinterpret_cast<SculptUndoStep *>(us);
296}
297
299{
300 if (SculptUndoStep *us = get_active_step()) {
301 return &us->data;
302 }
303 return nullptr;
304}
305
306static bool use_multires_undo(const StepData &step_data, const SculptSession &ss)
307{
308 return step_data.grids.grids_num != 0 && ss.subdiv_ccg != nullptr;
309}
310
311static bool topology_matches(const StepData &step_data, const Object &object)
312{
313 const SculptSession &ss = *object.sculpt;
314 if (use_multires_undo(step_data, ss)) {
315 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
316 return subdiv_ccg.grids_num == step_data.grids.grids_num &&
317 subdiv_ccg.grid_size == step_data.grids.grid_size;
318 }
319 const Mesh &mesh = *static_cast<Mesh *>(object.data);
320 return mesh.verts_num == step_data.mesh.verts_num;
321}
322
324{
325 return std::any_of(indices.begin(), indices.end(), [&](const int i) { return data[i]; });
326}
327
329 Depsgraph &depsgraph,
330 const StepData &step_data,
331 Object &object)
332{
333 const SculptSession &ss = *object.sculpt;
334 if (ss.shapekey_active && ss.shapekey_active->name != step_data.active_shape_key_name) {
335 /* Shape key has been changed before calling undo operator. */
336
337 Key *key = BKE_key_from_object(&object);
338 const KeyBlock *kb = key ?
339 BKE_keyblock_find_name(key, step_data.active_shape_key_name.c_str()) :
340 nullptr;
341
342 if (kb) {
343 object.shapenr = BLI_findindex(&key->block, kb) + 1;
344
347 }
348 else {
349 /* Key has been removed -- skip this undo node. */
350 return false;
351 }
352 }
353 return true;
354}
355
356template<typename T>
358{
359 BLI_assert(full.size() == indices.size());
360 for (const int i : indices.index_range()) {
361 std::swap(full[i], indexed[indices[i]]);
362 }
363}
364
365static void restore_position_mesh(Object &object,
366 const Span<std::unique_ptr<Node>> unodes,
367 const MutableSpan<bool> modified_verts)
368{
369 Mesh &mesh = *static_cast<Mesh *>(object.data);
370 MutableSpan<float3> positions = mesh.vert_positions_for_write();
371 std::optional<ShapeKeyData> shape_key_data = ShapeKeyData::from_object(object);
372
373 threading::parallel_for(unodes.index_range(), 1, [&](const IndexRange range) {
374 for (const int node_i : range) {
375 Node &unode = *unodes[node_i];
376 const Span<int> verts = unode.vert_indices.as_span().take_front(unode.unique_verts_num);
377
378 if (unode.orig_position.is_empty()) {
379 /* When original positions aren't written separately in the undo step, there are no
380 * deform modifiers. Therefore the original and evaluated deform positions will be the
381 * same, and modifying the positions from the original mesh is enough. */
382 swap_indexed_data(
383 unode.position.as_mutable_span().take_front(unode.unique_verts_num), verts, positions);
384 }
385 else {
386 /* When original positions are stored in the undo step, undo/redo will cause a reevaluation
387 * of the object. The evaluation will recompute the evaluated positions, so dealing with
388 * them here is unnecessary. */
389 MutableSpan<float3> undo_positions = unode.orig_position;
390
391 if (shape_key_data) {
392 MutableSpan<float3> active_data = shape_key_data->active_key_data;
393
394 if (!shape_key_data->dependent_keys.is_empty()) {
395 Array<float3, 1024> translations(verts.size());
396 translations_from_new_positions(undo_positions, verts, active_data, translations);
397 for (MutableSpan<float3> data : shape_key_data->dependent_keys) {
398 apply_translations(translations, verts, data);
399 }
400 }
401
402 if (shape_key_data->basis_key_active) {
403 /* The basis key positions and the mesh positions are always kept in sync. */
404 scatter_data_mesh(undo_positions.as_span(), verts, positions);
405 }
406 swap_indexed_data(undo_positions.take_front(unode.unique_verts_num), verts, active_data);
407 }
408 else {
409 /* There is a deform modifier, but no shape keys. */
410 swap_indexed_data(undo_positions.take_front(unode.unique_verts_num), verts, positions);
411 }
412 }
413 modified_verts.fill_indices(verts, true);
414 }
415 });
416}
417
418static void restore_position_grids(const MutableSpan<float3> positions,
419 const CCGKey &key,
420 Node &unode,
421 const MutableSpan<bool> modified_grids)
422{
423 const Span<int> grids = unode.grids;
424 const MutableSpan<float3> undo_position = unode.position;
425
426 for (const int i : grids.index_range()) {
427 MutableSpan data = positions.slice(bke::ccg::grid_range(key, grids[i]));
428 MutableSpan undo_data = undo_position.slice(bke::ccg::grid_range(key, i));
429 for (const int offset : data.index_range()) {
430 std::swap(data[offset], undo_data[offset]);
431 }
432 }
433
434 modified_grids.fill_indices(grids, true);
435}
436
438 Node &unode,
439 const MutableSpan<bool> modified_verts)
440{
441 Mesh &mesh = *static_cast<Mesh *>(object.data);
442 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
444 ".hide_vert", bke::AttrDomain::Point);
445 for (const int i : unode.vert_indices.index_range().take_front(unode.unique_verts_num)) {
446 const int vert = unode.vert_indices[i];
447 if (unode.vert_hidden[i].test() != hide_vert.span[vert]) {
448 unode.vert_hidden[i].set(!unode.vert_hidden[i].test());
449 hide_vert.span[vert] = !hide_vert.span[vert];
450 modified_verts[vert] = true;
451 }
452 }
453 hide_vert.finish();
454}
455
457 Node &unode,
458 const MutableSpan<bool> modified_grids)
459{
460 if (unode.grid_hidden.is_empty()) {
462 return;
463 }
464
465 BitGroupVector<> &grid_hidden = BKE_subdiv_ccg_grid_hidden_ensure(subdiv_ccg);
466 const Span<int> grids = unode.grids;
467 for (const int i : grids.index_range()) {
468 /* Swap the two bit spans. */
470 MutableBoundedBitSpan b = grid_hidden[grids[i]];
471 for (const int j : a.index_range()) {
472 const bool value_a = a[j];
473 const bool value_b = b[j];
474 a[j].set(value_b);
475 b[j].set(value_a);
476 }
477 }
478
479 modified_grids.fill_indices(grids, true);
480}
481
482static void restore_hidden_face(Object &object,
483 Node &unode,
484 const MutableSpan<bool> modified_faces)
485{
486 Mesh &mesh = *static_cast<Mesh *>(object.data);
487 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
488 bke::SpanAttributeWriter hide_poly = attributes.lookup_or_add_for_write_span<bool>(
489 ".hide_poly", bke::AttrDomain::Face);
490
491 const Span<int> face_indices = unode.face_indices;
492
493 for (const int i : face_indices.index_range()) {
494 const int face = face_indices[i];
495 if (unode.face_hidden[i].test() != hide_poly.span[face]) {
496 unode.face_hidden[i].set(!unode.face_hidden[i].test());
497 hide_poly.span[face] = !hide_poly.span[face];
498 modified_faces[face] = true;
499 }
500 }
501 hide_poly.finish();
502}
503
504static void restore_color(Object &object,
505 StepData &step_data,
506 const MutableSpan<bool> modified_verts)
507{
508 Mesh &mesh = *static_cast<Mesh *>(object.data);
510
511 for (std::unique_ptr<Node> &unode : step_data.nodes) {
512 if (color_attribute.domain == bke::AttrDomain::Point && !unode->col.is_empty()) {
514 unode->vert_indices.as_span().take_front(unode->unique_verts_num),
515 color_attribute.span,
516 unode->col);
517 }
518 else if (color_attribute.domain == bke::AttrDomain::Corner && !unode->loop_col.is_empty()) {
519 color::swap_gathered_colors(unode->corner_indices, color_attribute.span, unode->loop_col);
520 }
521
522 modified_verts.fill_indices(unode->vert_indices.as_span(), true);
523 }
524
525 color_attribute.finish();
526}
527
528static void restore_mask_mesh(Object &object, Node &unode, const MutableSpan<bool> modified_verts)
529{
531
532 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
534 ".sculpt_mask", bke::AttrDomain::Point);
535
536 const Span<int> index = unode.vert_indices.as_span().take_front(unode.unique_verts_num);
537
538 for (const int i : index.index_range()) {
539 const int vert = index[i];
540 if (mask.span[vert] != unode.mask[i]) {
541 std::swap(mask.span[vert], unode.mask[i]);
542 modified_verts[vert] = true;
543 }
544 }
545
546 mask.finish();
547}
548
549static void restore_mask_grids(Object &object, Node &unode, const MutableSpan<bool> modified_grids)
550{
551 SculptSession &ss = *object.sculpt;
552 SubdivCCG *subdiv_ccg = ss.subdiv_ccg;
553 MutableSpan<float> masks = subdiv_ccg->masks;
554
555 const CCGKey key = BKE_subdiv_ccg_key_top_level(*subdiv_ccg);
556
557 const Span<int> grids = unode.grids;
558 MutableSpan<float> undo_mask = unode.mask;
559
560 for (const int i : grids.index_range()) {
561 MutableSpan data = masks.slice(bke::ccg::grid_range(key, grids[i]));
562 MutableSpan undo_data = undo_mask.slice(bke::ccg::grid_range(key, i));
563 for (const int offset : data.index_range()) {
564 std::swap(data[offset], undo_data[offset]);
565 }
566 }
567
568 modified_grids.fill_indices(unode.grids.as_span(), true);
569}
570
571static bool restore_face_sets(Object &object,
572 Node &unode,
573 const MutableSpan<bool> modified_face_set_faces)
574{
575 const Span<int> face_indices = unode.face_indices;
576
578 *static_cast<Mesh *>(object.data));
579 bool modified = false;
580 for (const int i : face_indices.index_range()) {
581 const int face = face_indices[i];
582 if (unode.face_sets[i] == face_sets.span[face]) {
583 continue;
584 }
585 std::swap(unode.face_sets[i], face_sets.span[face]);
586 modified_face_set_faces[face] = true;
587 modified = true;
588 }
589 face_sets.finish();
590 return modified;
591}
592
593static void bmesh_restore_generic(StepData &step_data, Object &object)
594{
595 SculptSession &ss = *object.sculpt;
596 if (step_data.needs_undo()) {
597 BM_log_undo(ss.bm, ss.bm_log);
598 step_data.tag_needs_redo();
599 }
600 else {
601 BM_log_redo(ss.bm, ss.bm_log);
602 step_data.tag_needs_undo();
603 }
604
605 if (step_data.type == Type::Mask) {
606 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
607 IndexMaskMemory memory;
608 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
609 pbvh.tag_masks_changed(node_mask);
610 bke::pbvh::update_mask_bmesh(*ss.bm, node_mask, pbvh);
611 }
612 else {
616 }
617}
618
619/* Create empty sculpt BMesh and enable logging. */
620static void bmesh_enable(Object &object, const StepData &step_data)
621{
622 SculptSession &ss = *object.sculpt;
623 Mesh *mesh = static_cast<Mesh *>(object.data);
624
627
628 /* Create empty BMesh and enable logging. */
629 BMeshCreateParams bmesh_create_params{};
630 bmesh_create_params.use_toolflags = false;
631
632 ss.bm = BM_mesh_create(&bm_mesh_allocsize_default, &bmesh_create_params);
633 BM_data_layer_add_named(ss.bm, &ss.bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
634
636
637 /* Restore the BMLog using saved entries. */
639}
640
641static void bmesh_handle_dyntopo_begin(bContext *C, StepData &step_data, Object &object)
642{
643 if (step_data.needs_undo()) {
644 dyntopo::disable(C, &step_data);
645 step_data.tag_needs_redo();
646 }
647 else /* needs_redo */ {
648 SculptSession &ss = *object.sculpt;
649 bmesh_enable(object, step_data);
650
651 /* Restore the mesh from the first log entry. */
652 BM_log_redo(ss.bm, ss.bm_log);
653
654 step_data.tag_needs_undo();
655 }
656}
657
658static void bmesh_handle_dyntopo_end(bContext *C, StepData &step_data, Object &object)
659{
660 if (step_data.needs_undo()) {
661 SculptSession &ss = *object.sculpt;
662 bmesh_enable(object, step_data);
663
664 /* Restore the mesh from the last log entry. */
665 BM_log_undo(ss.bm, ss.bm_log);
666
667 step_data.tag_needs_redo();
668 }
669 else /* needs_redo */ {
670 /* Disable dynamic topology sculpting. */
671 dyntopo::disable(C, nullptr);
672 step_data.tag_needs_undo();
673 }
674}
675
677{
678 const Mesh *mesh = static_cast<const Mesh *>(object.data);
679
680 BLI_assert(!geometry->is_initialized);
681 geometry->is_initialized = true;
682
684 &mesh->vert_data, &geometry->vert_data, CD_MASK_MESH.vmask, mesh->verts_num);
686 &mesh->edge_data, &geometry->edge_data, CD_MASK_MESH.emask, mesh->edges_num);
688 &mesh->corner_data, &geometry->corner_data, CD_MASK_MESH.lmask, mesh->corners_num);
690 &mesh->face_data, &geometry->face_data, CD_MASK_MESH.pmask, mesh->faces_num);
691 implicit_sharing::copy_shared_pointer(mesh->face_offset_indices,
692 mesh->runtime->face_offsets_sharing_info,
693 &geometry->face_offset_indices,
694 &geometry->face_offsets_sharing_info);
695
696 geometry->verts_num = mesh->verts_num;
697 geometry->edges_num = mesh->edges_num;
698 geometry->corners_num = mesh->corners_num;
699 geometry->faces_num = mesh->faces_num;
700}
701
703{
704 BLI_assert(geometry->is_initialized);
705
707
708 mesh->verts_num = geometry->verts_num;
709 mesh->edges_num = geometry->edges_num;
710 mesh->corners_num = geometry->corners_num;
711 mesh->faces_num = geometry->faces_num;
712 mesh->totface_legacy = 0;
713
715 &geometry->vert_data, &mesh->vert_data, CD_MASK_MESH.vmask, geometry->verts_num);
717 &geometry->edge_data, &mesh->edge_data, CD_MASK_MESH.emask, geometry->edges_num);
719 &geometry->corner_data, &mesh->corner_data, CD_MASK_MESH.lmask, geometry->corners_num);
721 &geometry->face_data, &mesh->face_data, CD_MASK_MESH.pmask, geometry->faces_num);
723 geometry->face_offsets_sharing_info,
724 &mesh->face_offset_indices,
725 &mesh->runtime->face_offsets_sharing_info);
726}
727
729{
730 CustomData_free(&geometry->vert_data);
731 CustomData_free(&geometry->edge_data);
732 CustomData_free(&geometry->corner_data);
733 CustomData_free(&geometry->face_data);
734 implicit_sharing::free_shared_data(&geometry->face_offset_indices,
735 &geometry->face_offsets_sharing_info);
736}
737
738static void restore_geometry(StepData &step_data, Object &object)
739{
742
743 Mesh *mesh = static_cast<Mesh *>(object.data);
744
745 if (step_data.needs_undo()) {
747 step_data.tag_needs_redo();
748 }
749 else {
751 step_data.tag_needs_undo();
752 }
753}
754
755/* Handle all dynamic-topology updates
756 *
757 * Returns true if this was a dynamic-topology undo step, otherwise
758 * returns false to indicate the non-dyntopo code should run. */
759static int bmesh_restore(bContext *C, Depsgraph &depsgraph, StepData &step_data, Object &object)
760{
761 SculptSession &ss = *object.sculpt;
762 switch (step_data.type) {
765 bmesh_handle_dyntopo_begin(C, step_data, object);
766 return true;
767
768 case Type::DyntopoEnd:
770 bmesh_handle_dyntopo_end(C, step_data, object);
771 return true;
772 default:
773 if (ss.bm_log) {
775 bmesh_restore_generic(step_data, object);
776 return true;
777 }
778 break;
779 }
780
781 return false;
782}
783
788
790{
791 return get_step_data()->bmesh.bm_entry;
792}
793
794/* Geometry updates (such as Apply Base, for example) will re-evaluate the object and refine its
795 * Subdiv descriptor. Upon undo it is required that mesh, grids, and subdiv all stay consistent
796 * with each other. This means that when geometry coordinate changes the undo should refine the
797 * subdiv to the new coarse mesh coordinates. Tricky part is: this needs to happen without using
798 * dependency graph tag: tagging object for geometry update will either loose sculpted data from
799 * the sculpt grids, or will wrongly "commit" them to the CD_MDISPS.
800 *
801 * So what we do instead is do minimum object evaluation to get base mesh coordinates for the
802 * multires modifier input. While this is expensive, it is less expensive than dependency graph
803 * evaluation and is only happening when geometry coordinates changes on undo.
804 *
805 * Note that the dependency graph is ensured to be evaluated prior to the undo step is decoded,
806 * so if the object's modifier stack references other object it is all fine. */
807static void refine_subdiv(Depsgraph *depsgraph,
808 const SculptSession &ss,
809 Object &object,
810 bke::subdiv::Subdiv *subdiv)
811{
813 depsgraph, &object, ss.multires.modifier);
814
816 subdiv, static_cast<const Mesh *>(object.data), deformed_verts);
817}
818
819static void restore_list(bContext *C, Depsgraph *depsgraph, StepData &step_data)
820{
821 Scene *scene = CTX_data_scene(C);
822 ViewLayer *view_layer = CTX_data_view_layer(C);
824 BKE_view_layer_synced_ensure(scene, view_layer);
825 Object &object = *BKE_view_layer_active_object_get(view_layer);
826 if (step_data.object_name != object.id.name) {
827 return;
828 }
829 SculptSession &ss = *object.sculpt;
830 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
831
832 /* Restore pivot. */
833 ss.pivot_pos = step_data.pivot_pos;
834 ss.pivot_rot = step_data.pivot_rot;
835
836 if (bmesh_restore(C, *depsgraph, step_data, object)) {
837 return;
838 }
839
840 /* Switching to sculpt mode does not push a particular type.
841 * See #124484. */
842 /* TODO: Add explicit type for switching into Sculpt Mode. */
843 if (step_data.type == Type::None && step_data.nodes.is_empty()) {
844 return;
845 }
846
847 /* Adding multires via the `subdivision_set` operator results in the subsequent undo step
848 * not correctly performing a global undo step; we exit early here to avoid crashing.
849 * See: #131478 */
850 const bool multires_undo_step = use_multires_undo(step_data, ss);
851 if ((multires_undo_step && pbvh.type() != bke::pbvh::Type::Grids) ||
852 (!multires_undo_step && pbvh.type() != bke::pbvh::Type::Mesh))
853 {
854 CLOG_WARN(&LOG,
855 "Undo step type and sculpt geometry type do not match: skipping undo state restore");
856 return;
857 }
858
859 const bool tag_update = ID_REAL_USERS(object.data) > 1 ||
860 !BKE_sculptsession_use_pbvh_draw(&object, rv3d) || ss.shapekey_active ||
862
863 switch (step_data.type) {
864 case Type::None: {
866 break;
867 }
868 case Type::Position: {
869 IndexMaskMemory memory;
870 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
871
873 if (!topology_matches(step_data, object)) {
874 return;
875 }
876
877 if (use_multires_undo(step_data, ss)) {
879 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
880 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
881
882 Array<bool> modified_grids(subdiv_ccg.grids_num, false);
883 for (std::unique_ptr<Node> &unode : step_data.nodes) {
884 restore_position_grids(subdiv_ccg.positions, key, *unode, modified_grids);
885 }
886 const IndexMask changed_nodes = IndexMask::from_predicate(
887 node_mask, GrainSize(1), memory, [&](const int i) {
888 return indices_contain_true(modified_grids, nodes[i].grids());
889 });
890 pbvh.tag_positions_changed(changed_nodes);
892 }
893 else {
895 if (!restore_active_shape_key(*C, *depsgraph, step_data, object)) {
896 return;
897 }
898 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
899 Array<bool> modified_verts(mesh.verts_num, false);
900 restore_position_mesh(object, step_data.nodes, modified_verts);
901
902 const IndexMask changed_nodes = IndexMask::from_predicate(
903 node_mask, GrainSize(1), memory, [&](const int i) {
904 return indices_contain_true(modified_verts, nodes[i].all_verts());
905 });
906 pbvh.tag_positions_changed(changed_nodes);
907 }
908
909 if (tag_update) {
910 Mesh &mesh = *static_cast<Mesh *>(object.data);
911 mesh.tag_positions_changed();
913 }
914 else {
915 Mesh &mesh = *static_cast<Mesh *>(object.data);
916 /* The BVH normals recalculation that will happen later (caused by
917 * `pbvh.tag_positions_changed`) won't recalculate the face corner normals.
918 * We need to manually clear that cache. */
919 mesh.runtime->corner_normals_cache.tag_dirty();
920 }
921 pbvh.update_bounds(*depsgraph, object);
923 break;
924 }
925 case Type::HideVert: {
926 IndexMaskMemory memory;
927 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
928
930 if (!topology_matches(step_data, object)) {
931 return;
932 }
933
934 if (use_multires_undo(step_data, ss)) {
936 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
937 Array<bool> modified_grids(subdiv_ccg.grids_num, false);
938 for (std::unique_ptr<Node> &unode : step_data.nodes) {
939 restore_vert_visibility_grids(subdiv_ccg, *unode, modified_grids);
940 }
941 const IndexMask changed_nodes = IndexMask::from_predicate(
942 node_mask, GrainSize(1), memory, [&](const int i) {
943 return indices_contain_true(modified_grids, nodes[i].grids());
944 });
945 pbvh.tag_visibility_changed(changed_nodes);
946 }
947 else {
949 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
950 Array<bool> modified_verts(mesh.verts_num, false);
951 for (std::unique_ptr<Node> &unode : step_data.nodes) {
952 restore_vert_visibility_mesh(object, *unode, modified_verts);
953 }
954 const IndexMask changed_nodes = IndexMask::from_predicate(
955 node_mask, GrainSize(1), memory, [&](const int i) {
956 return indices_contain_true(modified_verts, nodes[i].all_verts());
957 });
958 pbvh.tag_visibility_changed(changed_nodes);
959 }
960
962 pbvh.update_visibility(object);
963 if (BKE_sculpt_multires_active(scene, &object)) {
965 }
966 break;
967 }
968 case Type::HideFace: {
969 IndexMaskMemory memory;
970 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
971
973 if (!topology_matches(step_data, object)) {
974 return;
975 }
976
977 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
978 Array<bool> modified_faces(mesh.faces_num, false);
979 for (std::unique_ptr<Node> &unode : step_data.nodes) {
980 restore_hidden_face(object, *unode, modified_faces);
981 }
982
983 if (use_multires_undo(step_data, ss)) {
985 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
986 const IndexMask changed_nodes = IndexMask::from_predicate(
987 node_mask, GrainSize(1), memory, [&](const int i) {
988 Vector<int> faces_vector;
990 subdiv_ccg, nodes[i], faces_vector);
991 return indices_contain_true(modified_faces, faces);
992 });
993 pbvh.tag_visibility_changed(changed_nodes);
994 }
995 else {
997 const IndexMask changed_nodes = IndexMask::from_predicate(
998 node_mask, GrainSize(1), memory, [&](const int i) {
999 return indices_contain_true(modified_faces, nodes[i].faces());
1000 });
1001 pbvh.tag_visibility_changed(changed_nodes);
1002 }
1003
1005 pbvh.update_visibility(object);
1006 break;
1007 }
1008 case Type::Mask: {
1009 IndexMaskMemory memory;
1010 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1011
1013 if (!topology_matches(step_data, object)) {
1014 return;
1015 }
1016
1017 if (use_multires_undo(step_data, ss)) {
1019 Array<bool> modified_grids(ss.subdiv_ccg->grids_num, false);
1020 for (std::unique_ptr<Node> &unode : step_data.nodes) {
1021 restore_mask_grids(object, *unode, modified_grids);
1022 }
1023 const IndexMask changed_nodes = IndexMask::from_predicate(
1024 node_mask, GrainSize(1), memory, [&](const int i) {
1025 return indices_contain_true(modified_grids, nodes[i].grids());
1026 });
1027 bke::pbvh::update_mask_grids(*ss.subdiv_ccg, changed_nodes, pbvh);
1028 pbvh.tag_masks_changed(changed_nodes);
1029 }
1030 else {
1032 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
1033 Array<bool> modified_verts(mesh.verts_num, false);
1034 for (std::unique_ptr<Node> &unode : step_data.nodes) {
1035 restore_mask_mesh(object, *unode, modified_verts);
1036 }
1037 const IndexMask changed_nodes = IndexMask::from_predicate(
1038 node_mask, GrainSize(1), memory, [&](const int i) {
1039 return indices_contain_true(modified_verts, nodes[i].all_verts());
1040 });
1041 bke::pbvh::update_mask_mesh(mesh, changed_nodes, pbvh);
1042 pbvh.tag_masks_changed(changed_nodes);
1043 }
1044 break;
1045 }
1046 case Type::FaceSet: {
1047 IndexMaskMemory memory;
1048 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1049
1051 if (!topology_matches(step_data, object)) {
1052 return;
1053 }
1054
1055 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
1056 Array<bool> modified_faces(mesh.faces_num, false);
1057 for (std::unique_ptr<Node> &unode : step_data.nodes) {
1058 restore_face_sets(object, *unode, modified_faces);
1059 }
1060 if (use_multires_undo(step_data, ss)) {
1062 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1063 const IndexMask changed_nodes = IndexMask::from_predicate(
1064 node_mask, GrainSize(1), memory, [&](const int i) {
1065 Vector<int> faces_vector;
1067 subdiv_ccg, nodes[i], faces_vector);
1068 return indices_contain_true(modified_faces, faces);
1069 });
1070 pbvh.tag_face_sets_changed(changed_nodes);
1071 }
1072 else {
1074 const IndexMask changed_nodes = IndexMask::from_predicate(
1075 node_mask, GrainSize(1), memory, [&](const int i) {
1076 return indices_contain_true(modified_faces, nodes[i].faces());
1077 });
1078 pbvh.tag_face_sets_changed(changed_nodes);
1079 }
1080 break;
1081 }
1082 case Type::Color: {
1083 IndexMaskMemory memory;
1084 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1085
1087 if (!topology_matches(step_data, object)) {
1088 return;
1089 }
1090
1092
1093 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
1094 Array<bool> modified_verts(mesh.verts_num, false);
1095 restore_color(object, step_data, modified_verts);
1096 const IndexMask changed_nodes = IndexMask::from_predicate(
1097 node_mask, GrainSize(1), memory, [&](const int i) {
1098 return indices_contain_true(modified_verts, nodes[i].all_verts());
1099 });
1100 pbvh.tag_attribute_changed(changed_nodes, mesh.active_color_attribute);
1101 break;
1102 }
1103 case Type::Geometry: {
1104 BLI_assert(!ss.bm);
1105
1106 restore_geometry(step_data, object);
1108 if (SubdivCCG *subdiv_ccg = ss.subdiv_ccg) {
1109 refine_subdiv(depsgraph, ss, object, subdiv_ccg->subdiv);
1110 }
1111 break;
1112 }
1113 case Type::DyntopoBegin:
1114 case Type::DyntopoEnd:
1115 /* Handled elsewhere. */
1117 break;
1118 }
1119
1121 if (tag_update) {
1123 }
1124}
1125
1126static void free_step_data(StepData &step_data)
1127{
1131 if (step_data.bmesh.bm_entry) {
1132 BM_log_entry_drop(step_data.bmesh.bm_entry);
1133 }
1134 step_data.~StepData();
1135}
1136
1143static const Node *get_node(const bke::pbvh::Node *node, const Type type)
1144{
1145 StepData *step_data = get_step_data();
1146 if (!step_data) {
1147 return nullptr;
1148 }
1149 if (step_data->type != type) {
1150 return nullptr;
1151 }
1152 /* This access does not need to be locked because this function is not expected to be called
1153 * while the per-node undo data is being pushed. In other words, this must not be called
1154 * concurrently with #push_node.*/
1155 std::unique_ptr<Node> *node_ptr = step_data->undo_nodes_by_pbvh_node.lookup_ptr(node);
1156 if (!node_ptr) {
1157 return nullptr;
1158 }
1159 return node_ptr->get();
1160}
1161
1162static void store_vert_visibility_grids(const SubdivCCG &subdiv_ccg,
1163 const bke::pbvh::GridsNode &node,
1164 Node &unode)
1165{
1166 const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
1167 if (grid_hidden.is_empty()) {
1168 return;
1169 }
1170
1171 const Span<int> grid_indices = node.grids();
1172 unode.grid_hidden = BitGroupVector<0>(grid_indices.size(), grid_hidden.group_size());
1173 for (const int i : grid_indices.index_range()) {
1174 unode.grid_hidden[i].copy_from(grid_hidden[grid_indices[i]]);
1175 }
1176}
1177
1178static void store_positions_mesh(const Depsgraph &depsgraph, const Object &object, Node &unode)
1179{
1180 const SculptSession &ss = *object.sculpt;
1182 unode.vert_indices.as_span(),
1183 unode.position.as_mutable_span());
1185 unode.vert_indices.as_span(),
1186 unode.normal.as_mutable_span());
1187
1188 if (ss.deform_modifiers_active) {
1189 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
1190 const Span<float3> orig_positions = ss.shapekey_active ? Span(static_cast<const float3 *>(
1191 ss.shapekey_active->data),
1192 mesh.verts_num) :
1193 mesh.vert_positions();
1194
1196 orig_positions, unode.vert_indices.as_span(), unode.orig_position.as_mutable_span());
1197 }
1198}
1199
1200static void store_positions_grids(const SubdivCCG &subdiv_ccg, Node &unode)
1201{
1203 subdiv_ccg, subdiv_ccg.positions.as_span(), unode.grids, unode.position.as_mutable_span());
1205 subdiv_ccg, subdiv_ccg.normals.as_span(), unode.grids, unode.normal.as_mutable_span());
1206}
1207
1208static void store_vert_visibility_mesh(const Mesh &mesh, const bke::pbvh::Node &node, Node &unode)
1209{
1210 const bke::AttributeAccessor attributes = mesh.attributes();
1211 const VArraySpan<bool> hide_vert = *attributes.lookup<bool>(".hide_vert",
1213 if (hide_vert.is_empty()) {
1214 return;
1215 }
1216
1217 const Span<int> verts = static_cast<const bke::pbvh::MeshNode &>(node).all_verts();
1218 for (const int i : verts.index_range()) {
1219 unode.vert_hidden[i].set(hide_vert[verts[i]]);
1220 }
1221}
1222
1223static void store_face_visibility(const Mesh &mesh, Node &unode)
1224{
1225 const bke::AttributeAccessor attributes = mesh.attributes();
1226 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
1227 if (hide_poly.is_empty()) {
1228 unode.face_hidden.fill(false);
1229 return;
1230 }
1231 const Span<int> faces = unode.face_indices;
1232 for (const int i : faces.index_range()) {
1233 unode.face_hidden[i].set(hide_poly[faces[i]]);
1234 }
1235}
1236
1237static void store_mask_mesh(const Mesh &mesh, Node &unode)
1238{
1239 const bke::AttributeAccessor attributes = mesh.attributes();
1240 const VArraySpan mask = *attributes.lookup<float>(".sculpt_mask", bke::AttrDomain::Point);
1241 if (mask.is_empty()) {
1242 unode.mask.fill(0.0f);
1243 }
1244 else {
1246 }
1247}
1248
1249static void store_mask_grids(const SubdivCCG &subdiv_ccg, Node &unode)
1250{
1251 if (!subdiv_ccg.masks.is_empty()) {
1253 subdiv_ccg, subdiv_ccg.masks.as_span(), unode.grids, unode.mask.as_mutable_span());
1254 }
1255 else {
1256 unode.mask.fill(0.0f);
1257 }
1258}
1259
1260static void store_color(const Mesh &mesh, const bke::pbvh::MeshNode &node, Node &unode)
1261{
1262 const OffsetIndices<int> faces = mesh.faces();
1263 const Span<int> corner_verts = mesh.corner_verts();
1264 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
1266 const GVArraySpan colors(*color_attribute);
1267
1268 /* NOTE: even with loop colors we still store (derived)
1269 * vertex colors for original data lookup. */
1270 const Span<int> verts = node.verts();
1271 unode.col.reinitialize(verts.size());
1273 faces, corner_verts, vert_to_face_map, colors, color_attribute.domain, verts, unode.col);
1274
1275 if (color_attribute.domain == bke::AttrDomain::Corner) {
1276 for (const int face : node.faces()) {
1277 for (const int corner : faces[face]) {
1278 unode.corner_indices.append(corner);
1279 }
1280 }
1281 unode.loop_col.reinitialize(unode.corner_indices.size());
1282 color::gather_colors(colors, unode.corner_indices, unode.loop_col);
1283 }
1284}
1285
1287{
1288 if (!step_data.geometry_original.is_initialized) {
1289 return &step_data.geometry_original;
1290 }
1291
1293
1294 return &step_data.geometry_modified;
1295}
1296
1297static void geometry_push(const Object &object)
1298{
1299 StepData *step_data = get_step_data();
1300
1301 step_data->type = Type::Geometry;
1302
1303 NodeGeometry *geometry = geometry_get(*step_data);
1305}
1306
1307static void store_face_sets(const Mesh &mesh, Node &unode)
1308{
1309 const bke::AttributeAccessor attributes = mesh.attributes();
1310 const VArraySpan face_sets = *attributes.lookup<int>(".sculpt_face_set", bke::AttrDomain::Face);
1311 if (face_sets.is_empty()) {
1312 unode.face_sets.fill(1);
1313 }
1314 else {
1315 gather_data_mesh(face_sets, unode.face_indices.as_span(), unode.face_sets.as_mutable_span());
1316 }
1317}
1318
1319static void fill_node_data_mesh(const Depsgraph &depsgraph,
1320 const Object &object,
1321 const bke::pbvh::MeshNode &node,
1322 const Type type,
1323 Node &unode)
1324{
1325 const SculptSession &ss = *object.sculpt;
1326 const Mesh &mesh = *static_cast<Mesh *>(object.data);
1327
1328 unode.vert_indices = node.all_verts();
1329 unode.unique_verts_num = node.verts().size();
1330
1331 const int verts_num = unode.vert_indices.size();
1332
1333 if (ELEM(type, Type::FaceSet, Type::HideFace)) {
1334 unode.face_indices = node.faces();
1335 }
1336
1337 switch (type) {
1338 case Type::None:
1340 break;
1341 case Type::Position: {
1342 unode.position.reinitialize(verts_num);
1343 /* Needed for original data lookup. */
1344 unode.normal.reinitialize(verts_num);
1345 if (ss.deform_modifiers_active) {
1346 unode.orig_position.reinitialize(verts_num);
1347 }
1348 store_positions_mesh(depsgraph, object, unode);
1349 break;
1350 }
1351 case Type::HideVert: {
1352 unode.vert_hidden.resize(unode.vert_indices.size());
1353 store_vert_visibility_mesh(mesh, node, unode);
1354 break;
1355 }
1356 case Type::HideFace: {
1357 unode.face_hidden.resize(unode.face_indices.size());
1359 break;
1360 }
1361 case Type::Mask: {
1362 unode.mask.reinitialize(verts_num);
1363 store_mask_mesh(mesh, unode);
1364 break;
1365 }
1366 case Type::Color: {
1367 store_color(mesh, node, unode);
1368 break;
1369 }
1370 case Type::DyntopoBegin:
1371 case Type::DyntopoEnd:
1372 /* Dyntopo should be handled elsewhere. */
1374 break;
1375 case Type::Geometry:
1376 /* See #geometry_push. */
1378 break;
1379 case Type::FaceSet: {
1380 unode.face_sets.reinitialize(unode.face_indices.size());
1381 store_face_sets(mesh, unode);
1382 break;
1383 }
1384 }
1385}
1386
1387static void fill_node_data_grids(const Object &object,
1388 const bke::pbvh::GridsNode &node,
1389 const Type type,
1390 Node &unode)
1391{
1392 const SculptSession &ss = *object.sculpt;
1393 const Mesh &base_mesh = *static_cast<const Mesh *>(object.data);
1394 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1395
1396 unode.grids = node.grids();
1397
1398 const int grid_area = subdiv_ccg.grid_size * subdiv_ccg.grid_size;
1399 const int verts_num = unode.grids.size() * grid_area;
1400
1401 if (ELEM(type, Type::FaceSet, Type::HideFace)) {
1403 }
1404
1405 switch (type) {
1406 case Type::None:
1408 break;
1409 case Type::Position: {
1410 unode.position.reinitialize(verts_num);
1411 /* Needed for original data lookup. */
1412 unode.normal.reinitialize(verts_num);
1413 store_positions_grids(subdiv_ccg, unode);
1414 break;
1415 }
1416 case Type::HideVert: {
1417 store_vert_visibility_grids(subdiv_ccg, node, unode);
1418 break;
1419 }
1420 case Type::HideFace: {
1421 unode.face_hidden.resize(unode.face_indices.size());
1422 store_face_visibility(base_mesh, unode);
1423 break;
1424 }
1425 case Type::Mask: {
1426 unode.mask.reinitialize(verts_num);
1427 store_mask_grids(subdiv_ccg, unode);
1428 break;
1429 }
1430 case Type::Color: {
1432 break;
1433 }
1434 case Type::DyntopoBegin:
1435 case Type::DyntopoEnd:
1436 /* Dyntopo should be handled elsewhere. */
1438 break;
1439 case Type::Geometry:
1440 /* See #geometry_push. */
1442 break;
1443 case Type::FaceSet: {
1444 unode.face_sets.reinitialize(unode.face_indices.size());
1445 store_face_sets(base_mesh, unode);
1446 break;
1447 }
1448 }
1449}
1450
1455BLI_NOINLINE static void bmesh_push(const Object &object,
1456 const bke::pbvh::BMeshNode *node,
1457 Type type)
1458{
1459 StepData *step_data = get_step_data();
1460 const SculptSession &ss = *object.sculpt;
1461
1462 std::scoped_lock lock(step_data->nodes_mutex);
1463
1464 if (step_data->nodes.is_empty()) {
1465 /* We currently need to append data here so that the overall undo system knows to indicate that
1466 * data should be flushed to the memfile */
1467 /* TODO: Once we store entering Sculpt Mode as a specific type of action, we can remove this
1468 * call. */
1469 step_data->nodes.append(std::make_unique<Node>());
1470
1471 step_data->type = type;
1472
1473 if (type == Type::DyntopoEnd) {
1474 step_data->bmesh.bm_entry = BM_log_entry_add(ss.bm_log);
1476 }
1477 else if (type == Type::DyntopoBegin) {
1478 /* Store a copy of the mesh's current vertices, loops, and
1479 * faces. A full copy like this is needed because entering
1480 * dynamic-topology immediately does topological edits
1481 * (converting faces to triangles) that the BMLog can't
1482 * fully restore from. */
1485
1486 step_data->bmesh.bm_entry = BM_log_entry_add(ss.bm_log);
1487 BM_log_all_added(ss.bm, ss.bm_log);
1488 }
1489 else {
1490 step_data->bmesh.bm_entry = BM_log_entry_add(ss.bm_log);
1491 }
1492 }
1493
1494 if (node) {
1495 const int cd_vert_mask_offset = CustomData_get_offset_named(
1496 &ss.bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
1497
1498 /* The vertices and node aren't changed, though pointers to them are stored in the log. */
1499 bke::pbvh::BMeshNode *node_mut = const_cast<bke::pbvh::BMeshNode *>(node);
1500
1501 switch (type) {
1502 case Type::None:
1504 break;
1505 case Type::Position:
1506 case Type::Mask:
1507 /* Before any vertex values get modified, ensure their
1508 * original positions are logged. */
1509 for (BMVert *vert : BKE_pbvh_bmesh_node_unique_verts(node_mut)) {
1510 BM_log_vert_before_modified(ss.bm_log, vert, cd_vert_mask_offset);
1511 }
1512 for (BMVert *vert : BKE_pbvh_bmesh_node_other_verts(node_mut)) {
1513 BM_log_vert_before_modified(ss.bm_log, vert, cd_vert_mask_offset);
1514 }
1515 break;
1516
1517 case Type::HideFace:
1518 case Type::HideVert: {
1519 for (BMVert *vert : BKE_pbvh_bmesh_node_unique_verts(node_mut)) {
1520 BM_log_vert_before_modified(ss.bm_log, vert, cd_vert_mask_offset);
1521 }
1522 for (BMVert *vert : BKE_pbvh_bmesh_node_other_verts(node_mut)) {
1523 BM_log_vert_before_modified(ss.bm_log, vert, cd_vert_mask_offset);
1524 }
1525
1526 for (BMFace *f : BKE_pbvh_bmesh_node_faces(node_mut)) {
1528 }
1529 break;
1530 }
1531
1532 case Type::DyntopoBegin:
1533 case Type::DyntopoEnd:
1534 case Type::Geometry:
1535 case Type::FaceSet:
1536 case Type::Color:
1537 break;
1538 }
1539 }
1540}
1541
1546static Node *ensure_node(StepData &step_data, const bke::pbvh::Node &node, bool &r_new)
1547{
1548 std::scoped_lock lock(step_data.nodes_mutex);
1549 r_new = false;
1550 std::unique_ptr<Node> &unode = step_data.undo_nodes_by_pbvh_node.lookup_or_add_cb(&node, [&]() {
1551 std::unique_ptr<Node> new_unode = std::make_unique<Node>();
1552 r_new = true;
1553 return new_unode;
1554 });
1555 return unode.get();
1556}
1557
1558void push_node(const Depsgraph &depsgraph,
1559 const Object &object,
1560 const bke::pbvh::Node *node,
1561 const Type type)
1562{
1563 SculptSession &ss = *object.sculpt;
1564 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1565 if (ss.bm || ELEM(type, Type::DyntopoBegin, Type::DyntopoEnd)) {
1566 bmesh_push(object, static_cast<const bke::pbvh::BMeshNode *>(node), type);
1567 return;
1568 }
1569
1570 StepData *step_data = get_step_data();
1571 BLI_assert(ELEM(step_data->type, Type::None, type));
1572 step_data->type = type;
1573
1574 bool newly_added;
1575 Node *unode = ensure_node(*step_data, *node, newly_added);
1576 if (!newly_added) {
1577 /* The node was already filled with data for this undo step. */
1578 return;
1579 }
1580
1581 ss.needs_flush_to_id = true;
1582
1583 switch (pbvh.type()) {
1586 depsgraph, object, static_cast<const bke::pbvh::MeshNode &>(*node), type, *unode);
1587 break;
1589 fill_node_data_grids(object, static_cast<const bke::pbvh::GridsNode &>(*node), type, *unode);
1590 break;
1593 break;
1594 }
1595}
1596
1597void push_nodes(const Depsgraph &depsgraph,
1598 Object &object,
1599 const IndexMask &node_mask,
1600 const Type type)
1601{
1602 SculptSession &ss = *object.sculpt;
1603
1604 ss.needs_flush_to_id = true;
1605
1606 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1607 if (ss.bm || ELEM(type, Type::DyntopoBegin, Type::DyntopoEnd)) {
1609 node_mask.foreach_index([&](const int i) { bmesh_push(object, &nodes[i], type); });
1610 return;
1611 }
1612
1613 StepData *step_data = get_step_data();
1614 BLI_assert(ELEM(step_data->type, Type::None, type));
1615 step_data->type = type;
1616
1617 switch (pbvh.type()) {
1618 case bke::pbvh::Type::Mesh: {
1621 node_mask.foreach_index([&](const int i) {
1622 bool newly_added;
1623 Node *unode = ensure_node(*step_data, nodes[i], newly_added);
1624 if (newly_added) {
1625 nodes_to_fill.append({&nodes[i], unode});
1626 }
1627 });
1628 threading::parallel_for(nodes_to_fill.index_range(), 1, [&](const IndexRange range) {
1629 for (const auto &[node, unode] : nodes_to_fill.as_span().slice(range)) {
1630 fill_node_data_mesh(depsgraph, object, *node, type, *unode);
1631 }
1632 });
1633 break;
1634 }
1638 node_mask.foreach_index([&](const int i) {
1639 bool newly_added;
1640 Node *unode = ensure_node(*step_data, nodes[i], newly_added);
1641 if (newly_added) {
1642 nodes_to_fill.append({&nodes[i], unode});
1643 }
1644 });
1645 threading::parallel_for(nodes_to_fill.index_range(), 1, [&](const IndexRange range) {
1646 for (const auto &[node, unode] : nodes_to_fill.as_span().slice(range)) {
1647 fill_node_data_grids(object, *node, type, *unode);
1648 }
1649 });
1650 break;
1651 }
1654 break;
1655 }
1656 }
1657}
1658
1659static void save_active_attribute(Object &object, SculptAttrRef *attr)
1660{
1662 attr->was_set = true;
1663 attr->domain = NO_ACTIVE_LAYER;
1664 attr->name[0] = 0;
1665 if (!mesh) {
1666 return;
1667 }
1668 const char *name = mesh->active_color_attribute;
1669 const bke::AttributeAccessor attributes = mesh->attributes();
1670 const std::optional<bke::AttributeMetaData> meta_data = attributes.lookup_meta_data(name);
1671 if (!meta_data) {
1672 return;
1673 }
1674 if (!(ATTR_DOMAIN_AS_MASK(meta_data->domain) & ATTR_DOMAIN_MASK_COLOR) ||
1675 !(CD_TYPE_AS_MASK(meta_data->data_type) & CD_MASK_COLOR_ALL))
1676 {
1677 return;
1678 }
1679 attr->domain = meta_data->domain;
1680 STRNCPY(attr->name, name);
1681 attr->type = meta_data->data_type;
1682}
1683
1689{
1690 us->data.object_name = ob.id.name;
1691
1692 if (!us->active_color_start.was_set) {
1694 }
1695
1696 /* Set end attribute in case push_end is not called,
1697 * so we don't end up with corrupted state.
1698 */
1699 if (!us->active_color_end.was_set) {
1701 us->active_color_end.was_set = false;
1702 }
1703
1704 const SculptSession &ss = *ob.sculpt;
1705
1706 us->data.pivot_pos = ss.pivot_pos;
1707 us->data.pivot_rot = ss.pivot_rot;
1708
1709 if (const KeyBlock *key = BKE_keyblock_from_object(&ob)) {
1710 us->data.active_shape_key_name = key->name;
1711 }
1712}
1713
1714void push_begin_ex(const Scene & /*scene*/, Object &ob, const char *name)
1715{
1716 UndoStack *ustack = ED_undo_stack_get();
1717
1718 /* If possible, we need to tag the object and its geometry data as 'changed in the future' in
1719 * the previous undo step if it's a memfile one. */
1721 ED_undosys_stack_memfile_id_changed_tag(ustack, static_cast<ID *>(ob.data));
1722
1723 /* Special case, we never read from this. */
1724 bContext *C = nullptr;
1725
1726 SculptUndoStep *us = reinterpret_cast<SculptUndoStep *>(
1728
1729 const SculptSession &ss = *ob.sculpt;
1730 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
1731
1732 save_common_data(ob, us);
1733
1734 switch (pbvh.type()) {
1735 case bke::pbvh::Type::Mesh: {
1736 const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
1737 us->data.mesh.verts_num = mesh.verts_num;
1738 us->data.mesh.corners_num = mesh.corners_num;
1739 break;
1740 }
1744 break;
1745 }
1747 break;
1748 }
1749 }
1750}
1751
1752void push_begin(const Scene &scene, Object &ob, const wmOperator *op)
1753{
1754 push_begin_ex(scene, ob, op->type->name);
1755}
1756
1757void push_enter_sculpt_mode(const Scene & /*scene*/, Object &ob, const wmOperator *op)
1758{
1759 UndoStack *ustack = ED_undo_stack_get();
1760
1761 /* If possible, we need to tag the object and its geometry data as 'changed in the future' in
1762 * the previous undo step if it's a memfile one. */
1764 ED_undosys_stack_memfile_id_changed_tag(ustack, static_cast<ID *>(ob.data));
1765
1766 /* Special case, we never read from this. */
1767 bContext *C = nullptr;
1768
1769 SculptUndoStep *us = reinterpret_cast<SculptUndoStep *>(
1771 save_common_data(ob, us);
1772}
1773
1774static size_t node_size_in_bytes(const Node &node)
1775{
1776 size_t size = sizeof(Node);
1777 size += node.position.as_span().size_in_bytes();
1778 size += node.orig_position.as_span().size_in_bytes();
1779 size += node.normal.as_span().size_in_bytes();
1780 size += node.col.as_span().size_in_bytes();
1781 size += node.mask.as_span().size_in_bytes();
1782 size += node.loop_col.as_span().size_in_bytes();
1785 size += node.vert_hidden.size() / 8;
1786 size += node.face_hidden.size() / 8;
1787 size += node.grids.as_span().size_in_bytes();
1788 size += node.grid_hidden.all_bits().size() / 8;
1789 size += node.face_sets.as_span().size_in_bytes();
1791 return size;
1792}
1793
1794void push_end_ex(Object &ob, const bool use_nested_undo)
1795{
1796 StepData *step_data = get_step_data();
1797
1798 /* Move undo node storage from map to vector. */
1799 step_data->nodes.reserve(step_data->undo_nodes_by_pbvh_node.size());
1800 for (std::unique_ptr<Node> &node : step_data->undo_nodes_by_pbvh_node.values()) {
1801 step_data->nodes.append(std::move(node));
1802 }
1803 step_data->undo_nodes_by_pbvh_node.clear();
1804
1805 /* We don't need normals in the undo stack. */
1806 for (std::unique_ptr<Node> &unode : step_data->nodes) {
1807 unode->normal = {};
1808 }
1809 /* TODO: When #Node.orig_positions is stored, #Node.positions is unnecessary, don't keep it in
1810 * the stored undo step. In the future the stored undo step should use a different format with
1811 * just one positions array that has a different semantic meaning depending on whether there are
1812 * deform modifiers. */
1813
1815 step_data->nodes.index_range(),
1816 16,
1817 0,
1818 [&](const IndexRange range, size_t size) {
1819 for (const int i : range) {
1820 size += node_size_in_bytes(*step_data->nodes[i]);
1821 }
1822 return size;
1823 },
1824 std::plus<size_t>());
1825
1826 /* We could remove this and enforce all callers run in an operator using 'OPTYPE_UNDO'. */
1827 wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first);
1828 if (wm->op_undo_depth == 0 || use_nested_undo) {
1829 UndoStack *ustack = ED_undo_stack_get();
1830 BKE_undosys_step_push(ustack, nullptr, nullptr);
1831 if (wm->op_undo_depth == 0) {
1833 }
1835 }
1836
1837 UndoStack *ustack = ED_undo_stack_get();
1838 SculptUndoStep *us = reinterpret_cast<SculptUndoStep *>(
1840
1841 save_active_attribute(ob, &us->active_color_end);
1842}
1843
1845{
1846 push_end_ex(ob, false);
1847}
1848
1849/* -------------------------------------------------------------------- */
1852
1853static void set_active_layer(bContext *C, const SculptAttrRef *attr)
1854{
1855 if (attr->domain == bke::AttrDomain::Auto) {
1856 return;
1857 }
1858
1861
1862 SculptAttrRef existing;
1863 save_active_attribute(*ob, &existing);
1864
1866 CustomDataLayer *layer = BKE_attribute_find(owner, attr->name, attr->type, attr->domain);
1867
1868 /* Temporary fix for #97408. This is a fundamental
1869 * bug in the undo stack; the operator code needs to push
1870 * an extra undo step before running an operator if a
1871 * non-memfile undo system is active.
1872 *
1873 * For now, detect if the layer does exist but with a different
1874 * domain and just unconvert it.
1875 */
1876 if (!layer) {
1879 if (layer) {
1881 mesh->attributes_for_write(),
1882 attr->name,
1883 attr->domain,
1884 eCustomDataType(attr->type),
1885 nullptr))
1886 {
1887 layer = BKE_attribute_find(owner, attr->name, attr->type, attr->domain);
1888 }
1889 }
1890 }
1891
1892 if (!layer) {
1893 /* Memfile undo killed the layer; re-create it. */
1894 mesh->attributes_for_write().add(
1895 attr->name, attr->domain, attr->type, bke::AttributeInitDefaultValue());
1896 layer = BKE_attribute_find(owner, attr->name, attr->type, attr->domain);
1898 }
1899
1900 if (layer) {
1902 }
1903}
1904
1905static void step_encode_init(bContext * /*C*/, UndoStep *us_p)
1906{
1907 SculptUndoStep *us = reinterpret_cast<SculptUndoStep *>(us_p);
1908 new (&us->data) StepData();
1909}
1910
1911static bool step_encode(bContext * /*C*/, Main *bmain, UndoStep *us_p)
1912{
1913 /* Dummy, encoding is done along the way by adding tiles
1914 * to the current 'SculptUndoStep' added by encode_init. */
1915 SculptUndoStep *us = reinterpret_cast<SculptUndoStep *>(us_p);
1916 us->step.data_size = us->data.undo_size;
1917
1918 if (us->data.type == Type::DyntopoEnd) {
1919 us->step.use_memfile_step = true;
1920 }
1921 us->step.is_applied = true;
1922
1923 /* We do not flush data when entering sculpt mode - this is currently indicated by Type::None */
1924 if (us->data.type != Type::None) {
1925 bmain->is_memfile_undo_flush_needed = true;
1926 }
1927
1928 return true;
1929}
1930
1932{
1933 BLI_assert(us->step.is_applied == true);
1934
1936 us->step.is_applied = false;
1937}
1938
1940{
1941 BLI_assert(us->step.is_applied == false);
1942
1944 us->step.is_applied = true;
1945}
1946
1948 Depsgraph *depsgraph,
1949 SculptUndoStep *us,
1950 const bool is_final)
1951{
1952 /* Walk forward over any applied steps of same type,
1953 * then walk back in the next loop, un-applying them. */
1954 SculptUndoStep *us_iter = us;
1955 while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) {
1956 if (us_iter->step.next->is_applied == false) {
1957 break;
1958 }
1959 us_iter = reinterpret_cast<SculptUndoStep *>(us_iter->step.next);
1960 }
1961
1962 while ((us_iter != us) || (!is_final && us_iter == us)) {
1963 BLI_assert(us_iter->step.type == us->step.type); /* Previous loop ensures this. */
1964
1967
1968 if (us_iter == us) {
1969 if (us_iter->step.prev && us_iter->step.prev->type == BKE_UNDOSYS_TYPE_SCULPT) {
1971 C, &reinterpret_cast<SculptUndoStep *>(us_iter->step.prev)->active_color_end);
1972 }
1973 break;
1974 }
1975
1976 us_iter = reinterpret_cast<SculptUndoStep *>(us_iter->step.prev);
1977 }
1978}
1979
1981{
1982 SculptUndoStep *us_iter = us;
1983 while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) {
1984 if (us_iter->step.prev->is_applied == true) {
1985 break;
1986 }
1987 us_iter = reinterpret_cast<SculptUndoStep *>(us_iter->step.prev);
1988 }
1989 while (us_iter && (us_iter->step.is_applied == false)) {
1992
1993 if (us_iter == us) {
1995 break;
1996 }
1997 us_iter = reinterpret_cast<SculptUndoStep *>(us_iter->step.next);
1998 }
1999}
2000
2001static void step_decode(
2002 bContext *C, Main *bmain, UndoStep *us_p, const eUndoStepDir dir, const bool is_final)
2003{
2004 /* NOTE: behavior for undo/redo closely matches image undo. */
2005 BLI_assert(dir != STEP_INVALID);
2006
2008
2009 /* Ensure sculpt mode. */
2010 {
2011 Scene *scene = CTX_data_scene(C);
2012 ViewLayer *view_layer = CTX_data_view_layer(C);
2013 BKE_view_layer_synced_ensure(scene, view_layer);
2014 Object *ob = BKE_view_layer_active_object_get(view_layer);
2015 if (ob && (ob->type == OB_MESH)) {
2017 /* Pass. */
2018 }
2019 else {
2020 object::mode_generic_exit(bmain, depsgraph, scene, ob);
2021
2022 /* Sculpt needs evaluated state.
2023 * NOTE: needs to be done here, as #object::mode_generic_exit will usually invalidate
2024 * (some) evaluated data. */
2026
2027 Mesh *mesh = static_cast<Mesh *>(ob->data);
2028 /* Don't add sculpt topology undo steps when reading back undo state.
2029 * The undo steps must enter/exit for us. */
2031 object_sculpt_mode_enter(*bmain, *depsgraph, *scene, *ob, true, nullptr);
2032 }
2033
2034 if (ob->sculpt) {
2035 ob->sculpt->needs_flush_to_id = true;
2036 }
2037 bmain->is_memfile_undo_flush_needed = true;
2038 }
2039 else {
2040 BLI_assert(0);
2041 return;
2042 }
2043 }
2044
2045 SculptUndoStep *us = reinterpret_cast<SculptUndoStep *>(us_p);
2046 if (dir == STEP_UNDO) {
2047 step_decode_undo(C, depsgraph, us, is_final);
2048 }
2049 else if (dir == STEP_REDO) {
2051 }
2052}
2053
2054static void step_free(UndoStep *us_p)
2055{
2056 SculptUndoStep *us = reinterpret_cast<SculptUndoStep *>(us_p);
2057 free_step_data(us->data);
2058}
2059
2060void geometry_begin(const Scene &scene, Object &ob, const wmOperator *op)
2061{
2062 geometry_begin_ex(scene, ob, op->type->name);
2063}
2064
2065void geometry_begin_ex(const Scene & /*scene*/, Object &ob, const char *name)
2066{
2067 UndoStack *ustack = ED_undo_stack_get();
2068
2069 /* If possible, we need to tag the object and its geometry data as 'changed in the future' in
2070 * the previous undo step if it's a memfile one. */
2072 ED_undosys_stack_memfile_id_changed_tag(ustack, static_cast<ID *>(ob.data));
2073
2074 /* Special case, we never read from this. */
2075 bContext *C = nullptr;
2076
2077 SculptUndoStep *us = reinterpret_cast<SculptUndoStep *>(
2079 save_common_data(ob, us);
2080 geometry_push(ob);
2081}
2082
2083static size_t calculate_node_geometry_allocated_size(const NodeGeometry &node_geometry)
2084{
2085 BLI_assert(node_geometry.is_initialized);
2086
2087 MemoryCount memory;
2089
2090 memory_counter.add_shared(node_geometry.face_offsets_sharing_info,
2091 sizeof(int) * (node_geometry.faces_num + 1));
2092
2093 CustomData_count_memory(node_geometry.corner_data, node_geometry.corners_num, memory_counter);
2094 CustomData_count_memory(node_geometry.face_data, node_geometry.faces_num, memory_counter);
2095 CustomData_count_memory(node_geometry.vert_data, node_geometry.verts_num, memory_counter);
2096 CustomData_count_memory(node_geometry.edge_data, node_geometry.edges_num, memory_counter);
2097
2098 return memory.total_bytes;
2099}
2100
2101static size_t estimate_geometry_step_size(const StepData &step_data)
2102{
2103 size_t step_size = 0;
2104
2105 /* TODO: This calculation is not entirely accurate, as the current amount of memory consumed by
2106 * Sculpt Undo is not updated when elements are evicted. Further changes to the overall undo
2107 * system would be needed to measure this accurately. */
2110
2111 return step_size;
2112}
2113
2115{
2116 geometry_push(ob);
2117
2118 StepData *step_data = get_step_data();
2119 step_data->undo_size = estimate_geometry_step_size(*step_data);
2120
2121 /* We could remove this and enforce all callers run in an operator using 'OPTYPE_UNDO'. */
2122 wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first);
2123 if (wm->op_undo_depth == 0) {
2124 UndoStack *ustack = ED_undo_stack_get();
2125 BKE_undosys_step_push(ustack, nullptr, nullptr);
2126 if (wm->op_undo_depth == 0) {
2128 }
2130 }
2131}
2132
2134{
2135 ut->name = "Sculpt";
2136 ut->poll = nullptr; /* No poll from context for now. */
2140 ut->step_free = step_free;
2141
2143
2144 ut->step_size = sizeof(SculptUndoStep);
2145}
2146
2148
2149/* -------------------------------------------------------------------- */
2168
2170{
2172 return false;
2173 }
2174
2175 const Object *object = CTX_data_active_object(C);
2176 const SculptSession *sculpt_session = object->sculpt;
2177
2178 return sculpt_session->multires.active;
2179}
2180
2182{
2183 if (!use_multires_mesh(C)) {
2184 return;
2185 }
2186
2187 const Scene &scene = *CTX_data_scene(C);
2188 Object *object = CTX_data_active_object(C);
2189
2191
2192 push_begin_ex(scene, *object, str);
2193
2194 geometry_push(*object);
2195}
2196
2198{
2199 if (!use_multires_mesh(C)) {
2200 ED_undo_push(C, str);
2201 return;
2202 }
2203
2204 Object *object = CTX_data_active_object(C);
2205
2206 geometry_push(*object);
2207
2208 push_end(*object);
2209}
2210
2212
2213} // namespace blender::ed::sculpt_paint::undo
2214
2215namespace blender::ed::sculpt_paint {
2216
2217std::optional<OrigPositionData> orig_position_data_lookup_mesh_all_verts(
2218 const Object & /*object*/, const bke::pbvh::MeshNode &node)
2219{
2220 const undo::Node *unode = undo::get_node(&node, undo::Type::Position);
2221 if (!unode) {
2222 return std::nullopt;
2223 }
2224 return OrigPositionData{unode->position.as_span(), unode->normal.as_span()};
2225}
2226
2227std::optional<OrigPositionData> orig_position_data_lookup_mesh(const Object &object,
2228 const bke::pbvh::MeshNode &node)
2229{
2230 const std::optional<OrigPositionData> result = orig_position_data_lookup_mesh_all_verts(object,
2231 node);
2232 if (!result) {
2233 return std::nullopt;
2234 }
2235 return OrigPositionData{result->positions.take_front(node.verts().size()),
2236 result->normals.take_front(node.verts().size())};
2237}
2238
2239std::optional<OrigPositionData> orig_position_data_lookup_grids(const Object & /*object*/,
2240 const bke::pbvh::GridsNode &node)
2241{
2242 const undo::Node *unode = undo::get_node(&node, undo::Type::Position);
2243 if (!unode) {
2244 return std::nullopt;
2245 }
2246 return OrigPositionData{unode->position.as_span(), unode->normal.as_span()};
2247}
2248
2250 const Set<BMVert *, 0> &verts,
2251 const MutableSpan<float3> positions,
2253{
2254 int i = 0;
2255 for (const BMVert *vert : verts) {
2256 const float *co;
2257 const float *no;
2258 BM_log_original_vert_data(&const_cast<BMLog &>(bm_log), const_cast<BMVert *>(vert), &co, &no);
2259 if (!positions.is_empty()) {
2260 positions[i] = co;
2261 }
2262 if (!normals.is_empty()) {
2263 normals[i] = no;
2264 }
2265 i++;
2266 }
2267}
2268
2269std::optional<Span<float4>> orig_color_data_lookup_mesh(const Object & /*object*/,
2270 const bke::pbvh::MeshNode &node)
2271{
2272 const undo::Node *unode = undo::get_node(&node, undo::Type::Color);
2273 if (!unode) {
2274 return std::nullopt;
2275 }
2276 return unode->col.as_span();
2277}
2278
2279std::optional<Span<int>> orig_face_set_data_lookup_mesh(const Object & /*object*/,
2280 const bke::pbvh::MeshNode &node)
2281{
2282 const undo::Node *unode = undo::get_node(&node, undo::Type::FaceSet);
2283 if (!unode) {
2284 return std::nullopt;
2285 }
2286 return unode->face_sets.as_span();
2287}
2288
2289std::optional<Span<int>> orig_face_set_data_lookup_grids(const Object & /*object*/,
2290 const bke::pbvh::GridsNode &node)
2291{
2292 const undo::Node *unode = undo::get_node(&node, undo::Type::FaceSet);
2293 if (!unode) {
2294 return std::nullopt;
2295 }
2296 return unode->face_sets.as_span();
2297}
2298
2299std::optional<Span<float>> orig_mask_data_lookup_mesh(const Object & /*object*/,
2300 const bke::pbvh::MeshNode &node)
2301{
2302 const undo::Node *unode = undo::get_node(&node, undo::Type::Mask);
2303 if (!unode) {
2304 return std::nullopt;
2305 }
2306 return unode->mask.as_span();
2307}
2308
2309std::optional<Span<float>> orig_mask_data_lookup_grids(const Object & /*object*/,
2310 const bke::pbvh::GridsNode &node)
2311{
2312 const undo::Node *unode = undo::get_node(&node, undo::Type::Mask);
2313 if (!unode) {
2314 return std::nullopt;
2315 }
2316 return unode->mask.as_span();
2317}
2318
2319} // namespace blender::ed::sculpt_paint
struct CustomDataLayer * BKE_attribute_search_for_write(AttributeOwner &owner, blender::StringRef name, eCustomDataMask type, AttrDomainMask domain_mask)
Definition attribute.cc:690
struct CustomDataLayer * BKE_attribute_find(const AttributeOwner &owner, blender::StringRef name, eCustomDataType type, blender::bke::AttrDomain domain)
Definition attribute.cc:632
@ ATTR_DOMAIN_MASK_ALL
#define ATTR_DOMAIN_MASK_COLOR
#define ATTR_DOMAIN_AS_MASK(domain)
void BKE_id_attributes_active_color_set(struct ID *id, std::optional< blender::StringRef > name)
Definition attribute.cc:986
Depsgraph * CTX_data_ensure_evaluated_depsgraph(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.
void CustomData_count_memory(const CustomData &data, int totelem, blender::MemoryCounter &memory)
int CustomData_get_offset_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
void CustomData_free(CustomData *data)
void CustomData_init_from(const CustomData *source, CustomData *dest, eCustomDataMask mask, 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:1922
KeyBlock * BKE_keyblock_find_name(Key *key, const char name[])
Definition key.cc:1949
Key * BKE_key_from_object(Object *ob)
Definition key.cc:1824
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:237
void multires_flush_sculpt_updates(Object *object)
Definition multires.cc:388
void multires_mark_as_modified(Depsgraph *depsgraph, Object *object, MultiresModifiedFlags flags)
Definition multires.cc:365
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:2928
void BKE_sculptsession_free_deformMats(SculptSession *ss)
Definition paint.cc:2096
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_sculptsession_free_pbvh(Object &object)
Definition paint.cc:2146
PaintMode BKE_paintmode_get_active_from_context(const bContext *C)
Definition paint.cc:496
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:2462
void BKE_scene_graph_evaluated_ensure(Depsgraph *depsgraph, Main *bmain)
Definition scene.cc:2623
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:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_NOINLINE
int BLI_findindex(const ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:586
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
#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
@ 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:99
UndoStack * ED_undo_stack_get()
Definition ed_undo.cc:441
void ED_undosys_stack_memfile_id_changed_tag(UndoStack *ustack, ID *id)
#define C
Definition RandGen.cpp:29
#define ND_DATA
Definition WM_types.hh:506
#define NC_OBJECT
Definition WM_types.hh:376
volatile int lock
void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const StringRef name)
BMesh const char void * data
void BM_log_all_added(BMesh *bm, BMLog *log)
Definition bmesh_log.cc:806
void BM_log_original_vert_data(BMLog *log, BMVert *v, const float **r_co, const float **r_no)
Definition bmesh_log.cc:875
void BM_log_face_modified(BMLog *log, BMFace *f)
Definition bmesh_log.cc:745
void BM_log_redo(BMesh *bm, BMLog *log)
Definition bmesh_log.cc:687
void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
Definition bmesh_log.cc:721
void BM_log_entry_drop(BMLogEntry *entry)
Definition bmesh_log.cc:595
BMLog * BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry)
Definition bmesh_log.cc:471
void BM_log_undo(BMesh *bm, BMLog *log)
Definition bmesh_log.cc:666
void BM_log_before_all_removed(BMesh *bm, BMLog *log)
Definition bmesh_log.cc:834
BMLogEntry * BM_log_entry_add(BMLog *log)
Definition bmesh_log.cc:581
const BMAllocTemplate bm_mesh_allocsize_default
Definition bmesh_mesh.cc:30
BMesh * BM_mesh_create(const BMAllocTemplate *allocsize, const BMeshCreateParams *params)
BMesh Make Mesh.
void BM_mesh_normals_update(BMesh *bm)
BPy_StructRNA * depsgraph
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
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:398
bool is_empty() const
Definition BLI_array.hh:253
static AttributeOwner from_id(ID *id)
Definition attribute.cc:43
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
constexpr int64_t size_in_bytes() const
Definition BLI_span.hh:268
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr Span take_front(int64_t n) const
Definition BLI_span.hh:193
int64_t size() const
void append(const T &value)
Span< T > as_span() const
constexpr IndexRange take_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 bool is_empty() const
Definition BLI_span.hh:509
constexpr void fill_indices(Span< IndexT > indices, const T &value) const
Definition BLI_span.hh:526
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool is_empty() const
Definition BLI_span.hh:260
int64_t size() const
Span< T > as_span() const
IndexRange index_range() const
GAttributeReader lookup(const StringRef attribute_id) const
std::optional< AttributeMetaData > lookup_meta_data(StringRef attribute_id) const
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
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_visibility_changed(const IndexMask &node_mask)
Definition pbvh.cc:570
void update_visibility(const Object &object)
Definition pbvh.cc:1395
void foreach_index(Fn &&fn) const
#define str(s)
static ushort indices[]
static float verts[][3]
static float normals[][3]
#define MAX_CUSTOMDATA_LAYER_NAME
#define CD_MASK_PROP_ALL
#define CD_MASK_COLOR_ALL
#define ID_REAL_USERS(id)
#define LOG(severity)
Definition log.h:32
static char faces[256]
IndexRange grid_range(const int grid_area, const int grid)
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:2912
void update_mask_bmesh(const BMesh &bm, const IndexMask &node_mask, Tree &pbvh)
Definition pbvh.cc:1312
void update_mask_mesh(const Mesh &mesh, const IndexMask &node_mask, Tree &pbvh)
Definition pbvh.cc:1248
IndexMask all_leaf_nodes(const Tree &pbvh, IndexMaskMemory &memory)
Definition pbvh.cc:2544
Span< float3 > vert_normals_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2435
void update_mask_grids(const SubdivCCG &subdiv_ccg, const IndexMask &node_mask, Tree &pbvh)
Definition pbvh.cc:1279
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
bool eval_refine_from_mesh(Subdiv *subdiv, const Mesh *mesh, Span< float3 > coarse_vert_positions)
bool convert_attribute(AttributeOwner &owner, bke::MutableAttributeAccessor attributes, const StringRef name, const bke::AttrDomain dst_domain, const eCustomDataType dst_type, ReportList *reports)
void mode_generic_exit(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
bke::GSpanAttributeWriter active_color_attribute_for_write(Mesh &mesh)
void gather_colors_vert(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face_map, GSpan color_attribute, bke::AttrDomain color_domain, Span< int > verts, MutableSpan< float4 > r_colors)
void gather_colors(GSpan color_attribute, Span< int > indices, MutableSpan< float4 > r_colors)
void swap_gathered_colors(Span< int > indices, GMutableSpan color_attribute, MutableSpan< float4 > r_colors)
bke::GAttributeReader active_color_attribute(const Mesh &mesh)
static void disable(Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob, undo::StepData *undo_step)
bke::SpanAttributeWriter< int > ensure_face_sets_mesh(Mesh &mesh)
void sync_all_from_faces(Object &object)
Definition paint_hide.cc:57
static void save_active_attribute(Object &object, SculptAttrRef *attr)
static void bmesh_enable(Object &object, const StepData &step_data)
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 step_decode(bContext *C, Main *bmain, UndoStep *us_p, const eUndoStepDir dir, const bool is_final)
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 refine_subdiv(Depsgraph *depsgraph, const SculptSession &ss, Object &object, bke::subdiv::Subdiv *subdiv)
static void bmesh_handle_dyntopo_end(bContext *C, StepData &step_data, Object &object)
static void restore_position_grids(const MutableSpan< float3 > positions, const CCGKey &key, Node &unode, const MutableSpan< bool > modified_grids)
static void restore_vert_visibility_mesh(Object &object, Node &unode, const MutableSpan< bool > modified_verts)
static void step_encode_init(bContext *, UndoStep *us_p)
static size_t estimate_geometry_step_size(const StepData &step_data)
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)
void push_enter_sculpt_mode(const Scene &, Object &ob, const wmOperator *op)
static StepData * get_step_data()
static void store_vert_visibility_mesh(const Mesh &mesh, const bke::pbvh::Node &node, Node &unode)
static void set_active_layer(bContext *C, const SculptAttrRef *attr)
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)
static void restore_hidden_face(Object &object, Node &unode, const MutableSpan< bool > modified_faces)
void geometry_begin_ex(const Scene &scene, Object &ob, const char *name)
static void step_free(UndoStep *us_p)
static const Node * get_node(const bke::pbvh::Node *node, const Type type)
static bool step_encode(bContext *, Main *bmain, UndoStep *us_p)
static void restore_vert_visibility_grids(SubdivCCG &subdiv_ccg, Node &unode, const MutableSpan< bool > modified_grids)
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)
static void save_common_data(Object &ob, SculptUndoStep *us)
void geometry_begin(const Scene &scene, Object &ob, const wmOperator *op)
static void restore_mask_grids(Object &object, Node &unode, const 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 step_decode_redo(bContext *C, Depsgraph *depsgraph, SculptUndoStep *us)
static void restore_color(Object &object, StepData &step_data, const MutableSpan< bool > modified_verts)
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)
static void restore_position_mesh(Object &object, const Span< std::unique_ptr< Node > > unodes, const MutableSpan< bool > modified_verts)
void push_node(const Depsgraph &depsgraph, const Object &object, const bke::pbvh::Node *node, const Type type)
static bool restore_active_shape_key(bContext &C, Depsgraph &depsgraph, const StepData &step_data, Object &object)
static void restore_mask_mesh(Object &object, Node &unode, const MutableSpan< bool > modified_verts)
static void store_color(const Mesh &mesh, const bke::pbvh::MeshNode &node, Node &unode)
void push_begin(const Scene &scene, Object &ob, const wmOperator *op)
void restore_from_bmesh_enter_geometry(const StepData &step_data, Mesh &mesh)
static void store_face_sets(const Mesh &mesh, Node &unode)
static bool restore_face_sets(Object &object, Node &unode, const MutableSpan< bool > modified_face_set_faces)
static int bmesh_restore(bContext *C, Depsgraph &depsgraph, StepData &step_data, Object &object)
static size_t calculate_node_geometry_allocated_size(const NodeGeometry &node_geometry)
void push_end_ex(Object &ob, const bool use_nested_undo)
static void swap_indexed_data(MutableSpan< T > full, const Span< int > indices, MutableSpan< T > indexed)
static void restore_geometry(StepData &step_data, Object &object)
static void bmesh_handle_dyntopo_begin(bContext *C, StepData &step_data, Object &object)
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:6389
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:6379
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 copy_shared_pointer(T *src_ptr, const ImplicitSharingInfo *src_sharing_info, T **r_dst_ptr, const ImplicitSharingInfo **r_dst_sharing_info)
void free_shared_data(T **data, const ImplicitSharingInfo **sharing_info)
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
VecBase< float, 4 > float4
std::mutex Mutex
Definition BLI_mutex.hh:47
VecBase< float, 3 > float3
#define NO_ACTIVE_LAYER
CustomData vdata
Definition DNA_ID.h:404
char name[66]
Definition DNA_ID.h:415
char name[64]
void * data
ListBase block
bool is_memfile_undo_flush_needed
Definition BKE_main.hh:185
struct SculptSession * sculpt
bool needs_flush_to_id
Definition BKE_paint.hh:521
BMLog * bm_log
Definition BKE_paint.hh:412
KeyBlock * shapekey_active
Definition BKE_paint.hh:397
blender::float4 pivot_rot
Definition BKE_paint.hh:487
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:415
struct SculptSession::@160233021176123211313176342066311124252220006052 multires
blender::float3 pivot_pos
Definition BKE_paint.hh:486
MultiresModifierData * modifier
Definition BKE_paint.hh:393
bool deform_modifiers_active
Definition BKE_paint.hh:421
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)
Span< int > all_verts() const
static std::optional< ShapeKeyData > from_object(Object &object)
Definition sculpt.cc:7397
const ImplicitSharingInfo * face_offsets_sharing_info
char name[MAX_CUSTOMDATA_LAYER_NAME]
Vector< std::unique_ptr< Node > > nodes
struct blender::ed::sculpt_paint::undo::StepData::@053046073077200031175220117327207063131001273131 mesh
Map< const bke::pbvh::Node *, std::unique_ptr< Node > > undo_nodes_by_pbvh_node
struct blender::ed::sculpt_paint::undo::StepData::@101023235205051017342327362236310150357270120007 bmesh
struct blender::ed::sculpt_paint::undo::StepData::@113150134257115302313257152361365210110131114324 grids
const char * name
Definition WM_types.hh:1030
struct wmOperatorType * type
i
Definition text_draw.cc:230
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void WM_file_tag_modified()
Definition wm_files.cc:174