Blender  V2.93
editmball_undo.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
21 #include <math.h>
22 #include <string.h>
23 
24 #include "MEM_guardedalloc.h"
25 
26 #include "CLG_log.h"
27 
28 #include "BLI_array_utils.h"
29 #include "BLI_listbase.h"
30 #include "BLI_utildefines.h"
31 
32 #include "DNA_defs.h"
33 #include "DNA_layer_types.h"
34 #include "DNA_meta_types.h"
35 #include "DNA_object_types.h"
36 #include "DNA_scene_types.h"
37 
38 #include "BKE_context.h"
39 #include "BKE_layer.h"
40 #include "BKE_main.h"
41 #include "BKE_object.h"
42 #include "BKE_undo_system.h"
43 
44 #include "DEG_depsgraph.h"
45 
46 #include "ED_mball.h"
47 #include "ED_object.h"
48 #include "ED_undo.h"
49 #include "ED_util.h"
50 
51 #include "WM_api.h"
52 #include "WM_types.h"
53 
55 static CLG_LogRef LOG = {"ed.undo.mball"};
56 
57 /* -------------------------------------------------------------------- */
61 typedef struct UndoMBall {
64  size_t undo_size;
66 
67 /* free all MetaElems from ListBase */
68 static void freeMetaElemlist(ListBase *lb)
69 {
70  MetaElem *ml;
71 
72  if (lb == NULL) {
73  return;
74  }
75 
76  while ((ml = BLI_pophead(lb))) {
77  MEM_freeN(ml);
78  }
79 }
80 
82 {
84  mb->lastelem = NULL;
85 
86  /* copy 'undo' MetaElems to 'edit' MetaElems */
87  int index = 0;
88  for (MetaElem *ml_undo = umb->editelems.first; ml_undo; ml_undo = ml_undo->next, index += 1) {
89  MetaElem *ml_edit = MEM_dupallocN(ml_undo);
90  BLI_addtail(mb->editelems, ml_edit);
91  if (index == umb->lastelem_index) {
92  mb->lastelem = ml_edit;
93  }
94  }
95 }
96 
98 {
100 
101  /* allocate memory for undo ListBase */
102  umb->lastelem_index = -1;
103 
104  /* copy contents of current ListBase to the undo ListBase */
105  int index = 0;
106  for (MetaElem *ml_edit = mb->editelems->first; ml_edit; ml_edit = ml_edit->next, index += 1) {
107  MetaElem *ml_undo = MEM_dupallocN(ml_edit);
108  BLI_addtail(&umb->editelems, ml_undo);
109  if (ml_edit == mb->lastelem) {
110  umb->lastelem_index = index;
111  }
112  umb->undo_size += sizeof(MetaElem);
113  }
114 
115  return umb;
116 }
117 
118 /* free undo ListBase of MetaElems */
120 {
122 }
123 
125 {
126  ViewLayer *view_layer = CTX_data_view_layer(C);
127  Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
128  if (obedit && obedit->type == OB_MBALL) {
129  MetaBall *mb = obedit->data;
130  if (mb->editelems != NULL) {
131  return obedit;
132  }
133  }
134  return NULL;
135 }
136 
139 /* -------------------------------------------------------------------- */
145 typedef struct MBallUndoStep_Elem {
146  UndoRefID_Object obedit_ref;
149 
150 typedef struct MBallUndoStep {
155 
157 {
159 }
160 
161 static bool mball_undosys_step_encode(struct bContext *C, struct Main *bmain, UndoStep *us_p)
162 {
163  MBallUndoStep *us = (MBallUndoStep *)us_p;
164 
165  /* Important not to use the 3D view when getting objects because all objects
166  * outside of this list will be moved out of edit-mode when reading back undo steps. */
167  ViewLayer *view_layer = CTX_data_view_layer(C);
168  uint objects_len = 0;
169  Object **objects = ED_undo_editmode_objects_from_view_layer(view_layer, &objects_len);
170 
171  us->elems = MEM_callocN(sizeof(*us->elems) * objects_len, __func__);
172  us->elems_len = objects_len;
173 
174  for (uint i = 0; i < objects_len; i++) {
175  Object *ob = objects[i];
176  MBallUndoStep_Elem *elem = &us->elems[i];
177 
178  elem->obedit_ref.ptr = ob;
179  MetaBall *mb = ob->data;
180  editmball_from_undomball(&elem->data, mb);
181  mb->needs_flush_to_id = 1;
182  us->step.data_size += elem->data.undo_size;
183  }
184  MEM_freeN(objects);
185 
186  bmain->is_memfile_undo_flush_needed = true;
187 
188  return true;
189 }
190 
192  struct Main *bmain,
193  UndoStep *us_p,
194  const eUndoStepDir UNUSED(dir),
195  bool UNUSED(is_final))
196 {
197  MBallUndoStep *us = (MBallUndoStep *)us_p;
198 
200  C, &us->elems[0].obedit_ref.ptr, us->elems_len, sizeof(*us->elems));
201 
203 
204  for (uint i = 0; i < us->elems_len; i++) {
205  MBallUndoStep_Elem *elem = &us->elems[i];
206  Object *obedit = elem->obedit_ref.ptr;
207  MetaBall *mb = obedit->data;
208  if (mb->editelems == NULL) {
209  /* Should never fail, may not crash but can give odd behavior. */
210  CLOG_ERROR(&LOG,
211  "name='%s', failed to enter edit-mode for object '%s', undo state invalid",
212  us_p->name,
213  obedit->id.name);
214  continue;
215  }
216  undomball_to_editmball(&elem->data, mb);
217  mb->needs_flush_to_id = 1;
219  }
220 
221  /* The first element is always active */
223  CTX_data_scene(C), CTX_data_view_layer(C), us->elems[0].obedit_ref.ptr, us_p->name, &LOG);
224 
225  /* Check after setting active. */
227 
228  bmain->is_memfile_undo_flush_needed = true;
229 
231 }
232 
234 {
235  MBallUndoStep *us = (MBallUndoStep *)us_p;
236 
237  for (uint i = 0; i < us->elems_len; i++) {
238  MBallUndoStep_Elem *elem = &us->elems[i];
239  undomball_free_data(&elem->data);
240  }
241  MEM_freeN(us->elems);
242 }
243 
245  UndoTypeForEachIDRefFn foreach_ID_ref_fn,
246  void *user_data)
247 {
248  MBallUndoStep *us = (MBallUndoStep *)us_p;
249 
250  for (uint i = 0; i < us->elems_len; i++) {
251  MBallUndoStep_Elem *elem = &us->elems[i];
252  foreach_ID_ref_fn(user_data, ((UndoRefID *)&elem->obedit_ref));
253  }
254 }
255 
256 /* Export for ED_undo_sys. */
258 {
259  ut->name = "Edit MBall";
260  ut->poll = mball_undosys_poll;
264 
266 
268 
269  ut->step_size = sizeof(MBallUndoStep);
270 }
271 
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1044
General operations, lookup, etc. for blender objects.
bool BKE_object_is_in_editmode(const struct Object *ob)
eUndoStepDir
@ UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE
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:58
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:257
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNUSED(x)
#define CLOG_ERROR(clg_ref,...)
Definition: CLG_log.h:204
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:611
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:897
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:877
struct Object ** ED_undo_editmode_objects_from_view_layer(struct ViewLayer *view_layer, uint *r_len)
Definition: ed_undo.c:968
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:39
#define NC_GEOM
Definition: WM_types.h:294
#define ND_DATA
Definition: WM_types.h:408
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:41
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:42
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
char name[66]
Definition: DNA_ID.h:283
void * first
Definition: DNA_listBase.h:47
UndoRefID_Object obedit_ref
MBallUndoStep_Elem * elems
Definition: BKE_main.h:116
char is_memfile_undo_flush_needed
Definition: BKE_main.h:130
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, const 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)