Blender V4.3
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
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_idprop.hh"
26#include "BKE_layer.hh"
27#include "BKE_main.hh"
28#include "BKE_object.hh"
29#include "BKE_undo_system.hh"
30
31#include "DEG_depsgraph.hh"
32
33#include "ED_armature.hh"
34#include "ED_object.hh"
35#include "ED_undo.hh"
36#include "ED_util.hh"
37
39
40#include "WM_api.hh"
41#include "WM_types.hh"
42
43using namespace blender::animrig;
44
46static CLG_LogRef LOG = {"ed.undo.armature"};
47
48/* Utility functions. */
49
58 ListBase /*EditBone*/ *edit_bones,
60{
61 LISTBASE_FOREACH (EditBone *, ebone, edit_bones) {
62 LISTBASE_FOREACH (BoneCollectionReference *, bcoll_ref, &ebone->bone_collections) {
63 bcoll_ref->bcoll = bcoll_map.lookup(bcoll_ref->bcoll);
64 }
65 }
66}
67
68/* -------------------------------------------------------------------- */
81
83{
84 /* Copy edit bones. */
87
88 /* Active bone. */
89 if (uarm->act_edbone) {
90 EditBone *ebone;
91 ebone = uarm->act_edbone;
92 arm->act_edbone = ebone->temp.ebone;
93 }
94 else {
95 arm->act_edbone = nullptr;
96 }
97
99
100 /* Before freeing the old bone collections, copy their 'expanded' flag. This
101 * flag is not supposed to be restored with any undo steps. */
103 arm->collections_span());
104
105 /* Copy bone collections. */
109 uarm->collection_array,
111 true);
113
114 /* Always do a lookup-by-name and assignment. Even when the name of the active collection is
115 * still the same, the order may have changed and thus the index needs to be updated. */
118 ANIM_armature_bonecoll_active_set(arm, active_bcoll);
119
121
123}
124
126{
128
129 /* Copy edit bones. */
130 ED_armature_ebone_listbase_copy(&uarm->ebones, arm->edbo, false);
131
132 /* Active bone. */
133 if (arm->act_edbone) {
134 EditBone *ebone = arm->act_edbone;
135 uarm->act_edbone = ebone->temp.ebone;
136 }
137
139
140 /* Copy bone collections. */
143 arm->collection_array,
145 false);
148
149 /* Point the new edit bones at the new collections. */
151
152 /* Undo size.
153 * TODO: include size of ID-properties. */
154 uarm->undo_size = 0;
155 LISTBASE_FOREACH (EditBone *, ebone, &uarm->ebones) {
156 uarm->undo_size += sizeof(EditBone);
157 uarm->undo_size += sizeof(BoneCollectionReference) *
158 BLI_listbase_count(&ebone->bone_collections);
159 }
160 /* Size of the bone collections + the size of the pointers to those
161 * bone collections in the bone collection array. */
162 uarm->undo_size += (sizeof(BoneCollection) + sizeof(BoneCollection *)) *
164
165 return uarm;
166}
167
173
175{
176 Scene *scene = CTX_data_scene(C);
177 ViewLayer *view_layer = CTX_data_view_layer(C);
178 BKE_view_layer_synced_ensure(scene, view_layer);
179 Object *obedit = BKE_view_layer_edit_object_get(view_layer);
180 if (obedit && obedit->type == OB_ARMATURE) {
181 bArmature *arm = static_cast<bArmature *>(obedit->data);
182 if (arm->edbo != nullptr) {
183 return obedit;
184 }
185 }
186 return nullptr;
187}
188
191/* -------------------------------------------------------------------- */
202
210
212{
213 return editarm_object_from_context(C) != nullptr;
214}
215
217{
219
220 /* Important not to use the 3D view when getting objects because all objects
221 * outside of this list will be moved out of edit-mode when reading back undo steps. */
222 Scene *scene = CTX_data_scene(C);
223 ViewLayer *view_layer = CTX_data_view_layer(C);
225
226 us->scene_ref.ptr = scene;
227 us->elems = static_cast<ArmatureUndoStep_Elem *>(
228 MEM_callocN(sizeof(*us->elems) * objects.size(), __func__));
229 us->elems_len = objects.size();
230
231 for (uint i = 0; i < objects.size(); i++) {
232 Object *ob = objects[i];
233 ArmatureUndoStep_Elem *elem = &us->elems[i];
234
235 elem->obedit_ref.ptr = ob;
236 bArmature *arm = static_cast<bArmature *>(elem->obedit_ref.ptr->data);
237 undoarm_from_editarm(&elem->data, arm);
238 arm->needs_flush_to_id = 1;
239 us->step.data_size += elem->data.undo_size;
240 }
241
242 bmain->is_memfile_undo_flush_needed = true;
243
244 return true;
245}
246
248 bContext *C, Main *bmain, UndoStep *us_p, const eUndoStepDir /*dir*/, bool /*is_final*/)
249{
251 Scene *scene = CTX_data_scene(C);
252 ViewLayer *view_layer = CTX_data_view_layer(C);
253
255 CTX_wm_manager(C), us->scene_ref.ptr, &scene, &view_layer);
257 scene, view_layer, &us->elems[0].obedit_ref.ptr, us->elems_len, sizeof(*us->elems));
258
260
261 for (uint i = 0; i < us->elems_len; i++) {
262 ArmatureUndoStep_Elem *elem = &us->elems[i];
263 Object *obedit = elem->obedit_ref.ptr;
264 bArmature *arm = static_cast<bArmature *>(obedit->data);
265 if (arm->edbo == nullptr) {
266 /* Should never fail, may not crash but can give odd behavior. */
268 "name='%s', failed to enter edit-mode for object '%s', undo state invalid",
269 us_p->name,
270 obedit->id.name);
271 continue;
272 }
273 undoarm_to_editarm(&elem->data, arm);
274 arm->needs_flush_to_id = 1;
276 }
277
278 /* The first element is always active */
280 scene, view_layer, us->elems[0].obedit_ref.ptr, us_p->name, &LOG);
281
282 /* Check after setting active (unless undoing into another scene). */
284
285 bmain->is_memfile_undo_flush_needed = true;
286
288}
289
291{
293
294 for (uint i = 0; i < us->elems_len; i++) {
295 ArmatureUndoStep_Elem *elem = &us->elems[i];
296 undoarm_free_data(&elem->data);
297 }
298 MEM_freeN(us->elems);
299}
300
302 UndoTypeForEachIDRefFn foreach_ID_ref_fn,
303 void *user_data)
304{
306
307 foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->scene_ref));
308 for (uint i = 0; i < us->elems_len; i++) {
309 ArmatureUndoStep_Elem *elem = &us->elems[i];
310 foreach_ID_ref_fn(user_data, ((UndoRefID *)&elem->obedit_ref));
311 }
312}
313
328
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:50
#define LISTBASE_FOREACH(type, var, list)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define STRNCPY(dst, src)
Definition BLI_string.h:593
unsigned int uint
#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 BoneCollectionReference BoneCollectionReference
struct BoneCollection BoneCollection
#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: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_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:506
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 CLG_LogRef LOG
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)
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
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::@4 temp
EditBone * ebone
char name[66]
Definition DNA_ID.h:425
bool is_memfile_undo_flush_needed
Definition BKE_main.hh:165
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
void WM_event_add_notifier(const bContext *C, uint type, void *reference)