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() && !shape_key_data) {
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.is_empty() ? unode.position :
390 unode.orig_position;
391
392 if (shape_key_data) {
393 MutableSpan<float3> active_data = shape_key_data->active_key_data;
394
395 if (!shape_key_data->dependent_keys.is_empty()) {
396 Array<float3, 1024> translations(verts.size());
397 translations_from_new_positions(undo_positions, verts, active_data, translations);
398 for (MutableSpan<float3> data : shape_key_data->dependent_keys) {
399 apply_translations(translations, verts, data);
400 }
401 }
402
403 if (shape_key_data->basis_key_active) {
404 /* The basis key positions and the mesh positions are always kept in sync. */
405 scatter_data_mesh(undo_positions.as_span(), verts, positions);
406 }
407 swap_indexed_data(undo_positions.take_front(unode.unique_verts_num), verts, active_data);
408 }
409 else {
410 /* There is a deform modifier, but no shape keys. */
411 swap_indexed_data(undo_positions.take_front(unode.unique_verts_num), verts, positions);
412 }
413 }
414 modified_verts.fill_indices(verts, true);
415 }
416 });
417}
418
419static void restore_position_grids(const MutableSpan<float3> positions,
420 const CCGKey &key,
421 Node &unode,
422 const MutableSpan<bool> modified_grids)
423{
424 const Span<int> grids = unode.grids;
425 const MutableSpan<float3> undo_position = unode.position;
426
427 for (const int i : grids.index_range()) {
428 MutableSpan data = positions.slice(bke::ccg::grid_range(key, grids[i]));
429 MutableSpan undo_data = undo_position.slice(bke::ccg::grid_range(key, i));
430 for (const int offset : data.index_range()) {
431 std::swap(data[offset], undo_data[offset]);
432 }
433 }
434
435 modified_grids.fill_indices(grids, true);
436}
437
439 Node &unode,
440 const MutableSpan<bool> modified_verts)
441{
442 Mesh &mesh = *static_cast<Mesh *>(object.data);
443 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
445 ".hide_vert", bke::AttrDomain::Point);
446 for (const int i : unode.vert_indices.index_range().take_front(unode.unique_verts_num)) {
447 const int vert = unode.vert_indices[i];
448 if (unode.vert_hidden[i].test() != hide_vert.span[vert]) {
449 unode.vert_hidden[i].set(!unode.vert_hidden[i].test());
450 hide_vert.span[vert] = !hide_vert.span[vert];
451 modified_verts[vert] = true;
452 }
453 }
454 hide_vert.finish();
455}
456
458 Node &unode,
459 const MutableSpan<bool> modified_grids)
460{
461 if (unode.grid_hidden.is_empty()) {
463 return;
464 }
465
466 BitGroupVector<> &grid_hidden = BKE_subdiv_ccg_grid_hidden_ensure(subdiv_ccg);
467 const Span<int> grids = unode.grids;
468 for (const int i : grids.index_range()) {
469 /* Swap the two bit spans. */
471 MutableBoundedBitSpan b = grid_hidden[grids[i]];
472 for (const int j : a.index_range()) {
473 const bool value_a = a[j];
474 const bool value_b = b[j];
475 a[j].set(value_b);
476 b[j].set(value_a);
477 }
478 }
479
480 modified_grids.fill_indices(grids, true);
481}
482
483static void restore_hidden_face(Object &object,
484 Node &unode,
485 const MutableSpan<bool> modified_faces)
486{
487 Mesh &mesh = *static_cast<Mesh *>(object.data);
488 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
489 bke::SpanAttributeWriter hide_poly = attributes.lookup_or_add_for_write_span<bool>(
490 ".hide_poly", bke::AttrDomain::Face);
491
492 const Span<int> face_indices = unode.face_indices;
493
494 for (const int i : face_indices.index_range()) {
495 const int face = face_indices[i];
496 if (unode.face_hidden[i].test() != hide_poly.span[face]) {
497 unode.face_hidden[i].set(!unode.face_hidden[i].test());
498 hide_poly.span[face] = !hide_poly.span[face];
499 modified_faces[face] = true;
500 }
501 }
502 hide_poly.finish();
503}
504
505static void restore_color(Object &object,
506 StepData &step_data,
507 const MutableSpan<bool> modified_verts)
508{
509 Mesh &mesh = *static_cast<Mesh *>(object.data);
511
512 for (std::unique_ptr<Node> &unode : step_data.nodes) {
513 if (color_attribute.domain == bke::AttrDomain::Point && !unode->col.is_empty()) {
515 unode->vert_indices.as_span().take_front(unode->unique_verts_num),
516 color_attribute.span,
517 unode->col);
518 }
519 else if (color_attribute.domain == bke::AttrDomain::Corner && !unode->loop_col.is_empty()) {
520 color::swap_gathered_colors(unode->corner_indices, color_attribute.span, unode->loop_col);
521 }
522
523 modified_verts.fill_indices(unode->vert_indices.as_span(), true);
524 }
525
526 color_attribute.finish();
527}
528
529static void restore_mask_mesh(Object &object, Node &unode, const MutableSpan<bool> modified_verts)
530{
532
533 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
535 ".sculpt_mask", bke::AttrDomain::Point);
536
537 const Span<int> index = unode.vert_indices.as_span().take_front(unode.unique_verts_num);
538
539 for (const int i : index.index_range()) {
540 const int vert = index[i];
541 if (mask.span[vert] != unode.mask[i]) {
542 std::swap(mask.span[vert], unode.mask[i]);
543 modified_verts[vert] = true;
544 }
545 }
546
547 mask.finish();
548}
549
550static void restore_mask_grids(Object &object, Node &unode, const MutableSpan<bool> modified_grids)
551{
552 SculptSession &ss = *object.sculpt;
553 SubdivCCG *subdiv_ccg = ss.subdiv_ccg;
554 MutableSpan<float> masks = subdiv_ccg->masks;
555
556 const CCGKey key = BKE_subdiv_ccg_key_top_level(*subdiv_ccg);
557
558 const Span<int> grids = unode.grids;
559 MutableSpan<float> undo_mask = unode.mask;
560
561 for (const int i : grids.index_range()) {
562 MutableSpan data = masks.slice(bke::ccg::grid_range(key, grids[i]));
563 MutableSpan undo_data = undo_mask.slice(bke::ccg::grid_range(key, i));
564 for (const int offset : data.index_range()) {
565 std::swap(data[offset], undo_data[offset]);
566 }
567 }
568
569 modified_grids.fill_indices(unode.grids.as_span(), true);
570}
571
572static bool restore_face_sets(Object &object,
573 Node &unode,
574 const MutableSpan<bool> modified_face_set_faces)
575{
576 const Span<int> face_indices = unode.face_indices;
577
579 *static_cast<Mesh *>(object.data));
580 bool modified = false;
581 for (const int i : face_indices.index_range()) {
582 const int face = face_indices[i];
583 if (unode.face_sets[i] == face_sets.span[face]) {
584 continue;
585 }
586 std::swap(unode.face_sets[i], face_sets.span[face]);
587 modified_face_set_faces[face] = true;
588 modified = true;
589 }
590 face_sets.finish();
591 return modified;
592}
593
594static void bmesh_restore_generic(StepData &step_data, Object &object)
595{
596 SculptSession &ss = *object.sculpt;
597 if (step_data.needs_undo()) {
598 BM_log_undo(ss.bm, ss.bm_log);
599 step_data.tag_needs_redo();
600 }
601 else {
602 BM_log_redo(ss.bm, ss.bm_log);
603 step_data.tag_needs_undo();
604 }
605
606 if (step_data.type == Type::Mask) {
607 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
608 IndexMaskMemory memory;
609 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
610 pbvh.tag_masks_changed(node_mask);
611 bke::pbvh::update_mask_bmesh(*ss.bm, node_mask, pbvh);
612 }
613 else {
617 }
618}
619
620/* Create empty sculpt BMesh and enable logging. */
621static void bmesh_enable(Object &object, const StepData &step_data)
622{
623 SculptSession &ss = *object.sculpt;
624 Mesh *mesh = static_cast<Mesh *>(object.data);
625
628
629 /* Create empty BMesh and enable logging. */
630 BMeshCreateParams bmesh_create_params{};
631 bmesh_create_params.use_toolflags = false;
632
633 ss.bm = BM_mesh_create(&bm_mesh_allocsize_default, &bmesh_create_params);
634 BM_data_layer_add_named(ss.bm, &ss.bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
635
637
638 /* Restore the BMLog using saved entries. */
640}
641
642static void bmesh_handle_dyntopo_begin(bContext *C, StepData &step_data, Object &object)
643{
644 if (step_data.needs_undo()) {
645 dyntopo::disable(C, &step_data);
646 step_data.tag_needs_redo();
647 }
648 else /* needs_redo */ {
649 SculptSession &ss = *object.sculpt;
650 bmesh_enable(object, step_data);
651
652 /* Restore the mesh from the first log entry. */
653 BM_log_redo(ss.bm, ss.bm_log);
654
655 step_data.tag_needs_undo();
656 }
657}
658
659static void bmesh_handle_dyntopo_end(bContext *C, StepData &step_data, Object &object)
660{
661 if (step_data.needs_undo()) {
662 SculptSession &ss = *object.sculpt;
663 bmesh_enable(object, step_data);
664
665 /* Restore the mesh from the last log entry. */
666 BM_log_undo(ss.bm, ss.bm_log);
667
668 step_data.tag_needs_redo();
669 }
670 else /* needs_redo */ {
671 /* Disable dynamic topology sculpting. */
672 dyntopo::disable(C, nullptr);
673 step_data.tag_needs_undo();
674 }
675}
676
678{
679 const Mesh *mesh = static_cast<const Mesh *>(object.data);
680
681 BLI_assert(!geometry->is_initialized);
682 geometry->is_initialized = true;
683
685 &mesh->vert_data, &geometry->vert_data, CD_MASK_MESH.vmask, mesh->verts_num);
687 &mesh->edge_data, &geometry->edge_data, CD_MASK_MESH.emask, mesh->edges_num);
689 &mesh->corner_data, &geometry->corner_data, CD_MASK_MESH.lmask, mesh->corners_num);
691 &mesh->face_data, &geometry->face_data, CD_MASK_MESH.pmask, mesh->faces_num);
692 implicit_sharing::copy_shared_pointer(mesh->face_offset_indices,
693 mesh->runtime->face_offsets_sharing_info,
694 &geometry->face_offset_indices,
695 &geometry->face_offsets_sharing_info);
696
697 geometry->verts_num = mesh->verts_num;
698 geometry->edges_num = mesh->edges_num;
699 geometry->corners_num = mesh->corners_num;
700 geometry->faces_num = mesh->faces_num;
701}
702
704{
705 BLI_assert(geometry->is_initialized);
706
708
709 mesh->verts_num = geometry->verts_num;
710 mesh->edges_num = geometry->edges_num;
711 mesh->corners_num = geometry->corners_num;
712 mesh->faces_num = geometry->faces_num;
713 mesh->totface_legacy = 0;
714
716 &geometry->vert_data, &mesh->vert_data, CD_MASK_MESH.vmask, geometry->verts_num);
718 &geometry->edge_data, &mesh->edge_data, CD_MASK_MESH.emask, geometry->edges_num);
720 &geometry->corner_data, &mesh->corner_data, CD_MASK_MESH.lmask, geometry->corners_num);
722 &geometry->face_data, &mesh->face_data, CD_MASK_MESH.pmask, geometry->faces_num);
724 geometry->face_offsets_sharing_info,
725 &mesh->face_offset_indices,
726 &mesh->runtime->face_offsets_sharing_info);
727}
728
730{
731 CustomData_free(&geometry->vert_data);
732 CustomData_free(&geometry->edge_data);
733 CustomData_free(&geometry->corner_data);
734 CustomData_free(&geometry->face_data);
735 implicit_sharing::free_shared_data(&geometry->face_offset_indices,
736 &geometry->face_offsets_sharing_info);
737}
738
739static void restore_geometry(StepData &step_data, Object &object)
740{
743
744 Mesh *mesh = static_cast<Mesh *>(object.data);
745
746 if (step_data.needs_undo()) {
748 step_data.tag_needs_redo();
749 }
750 else {
752 step_data.tag_needs_undo();
753 }
754}
755
756/* Handle all dynamic-topology updates
757 *
758 * Returns true if this was a dynamic-topology undo step, otherwise
759 * returns false to indicate the non-dyntopo code should run. */
760static int bmesh_restore(bContext *C, Depsgraph &depsgraph, StepData &step_data, Object &object)
761{
762 SculptSession &ss = *object.sculpt;
763 switch (step_data.type) {
766 bmesh_handle_dyntopo_begin(C, step_data, object);
767 return true;
768
769 case Type::DyntopoEnd:
771 bmesh_handle_dyntopo_end(C, step_data, object);
772 return true;
773 default:
774 if (ss.bm_log) {
776 bmesh_restore_generic(step_data, object);
777 return true;
778 }
779 break;
780 }
781
782 return false;
783}
784
789
791{
792 return get_step_data()->bmesh.bm_entry;
793}
794
795/* Geometry updates (such as Apply Base, for example) will re-evaluate the object and refine its
796 * Subdiv descriptor. Upon undo it is required that mesh, grids, and subdiv all stay consistent
797 * with each other. This means that when geometry coordinate changes the undo should refine the
798 * subdiv to the new coarse mesh coordinates. Tricky part is: this needs to happen without using
799 * dependency graph tag: tagging object for geometry update will either loose sculpted data from
800 * the sculpt grids, or will wrongly "commit" them to the CD_MDISPS.
801 *
802 * So what we do instead is do minimum object evaluation to get base mesh coordinates for the
803 * multires modifier input. While this is expensive, it is less expensive than dependency graph
804 * evaluation and is only happening when geometry coordinates changes on undo.
805 *
806 * Note that the dependency graph is ensured to be evaluated prior to the undo step is decoded,
807 * so if the object's modifier stack references other object it is all fine. */
808static void refine_subdiv(Depsgraph *depsgraph,
809 const SculptSession &ss,
810 Object &object,
811 bke::subdiv::Subdiv *subdiv)
812{
814 depsgraph, &object, ss.multires.modifier);
815
817 subdiv, static_cast<const Mesh *>(object.data), deformed_verts);
818}
819
820static void restore_list(bContext *C, Depsgraph *depsgraph, StepData &step_data)
821{
822 Scene *scene = CTX_data_scene(C);
823 ViewLayer *view_layer = CTX_data_view_layer(C);
825 BKE_view_layer_synced_ensure(scene, view_layer);
826 Object &object = *BKE_view_layer_active_object_get(view_layer);
827 if (step_data.object_name != object.id.name) {
828 return;
829 }
830 SculptSession &ss = *object.sculpt;
832
833 /* Restore pivot. */
834 ss.pivot_pos = step_data.pivot_pos;
835 ss.pivot_rot = step_data.pivot_rot;
836
837 if (bmesh_restore(C, *depsgraph, step_data, object)) {
838 return;
839 }
840
841 /* Switching to sculpt mode does not push a particular type.
842 * See #124484. */
843 /* TODO: Add explicit type for switching into Sculpt Mode. */
844 if (step_data.type == Type::None && step_data.nodes.is_empty()) {
845 return;
846 }
847
848 /* Adding multires via the `subdivision_set` operator results in the subsequent undo step
849 * not correctly performing a global undo step; we exit early here to avoid crashing.
850 * See: #131478 */
851 const bool multires_undo_step = use_multires_undo(step_data, ss);
852 if ((multires_undo_step && pbvh.type() != bke::pbvh::Type::Grids) ||
853 (!multires_undo_step && pbvh.type() != bke::pbvh::Type::Mesh))
854 {
855 CLOG_WARN(&LOG,
856 "Undo step type and sculpt geometry type do not match: skipping undo state restore");
857 return;
858 }
859
860 const bool tag_update = ID_REAL_USERS(object.data) > 1 ||
861 !BKE_sculptsession_use_pbvh_draw(&object, rv3d) || ss.shapekey_active ||
863
864 switch (step_data.type) {
865 case Type::None: {
867 break;
868 }
869 case Type::Position: {
870 IndexMaskMemory memory;
871 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
872
874 if (!topology_matches(step_data, object)) {
875 return;
876 }
877
878 if (use_multires_undo(step_data, ss)) {
880 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
881 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
882
883 Array<bool> modified_grids(subdiv_ccg.grids_num, false);
884 for (std::unique_ptr<Node> &unode : step_data.nodes) {
885 restore_position_grids(subdiv_ccg.positions, key, *unode, modified_grids);
886 }
887 const IndexMask changed_nodes = IndexMask::from_predicate(
888 node_mask, GrainSize(1), memory, [&](const int i) {
889 return indices_contain_true(modified_grids, nodes[i].grids());
890 });
891 pbvh.tag_positions_changed(changed_nodes);
893 }
894 else {
896 if (!restore_active_shape_key(*C, *depsgraph, step_data, object)) {
897 return;
898 }
899 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
900 Array<bool> modified_verts(mesh.verts_num, false);
901 restore_position_mesh(object, step_data.nodes, modified_verts);
902
903 const IndexMask changed_nodes = IndexMask::from_predicate(
904 node_mask, GrainSize(1), memory, [&](const int i) {
905 return indices_contain_true(modified_verts, nodes[i].all_verts());
906 });
907 pbvh.tag_positions_changed(changed_nodes);
908 }
909
910 if (tag_update) {
911 Mesh &mesh = *static_cast<Mesh *>(object.data);
912 mesh.tag_positions_changed();
914 }
915 else {
916 Mesh &mesh = *static_cast<Mesh *>(object.data);
917 /* The BVH normals recalculation that will happen later (caused by
918 * `pbvh.tag_positions_changed`) won't recalculate the face corner normals.
919 * We need to manually clear that cache. */
920 mesh.runtime->corner_normals_cache.tag_dirty();
921 }
922 pbvh.update_bounds(*depsgraph, object);
924 break;
925 }
926 case Type::HideVert: {
927 IndexMaskMemory memory;
928 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
929
931 if (!topology_matches(step_data, object)) {
932 return;
933 }
934
935 if (use_multires_undo(step_data, ss)) {
937 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
938 Array<bool> modified_grids(subdiv_ccg.grids_num, false);
939 for (std::unique_ptr<Node> &unode : step_data.nodes) {
940 restore_vert_visibility_grids(subdiv_ccg, *unode, modified_grids);
941 }
942 const IndexMask changed_nodes = IndexMask::from_predicate(
943 node_mask, GrainSize(1), memory, [&](const int i) {
944 return indices_contain_true(modified_grids, nodes[i].grids());
945 });
946 pbvh.tag_visibility_changed(changed_nodes);
947 }
948 else {
950 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
951 Array<bool> modified_verts(mesh.verts_num, false);
952 for (std::unique_ptr<Node> &unode : step_data.nodes) {
953 restore_vert_visibility_mesh(object, *unode, modified_verts);
954 }
955 const IndexMask changed_nodes = IndexMask::from_predicate(
956 node_mask, GrainSize(1), memory, [&](const int i) {
957 return indices_contain_true(modified_verts, nodes[i].all_verts());
958 });
959 pbvh.tag_visibility_changed(changed_nodes);
960 }
961
963 pbvh.update_visibility(object);
964 if (BKE_sculpt_multires_active(scene, &object)) {
966 }
967 break;
968 }
969 case Type::HideFace: {
970 IndexMaskMemory memory;
971 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
972
974 if (!topology_matches(step_data, object)) {
975 return;
976 }
977
978 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
979 Array<bool> modified_faces(mesh.faces_num, false);
980 for (std::unique_ptr<Node> &unode : step_data.nodes) {
981 restore_hidden_face(object, *unode, modified_faces);
982 }
983
984 if (use_multires_undo(step_data, ss)) {
986 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
987 const IndexMask changed_nodes = IndexMask::from_predicate(
988 node_mask, GrainSize(1), memory, [&](const int i) {
989 Vector<int> faces_vector;
991 subdiv_ccg, nodes[i], faces_vector);
992 return indices_contain_true(modified_faces, faces);
993 });
994 pbvh.tag_visibility_changed(changed_nodes);
995 }
996 else {
998 const IndexMask changed_nodes = IndexMask::from_predicate(
999 node_mask, GrainSize(1), memory, [&](const int i) {
1000 return indices_contain_true(modified_faces, nodes[i].faces());
1001 });
1002 pbvh.tag_visibility_changed(changed_nodes);
1003 }
1004
1006 pbvh.update_visibility(object);
1007 break;
1008 }
1009 case Type::Mask: {
1010 IndexMaskMemory memory;
1011 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1012
1014 if (!topology_matches(step_data, object)) {
1015 return;
1016 }
1017
1018 if (use_multires_undo(step_data, ss)) {
1020 Array<bool> modified_grids(ss.subdiv_ccg->grids_num, false);
1021 for (std::unique_ptr<Node> &unode : step_data.nodes) {
1022 restore_mask_grids(object, *unode, modified_grids);
1023 }
1024 const IndexMask changed_nodes = IndexMask::from_predicate(
1025 node_mask, GrainSize(1), memory, [&](const int i) {
1026 return indices_contain_true(modified_grids, nodes[i].grids());
1027 });
1028 bke::pbvh::update_mask_grids(*ss.subdiv_ccg, changed_nodes, pbvh);
1029 pbvh.tag_masks_changed(changed_nodes);
1030 }
1031 else {
1033 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
1034 Array<bool> modified_verts(mesh.verts_num, false);
1035 for (std::unique_ptr<Node> &unode : step_data.nodes) {
1036 restore_mask_mesh(object, *unode, modified_verts);
1037 }
1038 const IndexMask changed_nodes = IndexMask::from_predicate(
1039 node_mask, GrainSize(1), memory, [&](const int i) {
1040 return indices_contain_true(modified_verts, nodes[i].all_verts());
1041 });
1042 bke::pbvh::update_mask_mesh(mesh, changed_nodes, pbvh);
1043 pbvh.tag_masks_changed(changed_nodes);
1044 }
1045 break;
1046 }
1047 case Type::FaceSet: {
1048 IndexMaskMemory memory;
1049 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1050
1052 if (!topology_matches(step_data, object)) {
1053 return;
1054 }
1055
1056 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
1057 Array<bool> modified_faces(mesh.faces_num, false);
1058 for (std::unique_ptr<Node> &unode : step_data.nodes) {
1059 restore_face_sets(object, *unode, modified_faces);
1060 }
1061 if (use_multires_undo(step_data, ss)) {
1063 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1064 const IndexMask changed_nodes = IndexMask::from_predicate(
1065 node_mask, GrainSize(1), memory, [&](const int i) {
1066 Vector<int> faces_vector;
1068 subdiv_ccg, nodes[i], faces_vector);
1069 return indices_contain_true(modified_faces, faces);
1070 });
1071 pbvh.tag_face_sets_changed(changed_nodes);
1072 }
1073 else {
1075 const IndexMask changed_nodes = IndexMask::from_predicate(
1076 node_mask, GrainSize(1), memory, [&](const int i) {
1077 return indices_contain_true(modified_faces, nodes[i].faces());
1078 });
1079 pbvh.tag_face_sets_changed(changed_nodes);
1080 }
1081 break;
1082 }
1083 case Type::Color: {
1084 IndexMaskMemory memory;
1085 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1086
1088 if (!topology_matches(step_data, object)) {
1089 return;
1090 }
1091
1093
1094 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
1095 Array<bool> modified_verts(mesh.verts_num, false);
1096 restore_color(object, step_data, modified_verts);
1097 const IndexMask changed_nodes = IndexMask::from_predicate(
1098 node_mask, GrainSize(1), memory, [&](const int i) {
1099 return indices_contain_true(modified_verts, nodes[i].all_verts());
1100 });
1101 pbvh.tag_attribute_changed(changed_nodes, mesh.active_color_attribute);
1102 break;
1103 }
1104 case Type::Geometry: {
1105 BLI_assert(!ss.bm);
1106
1107 restore_geometry(step_data, object);
1109 if (SubdivCCG *subdiv_ccg = ss.subdiv_ccg) {
1110 refine_subdiv(depsgraph, ss, object, subdiv_ccg->subdiv);
1111 }
1112 break;
1113 }
1114 case Type::DyntopoBegin:
1115 case Type::DyntopoEnd:
1116 /* Handled elsewhere. */
1118 break;
1119 }
1120
1122 if (tag_update) {
1124 }
1125}
1126
1127static void free_step_data(StepData &step_data)
1128{
1132 if (step_data.bmesh.bm_entry) {
1133 BM_log_entry_drop(step_data.bmesh.bm_entry);
1134 }
1135 step_data.~StepData();
1136}
1137
1144static const Node *get_node(const bke::pbvh::Node *node, const Type type)
1145{
1146 StepData *step_data = get_step_data();
1147 if (!step_data) {
1148 return nullptr;
1149 }
1150 if (step_data->type != type) {
1151 return nullptr;
1152 }
1153 /* This access does not need to be locked because this function is not expected to be called
1154 * while the per-node undo data is being pushed. In other words, this must not be called
1155 * concurrently with #push_node.*/
1156 std::unique_ptr<Node> *node_ptr = step_data->undo_nodes_by_pbvh_node.lookup_ptr(node);
1157 if (!node_ptr) {
1158 return nullptr;
1159 }
1160 return node_ptr->get();
1161}
1162
1163static void store_vert_visibility_grids(const SubdivCCG &subdiv_ccg,
1164 const bke::pbvh::GridsNode &node,
1165 Node &unode)
1166{
1167 const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
1168 if (grid_hidden.is_empty()) {
1169 return;
1170 }
1171
1172 const Span<int> grid_indices = node.grids();
1173 unode.grid_hidden = BitGroupVector<0>(grid_indices.size(), grid_hidden.group_size());
1174 for (const int i : grid_indices.index_range()) {
1175 unode.grid_hidden[i].copy_from(grid_hidden[grid_indices[i]]);
1176 }
1177}
1178
1179static void store_positions_mesh(const Depsgraph &depsgraph, const Object &object, Node &unode)
1180{
1181 const SculptSession &ss = *object.sculpt;
1183 unode.vert_indices.as_span(),
1184 unode.position.as_mutable_span());
1186 unode.vert_indices.as_span(),
1187 unode.normal.as_mutable_span());
1188
1189 if (ss.deform_modifiers_active) {
1190 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
1191 const Span<float3> orig_positions = ss.shapekey_active ? Span(static_cast<const float3 *>(
1192 ss.shapekey_active->data),
1193 mesh.verts_num) :
1194 mesh.vert_positions();
1195
1197 orig_positions, unode.vert_indices.as_span(), unode.orig_position.as_mutable_span());
1198 }
1199}
1200
1201static void store_positions_grids(const SubdivCCG &subdiv_ccg, Node &unode)
1202{
1204 subdiv_ccg, subdiv_ccg.positions.as_span(), unode.grids, unode.position.as_mutable_span());
1206 subdiv_ccg, subdiv_ccg.normals.as_span(), unode.grids, unode.normal.as_mutable_span());
1207}
1208
1209static void store_vert_visibility_mesh(const Mesh &mesh, const bke::pbvh::Node &node, Node &unode)
1210{
1211 const bke::AttributeAccessor attributes = mesh.attributes();
1212 const VArraySpan<bool> hide_vert = *attributes.lookup<bool>(".hide_vert",
1214 if (hide_vert.is_empty()) {
1215 return;
1216 }
1217
1218 const Span<int> verts = static_cast<const bke::pbvh::MeshNode &>(node).all_verts();
1219 for (const int i : verts.index_range()) {
1220 unode.vert_hidden[i].set(hide_vert[verts[i]]);
1221 }
1222}
1223
1224static void store_face_visibility(const Mesh &mesh, Node &unode)
1225{
1226 const bke::AttributeAccessor attributes = mesh.attributes();
1227 const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
1228 if (hide_poly.is_empty()) {
1229 unode.face_hidden.fill(false);
1230 return;
1231 }
1232 const Span<int> faces = unode.face_indices;
1233 for (const int i : faces.index_range()) {
1234 unode.face_hidden[i].set(hide_poly[faces[i]]);
1235 }
1236}
1237
1238static void store_mask_mesh(const Mesh &mesh, Node &unode)
1239{
1240 const bke::AttributeAccessor attributes = mesh.attributes();
1241 const VArraySpan mask = *attributes.lookup<float>(".sculpt_mask", bke::AttrDomain::Point);
1242 if (mask.is_empty()) {
1243 unode.mask.fill(0.0f);
1244 }
1245 else {
1247 }
1248}
1249
1250static void store_mask_grids(const SubdivCCG &subdiv_ccg, Node &unode)
1251{
1252 if (!subdiv_ccg.masks.is_empty()) {
1254 subdiv_ccg, subdiv_ccg.masks.as_span(), unode.grids, unode.mask.as_mutable_span());
1255 }
1256 else {
1257 unode.mask.fill(0.0f);
1258 }
1259}
1260
1261static void store_color(const Mesh &mesh, const bke::pbvh::MeshNode &node, Node &unode)
1262{
1263 const OffsetIndices<int> faces = mesh.faces();
1264 const Span<int> corner_verts = mesh.corner_verts();
1265 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
1267 const GVArraySpan colors(*color_attribute);
1268
1269 /* NOTE: even with loop colors we still store (derived)
1270 * vertex colors for original data lookup. */
1271 const Span<int> verts = node.verts();
1272 unode.col.reinitialize(verts.size());
1274 faces, corner_verts, vert_to_face_map, colors, color_attribute.domain, verts, unode.col);
1275
1276 if (color_attribute.domain == bke::AttrDomain::Corner) {
1277 for (const int face : node.faces()) {
1278 for (const int corner : faces[face]) {
1279 unode.corner_indices.append(corner);
1280 }
1281 }
1282 unode.loop_col.reinitialize(unode.corner_indices.size());
1283 color::gather_colors(colors, unode.corner_indices, unode.loop_col);
1284 }
1285}
1286
1288{
1289 if (!step_data.geometry_original.is_initialized) {
1290 return &step_data.geometry_original;
1291 }
1292
1294
1295 return &step_data.geometry_modified;
1296}
1297
1298static void geometry_push(const Object &object)
1299{
1300 StepData *step_data = get_step_data();
1301
1302 step_data->type = Type::Geometry;
1303
1304 NodeGeometry *geometry = geometry_get(*step_data);
1306}
1307
1308static void store_face_sets(const Mesh &mesh, Node &unode)
1309{
1310 const bke::AttributeAccessor attributes = mesh.attributes();
1311 const VArraySpan face_sets = *attributes.lookup<int>(".sculpt_face_set", bke::AttrDomain::Face);
1312 if (face_sets.is_empty()) {
1313 unode.face_sets.fill(1);
1314 }
1315 else {
1316 gather_data_mesh(face_sets, unode.face_indices.as_span(), unode.face_sets.as_mutable_span());
1317 }
1318}
1319
1320static void fill_node_data_mesh(const Depsgraph &depsgraph,
1321 const Object &object,
1322 const bke::pbvh::MeshNode &node,
1323 const Type type,
1324 Node &unode)
1325{
1326 const SculptSession &ss = *object.sculpt;
1327 const Mesh &mesh = *static_cast<Mesh *>(object.data);
1328
1329 unode.vert_indices = node.all_verts();
1330 unode.unique_verts_num = node.verts().size();
1331
1332 const int verts_num = unode.vert_indices.size();
1333
1334 if (ELEM(type, Type::FaceSet, Type::HideFace)) {
1335 unode.face_indices = node.faces();
1336 }
1337
1338 switch (type) {
1339 case Type::None:
1341 break;
1342 case Type::Position: {
1343 unode.position.reinitialize(verts_num);
1344 /* Needed for original data lookup. */
1345 unode.normal.reinitialize(verts_num);
1346 if (ss.deform_modifiers_active) {
1347 unode.orig_position.reinitialize(verts_num);
1348 }
1349 store_positions_mesh(depsgraph, object, unode);
1350 break;
1351 }
1352 case Type::HideVert: {
1353 unode.vert_hidden.resize(unode.vert_indices.size());
1354 store_vert_visibility_mesh(mesh, node, unode);
1355 break;
1356 }
1357 case Type::HideFace: {
1358 unode.face_hidden.resize(unode.face_indices.size());
1360 break;
1361 }
1362 case Type::Mask: {
1363 unode.mask.reinitialize(verts_num);
1364 store_mask_mesh(mesh, unode);
1365 break;
1366 }
1367 case Type::Color: {
1368 store_color(mesh, node, unode);
1369 break;
1370 }
1371 case Type::DyntopoBegin:
1372 case Type::DyntopoEnd:
1373 /* Dyntopo should be handled elsewhere. */
1375 break;
1376 case Type::Geometry:
1377 /* See #geometry_push. */
1379 break;
1380 case Type::FaceSet: {
1381 unode.face_sets.reinitialize(unode.face_indices.size());
1382 store_face_sets(mesh, unode);
1383 break;
1384 }
1385 }
1386}
1387
1388static void fill_node_data_grids(const Object &object,
1389 const bke::pbvh::GridsNode &node,
1390 const Type type,
1391 Node &unode)
1392{
1393 const SculptSession &ss = *object.sculpt;
1394 const Mesh &base_mesh = *static_cast<const Mesh *>(object.data);
1395 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1396
1397 unode.grids = node.grids();
1398
1399 const int grid_area = subdiv_ccg.grid_size * subdiv_ccg.grid_size;
1400 const int verts_num = unode.grids.size() * grid_area;
1401
1402 if (ELEM(type, Type::FaceSet, Type::HideFace)) {
1404 }
1405
1406 switch (type) {
1407 case Type::None:
1409 break;
1410 case Type::Position: {
1411 unode.position.reinitialize(verts_num);
1412 /* Needed for original data lookup. */
1413 unode.normal.reinitialize(verts_num);
1414 store_positions_grids(subdiv_ccg, unode);
1415 break;
1416 }
1417 case Type::HideVert: {
1418 store_vert_visibility_grids(subdiv_ccg, node, unode);
1419 break;
1420 }
1421 case Type::HideFace: {
1422 unode.face_hidden.resize(unode.face_indices.size());
1423 store_face_visibility(base_mesh, unode);
1424 break;
1425 }
1426 case Type::Mask: {
1427 unode.mask.reinitialize(verts_num);
1428 store_mask_grids(subdiv_ccg, unode);
1429 break;
1430 }
1431 case Type::Color: {
1433 break;
1434 }
1435 case Type::DyntopoBegin:
1436 case Type::DyntopoEnd:
1437 /* Dyntopo should be handled elsewhere. */
1439 break;
1440 case Type::Geometry:
1441 /* See #geometry_push. */
1443 break;
1444 case Type::FaceSet: {
1445 unode.face_sets.reinitialize(unode.face_indices.size());
1446 store_face_sets(base_mesh, unode);
1447 break;
1448 }
1449 }
1450}
1451
1456BLI_NOINLINE static void bmesh_push(const Object &object,
1457 const bke::pbvh::BMeshNode *node,
1458 Type type)
1459{
1460 StepData *step_data = get_step_data();
1461 const SculptSession &ss = *object.sculpt;
1462
1463 std::scoped_lock lock(step_data->nodes_mutex);
1464
1465 if (step_data->nodes.is_empty()) {
1466 /* We currently need to append data here so that the overall undo system knows to indicate that
1467 * data should be flushed to the memfile */
1468 /* TODO: Once we store entering Sculpt Mode as a specific type of action, we can remove this
1469 * call. */
1470 step_data->nodes.append(std::make_unique<Node>());
1471
1472 step_data->type = type;
1473
1474 if (type == Type::DyntopoEnd) {
1475 step_data->bmesh.bm_entry = BM_log_entry_add(ss.bm_log);
1477 }
1478 else if (type == Type::DyntopoBegin) {
1479 /* Store a copy of the mesh's current vertices, loops, and
1480 * faces. A full copy like this is needed because entering
1481 * dynamic-topology immediately does topological edits
1482 * (converting faces to triangles) that the BMLog can't
1483 * fully restore from. */
1486
1487 step_data->bmesh.bm_entry = BM_log_entry_add(ss.bm_log);
1488 BM_log_all_added(ss.bm, ss.bm_log);
1489 }
1490 else {
1491 step_data->bmesh.bm_entry = BM_log_entry_add(ss.bm_log);
1492 }
1493 }
1494
1495 if (node) {
1496 const int cd_vert_mask_offset = CustomData_get_offset_named(
1497 &ss.bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
1498
1499 /* The vertices and node aren't changed, though pointers to them are stored in the log. */
1500 bke::pbvh::BMeshNode *node_mut = const_cast<bke::pbvh::BMeshNode *>(node);
1501
1502 switch (type) {
1503 case Type::None:
1505 break;
1506 case Type::Position:
1507 case Type::Mask:
1508 /* Before any vertex values get modified, ensure their
1509 * original positions are logged. */
1510 for (BMVert *vert : BKE_pbvh_bmesh_node_unique_verts(node_mut)) {
1511 BM_log_vert_before_modified(ss.bm_log, vert, cd_vert_mask_offset);
1512 }
1513 for (BMVert *vert : BKE_pbvh_bmesh_node_other_verts(node_mut)) {
1514 BM_log_vert_before_modified(ss.bm_log, vert, cd_vert_mask_offset);
1515 }
1516 break;
1517
1518 case Type::HideFace:
1519 case Type::HideVert: {
1520 for (BMVert *vert : BKE_pbvh_bmesh_node_unique_verts(node_mut)) {
1521 BM_log_vert_before_modified(ss.bm_log, vert, cd_vert_mask_offset);
1522 }
1523 for (BMVert *vert : BKE_pbvh_bmesh_node_other_verts(node_mut)) {
1524 BM_log_vert_before_modified(ss.bm_log, vert, cd_vert_mask_offset);
1525 }
1526
1527 for (BMFace *f : BKE_pbvh_bmesh_node_faces(node_mut)) {
1529 }
1530 break;
1531 }
1532
1533 case Type::DyntopoBegin:
1534 case Type::DyntopoEnd:
1535 case Type::Geometry:
1536 case Type::FaceSet:
1537 case Type::Color:
1538 break;
1539 }
1540 }
1541}
1542
1547static Node *ensure_node(StepData &step_data, const bke::pbvh::Node &node, bool &r_new)
1548{
1549 std::scoped_lock lock(step_data.nodes_mutex);
1550 r_new = false;
1551 std::unique_ptr<Node> &unode = step_data.undo_nodes_by_pbvh_node.lookup_or_add_cb(&node, [&]() {
1552 std::unique_ptr<Node> new_unode = std::make_unique<Node>();
1553 r_new = true;
1554 return new_unode;
1555 });
1556 return unode.get();
1557}
1558
1559void push_node(const Depsgraph &depsgraph,
1560 const Object &object,
1561 const bke::pbvh::Node *node,
1562 const Type type)
1563{
1564 SculptSession &ss = *object.sculpt;
1565 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1566 if (ss.bm || ELEM(type, Type::DyntopoBegin, Type::DyntopoEnd)) {
1567 bmesh_push(object, static_cast<const bke::pbvh::BMeshNode *>(node), type);
1568 return;
1569 }
1570
1571 StepData *step_data = get_step_data();
1572 BLI_assert(ELEM(step_data->type, Type::None, type));
1573 step_data->type = type;
1574
1575 bool newly_added;
1576 Node *unode = ensure_node(*step_data, *node, newly_added);
1577 if (!newly_added) {
1578 /* The node was already filled with data for this undo step. */
1579 return;
1580 }
1581
1582 ss.needs_flush_to_id = true;
1583
1584 switch (pbvh.type()) {
1587 depsgraph, object, static_cast<const bke::pbvh::MeshNode &>(*node), type, *unode);
1588 break;
1590 fill_node_data_grids(object, static_cast<const bke::pbvh::GridsNode &>(*node), type, *unode);
1591 break;
1594 break;
1595 }
1596}
1597
1598void push_nodes(const Depsgraph &depsgraph,
1599 Object &object,
1600 const IndexMask &node_mask,
1601 const Type type)
1602{
1603 SculptSession &ss = *object.sculpt;
1604
1605 ss.needs_flush_to_id = true;
1606
1607 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1608 if (ss.bm || ELEM(type, Type::DyntopoBegin, Type::DyntopoEnd)) {
1610 node_mask.foreach_index([&](const int i) { bmesh_push(object, &nodes[i], type); });
1611 return;
1612 }
1613
1614 StepData *step_data = get_step_data();
1615 BLI_assert(ELEM(step_data->type, Type::None, type));
1616 step_data->type = type;
1617
1618 switch (pbvh.type()) {
1619 case bke::pbvh::Type::Mesh: {
1622 node_mask.foreach_index([&](const int i) {
1623 bool newly_added;
1624 Node *unode = ensure_node(*step_data, nodes[i], newly_added);
1625 if (newly_added) {
1626 nodes_to_fill.append({&nodes[i], unode});
1627 }
1628 });
1629 threading::parallel_for(nodes_to_fill.index_range(), 1, [&](const IndexRange range) {
1630 for (const auto &[node, unode] : nodes_to_fill.as_span().slice(range)) {
1631 fill_node_data_mesh(depsgraph, object, *node, type, *unode);
1632 }
1633 });
1634 break;
1635 }
1639 node_mask.foreach_index([&](const int i) {
1640 bool newly_added;
1641 Node *unode = ensure_node(*step_data, nodes[i], newly_added);
1642 if (newly_added) {
1643 nodes_to_fill.append({&nodes[i], unode});
1644 }
1645 });
1646 threading::parallel_for(nodes_to_fill.index_range(), 1, [&](const IndexRange range) {
1647 for (const auto &[node, unode] : nodes_to_fill.as_span().slice(range)) {
1648 fill_node_data_grids(object, *node, type, *unode);
1649 }
1650 });
1651 break;
1652 }
1655 break;
1656 }
1657 }
1658}
1659
1660static void save_active_attribute(Object &object, SculptAttrRef *attr)
1661{
1663 attr->was_set = true;
1664 attr->domain = NO_ACTIVE_LAYER;
1665 attr->name[0] = 0;
1666 if (!mesh) {
1667 return;
1668 }
1669 const char *name = mesh->active_color_attribute;
1670 const bke::AttributeAccessor attributes = mesh->attributes();
1671 const std::optional<bke::AttributeMetaData> meta_data = attributes.lookup_meta_data(name);
1672 if (!meta_data) {
1673 return;
1674 }
1675 if (!(ATTR_DOMAIN_AS_MASK(meta_data->domain) & ATTR_DOMAIN_MASK_COLOR) ||
1676 !(CD_TYPE_AS_MASK(meta_data->data_type) & CD_MASK_COLOR_ALL))
1677 {
1678 return;
1679 }
1680 attr->domain = meta_data->domain;
1681 STRNCPY(attr->name, name);
1682 attr->type = meta_data->data_type;
1683}
1684
1690{
1691 us->data.object_name = ob.id.name;
1692
1693 if (!us->active_color_start.was_set) {
1695 }
1696
1697 /* Set end attribute in case push_end is not called,
1698 * so we don't end up with corrupted state.
1699 */
1700 if (!us->active_color_end.was_set) {
1702 us->active_color_end.was_set = false;
1703 }
1704
1705 const SculptSession &ss = *ob.sculpt;
1706
1707 us->data.pivot_pos = ss.pivot_pos;
1708 us->data.pivot_rot = ss.pivot_rot;
1709
1710 if (const KeyBlock *key = BKE_keyblock_from_object(&ob)) {
1711 us->data.active_shape_key_name = key->name;
1712 }
1713}
1714
1715void push_begin_ex(const Scene & /*scene*/, Object &ob, const char *name)
1716{
1717 UndoStack *ustack = ED_undo_stack_get();
1718
1719 /* If possible, we need to tag the object and its geometry data as 'changed in the future' in
1720 * the previous undo step if it's a memfile one. */
1722 ED_undosys_stack_memfile_id_changed_tag(ustack, static_cast<ID *>(ob.data));
1723
1724 /* Special case, we never read from this. */
1725 bContext *C = nullptr;
1726
1727 SculptUndoStep *us = reinterpret_cast<SculptUndoStep *>(
1729
1730 const SculptSession &ss = *ob.sculpt;
1731 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
1732
1733 save_common_data(ob, us);
1734
1735 switch (pbvh.type()) {
1736 case bke::pbvh::Type::Mesh: {
1737 const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
1738 us->data.mesh.verts_num = mesh.verts_num;
1739 us->data.mesh.corners_num = mesh.corners_num;
1740 break;
1741 }
1745 break;
1746 }
1748 break;
1749 }
1750 }
1751}
1752
1753void push_begin(const Scene &scene, Object &ob, const wmOperator *op)
1754{
1755 push_begin_ex(scene, ob, op->type->name);
1756}
1757
1758void push_enter_sculpt_mode(const Scene & /*scene*/, Object &ob, const wmOperator *op)
1759{
1760 UndoStack *ustack = ED_undo_stack_get();
1761
1762 /* If possible, we need to tag the object and its geometry data as 'changed in the future' in
1763 * the previous undo step if it's a memfile one. */
1765 ED_undosys_stack_memfile_id_changed_tag(ustack, static_cast<ID *>(ob.data));
1766
1767 /* Special case, we never read from this. */
1768 bContext *C = nullptr;
1769
1770 SculptUndoStep *us = reinterpret_cast<SculptUndoStep *>(
1772 save_common_data(ob, us);
1773}
1774
1775static size_t node_size_in_bytes(const Node &node)
1776{
1777 size_t size = sizeof(Node);
1778 size += node.position.as_span().size_in_bytes();
1779 size += node.orig_position.as_span().size_in_bytes();
1780 size += node.normal.as_span().size_in_bytes();
1781 size += node.col.as_span().size_in_bytes();
1782 size += node.mask.as_span().size_in_bytes();
1783 size += node.loop_col.as_span().size_in_bytes();
1786 size += node.vert_hidden.size() / 8;
1787 size += node.face_hidden.size() / 8;
1788 size += node.grids.as_span().size_in_bytes();
1789 size += node.grid_hidden.all_bits().size() / 8;
1790 size += node.face_sets.as_span().size_in_bytes();
1792 return size;
1793}
1794
1795void push_end_ex(Object &ob, const bool use_nested_undo)
1796{
1797 StepData *step_data = get_step_data();
1798
1799 /* Move undo node storage from map to vector. */
1800 step_data->nodes.reserve(step_data->undo_nodes_by_pbvh_node.size());
1801 for (std::unique_ptr<Node> &node : step_data->undo_nodes_by_pbvh_node.values()) {
1802 step_data->nodes.append(std::move(node));
1803 }
1804 step_data->undo_nodes_by_pbvh_node.clear();
1805
1806 /* We don't need normals in the undo stack. */
1807 for (std::unique_ptr<Node> &unode : step_data->nodes) {
1808 unode->normal = {};
1809 }
1810 /* TODO: When #Node.orig_positions is stored, #Node.positions is unnecessary, don't keep it in
1811 * the stored undo step. In the future the stored undo step should use a different format with
1812 * just one positions array that has a different semantic meaning depending on whether there are
1813 * deform modifiers. */
1814
1816 step_data->nodes.index_range(),
1817 16,
1818 0,
1819 [&](const IndexRange range, size_t size) {
1820 for (const int i : range) {
1821 size += node_size_in_bytes(*step_data->nodes[i]);
1822 }
1823 return size;
1824 },
1825 std::plus<size_t>());
1826
1827 /* We could remove this and enforce all callers run in an operator using 'OPTYPE_UNDO'. */
1828 wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first);
1829 if (wm->op_undo_depth == 0 || use_nested_undo) {
1830 UndoStack *ustack = ED_undo_stack_get();
1831 BKE_undosys_step_push(ustack, nullptr, nullptr);
1832 if (wm->op_undo_depth == 0) {
1834 }
1836 }
1837
1838 UndoStack *ustack = ED_undo_stack_get();
1839 SculptUndoStep *us = reinterpret_cast<SculptUndoStep *>(
1841
1842 save_active_attribute(ob, &us->active_color_end);
1843}
1844
1846{
1847 push_end_ex(ob, false);
1848}
1849
1850/* -------------------------------------------------------------------- */
1853
1854static void set_active_layer(bContext *C, const SculptAttrRef *attr)
1855{
1856 if (attr->domain == bke::AttrDomain::Auto) {
1857 return;
1858 }
1859
1862
1863 SculptAttrRef existing;
1864 save_active_attribute(*ob, &existing);
1865
1867 CustomDataLayer *layer = BKE_attribute_find(owner, attr->name, attr->type, attr->domain);
1868
1869 /* Temporary fix for #97408. This is a fundamental
1870 * bug in the undo stack; the operator code needs to push
1871 * an extra undo step before running an operator if a
1872 * non-memfile undo system is active.
1873 *
1874 * For now, detect if the layer does exist but with a different
1875 * domain and just unconvert it.
1876 */
1877 if (!layer) {
1880 if (layer) {
1882 mesh->attributes_for_write(),
1883 attr->name,
1884 attr->domain,
1885 eCustomDataType(attr->type),
1886 nullptr))
1887 {
1888 layer = BKE_attribute_find(owner, attr->name, attr->type, attr->domain);
1889 }
1890 }
1891 }
1892
1893 if (!layer) {
1894 /* Memfile undo killed the layer; re-create it. */
1895 mesh->attributes_for_write().add(
1896 attr->name, attr->domain, attr->type, bke::AttributeInitDefaultValue());
1897 layer = BKE_attribute_find(owner, attr->name, attr->type, attr->domain);
1899 }
1900
1901 if (layer) {
1903 }
1904}
1905
1906static void step_encode_init(bContext * /*C*/, UndoStep *us_p)
1907{
1908 SculptUndoStep *us = reinterpret_cast<SculptUndoStep *>(us_p);
1909 new (&us->data) StepData();
1910}
1911
1912static bool step_encode(bContext * /*C*/, Main *bmain, UndoStep *us_p)
1913{
1914 /* Dummy, encoding is done along the way by adding tiles
1915 * to the current 'SculptUndoStep' added by encode_init. */
1916 SculptUndoStep *us = reinterpret_cast<SculptUndoStep *>(us_p);
1917 us->step.data_size = us->data.undo_size;
1918
1919 if (us->data.type == Type::DyntopoEnd) {
1920 us->step.use_memfile_step = true;
1921 }
1922 us->step.is_applied = true;
1923
1924 /* We do not flush data when entering sculpt mode - this is currently indicated by Type::None */
1925 if (us->data.type != Type::None) {
1926 bmain->is_memfile_undo_flush_needed = true;
1927 }
1928
1929 return true;
1930}
1931
1933{
1934 BLI_assert(us->step.is_applied == true);
1935
1937 us->step.is_applied = false;
1938}
1939
1941{
1942 BLI_assert(us->step.is_applied == false);
1943
1945 us->step.is_applied = true;
1946}
1947
1949 Depsgraph *depsgraph,
1950 SculptUndoStep *us,
1951 const bool is_final)
1952{
1953 /* Walk forward over any applied steps of same type,
1954 * then walk back in the next loop, un-applying them. */
1955 SculptUndoStep *us_iter = us;
1956 while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) {
1957 if (us_iter->step.next->is_applied == false) {
1958 break;
1959 }
1960 us_iter = reinterpret_cast<SculptUndoStep *>(us_iter->step.next);
1961 }
1962
1963 while ((us_iter != us) || (!is_final && us_iter == us)) {
1964 BLI_assert(us_iter->step.type == us->step.type); /* Previous loop ensures this. */
1965
1968
1969 if (us_iter == us) {
1970 if (us_iter->step.prev && us_iter->step.prev->type == BKE_UNDOSYS_TYPE_SCULPT) {
1972 C, &reinterpret_cast<SculptUndoStep *>(us_iter->step.prev)->active_color_end);
1973 }
1974 break;
1975 }
1976
1977 us_iter = reinterpret_cast<SculptUndoStep *>(us_iter->step.prev);
1978 }
1979}
1980
1982{
1983 SculptUndoStep *us_iter = us;
1984 while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) {
1985 if (us_iter->step.prev->is_applied == true) {
1986 break;
1987 }
1988 us_iter = reinterpret_cast<SculptUndoStep *>(us_iter->step.prev);
1989 }
1990 while (us_iter && (us_iter->step.is_applied == false)) {
1993
1994 if (us_iter == us) {
1996 break;
1997 }
1998 us_iter = reinterpret_cast<SculptUndoStep *>(us_iter->step.next);
1999 }
2000}
2001
2002static void step_decode(
2003 bContext *C, Main *bmain, UndoStep *us_p, const eUndoStepDir dir, const bool is_final)
2004{
2005 /* NOTE: behavior for undo/redo closely matches image undo. */
2006 BLI_assert(dir != STEP_INVALID);
2007
2009
2010 /* Ensure sculpt mode. */
2011 {
2012 Scene *scene = CTX_data_scene(C);
2013 ViewLayer *view_layer = CTX_data_view_layer(C);
2014 BKE_view_layer_synced_ensure(scene, view_layer);
2015 Object *ob = BKE_view_layer_active_object_get(view_layer);
2016 if (ob && (ob->type == OB_MESH)) {
2017 if (ob->mode & (OB_MODE_SCULPT)) {
2018 /* Pass. */
2019 }
2020 else {
2021 object::mode_generic_exit(bmain, depsgraph, scene, ob);
2022
2023 /* Sculpt needs evaluated state.
2024 * NOTE: needs to be done here, as #object::mode_generic_exit will usually invalidate
2025 * (some) evaluated data. */
2027
2028 Mesh *mesh = static_cast<Mesh *>(ob->data);
2029 /* Don't add sculpt topology undo steps when reading back undo state.
2030 * The undo steps must enter/exit for us. */
2032 object_sculpt_mode_enter(*bmain, *depsgraph, *scene, *ob, true, nullptr);
2033 }
2034
2035 if (ob->sculpt) {
2036 ob->sculpt->needs_flush_to_id = true;
2037 }
2038 bmain->is_memfile_undo_flush_needed = true;
2039 }
2040 else {
2041 BLI_assert(0);
2042 return;
2043 }
2044 }
2045
2046 SculptUndoStep *us = reinterpret_cast<SculptUndoStep *>(us_p);
2047 if (dir == STEP_UNDO) {
2048 step_decode_undo(C, depsgraph, us, is_final);
2049 }
2050 else if (dir == STEP_REDO) {
2052 }
2053}
2054
2055static void step_free(UndoStep *us_p)
2056{
2057 SculptUndoStep *us = reinterpret_cast<SculptUndoStep *>(us_p);
2058 free_step_data(us->data);
2059}
2060
2061void geometry_begin(const Scene &scene, Object &ob, const wmOperator *op)
2062{
2063 geometry_begin_ex(scene, ob, op->type->name);
2064}
2065
2066void geometry_begin_ex(const Scene & /*scene*/, Object &ob, const char *name)
2067{
2068 UndoStack *ustack = ED_undo_stack_get();
2069
2070 /* If possible, we need to tag the object and its geometry data as 'changed in the future' in
2071 * the previous undo step if it's a memfile one. */
2073 ED_undosys_stack_memfile_id_changed_tag(ustack, static_cast<ID *>(ob.data));
2074
2075 /* Special case, we never read from this. */
2076 bContext *C = nullptr;
2077
2078 SculptUndoStep *us = reinterpret_cast<SculptUndoStep *>(
2080 save_common_data(ob, us);
2081 geometry_push(ob);
2082}
2083
2084static size_t calculate_node_geometry_allocated_size(const NodeGeometry &node_geometry)
2085{
2086 BLI_assert(node_geometry.is_initialized);
2087
2088 MemoryCount memory;
2090
2091 memory_counter.add_shared(node_geometry.face_offsets_sharing_info,
2092 sizeof(int) * (node_geometry.faces_num + 1));
2093
2094 CustomData_count_memory(node_geometry.corner_data, node_geometry.corners_num, memory_counter);
2095 CustomData_count_memory(node_geometry.face_data, node_geometry.faces_num, memory_counter);
2096 CustomData_count_memory(node_geometry.vert_data, node_geometry.verts_num, memory_counter);
2097 CustomData_count_memory(node_geometry.edge_data, node_geometry.edges_num, memory_counter);
2098
2099 return memory.total_bytes;
2100}
2101
2102static size_t estimate_geometry_step_size(const StepData &step_data)
2103{
2104 size_t step_size = 0;
2105
2106 /* TODO: This calculation is not entirely accurate, as the current amount of memory consumed by
2107 * Sculpt Undo is not updated when elements are evicted. Further changes to the overall undo
2108 * system would be needed to measure this accurately. */
2111
2112 return step_size;
2113}
2114
2116{
2117 geometry_push(ob);
2118
2119 StepData *step_data = get_step_data();
2120 step_data->undo_size = estimate_geometry_step_size(*step_data);
2121
2122 /* We could remove this and enforce all callers run in an operator using 'OPTYPE_UNDO'. */
2123 wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first);
2124 if (wm->op_undo_depth == 0) {
2125 UndoStack *ustack = ED_undo_stack_get();
2126 BKE_undosys_step_push(ustack, nullptr, nullptr);
2127 if (wm->op_undo_depth == 0) {
2129 }
2131 }
2132}
2133
2135{
2136 ut->name = "Sculpt";
2137 ut->poll = nullptr; /* No poll from context for now. */
2141 ut->step_free = step_free;
2142
2144
2145 ut->step_size = sizeof(SculptUndoStep);
2146}
2147
2149
2150/* -------------------------------------------------------------------- */
2169
2171{
2173 return false;
2174 }
2175
2176 const Object *object = CTX_data_active_object(C);
2177 const SculptSession *sculpt_session = object->sculpt;
2178
2179 return sculpt_session->multires.active;
2180}
2181
2183{
2184 if (!use_multires_mesh(C)) {
2185 return;
2186 }
2187
2188 const Scene &scene = *CTX_data_scene(C);
2189 Object *object = CTX_data_active_object(C);
2190
2192
2193 push_begin_ex(scene, *object, str);
2194
2195 geometry_push(*object);
2196}
2197
2199{
2200 if (!use_multires_mesh(C)) {
2201 ED_undo_push(C, str);
2202 return;
2203 }
2204
2205 Object *object = CTX_data_active_object(C);
2206
2207 geometry_push(*object);
2208
2209 push_end(*object);
2210}
2211
2213
2214} // namespace blender::ed::sculpt_paint::undo
2215
2216namespace blender::ed::sculpt_paint {
2217
2218std::optional<OrigPositionData> orig_position_data_lookup_mesh_all_verts(
2219 const Object & /*object*/, const bke::pbvh::MeshNode &node)
2220{
2221 const undo::Node *unode = undo::get_node(&node, undo::Type::Position);
2222 if (!unode) {
2223 return std::nullopt;
2224 }
2225 return OrigPositionData{unode->position.as_span(), unode->normal.as_span()};
2226}
2227
2228std::optional<OrigPositionData> orig_position_data_lookup_mesh(const Object &object,
2229 const bke::pbvh::MeshNode &node)
2230{
2231 const std::optional<OrigPositionData> result = orig_position_data_lookup_mesh_all_verts(object,
2232 node);
2233 if (!result) {
2234 return std::nullopt;
2235 }
2236 return OrigPositionData{result->positions.take_front(node.verts().size()),
2237 result->normals.take_front(node.verts().size())};
2238}
2239
2240std::optional<OrigPositionData> orig_position_data_lookup_grids(const Object & /*object*/,
2241 const bke::pbvh::GridsNode &node)
2242{
2243 const undo::Node *unode = undo::get_node(&node, undo::Type::Position);
2244 if (!unode) {
2245 return std::nullopt;
2246 }
2247 return OrigPositionData{unode->position.as_span(), unode->normal.as_span()};
2248}
2249
2251 const Set<BMVert *, 0> &verts,
2252 const MutableSpan<float3> positions,
2254{
2255 int i = 0;
2256 for (const BMVert *vert : verts) {
2257 const float *co;
2258 const float *no;
2259 BM_log_original_vert_data(&const_cast<BMLog &>(bm_log), const_cast<BMVert *>(vert), &co, &no);
2260 if (!positions.is_empty()) {
2261 positions[i] = co;
2262 }
2263 if (!normals.is_empty()) {
2264 normals[i] = no;
2265 }
2266 i++;
2267 }
2268}
2269
2270std::optional<Span<float4>> orig_color_data_lookup_mesh(const Object & /*object*/,
2271 const bke::pbvh::MeshNode &node)
2272{
2273 const undo::Node *unode = undo::get_node(&node, undo::Type::Color);
2274 if (!unode) {
2275 return std::nullopt;
2276 }
2277 return unode->col.as_span();
2278}
2279
2280std::optional<Span<int>> orig_face_set_data_lookup_mesh(const Object & /*object*/,
2281 const bke::pbvh::MeshNode &node)
2282{
2283 const undo::Node *unode = undo::get_node(&node, undo::Type::FaceSet);
2284 if (!unode) {
2285 return std::nullopt;
2286 }
2287 return unode->face_sets.as_span();
2288}
2289
2290std::optional<Span<int>> orig_face_set_data_lookup_grids(const Object & /*object*/,
2291 const bke::pbvh::GridsNode &node)
2292{
2293 const undo::Node *unode = undo::get_node(&node, undo::Type::FaceSet);
2294 if (!unode) {
2295 return std::nullopt;
2296 }
2297 return unode->face_sets.as_span();
2298}
2299
2300std::optional<Span<float>> orig_mask_data_lookup_mesh(const Object & /*object*/,
2301 const bke::pbvh::MeshNode &node)
2302{
2303 const undo::Node *unode = undo::get_node(&node, undo::Type::Mask);
2304 if (!unode) {
2305 return std::nullopt;
2306 }
2307 return unode->mask.as_span();
2308}
2309
2310std::optional<Span<float>> orig_mask_data_lookup_grids(const Object & /*object*/,
2311 const bke::pbvh::GridsNode &node)
2312{
2313 const undo::Node *unode = undo::get_node(&node, undo::Type::Mask);
2314 if (!unode) {
2315 return std::nullopt;
2316 }
2317 return unode->mask.as_span();
2318}
2319
2320} // 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
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_ensure(Depsgraph &depsgraph, Object &object)
Definition paint.cc:2877
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:6391
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:6381
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
blender::float3 pivot_pos
Definition BKE_paint.hh:486
struct SculptSession::@323057044041335216000265171165256227034374206114 multires
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:7399
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::@205353162113312325202166173342174005247067053162 grids
struct blender::ed::sculpt_paint::undo::StepData::@312030152261047154154007114345203354355113156323 bmesh
Map< const bke::pbvh::Node *, std::unique_ptr< Node > > undo_nodes_by_pbvh_node
struct blender::ed::sculpt_paint::undo::StepData::@120042175076163017161062030006224243135210055325 mesh
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