Blender  V3.3
editarmature_undo.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
3 
8 #include "MEM_guardedalloc.h"
9 
10 #include "CLG_log.h"
11 
12 #include "DNA_armature_types.h"
13 #include "DNA_layer_types.h"
14 #include "DNA_object_types.h"
15 #include "DNA_scene_types.h"
16 
17 #include "BLI_array_utils.h"
18 #include "BLI_listbase.h"
19 
20 #include "BKE_armature.h"
21 #include "BKE_context.h"
22 #include "BKE_layer.h"
23 #include "BKE_main.h"
24 #include "BKE_object.h"
25 #include "BKE_undo_system.h"
26 
27 #include "DEG_depsgraph.h"
28 
29 #include "ED_armature.h"
30 #include "ED_object.h"
31 #include "ED_undo.h"
32 #include "ED_util.h"
33 
34 #include "WM_api.h"
35 #include "WM_types.h"
36 
38 static CLG_LogRef LOG = {"ed.undo.armature"};
39 
40 /* -------------------------------------------------------------------- */
44 typedef struct UndoArmature {
47  size_t undo_size;
49 
50 static void undoarm_to_editarm(UndoArmature *uarm, bArmature *arm)
51 {
52  EditBone *ebone;
53 
55  ED_armature_ebone_listbase_copy(arm->edbo, &uarm->lb, true);
56 
57  /* active bone */
58  if (uarm->act_edbone) {
59  ebone = uarm->act_edbone;
60  arm->act_edbone = ebone->temp.ebone;
61  }
62  else {
63  arm->act_edbone = NULL;
64  }
65 
67 }
68 
69 static void *undoarm_from_editarm(UndoArmature *uarm, bArmature *arm)
70 {
72 
73  /* TODO: include size of ID-properties. */
74  uarm->undo_size = 0;
75 
76  ED_armature_ebone_listbase_copy(&uarm->lb, arm->edbo, false);
77 
78  /* active bone */
79  if (arm->act_edbone) {
80  EditBone *ebone = arm->act_edbone;
81  uarm->act_edbone = ebone->temp.ebone;
82  }
83 
85 
86  LISTBASE_FOREACH (EditBone *, ebone, &uarm->lb) {
87  uarm->undo_size += sizeof(EditBone);
88  }
89 
90  return uarm;
91 }
92 
93 static void undoarm_free_data(UndoArmature *uarm)
94 {
95  ED_armature_ebone_listbase_free(&uarm->lb, false);
96 }
97 
99 {
100  ViewLayer *view_layer = CTX_data_view_layer(C);
101  Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
102  if (obedit && obedit->type == OB_ARMATURE) {
103  bArmature *arm = obedit->data;
104  if (arm->edbo != NULL) {
105  return obedit;
106  }
107  }
108  return NULL;
109 }
110 
113 /* -------------------------------------------------------------------- */
119 typedef struct ArmatureUndoStep_Elem {
121  UndoRefID_Object obedit_ref;
124 
125 typedef struct ArmatureUndoStep {
130 
132 {
134 }
135 
136 static bool armature_undosys_step_encode(struct bContext *C, struct Main *bmain, UndoStep *us_p)
137 {
138  ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
139 
140  /* Important not to use the 3D view when getting objects because all objects
141  * outside of this list will be moved out of edit-mode when reading back undo steps. */
142  ViewLayer *view_layer = CTX_data_view_layer(C);
143  uint objects_len = 0;
144  Object **objects = ED_undo_editmode_objects_from_view_layer(view_layer, &objects_len);
145 
146  us->elems = MEM_callocN(sizeof(*us->elems) * objects_len, __func__);
147  us->elems_len = objects_len;
148 
149  for (uint i = 0; i < objects_len; i++) {
150  Object *ob = objects[i];
151  ArmatureUndoStep_Elem *elem = &us->elems[i];
152 
153  elem->obedit_ref.ptr = ob;
154  bArmature *arm = elem->obedit_ref.ptr->data;
155  undoarm_from_editarm(&elem->data, arm);
156  arm->needs_flush_to_id = 1;
157  us->step.data_size += elem->data.undo_size;
158  }
159  MEM_freeN(objects);
160 
161  bmain->is_memfile_undo_flush_needed = true;
162 
163  return true;
164 }
165 
167  struct Main *bmain,
168  UndoStep *us_p,
169  const eUndoStepDir UNUSED(dir),
170  bool UNUSED(is_final))
171 {
172  ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
173 
175  C, &us->elems[0].obedit_ref.ptr, us->elems_len, sizeof(*us->elems));
176 
178 
179  for (uint i = 0; i < us->elems_len; i++) {
180  ArmatureUndoStep_Elem *elem = &us->elems[i];
181  Object *obedit = elem->obedit_ref.ptr;
182  bArmature *arm = obedit->data;
183  if (arm->edbo == NULL) {
184  /* Should never fail, may not crash but can give odd behavior. */
185  CLOG_ERROR(&LOG,
186  "name='%s', failed to enter edit-mode for object '%s', undo state invalid",
187  us_p->name,
188  obedit->id.name);
189  continue;
190  }
191  undoarm_to_editarm(&elem->data, arm);
192  arm->needs_flush_to_id = 1;
194  }
195 
196  /* The first element is always active */
198  CTX_data_scene(C), CTX_data_view_layer(C), us->elems[0].obedit_ref.ptr, us_p->name, &LOG);
199 
200  /* Check after setting active. */
202 
203  bmain->is_memfile_undo_flush_needed = true;
204 
206 }
207 
209 {
210  ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
211 
212  for (uint i = 0; i < us->elems_len; i++) {
213  ArmatureUndoStep_Elem *elem = &us->elems[i];
214  undoarm_free_data(&elem->data);
215  }
216  MEM_freeN(us->elems);
217 }
218 
220  UndoTypeForEachIDRefFn foreach_ID_ref_fn,
221  void *user_data)
222 {
223  ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
224 
225  for (uint i = 0; i < us->elems_len; i++) {
226  ArmatureUndoStep_Elem *elem = &us->elems[i];
227  foreach_ID_ref_fn(user_data, ((UndoRefID *)&elem->obedit_ref));
228  }
229 }
230 
232 {
233  ut->name = "Edit Armature";
238 
240 
242 
243  ut->step_size = sizeof(ArmatureUndoStep);
244 }
245 
struct EditBone EditBone
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1100
General operations, lookup, etc. for blender objects.
bool BKE_object_is_in_editmode(const struct Object *ob)
@ UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE
eUndoStepDir
void(* UndoTypeForEachIDRefFn)(void *user_data, struct UndoRefID *id_ref)
Generic array manipulation API.
#define BLI_array_is_zeroed(arr, arr_len)
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
unsigned int uint
Definition: BLI_sys_types.h:67
#define UNUSED(x)
#define CLOG_ERROR(clg_ref,...)
Definition: CLG_log.h:190
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
Object is a sort of wrapper for general info.
@ OB_ARMATURE
#define OBEDIT_FROM_VIEW_LAYER(view_layer)
void ED_undo_object_editmode_restore_helper(struct bContext *C, struct Object **object_array, uint object_array_len, uint object_array_stride)
Definition: ed_undo.c:817
void ED_undo_object_set_active_or_warn(struct Scene *scene, struct ViewLayer *view_layer, struct Object *ob, const char *info, struct CLG_LogRef *log)
Definition: ed_undo.c:800
struct Object ** ED_undo_editmode_objects_from_view_layer(struct ViewLayer *view_layer, uint *r_len)
Definition: ed_undo.c:888
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:25
#define NC_GEOM
Definition: WM_types.h:343
#define ND_DATA
Definition: WM_types.h:456
void ED_armature_ebone_listbase_temp_clear(ListBase *lb)
void ED_armature_ebone_listbase_free(ListBase *lb, const bool do_id_user)
void ED_armature_ebone_listbase_copy(ListBase *lb_dst, ListBase *lb_src, const bool do_id_user)
void * user_data
static void armature_undosys_foreach_ID_ref(UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
static bool armature_undosys_poll(bContext *C)
static void armature_undosys_step_decode(struct bContext *C, struct Main *bmain, UndoStep *us_p, const eUndoStepDir UNUSED(dir), bool UNUSED(is_final))
struct ArmatureUndoStep_Elem ArmatureUndoStep_Elem
static bool armature_undosys_step_encode(struct bContext *C, struct Main *bmain, UndoStep *us_p)
static void * undoarm_from_editarm(UndoArmature *uarm, bArmature *arm)
static Object * editarm_object_from_context(bContext *C)
static void armature_undosys_step_free(UndoStep *us_p)
void ED_armature_undosys_type(UndoType *ut)
static void undoarm_free_data(UndoArmature *uarm)
struct ArmatureUndoStep ArmatureUndoStep
static void undoarm_to_editarm(UndoArmature *uarm, bArmature *arm)
static CLG_LogRef LOG
struct UndoArmature UndoArmature
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
struct ArmatureUndoStep_Elem * next
UndoRefID_Object obedit_ref
struct ArmatureUndoStep_Elem * prev
ArmatureUndoStep_Elem * elems
struct EditBone * ebone
Definition: BKE_armature.h:105
union EditBone::@3 temp
char name[66]
Definition: DNA_ID.h:378
Definition: BKE_main.h:121
char is_memfile_undo_flush_needed
Definition: BKE_main.h:145
void * data
EditBone * act_edbone
size_t data_size
char name[64]
size_t step_size
void(* step_decode)(struct bContext *C, struct Main *bmain, UndoStep *us, eUndoStepDir dir, bool is_final)
bool(* step_encode)(struct bContext *C, struct Main *bmain, UndoStep *us)
void(* step_foreach_ID_ref)(UndoStep *us, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
const char * name
void(* step_free)(UndoStep *us)
bool(* poll)(struct bContext *C)
struct EditBone * act_edbone
ListBase * edbo
void WM_event_add_notifier(const bContext *C, uint type, void *reference)