Blender  V3.3
editmball_undo.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include <math.h>
8 #include <string.h>
9 
10 #include "MEM_guardedalloc.h"
11 
12 #include "CLG_log.h"
13 
14 #include "BLI_array_utils.h"
15 #include "BLI_listbase.h"
16 #include "BLI_utildefines.h"
17 
18 #include "DNA_defs.h"
19 #include "DNA_layer_types.h"
20 #include "DNA_meta_types.h"
21 #include "DNA_object_types.h"
22 #include "DNA_scene_types.h"
23 
24 #include "BKE_context.h"
25 #include "BKE_layer.h"
26 #include "BKE_main.h"
27 #include "BKE_object.h"
28 #include "BKE_undo_system.h"
29 
30 #include "DEG_depsgraph.h"
31 
32 #include "ED_mball.h"
33 #include "ED_object.h"
34 #include "ED_undo.h"
35 #include "ED_util.h"
36 
37 #include "WM_api.h"
38 #include "WM_types.h"
39 
41 static CLG_LogRef LOG = {"ed.undo.mball"};
42 
43 /* -------------------------------------------------------------------- */
47 typedef struct UndoMBall {
50  size_t undo_size;
52 
53 /* free all MetaElems from ListBase */
54 static void freeMetaElemlist(ListBase *lb)
55 {
56  MetaElem *ml;
57 
58  if (lb == NULL) {
59  return;
60  }
61 
62  while ((ml = BLI_pophead(lb))) {
63  MEM_freeN(ml);
64  }
65 }
66 
68 {
70  mb->lastelem = NULL;
71 
72  /* copy 'undo' MetaElems to 'edit' MetaElems */
73  int index = 0;
74  for (MetaElem *ml_undo = umb->editelems.first; ml_undo; ml_undo = ml_undo->next, index += 1) {
75  MetaElem *ml_edit = MEM_dupallocN(ml_undo);
76  BLI_addtail(mb->editelems, ml_edit);
77  if (index == umb->lastelem_index) {
78  mb->lastelem = ml_edit;
79  }
80  }
81 }
82 
84 {
86 
87  /* allocate memory for undo ListBase */
88  umb->lastelem_index = -1;
89 
90  /* copy contents of current ListBase to the undo ListBase */
91  int index = 0;
92  for (MetaElem *ml_edit = mb->editelems->first; ml_edit; ml_edit = ml_edit->next, index += 1) {
93  MetaElem *ml_undo = MEM_dupallocN(ml_edit);
94  BLI_addtail(&umb->editelems, ml_undo);
95  if (ml_edit == mb->lastelem) {
96  umb->lastelem_index = index;
97  }
98  umb->undo_size += sizeof(MetaElem);
99  }
100 
101  return umb;
102 }
103 
104 /* free undo ListBase of MetaElems */
106 {
108 }
109 
111 {
112  ViewLayer *view_layer = CTX_data_view_layer(C);
113  Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
114  if (obedit && obedit->type == OB_MBALL) {
115  MetaBall *mb = obedit->data;
116  if (mb->editelems != NULL) {
117  return obedit;
118  }
119  }
120  return NULL;
121 }
122 
125 /* -------------------------------------------------------------------- */
131 typedef struct MBallUndoStep_Elem {
132  UndoRefID_Object obedit_ref;
135 
136 typedef struct MBallUndoStep {
141 
143 {
145 }
146 
147 static bool mball_undosys_step_encode(struct bContext *C, struct Main *bmain, UndoStep *us_p)
148 {
149  MBallUndoStep *us = (MBallUndoStep *)us_p;
150 
151  /* Important not to use the 3D view when getting objects because all objects
152  * outside of this list will be moved out of edit-mode when reading back undo steps. */
153  ViewLayer *view_layer = CTX_data_view_layer(C);
154  uint objects_len = 0;
155  Object **objects = ED_undo_editmode_objects_from_view_layer(view_layer, &objects_len);
156 
157  us->elems = MEM_callocN(sizeof(*us->elems) * objects_len, __func__);
158  us->elems_len = objects_len;
159 
160  for (uint i = 0; i < objects_len; i++) {
161  Object *ob = objects[i];
162  MBallUndoStep_Elem *elem = &us->elems[i];
163 
164  elem->obedit_ref.ptr = ob;
165  MetaBall *mb = ob->data;
166  editmball_from_undomball(&elem->data, mb);
167  mb->needs_flush_to_id = 1;
168  us->step.data_size += elem->data.undo_size;
169  }
170  MEM_freeN(objects);
171 
172  bmain->is_memfile_undo_flush_needed = true;
173 
174  return true;
175 }
176 
178  struct Main *bmain,
179  UndoStep *us_p,
180  const eUndoStepDir UNUSED(dir),
181  bool UNUSED(is_final))
182 {
183  MBallUndoStep *us = (MBallUndoStep *)us_p;
184 
186  C, &us->elems[0].obedit_ref.ptr, us->elems_len, sizeof(*us->elems));
187 
189 
190  for (uint i = 0; i < us->elems_len; i++) {
191  MBallUndoStep_Elem *elem = &us->elems[i];
192  Object *obedit = elem->obedit_ref.ptr;
193  MetaBall *mb = obedit->data;
194  if (mb->editelems == NULL) {
195  /* Should never fail, may not crash but can give odd behavior. */
196  CLOG_ERROR(&LOG,
197  "name='%s', failed to enter edit-mode for object '%s', undo state invalid",
198  us_p->name,
199  obedit->id.name);
200  continue;
201  }
202  undomball_to_editmball(&elem->data, mb);
203  mb->needs_flush_to_id = 1;
205  }
206 
207  /* The first element is always active */
209  CTX_data_scene(C), CTX_data_view_layer(C), us->elems[0].obedit_ref.ptr, us_p->name, &LOG);
210 
211  /* Check after setting active. */
213 
214  bmain->is_memfile_undo_flush_needed = true;
215 
217 }
218 
220 {
221  MBallUndoStep *us = (MBallUndoStep *)us_p;
222 
223  for (uint i = 0; i < us->elems_len; i++) {
224  MBallUndoStep_Elem *elem = &us->elems[i];
225  undomball_free_data(&elem->data);
226  }
227  MEM_freeN(us->elems);
228 }
229 
231  UndoTypeForEachIDRefFn foreach_ID_ref_fn,
232  void *user_data)
233 {
234  MBallUndoStep *us = (MBallUndoStep *)us_p;
235 
236  for (uint i = 0; i < us->elems_len; i++) {
237  MBallUndoStep_Elem *elem = &us->elems[i];
238  foreach_ID_ref_fn(user_data, ((UndoRefID *)&elem->obedit_ref));
239  }
240 }
241 
243 {
244  ut->name = "Edit MBall";
245  ut->poll = mball_undosys_poll;
249 
251 
253 
254  ut->step_size = sizeof(MBallUndoStep);
255 }
256 
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
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:221
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
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
struct MetaElem MetaElem
Object is a sort of wrapper for general info.
@ OB_MBALL
#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 * user_data
struct UndoMBall UndoMBall
static void undomball_free_data(UndoMBall *umb)
static Object * editmball_object_from_context(bContext *C)
static void * editmball_from_undomball(UndoMBall *umb, MetaBall *mb)
static void freeMetaElemlist(ListBase *lb)
static void mball_undosys_foreach_ID_ref(UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
static bool mball_undosys_poll(bContext *C)
static void undomball_to_editmball(UndoMBall *umb, MetaBall *mb)
struct MBallUndoStep_Elem MBallUndoStep_Elem
static CLG_LogRef LOG
void ED_mball_undosys_type(UndoType *ut)
struct MBallUndoStep MBallUndoStep
static void mball_undosys_step_decode(struct bContext *C, struct Main *bmain, UndoStep *us_p, const eUndoStepDir UNUSED(dir), bool UNUSED(is_final))
static void mball_undosys_step_free(UndoStep *us_p)
static bool mball_undosys_step_encode(struct bContext *C, struct Main *bmain, UndoStep *us_p)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:28
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
char name[66]
Definition: DNA_ID.h:378
void * first
Definition: DNA_listBase.h:31
UndoRefID_Object obedit_ref
MBallUndoStep_Elem * elems
Definition: BKE_main.h:121
char is_memfile_undo_flush_needed
Definition: BKE_main.h:145
MetaElem * lastelem
ListBase * editelems
char needs_flush_to_id
void * data
ListBase editelems
int lastelem_index
size_t undo_size
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)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)