Blender V5.0
editarmature_undo.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "MEM_guardedalloc.h"
10
11#include "CLG_log.h"
12
13#include "DNA_armature_types.h"
14#include "DNA_layer_types.h"
15#include "DNA_object_types.h"
16#include "DNA_scene_types.h"
17
18#include "BLI_array_utils.h"
19#include "BLI_listbase.h"
20#include "BLI_map.hh"
21#include "BLI_string.h"
22
23#include "BKE_armature.hh"
24#include "BKE_context.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_armature.hh"
33#include "ED_object.hh"
34#include "ED_undo.hh"
35#include "ED_util.hh"
36
38
39#include "WM_api.hh"
40#include "WM_types.hh"
41
42using namespace blender::animrig;
43
45static CLG_LogRef LOG = {"undo.armature"};
46
47/* Utility functions. */
48
57 ListBase /*EditBone*/ *edit_bones,
59{
60 LISTBASE_FOREACH (EditBone *, ebone, edit_bones) {
61 LISTBASE_FOREACH (BoneCollectionReference *, bcoll_ref, &ebone->bone_collections) {
62 bcoll_ref->bcoll = bcoll_map.lookup(bcoll_ref->bcoll);
63 }
64 }
65}
66
67/* -------------------------------------------------------------------- */
70
80
82{
83 /* Copy edit bones. */
86
87 /* Active bone. */
88 if (uarm->act_edbone) {
89 EditBone *ebone;
90 ebone = uarm->act_edbone;
91 arm->act_edbone = ebone->temp.ebone;
92 }
93 else {
94 arm->act_edbone = nullptr;
95 }
96
98
99 /* Before freeing the old bone collections, copy their 'expanded' flag. This
100 * flag is not supposed to be restored with any undo steps. */
102 arm->collections_span());
103
104 /* Copy bone collections. */
108 uarm->collection_array,
110 true);
112
113 /* Always do a lookup-by-name and assignment. Even when the name of the active collection is
114 * still the same, the order may have changed and thus the index needs to be updated. */
117 ANIM_armature_bonecoll_active_set(arm, active_bcoll);
118
120
122}
123
125{
127
128 /* Copy edit bones. */
129 ED_armature_ebone_listbase_copy(&uarm->ebones, arm->edbo, false);
130
131 /* Active bone. */
132 if (arm->act_edbone) {
133 EditBone *ebone = arm->act_edbone;
134 uarm->act_edbone = ebone->temp.ebone;
135 }
136
138
139 /* Copy bone collections. */
142 arm->collection_array,
144 false);
147
148 /* Point the new edit bones at the new collections. */
150
151 /* Undo size.
152 * TODO: include size of ID-properties. */
153 uarm->undo_size = 0;
154 LISTBASE_FOREACH (EditBone *, ebone, &uarm->ebones) {
155 uarm->undo_size += sizeof(EditBone);
156 uarm->undo_size += sizeof(BoneCollectionReference) *
157 BLI_listbase_count(&ebone->bone_collections);
158 }
159 /* Size of the bone collections + the size of the pointers to those
160 * bone collections in the bone collection array. */
161 uarm->undo_size += (sizeof(BoneCollection) + sizeof(BoneCollection *)) *
163
164 return uarm;
165}
166
172
174{
175 Scene *scene = CTX_data_scene(C);
176 ViewLayer *view_layer = CTX_data_view_layer(C);
177 BKE_view_layer_synced_ensure(scene, view_layer);
178 Object *obedit = BKE_view_layer_edit_object_get(view_layer);
179 if (obedit && obedit->type == OB_ARMATURE) {
180 bArmature *arm = static_cast<bArmature *>(obedit->data);
181 if (arm->edbo != nullptr) {
182 return obedit;
183 }
184 }
185 return nullptr;
186}
187
189
190/* -------------------------------------------------------------------- */
195
201
209
211{
212 return editarm_object_from_context(C) != nullptr;
213}
214
216{
217 ArmatureUndoStep *us = reinterpret_cast<ArmatureUndoStep *>(us_p);
218
219 /* Important not to use the 3D view when getting objects because all objects
220 * outside of this list will be moved out of edit-mode when reading back undo steps. */
221 Scene *scene = CTX_data_scene(C);
222 ViewLayer *view_layer = CTX_data_view_layer(C);
224
225 us->scene_ref.ptr = scene;
226 us->elems = MEM_calloc_arrayN<ArmatureUndoStep_Elem>(objects.size(), __func__);
227 us->elems_len = objects.size();
228
229 for (uint i = 0; i < objects.size(); i++) {
230 Object *ob = objects[i];
231 ArmatureUndoStep_Elem *elem = &us->elems[i];
232
233 elem->obedit_ref.ptr = ob;
234 bArmature *arm = static_cast<bArmature *>(elem->obedit_ref.ptr->data);
235 undoarm_from_editarm(&elem->data, arm);
236 arm->needs_flush_to_id = 1;
237 us->step.data_size += elem->data.undo_size;
238 }
239
240 bmain->is_memfile_undo_flush_needed = true;
241
242 return true;
243}
244
246 bContext *C, Main *bmain, UndoStep *us_p, const eUndoStepDir /*dir*/, bool /*is_final*/)
247{
248 ArmatureUndoStep *us = reinterpret_cast<ArmatureUndoStep *>(us_p);
249 Scene *scene = CTX_data_scene(C);
250 ViewLayer *view_layer = CTX_data_view_layer(C);
251
253 CTX_wm_manager(C), us->scene_ref.ptr, &scene, &view_layer);
255 scene, view_layer, &us->elems[0].obedit_ref.ptr, us->elems_len, sizeof(*us->elems));
256
258
259 for (uint i = 0; i < us->elems_len; i++) {
260 ArmatureUndoStep_Elem *elem = &us->elems[i];
261 Object *obedit = elem->obedit_ref.ptr;
262 bArmature *arm = static_cast<bArmature *>(obedit->data);
263 if (arm->edbo == nullptr) {
264 /* Should never fail, may not crash but can give odd behavior. */
266 "name='%s', failed to enter edit-mode for object '%s', undo state invalid",
267 us_p->name,
268 obedit->id.name);
269 continue;
270 }
271 undoarm_to_editarm(&elem->data, arm);
272 arm->needs_flush_to_id = 1;
274 }
275
276 /* The first element is always active */
278 scene, view_layer, us->elems[0].obedit_ref.ptr, us_p->name, &LOG);
279
280 /* Check after setting active (unless undoing into another scene). */
282
283 bmain->is_memfile_undo_flush_needed = true;
284
286}
287
289{
290 ArmatureUndoStep *us = reinterpret_cast<ArmatureUndoStep *>(us_p);
291
292 for (uint i = 0; i < us->elems_len; i++) {
293 ArmatureUndoStep_Elem *elem = &us->elems[i];
294 undoarm_free_data(&elem->data);
295 }
296 MEM_freeN(us->elems);
297}
298
300 UndoTypeForEachIDRefFn foreach_ID_ref_fn,
301 void *user_data)
302{
303 ArmatureUndoStep *us = reinterpret_cast<ArmatureUndoStep *>(us_p);
304
305 foreach_ID_ref_fn(user_data, reinterpret_cast<UndoRefID *>(&us->scene_ref));
306 for (uint i = 0; i < us->elems_len; i++) {
307 ArmatureUndoStep_Elem *elem = &us->elems[i];
308 foreach_ID_ref_fn(user_data, reinterpret_cast<UndoRefID *>(&elem->obedit_ref));
309 }
310}
311
326
C++ functions to deal with Armature collections (i.e. the successor of bone layers).
void ANIM_armature_bonecoll_active_set(bArmature *armature, BoneCollection *bcoll)
void ANIM_armature_runtime_refresh(bArmature *armature)
BoneCollection * ANIM_armature_bonecoll_get_by_name(bArmature *armature, const char *name) ATTR_WARN_UNUSED_RESULT
Scene * CTX_data_scene(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
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:46
#define LISTBASE_FOREACH(type, var, list)
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
unsigned int uint
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:188
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
#define MAX_NAME
Definition DNA_defs.h:50
Object is a sort of wrapper for general info.
@ OB_ARMATURE
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:775
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:811
blender::Vector< Object * > ED_undo_editmode_objects_from_view_layer(const Scene *scene, ViewLayer *view_layer)
Definition ed_undo.cc:856
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:794
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
#define NC_GEOM
Definition WM_types.hh:393
#define ND_DATA
Definition WM_types.hh:509
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)
const Value & lookup(const Key &key) const
Definition BLI_map.hh:545
int64_t size() const
static bool armature_undosys_step_encode(bContext *C, Main *bmain, UndoStep *us_p)
static void * undoarm_from_editarm(UndoArmature *uarm, bArmature *arm)
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_free(UndoStep *us_p)
void ED_armature_undosys_type(UndoType *ut)
static void undoarm_free_data(UndoArmature *uarm)
static Object * editarm_object_from_context(bContext *C)
static void undoarm_to_editarm(UndoArmature *uarm, bArmature *arm)
static void remap_ebone_bone_collection_references(ListBase *edit_bones, const blender::Map< BoneCollection *, BoneCollection * > &bcoll_map)
static void armature_undosys_step_decode(bContext *C, Main *bmain, UndoStep *us_p, const eUndoStepDir, bool)
#define LOG(level)
Definition log.h:97
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
blender::Map< BoneCollection *, BoneCollection * > ANIM_bonecoll_array_copy_no_membership(BoneCollection ***bcoll_array_dst, int *bcoll_array_dst_num, BoneCollection **bcoll_array_src, int bcoll_array_src_num, bool do_id_user)
void bonecolls_copy_expanded_flag(Span< BoneCollection * > bcolls_dest, Span< const BoneCollection * > bcolls_source)
void ANIM_bonecoll_array_free(BoneCollection ***bcoll_array, int *bcoll_array_num, bool do_id_user)
ArmatureUndoStep_Elem * next
UndoRefID_Object obedit_ref
ArmatureUndoStep_Elem * prev
ArmatureUndoStep_Elem * elems
UndoRefID_Scene scene_ref
union EditBone::@275371335250266324235150226366250166246037204077 temp
EditBone * ebone
char name[258]
Definition DNA_ID.h:432
bool is_memfile_undo_flush_needed
Definition BKE_main.hh:213
char active_collection_name[MAX_NAME]
EditBone * act_edbone
BoneCollection ** collection_array
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)
struct BoneCollection ** collection_array
char active_collection_name[64]
struct EditBone * act_edbone
ListBase * edbo
i
Definition text_draw.cc:230
void WM_event_add_notifier(const bContext *C, uint type, void *reference)