Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/mesh/editmesh_undo.c
| Show All 18 Lines | |||||
| */ | */ | ||||
| /** \file blender/editors/mesh/editmesh_undo.c | /** \file blender/editors/mesh/editmesh_undo.c | ||||
| * \ingroup edmesh | * \ingroup edmesh | ||||
| */ | */ | ||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "CLG_log.h" | |||||
| #include "DNA_mesh_types.h" | #include "DNA_mesh_types.h" | ||||
| #include "DNA_object_types.h" | #include "DNA_object_types.h" | ||||
| #include "DNA_key_types.h" | #include "DNA_key_types.h" | ||||
| #include "DNA_layer_types.h" | |||||
| #include "BLI_listbase.h" | #include "BLI_listbase.h" | ||||
| #include "BLI_array_utils.h" | #include "BLI_array_utils.h" | ||||
| #include "BLI_alloca.h" | #include "BLI_alloca.h" | ||||
| #include "BKE_DerivedMesh.h" | #include "BKE_DerivedMesh.h" | ||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "BKE_key.h" | #include "BKE_key.h" | ||||
| #include "BKE_layer.h" | |||||
| #include "BKE_mesh.h" | #include "BKE_mesh.h" | ||||
| #include "BKE_editmesh.h" | #include "BKE_editmesh.h" | ||||
| #include "BKE_undo_system.h" | #include "BKE_undo_system.h" | ||||
| #include "DEG_depsgraph.h" | #include "DEG_depsgraph.h" | ||||
| #include "ED_object.h" | #include "ED_object.h" | ||||
| #include "ED_mesh.h" | #include "ED_mesh.h" | ||||
| #include "ED_util.h" | #include "ED_util.h" | ||||
| #include "ED_undo.h" | |||||
| #include "WM_types.h" | #include "WM_types.h" | ||||
| #include "WM_api.h" | #include "WM_api.h" | ||||
| #define USE_ARRAY_STORE | #define USE_ARRAY_STORE | ||||
| #ifdef USE_ARRAY_STORE | #ifdef USE_ARRAY_STORE | ||||
| // # define DEBUG_PRINT | // # define DEBUG_PRINT | ||||
| Show All 9 Lines | |||||
| # define USE_ARRAY_STORE_THREAD | # define USE_ARRAY_STORE_THREAD | ||||
| #endif | #endif | ||||
| #ifdef USE_ARRAY_STORE_THREAD | #ifdef USE_ARRAY_STORE_THREAD | ||||
| # include "BLI_task.h" | # include "BLI_task.h" | ||||
| #endif | #endif | ||||
| /** We only need this locally. */ | |||||
| static CLG_LogRef LOG = {"ed.undo.mesh"}; | |||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Undo Conversion | /** \name Undo Conversion | ||||
| * \{ */ | * \{ */ | ||||
| #ifdef USE_ARRAY_STORE | #ifdef USE_ARRAY_STORE | ||||
| /* Single linked list of layers stored per type */ | /* Single linked list of layers stored per type */ | ||||
| typedef struct BArrayCustomData { | typedef struct BArrayCustomData { | ||||
| ▲ Show 20 Lines • Show All 583 Lines • ▼ Show 20 Lines | static Object *editmesh_object_from_context(bContext *C) | ||||
| } | } | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Implements ED Undo System | /** \name Implements ED Undo System | ||||
| * | |||||
| * \note This is similar for all edit-mode types. | |||||
| * \{ */ | * \{ */ | ||||
| typedef struct MeshUndoStep_Elem { | |||||
| struct MeshUndoStep_Elem *next, *prev; | |||||
| UndoRefID_Object obedit_ref; | |||||
| UndoMesh data; | |||||
| } MeshUndoStep_Elem; | |||||
| typedef struct MeshUndoStep { | typedef struct MeshUndoStep { | ||||
| UndoStep step; | UndoStep step; | ||||
| /* Use for all ID lookups (can be NULL). */ | |||||
| struct UndoIDPtrMap *id_map; | struct UndoIDPtrMap *id_map; | ||||
| MeshUndoStep_Elem *elems; | |||||
| /* note: will split out into list for multi-object-editmode. */ | uint elems_len; | ||||
| UndoRefID_Object obedit_ref; | |||||
| UndoMesh data; | |||||
| } MeshUndoStep; | } MeshUndoStep; | ||||
| static bool mesh_undosys_poll(bContext *C) | static bool mesh_undosys_poll(bContext *C) | ||||
| { | { | ||||
| return editmesh_object_from_context(C) != NULL; | return editmesh_object_from_context(C) != NULL; | ||||
| } | } | ||||
| static bool mesh_undosys_step_encode(struct bContext *C, UndoStep *us_p) | static bool mesh_undosys_step_encode(struct bContext *C, UndoStep *us_p) | ||||
| { | { | ||||
| MeshUndoStep *us = (MeshUndoStep *)us_p; | MeshUndoStep *us = (MeshUndoStep *)us_p; | ||||
| us->obedit_ref.ptr = editmesh_object_from_context(C); | |||||
| Mesh *me = us->obedit_ref.ptr->data; | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| undomesh_from_editmesh(&us->data, me->edit_btmesh, me->key); | uint objects_len = 0; | ||||
| us->step.data_size = us->data.undo_size; | Object **objects = BKE_view_layer_array_from_objects_in_mode( | ||||
| view_layer, &objects_len, { | |||||
| .object_mode = OB_MODE_EDIT, | |||||
| .no_dup_data = true}); | |||||
| us->elems = MEM_callocN(sizeof(*us->elems) * objects_len, __func__); | |||||
| us->elems_len = objects_len; | |||||
| for (uint i = 0; i < objects_len; i++) { | |||||
| Object *ob = objects[i]; | |||||
| MeshUndoStep_Elem *elem = &us->elems[i]; | |||||
| elem->obedit_ref.ptr = ob; | |||||
| Mesh *me = elem->obedit_ref.ptr->data; | |||||
| undomesh_from_editmesh(&elem->data, me->edit_btmesh, me->key); | |||||
| us->step.data_size += elem->data.undo_size; | |||||
| } | |||||
| MEM_freeN(objects); | |||||
| return true; | return true; | ||||
| } | } | ||||
| static void mesh_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir)) | static void mesh_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir)) | ||||
| { | { | ||||
| /* TODO(campbell): undo_system: use low-level API to set mode. */ | /* TODO(campbell): undo_system: use low-level API to set mode. */ | ||||
| ED_object_mode_set(C, OB_MODE_EDIT); | ED_object_mode_set(C, OB_MODE_EDIT); | ||||
| BLI_assert(mesh_undosys_poll(C)); | BLI_assert(mesh_undosys_poll(C)); | ||||
| MeshUndoStep *us = (MeshUndoStep *)us_p; | MeshUndoStep *us = (MeshUndoStep *)us_p; | ||||
| Object *obedit = us->obedit_ref.ptr; | |||||
| for (uint i = 0; i < us->elems_len; i++) { | |||||
| MeshUndoStep_Elem *elem = &us->elems[i]; | |||||
| Object *obedit = elem->obedit_ref.ptr; | |||||
| Mesh *me = obedit->data; | Mesh *me = obedit->data; | ||||
| if (me->edit_btmesh == NULL) { | |||||
| /* Should never fail, may not crash but can give odd behavior. */ | |||||
| CLOG_ERROR(&LOG, "name='%s', failed to enter edit-mode for object '%s', undo state invalid", | |||||
| us_p->name, obedit->id.name); | |||||
| continue; | |||||
| } | |||||
| BMEditMesh *em = me->edit_btmesh; | BMEditMesh *em = me->edit_btmesh; | ||||
| undomesh_to_editmesh(&us->data, em, obedit->data); | undomesh_to_editmesh(&elem->data, em, obedit->data); | ||||
| DEG_id_tag_update(&obedit->id, OB_RECALC_DATA); | DEG_id_tag_update(&obedit->id, OB_RECALC_DATA); | ||||
| } | |||||
| /* The first element is always active */ | |||||
| ED_undo_object_set_active_or_warn(CTX_data_view_layer(C), us->elems[0].obedit_ref.ptr, us_p->name, &LOG); | |||||
| WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); | WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); | ||||
| } | } | ||||
| static void mesh_undosys_step_free(UndoStep *us_p) | static void mesh_undosys_step_free(UndoStep *us_p) | ||||
| { | { | ||||
| MeshUndoStep *us = (MeshUndoStep *)us_p; | MeshUndoStep *us = (MeshUndoStep *)us_p; | ||||
| undomesh_free_data(&us->data); | |||||
| for (uint i = 0; i < us->elems_len; i++) { | |||||
| MeshUndoStep_Elem *elem = &us->elems[i]; | |||||
| undomesh_free_data(&elem->data); | |||||
| } | |||||
| MEM_freeN(us->elems); | |||||
| if (us->id_map != NULL) { | if (us->id_map != NULL) { | ||||
| BKE_undosys_ID_map_destroy(us->id_map); | BKE_undosys_ID_map_destroy(us->id_map); | ||||
| } | } | ||||
| } | } | ||||
| static void mesh_undosys_foreach_ID_ref( | static void mesh_undosys_foreach_ID_ref( | ||||
| UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data) | UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data) | ||||
| { | { | ||||
| MeshUndoStep *us = (MeshUndoStep *)us_p; | MeshUndoStep *us = (MeshUndoStep *)us_p; | ||||
| foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref)); | |||||
| for (uint i = 0; i < us->elems_len; i++) { | |||||
| MeshUndoStep_Elem *elem = &us->elems[i]; | |||||
| foreach_ID_ref_fn(user_data, ((UndoRefID *)&elem->obedit_ref)); | |||||
| } | |||||
| if (us->id_map != NULL) { | if (us->id_map != NULL) { | ||||
| BKE_undosys_ID_map_foreach_ID_ref(us->id_map, foreach_ID_ref_fn, user_data); | BKE_undosys_ID_map_foreach_ID_ref(us->id_map, foreach_ID_ref_fn, user_data); | ||||
| } | } | ||||
| } | } | ||||
| /* Export for ED_undo_sys. */ | /* Export for ED_undo_sys. */ | ||||
| void ED_mesh_undosys_type(UndoType *ut) | void ED_mesh_undosys_type(UndoType *ut) | ||||
| { | { | ||||
| Show All 15 Lines | |||||