Blender V4.3
editcurve_undo.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "MEM_guardedalloc.h"
10
11#include "CLG_log.h"
12
13#include "DNA_anim_types.h"
14#include "DNA_object_types.h"
15#include "DNA_scene_types.h"
16
17#include "BLI_array_utils.h"
18#include "BLI_blenlib.h"
19#include "BLI_ghash.h"
20
21#include "BKE_anim_data.hh"
22#include "BKE_context.hh"
23#include "BKE_curve.hh"
24#include "BKE_fcurve.hh"
25#include "BKE_layer.hh"
26#include "BKE_main.hh"
27#include "BKE_object.hh"
28#include "BKE_undo_system.hh"
29
30#include "DEG_depsgraph.hh"
31
32#include "ED_curve.hh"
33#include "ED_undo.hh"
34
35#include "WM_api.hh"
36#include "WM_types.hh"
37
38#include "curve_intern.hh"
39
40using blender::Vector;
41
43static CLG_LogRef LOG = {"ed.undo.curve"};
44
45/* -------------------------------------------------------------------- */
49struct UndoCurve {
54 int actnu;
55 int flag;
56
57 /* Stored in the object, needed since users may change the active key while in edit-mode. */
58 struct {
59 short shapenr;
61
62 size_t undo_size;
63};
64
65static void undocurve_to_editcurve(Main *bmain, UndoCurve *ucu, Curve *cu, short *r_shapenr)
66{
67 ListBase *undobase = &ucu->nubase;
68 ListBase *editbase = BKE_curve_editNurbs_get(cu);
69 EditNurb *editnurb = cu->editnurb;
71
72 BKE_nurbList_free(editbase);
73
74 if (ucu->undoIndex) {
77 }
78
79 if (ad) {
80 if (ad->action) {
83 }
84
86 BKE_fcurves_copy(&ad->drivers, &ucu->drivers);
87 }
88
89 /* Copy. */
90 LISTBASE_FOREACH (Nurb *, nu, undobase) {
91 Nurb *newnu = BKE_nurb_duplicate(nu);
92
93 if (editnurb->keyindex) {
94 ED_curve_keyindex_update_nurb(editnurb, nu, newnu);
95 }
96
97 BLI_addtail(editbase, newnu);
98 }
99
100 cu->actvert = ucu->actvert;
101 cu->actnu = ucu->actnu;
102 cu->flag = ucu->flag;
103 *r_shapenr = ucu->obedit.shapenr;
104 ED_curve_updateAnimPaths(bmain, cu);
105}
106
107static void undocurve_from_editcurve(UndoCurve *ucu, Curve *cu, const short shapenr)
108{
110 ListBase *nubase = BKE_curve_editNurbs_get(cu);
111 EditNurb *editnurb = cu->editnurb, tmpEditnurb;
112 AnimData *ad = BKE_animdata_from_id(&cu->id);
113
114 /* TODO: include size of fcurve & undoIndex */
115 // ucu->undo_size = 0;
116
117 if (editnurb->keyindex) {
119 tmpEditnurb.keyindex = ucu->undoIndex;
120 }
121
122 if (ad) {
123 if (ad->action) {
125 }
126
127 BKE_fcurves_copy(&ucu->drivers, &ad->drivers);
128 }
129
130 /* Copy. */
131 LISTBASE_FOREACH (Nurb *, nu, nubase) {
132 Nurb *newnu = BKE_nurb_duplicate(nu);
133
134 if (ucu->undoIndex) {
135 ED_curve_keyindex_update_nurb(&tmpEditnurb, nu, newnu);
136 }
137
138 BLI_addtail(&ucu->nubase, newnu);
139
140 ucu->undo_size += ((nu->bezt ? (sizeof(BezTriple) * nu->pntsu) : 0) +
141 (nu->bp ? (sizeof(BPoint) * (nu->pntsu * nu->pntsv)) : 0) +
142 (nu->knotsu ? (sizeof(float) * KNOTSU(nu)) : 0) +
143 (nu->knotsv ? (sizeof(float) * KNOTSV(nu)) : 0) + sizeof(Nurb));
144 }
145
146 ucu->actvert = cu->actvert;
147 ucu->actnu = cu->actnu;
148 ucu->flag = cu->flag;
149
150 ucu->obedit.shapenr = shapenr;
151}
152
162
164{
165 Scene *scene = CTX_data_scene(C);
166 ViewLayer *view_layer = CTX_data_view_layer(C);
167 BKE_view_layer_synced_ensure(scene, view_layer);
168 Object *obedit = BKE_view_layer_edit_object_get(view_layer);
169 if (obedit && ELEM(obedit->type, OB_CURVES_LEGACY, OB_SURF)) {
170 Curve *cu = static_cast<Curve *>(obedit->data);
171 if (BKE_curve_editNurbs_get(cu) != nullptr) {
172 return obedit;
173 }
174 }
175 return nullptr;
176}
177
180/* -------------------------------------------------------------------- */
187 UndoRefID_Object obedit_ref;
189};
190
198
200{
202 return (obedit != nullptr);
203}
204
205static bool curve_undosys_step_encode(bContext *C, Main *bmain, UndoStep *us_p)
206{
207 CurveUndoStep *us = (CurveUndoStep *)us_p;
208
209 /* Important not to use the 3D view when getting objects because all objects
210 * outside of this list will be moved out of edit-mode when reading back undo steps. */
211 Scene *scene = CTX_data_scene(C);
212 ViewLayer *view_layer = CTX_data_view_layer(C);
214
215 us->scene_ref.ptr = scene;
216 us->elems = static_cast<CurveUndoStep_Elem *>(
217 MEM_callocN(sizeof(*us->elems) * objects.size(), __func__));
218 us->elems_len = objects.size();
219
220 for (uint i = 0; i < objects.size(); i++) {
221 Object *ob = objects[i];
222 Curve *cu = static_cast<Curve *>(ob->data);
223 CurveUndoStep_Elem *elem = &us->elems[i];
224
225 elem->obedit_ref.ptr = ob;
226 undocurve_from_editcurve(&elem->data, static_cast<Curve *>(ob->data), ob->shapenr);
228 us->step.data_size += elem->data.undo_size;
229 }
230
231 bmain->is_memfile_undo_flush_needed = true;
232
233 return true;
234}
235
237 bContext *C, Main *bmain, UndoStep *us_p, const eUndoStepDir /*dir*/, bool /*is_final*/)
238{
239 CurveUndoStep *us = (CurveUndoStep *)us_p;
240 Scene *scene = CTX_data_scene(C);
241 ViewLayer *view_layer = CTX_data_view_layer(C);
242
244 CTX_wm_manager(C), us->scene_ref.ptr, &scene, &view_layer);
246 scene, view_layer, &us->elems[0].obedit_ref.ptr, us->elems_len, sizeof(*us->elems));
247
249
250 for (uint i = 0; i < us->elems_len; i++) {
251 CurveUndoStep_Elem *elem = &us->elems[i];
252 Object *obedit = elem->obedit_ref.ptr;
253 Curve *cu = static_cast<Curve *>(obedit->data);
254 if (cu->editnurb == nullptr) {
255 /* Should never fail, may not crash but can give odd behavior. */
257 "name='%s', failed to enter edit-mode for object '%s', undo state invalid",
258 us_p->name,
259 obedit->id.name);
260 continue;
261 }
263 bmain, &elem->data, static_cast<Curve *>(obedit->data), &obedit->shapenr);
266 }
267
268 /* The first element is always active */
270 scene, view_layer, us->elems[0].obedit_ref.ptr, us_p->name, &LOG);
271
272 /* Check after setting active (unless undoing into another scene). */
273 BLI_assert(curve_undosys_poll(C) || (scene != CTX_data_scene(C)));
274
275 bmain->is_memfile_undo_flush_needed = true;
276
278}
279
281{
282 CurveUndoStep *us = (CurveUndoStep *)us_p;
283
284 for (uint i = 0; i < us->elems_len; i++) {
285 CurveUndoStep_Elem *elem = &us->elems[i];
287 }
288 MEM_freeN(us->elems);
289}
290
292 UndoTypeForEachIDRefFn foreach_ID_ref_fn,
293 void *user_data)
294{
295 CurveUndoStep *us = (CurveUndoStep *)us_p;
296
297 foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->scene_ref));
298 for (uint i = 0; i < us->elems_len; i++) {
299 CurveUndoStep_Elem *elem = &us->elems[i];
300 foreach_ID_ref_fn(user_data, ((UndoRefID *)&elem->obedit_ref));
301 }
302}
303
318
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:89
Scene * CTX_data_scene(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
#define KNOTSU(nu)
Definition BKE_curve.hh:71
#define KNOTSV(nu)
Definition BKE_curve.hh:73
void BKE_curve_editNurb_keyIndex_free(GHash **keyindex)
Definition curve.cc:328
void BKE_nurbList_free(ListBase *lb)
Definition curve.cc:596
ListBase * BKE_curve_editNurbs_get(Curve *cu)
Definition curve.cc:398
Nurb * BKE_nurb_duplicate(const Nurb *nu)
Definition curve.cc:608
void BKE_fcurves_free(ListBase *list)
void BKE_fcurves_copy(ListBase *dst, ListBase *src)
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
Object * BKE_view_layer_edit_object_get(const ViewLayer *view_layer)
General operations, lookup, etc. for blender objects.
bool BKE_object_is_in_editmode(const Object *ob)
@ UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE
void(*)(void *user_data, UndoRefID *id_ref) UndoTypeForEachIDRefFn
eUndoStepDir
Generic array manipulation API.
#define BLI_array_is_zeroed(arr, arr_len)
#define BLI_assert(a)
Definition BLI_assert.h:50
#define LISTBASE_FOREACH(type, var, list)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
unsigned int uint
#define ELEM(...)
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:182
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
struct BezTriple BezTriple
Object is a sort of wrapper for general info.
@ OB_SURF
@ OB_CURVES_LEGACY
void ED_undo_object_set_active_or_warn(Scene *scene, ViewLayer *view_layer, Object *ob, const char *info, CLG_LogRef *log)
Definition ed_undo.cc:790
void ED_undo_object_editmode_restore_helper(Scene *scene, ViewLayer *view_layer, Object **object_array, uint object_array_len, uint object_array_stride)
Definition ed_undo.cc:826
blender::Vector< Object * > ED_undo_editmode_objects_from_view_layer(const Scene *scene, ViewLayer *view_layer)
Definition ed_undo.cc:871
void ED_undo_object_editmode_validate_scene_from_windows(wmWindowManager *wm, const Scene *scene_ref, Scene **scene_p, ViewLayer **view_layer_p)
Definition ed_undo.cc:809
Read Guarded memory(de)allocation.
#define NC_GEOM
Definition WM_types.hh:360
#define ND_DATA
Definition WM_types.hh:475
void ED_curve_keyindex_update_nurb(EditNurb *editnurb, Nurb *nu, Nurb *newnu)
Definition editcurve.cc:354
GHash * ED_curve_keyindex_hash_duplicate(GHash *keyindex)
Definition editcurve.cc:543
int ED_curve_updateAnimPaths(Main *bmain, Curve *cu)
static void curve_undosys_foreach_ID_ref(UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
static void curve_undosys_step_free(UndoStep *us_p)
static bool curve_undosys_poll(bContext *C)
static Object * editcurve_object_from_context(bContext *C)
static bool curve_undosys_step_encode(bContext *C, 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)
static void undocurve_free_data(UndoCurve *uc)
static void undocurve_from_editcurve(UndoCurve *ucu, Curve *cu, const short shapenr)
static void curve_undosys_step_decode(bContext *C, Main *bmain, UndoStep *us_p, const eUndoStepDir, bool)
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
bAction * action
ListBase drivers
UndoRefID_Object obedit_ref
CurveUndoStep_Elem * elems
UndoRefID_Scene scene_ref
EditNurb * editnurb
char needs_flush_to_id
struct GHash * keyindex
char name[66]
Definition DNA_ID.h:425
bool is_memfile_undo_flush_needed
Definition BKE_main.hh:165
struct UndoCurve::@317 obedit
size_t undo_size
ListBase drivers
GHash * undoIndex
ListBase fcurves
ListBase nubase
size_t data_size
char name[64]
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(* step_decode)(bContext *C, Main *bmain, UndoStep *us, eUndoStepDir dir, bool is_final)
bool(* step_encode)(bContext *C, Main *bmain, UndoStep *us)
ListBase curves
void WM_event_add_notifier(const bContext *C, uint type, void *reference)