diff --git a/source/blender/editors/include/ED_point_cloud.hh b/source/blender/editors/include/ED_point_cloud.hh index 2453e17dfec..888081bcfc6 100644 --- a/source/blender/editors/include/ED_point_cloud.hh +++ b/source/blender/editors/include/ED_point_cloud.hh @@ -22,6 +22,7 @@ struct ARegion; struct bContext; struct PointCloud; struct rcti; +struct UndoType; struct wmKeyConfig; struct wmOperatorType; namespace blender::bke { @@ -37,6 +38,7 @@ namespace blender::ed::point_cloud { void operatortypes_point_cloud(); void operatormacros_point_cloud(); void keymap_point_cloud(wmKeyConfig *keyconf); +void undosys_type_register(UndoType *ut); VectorSet get_unique_editable_point_clouds(const bContext &C); diff --git a/source/blender/editors/point_cloud/CMakeLists.txt b/source/blender/editors/point_cloud/CMakeLists.txt index 1b73e9fd7ee..455efa76736 100644 --- a/source/blender/editors/point_cloud/CMakeLists.txt +++ b/source/blender/editors/point_cloud/CMakeLists.txt @@ -18,6 +18,7 @@ set(SRC intern/duplicate.cc intern/point_cloud_ops.cc intern/point_cloud_selection.cc + intern/point_cloud_undo.cc ) set(LIB @@ -26,6 +27,7 @@ set(LIB PRIVATE bf::depsgraph PRIVATE bf::dna PRIVATE bf::functions + PRIVATE bf::intern::clog PRIVATE bf::intern::guardedalloc PRIVATE bf::windowmanager ) diff --git a/source/blender/editors/point_cloud/intern/point_cloud_undo.cc b/source/blender/editors/point_cloud/intern/point_cloud_undo.cc new file mode 100644 index 00000000000..a2b061b8424 --- /dev/null +++ b/source/blender/editors/point_cloud/intern/point_cloud_undo.cc @@ -0,0 +1,153 @@ +/* SPDX-FileCopyrightText: 2025 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup edpointcloud + */ + +#include "BLI_task.hh" + +#include "BKE_context.hh" +#include "BKE_customdata.hh" +#include "BKE_main.hh" +#include "BKE_object.hh" +#include "BKE_pointcloud.hh" +#include "BKE_undo_system.hh" + +#include "CLG_log.h" + +#include "DEG_depsgraph.hh" + +#include "ED_point_cloud.hh" +#include "ED_undo.hh" + +#include "WM_api.hh" +#include "WM_types.hh" + +static CLG_LogRef LOG = {"ed.undo.point_cloud"}; + +namespace blender::ed::point_cloud { +namespace undo { + +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * + * \note This is similar for all edit-mode types. + * \{ */ + +struct StepObject { + UndoRefID_Object obedit_ref = {}; + CustomData custom_data = {}; + int totpoint = 0; +}; + +struct PointCloudUndoStep { + UndoStep step; + /** See #ED_undo_object_editmode_validate_scene_from_windows code comment for details. */ + UndoRefID_Scene scene_ref = {}; + Array objects; +}; + +static bool step_encode(bContext *C, Main *bmain, UndoStep *us_p) +{ + PointCloudUndoStep *us = reinterpret_cast(us_p); + + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Vector objects = ED_undo_editmode_objects_from_view_layer(scene, view_layer); + + us->scene_ref.ptr = scene; + new (&us->objects) Array(objects.size()); + + threading::parallel_for(us->objects.index_range(), 8, [&](const IndexRange range) { + for (const int i : range) { + Object *ob = objects[i]; + StepObject &object = us->objects[i]; + PointCloud &point_cloud = *static_cast(ob->data); + object.obedit_ref.ptr = ob; + CustomData_init_from( + &point_cloud.pdata, &object.custom_data, CD_MASK_ALL, point_cloud.totpoint); + object.totpoint = point_cloud.totpoint; + } + }); + + bmain->is_memfile_undo_flush_needed = true; + + return true; +} + +static void step_decode( + bContext *C, Main *bmain, UndoStep *us_p, const eUndoStepDir /*dir*/, bool /*is_final*/) +{ + PointCloudUndoStep *us = reinterpret_cast(us_p); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + + ED_undo_object_editmode_validate_scene_from_windows( + CTX_wm_manager(C), us->scene_ref.ptr, &scene, &view_layer); + ED_undo_object_editmode_restore_helper(scene, + view_layer, + &us->objects.first().obedit_ref.ptr, + us->objects.size(), + sizeof(decltype(us->objects)::value_type)); + + BLI_assert(BKE_object_is_in_editmode(us->objects.first().obedit_ref.ptr)); + + for (const StepObject &object : us->objects) { + PointCloud &point_cloud = *static_cast(object.obedit_ref.ptr->data); + CustomData_free(&point_cloud.pdata); + CustomData_init_from(&object.custom_data, &point_cloud.pdata, CD_MASK_ALL, object.totpoint); + point_cloud.totpoint = object.totpoint; + DEG_id_tag_update(&point_cloud.id, ID_RECALC_GEOMETRY); + } + + ED_undo_object_set_active_or_warn( + scene, view_layer, us->objects.first().obedit_ref.ptr, us_p->name, &LOG); + + bmain->is_memfile_undo_flush_needed = true; + + WM_event_add_notifier(C, NC_GEOM | ND_DATA, nullptr); +} + +static void step_free(UndoStep *us_p) +{ + PointCloudUndoStep *us = reinterpret_cast(us_p); + for (StepObject &object : us->objects) { + CustomData_free(&object.custom_data); + } + us->objects.~Array(); +} + +static void foreach_ID_ref(UndoStep *us_p, + UndoTypeForEachIDRefFn foreach_ID_ref_fn, + void *user_data) +{ + PointCloudUndoStep *us = reinterpret_cast(us_p); + + foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->scene_ref)); + for (const StepObject &object : us->objects) { + foreach_ID_ref_fn(user_data, ((UndoRefID *)&object.obedit_ref)); + } +} + +/** \} */ + +} // namespace undo + +void undosys_type_register(UndoType *ut) +{ + ut->name = "Edit Point Cloud"; + ut->poll = editable_point_cloud_in_edit_mode_poll; + ut->step_encode = undo::step_encode; + ut->step_decode = undo::step_decode; + ut->step_free = undo::step_free; + + ut->step_foreach_ID_ref = undo::foreach_ID_ref; + + ut->flags = UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE; + + ut->step_size = sizeof(undo::PointCloudUndoStep); +} + +} // namespace blender::ed::point_cloud diff --git a/source/blender/editors/undo/undo_system_types.cc b/source/blender/editors/undo/undo_system_types.cc index 91e4201d46f..1b2e8672b30 100644 --- a/source/blender/editors/undo/undo_system_types.cc +++ b/source/blender/editors/undo/undo_system_types.cc @@ -17,6 +17,7 @@ #include "ED_mesh.hh" #include "ED_paint.hh" #include "ED_particle.hh" +#include "ED_point_cloud.hh" #include "ED_sculpt.hh" #include "ED_text.hh" #include "ED_undo.hh" @@ -37,6 +38,7 @@ void ED_undosys_type_init() BKE_undosys_type_append(ED_mball_undosys_type); BKE_undosys_type_append(ED_mesh_undosys_type); BKE_undosys_type_append(curves::undosys_type_register); + BKE_undosys_type_append(point_cloud::undosys_type_register); BKE_undosys_type_append(ED_undosys_type_grease_pencil); /* Paint Modes */