Blender  V3.3
editcurve_undo.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include "MEM_guardedalloc.h"
8 
9 #include "CLG_log.h"
10 
11 #include "DNA_anim_types.h"
12 #include "DNA_object_types.h"
13 #include "DNA_scene_types.h"
14 
15 #include "BLI_array_utils.h"
16 #include "BLI_blenlib.h"
17 #include "BLI_ghash.h"
18 
19 #include "BKE_anim_data.h"
20 #include "BKE_context.h"
21 #include "BKE_curve.h"
22 #include "BKE_fcurve.h"
23 #include "BKE_layer.h"
24 #include "BKE_main.h"
25 #include "BKE_object.h"
26 #include "BKE_undo_system.h"
27 
28 #include "DEG_depsgraph.h"
29 
30 #include "ED_curve.h"
31 #include "ED_undo.h"
32 
33 #include "WM_api.h"
34 #include "WM_types.h"
35 
36 #include "curve_intern.h"
37 
39 static CLG_LogRef LOG = {"ed.undo.curve"};
40 
41 /* -------------------------------------------------------------------- */
45 typedef struct {
47  int actvert;
49  ListBase fcurves, drivers;
50  int actnu;
51  int flag;
52 
53  /* Stored in the object, needed since users may change the active key while in edit-mode. */
54  struct {
55  short shapenr;
56  } obedit;
57 
58  size_t undo_size;
59 } UndoCurve;
60 
61 static void undocurve_to_editcurve(Main *bmain, UndoCurve *ucu, Curve *cu, short *r_shapenr)
62 {
63  ListBase *undobase = &ucu->nubase;
64  ListBase *editbase = BKE_curve_editNurbs_get(cu);
65  Nurb *nu, *newnu;
66  EditNurb *editnurb = cu->editnurb;
67  AnimData *ad = BKE_animdata_from_id(&cu->id);
68 
69  BKE_nurbList_free(editbase);
70 
71  if (ucu->undoIndex) {
74  }
75 
76  if (ad) {
77  if (ad->action) {
79  BKE_fcurves_copy(&ad->action->curves, &ucu->fcurves);
80  }
81 
83  BKE_fcurves_copy(&ad->drivers, &ucu->drivers);
84  }
85 
86  /* Copy. */
87  for (nu = undobase->first; nu; nu = nu->next) {
88  newnu = BKE_nurb_duplicate(nu);
89 
90  if (editnurb->keyindex) {
91  ED_curve_keyindex_update_nurb(editnurb, nu, newnu);
92  }
93 
94  BLI_addtail(editbase, newnu);
95  }
96 
97  cu->actvert = ucu->actvert;
98  cu->actnu = ucu->actnu;
99  cu->flag = ucu->flag;
100  *r_shapenr = ucu->obedit.shapenr;
101  ED_curve_updateAnimPaths(bmain, cu);
102 }
103 
104 static void undocurve_from_editcurve(UndoCurve *ucu, Curve *cu, const short shapenr)
105 {
107  ListBase *nubase = BKE_curve_editNurbs_get(cu);
108  EditNurb *editnurb = cu->editnurb, tmpEditnurb;
109  Nurb *nu, *newnu;
110  AnimData *ad = BKE_animdata_from_id(&cu->id);
111 
112  /* TODO: include size of fcurve & undoIndex */
113  // ucu->undo_size = 0;
114 
115  if (editnurb->keyindex) {
117  tmpEditnurb.keyindex = ucu->undoIndex;
118  }
119 
120  if (ad) {
121  if (ad->action) {
122  BKE_fcurves_copy(&ucu->fcurves, &ad->action->curves);
123  }
124 
125  BKE_fcurves_copy(&ucu->drivers, &ad->drivers);
126  }
127 
128  /* Copy. */
129  for (nu = nubase->first; nu; nu = nu->next) {
130  newnu = BKE_nurb_duplicate(nu);
131 
132  if (ucu->undoIndex) {
133  ED_curve_keyindex_update_nurb(&tmpEditnurb, nu, newnu);
134  }
135 
136  BLI_addtail(&ucu->nubase, newnu);
137 
138  ucu->undo_size += ((nu->bezt ? (sizeof(BezTriple) * nu->pntsu) : 0) +
139  (nu->bp ? (sizeof(BPoint) * (nu->pntsu * nu->pntsv)) : 0) +
140  (nu->knotsu ? (sizeof(float) * KNOTSU(nu)) : 0) +
141  (nu->knotsv ? (sizeof(float) * KNOTSV(nu)) : 0) + sizeof(Nurb));
142  }
143 
144  ucu->actvert = cu->actvert;
145  ucu->actnu = cu->actnu;
146  ucu->flag = cu->flag;
147 
148  ucu->obedit.shapenr = shapenr;
149 }
150 
152 {
154 
156 
159 }
160 
162 {
163  ViewLayer *view_layer = CTX_data_view_layer(C);
164  Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
165  if (obedit && ELEM(obedit->type, OB_CURVES_LEGACY, OB_SURF)) {
166  Curve *cu = obedit->data;
167  if (BKE_curve_editNurbs_get(cu) != NULL) {
168  return obedit;
169  }
170  }
171  return NULL;
172 }
173 
176 /* -------------------------------------------------------------------- */
182 typedef struct CurveUndoStep_Elem {
183  UndoRefID_Object obedit_ref;
186 
187 typedef struct CurveUndoStep {
192 
194 {
196  return (obedit != NULL);
197 }
198 
199 static bool curve_undosys_step_encode(struct bContext *C, struct Main *bmain, UndoStep *us_p)
200 {
201  CurveUndoStep *us = (CurveUndoStep *)us_p;
202 
203  /* Important not to use the 3D view when getting objects because all objects
204  * outside of this list will be moved out of edit-mode when reading back undo steps. */
205  ViewLayer *view_layer = CTX_data_view_layer(C);
206  uint objects_len = 0;
207  Object **objects = ED_undo_editmode_objects_from_view_layer(view_layer, &objects_len);
208 
209  us->elems = MEM_callocN(sizeof(*us->elems) * objects_len, __func__);
210  us->elems_len = objects_len;
211 
212  for (uint i = 0; i < objects_len; i++) {
213  Object *ob = objects[i];
214  Curve *cu = ob->data;
215  CurveUndoStep_Elem *elem = &us->elems[i];
216 
217  elem->obedit_ref.ptr = ob;
218  undocurve_from_editcurve(&elem->data, ob->data, ob->shapenr);
219  cu->editnurb->needs_flush_to_id = 1;
220  us->step.data_size += elem->data.undo_size;
221  }
222  MEM_freeN(objects);
223 
224  bmain->is_memfile_undo_flush_needed = true;
225 
226  return true;
227 }
228 
230  struct Main *bmain,
231  UndoStep *us_p,
232  const eUndoStepDir UNUSED(dir),
233  bool UNUSED(is_final))
234 {
235  CurveUndoStep *us = (CurveUndoStep *)us_p;
236 
238  C, &us->elems[0].obedit_ref.ptr, us->elems_len, sizeof(*us->elems));
239 
241 
242  for (uint i = 0; i < us->elems_len; i++) {
243  CurveUndoStep_Elem *elem = &us->elems[i];
244  Object *obedit = elem->obedit_ref.ptr;
245  Curve *cu = obedit->data;
246  if (cu->editnurb == NULL) {
247  /* Should never fail, may not crash but can give odd behavior. */
248  CLOG_ERROR(&LOG,
249  "name='%s', failed to enter edit-mode for object '%s', undo state invalid",
250  us_p->name,
251  obedit->id.name);
252  continue;
253  }
254  undocurve_to_editcurve(bmain, &elem->data, obedit->data, &obedit->shapenr);
255  cu->editnurb->needs_flush_to_id = 1;
257  }
258 
259  /* The first element is always active */
261  CTX_data_scene(C), CTX_data_view_layer(C), us->elems[0].obedit_ref.ptr, us_p->name, &LOG);
262 
263  /* Check after setting active. */
265 
266  bmain->is_memfile_undo_flush_needed = true;
267 
269 }
270 
272 {
273  CurveUndoStep *us = (CurveUndoStep *)us_p;
274 
275  for (uint i = 0; i < us->elems_len; i++) {
276  CurveUndoStep_Elem *elem = &us->elems[i];
277  undocurve_free_data(&elem->data);
278  }
279  MEM_freeN(us->elems);
280 }
281 
283  UndoTypeForEachIDRefFn foreach_ID_ref_fn,
284  void *user_data)
285 {
286  CurveUndoStep *us = (CurveUndoStep *)us_p;
287 
288  for (uint i = 0; i < us->elems_len; i++) {
289  CurveUndoStep_Elem *elem = &us->elems[i];
290  foreach_ID_ref_fn(user_data, ((UndoRefID *)&elem->obedit_ref));
291  }
292 }
293 
295 {
296  ut->name = "Edit Curve";
297  ut->poll = curve_undosys_poll;
301 
303 
305 
306  ut->step_size = sizeof(CurveUndoStep);
307 }
308 
typedef float(TangentPoint)[2]
struct AnimData * BKE_animdata_from_id(const struct ID *id)
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
#define KNOTSU(nu)
Definition: BKE_curve.h:52
struct ListBase * BKE_curve_editNurbs_get(struct Curve *cu)
Definition: curve.cc:426
struct Nurb * BKE_nurb_duplicate(const struct Nurb *nu)
#define KNOTSV(nu)
Definition: BKE_curve.h:54
void BKE_nurbList_free(struct ListBase *lb)
Definition: curve.cc:649
void BKE_curve_editNurb_keyIndex_free(struct GHash **keyindex)
Definition: curve.cc:369
void BKE_fcurves_free(ListBase *list)
Definition: fcurve.c:86
void BKE_fcurves_copy(ListBase *dst, ListBase *src)
Definition: fcurve.c:146
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_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 ELEM(...)
#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 Nurb Nurb
struct BezTriple BezTriple
Object is a sort of wrapper for general info.
@ OB_SURF
@ OB_CURVES_LEGACY
#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
struct GHash * ED_curve_keyindex_hash_duplicate(struct GHash *keyindex)
Definition: editcurve.c:521
void ED_curve_keyindex_update_nurb(struct EditNurb *editnurb, struct Nurb *nu, struct Nurb *newnu)
Definition: editcurve.c:332
void * user_data
int ED_curve_updateAnimPaths(Main *bmain, Curve *cu)
Definition: editcurve.c:1062
static void curve_undosys_foreach_ID_ref(UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
static Object * editcurve_object_from_context(bContext *C)
static void curve_undosys_step_free(UndoStep *us_p)
static bool curve_undosys_poll(bContext *C)
static bool curve_undosys_step_encode(struct bContext *C, struct Main *bmain, UndoStep *us_p)
void ED_curve_undosys_type(UndoType *ut)
static CLG_LogRef LOG
static void undocurve_to_editcurve(Main *bmain, UndoCurve *ucu, Curve *cu, short *r_shapenr)
struct CurveUndoStep_Elem CurveUndoStep_Elem
static void undocurve_free_data(UndoCurve *uc)
static void undocurve_from_editcurve(UndoCurve *ucu, Curve *cu, const short shapenr)
struct CurveUndoStep CurveUndoStep
static void curve_undosys_step_decode(struct bContext *C, struct Main *bmain, UndoStep *us_p, const eUndoStepDir UNUSED(dir), bool UNUSED(is_final))
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
struct UndoCurve UndoCurve
bAction * action
ListBase drivers
UndoRefID_Object obedit_ref
CurveUndoStep_Elem * elems
EditNurb * editnurb
char needs_flush_to_id
struct GHash * keyindex
char name[66]
Definition: DNA_ID.h:378
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
char is_memfile_undo_flush_needed
Definition: BKE_main.h:145
struct Nurb * next
float * knotsu
float * knotsv
BezTriple * bezt
BPoint * bp
short shapenr
void * data
struct UndoCurve::@341 obedit
short shapenr
size_t undo_size
ListBase drivers
GHash * undoIndex
ListBase fcurves
ListBase nubase
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)
ListBase curves
void WM_event_add_notifier(const bContext *C, uint type, void *reference)