Blender V4.5
versioning.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9/* This is versioning code, so it's allowed to touch on deprecated DNA fields. */
10
11#define DNA_DEPRECATED_ALLOW
12
13#include "ANIM_action.hh"
15#include "ANIM_action_legacy.hh"
16#include "ANIM_versioning.hh"
17
18#include "DNA_action_defaults.h"
19#include "DNA_action_types.h"
20
21#include "BKE_main.hh"
22#include "BKE_node.hh"
23#include "BKE_report.hh"
24
25#include "BLI_listbase.h"
26#include "BLI_string_utf8.h"
27
28#include "BLT_translation.hh"
29
30#include "BLO_readfile.hh"
31
32#include "RNA_access.hh"
33#include "RNA_prototypes.hh"
34
36
37bool action_is_layered(const bAction &dna_action)
38{
39 /* NOTE: due to how forward-compatibility is handled when writing Actions to
40 * blend files, it is important that this function does NOT check
41 * `Action.idroot` as part of its determination of whether this is a layered
42 * action or not.
43 *
44 * See: `action_blend_write()` and `action_blend_read_data()`
45 */
46
47 const animrig::Action &action = dna_action.wrap();
48
49 const bool has_layered_data = action.layer_array_num > 0 || action.slot_array_num > 0;
50 const bool has_animato_data = !(BLI_listbase_is_empty(&action.curves) &&
52 const bool has_pre_animato_data = !BLI_listbase_is_empty(&action.chanbase);
53
54 return has_layered_data || (!has_animato_data && !has_pre_animato_data);
55}
56
58{
59 LISTBASE_FOREACH (bAction *, dna_action, &bmain.actions) {
60 blender::animrig::Action &action = dna_action->wrap();
61
62 if (action_is_layered(action) && !action.is_empty()) {
63 /* This is just a safety net. Blender files that trigger this versioning code are not
64 * expected to have any layered/slotted Actions.
65 *
66 * Empty Actions, even though they are valid "layered" Actions, should still get through
67 * versioning, though, to ensure they have the default "Legacy Slot" and a zero idroot. */
68 continue;
69 }
70
71 /* This function should skip pre-2.50 Actions, as those are versioned in a special step (see
72 * `do_versions_after_setup()` in `versioning_common.cc`). */
73 if (!BLI_listbase_is_empty(&action.chanbase)) {
74 continue;
75 }
76
78 }
79}
80
82{
83 BLI_assert_msg(BLI_listbase_is_empty(&dna_action.chanbase),
84 "this function cannot handle pre-2.50 Actions");
85 if (!BLI_listbase_is_empty(&dna_action.chanbase)) {
86 /* This is a pre-2.5 Action, which cannot be converted here. It's converted in another function
87 * to a post-2.5 Action (aka Animato Action), and after that, this function will be called
88 * again. */
89 return;
90 }
91
92 Action &action = dna_action.wrap();
94
95 /* Store this ahead of time, because adding the slot sets the action's idroot
96 * to 0. We also set the action's idroot to 0 manually, just to be defensive
97 * so we don't depend on esoteric behavior in `slot_add()`. */
98 const int16_t idtype = action.idroot;
99 action.idroot = 0;
100
101 /* Initialize the Action's last_slot_handle field to its default value, before
102 * we create a new slot. */
104
105 Slot &slot = action.slot_add();
106 slot.idtype = idtype;
107
108 const std::string slot_identifier{slot.idtype_string() +
110 action.slot_identifier_define(slot, slot_identifier);
111
113 blender::animrig::Strip &strip = layer.strip_add(action,
114 blender::animrig::Strip::Type::Keyframe);
115 Channelbag &bag = strip.data<StripKeyframeData>(action).channelbag_for_slot_ensure(slot);
116 const int fcu_count = BLI_listbase_count(&action.curves);
117 const int group_count = BLI_listbase_count(&action.groups);
118 bag.fcurve_array = MEM_calloc_arrayN<FCurve *>(fcu_count, "Action versioning - fcurves");
119 bag.fcurve_array_num = fcu_count;
120 bag.group_array = MEM_calloc_arrayN<bActionGroup *>(group_count, "Action versioning - groups");
121 bag.group_array_num = group_count;
122
123 int group_index = 0;
124 int fcurve_index = 0;
125 LISTBASE_FOREACH_INDEX (bActionGroup *, group, &action.groups, group_index) {
126 bag.group_array[group_index] = group;
127
128 group->channelbag = &bag;
129 group->fcurve_range_start = fcurve_index;
130
131 LISTBASE_FOREACH (FCurve *, fcu, &group->channels) {
132 if (fcu->grp != group) {
133 break;
134 }
135 bag.fcurve_array[fcurve_index++] = fcu;
136 }
137
138 group->fcurve_range_length = fcurve_index - group->fcurve_range_start;
139 }
140
141 LISTBASE_FOREACH (FCurve *, fcu, &action.curves) {
142 /* Any fcurves with groups have already been added to the fcurve array. */
143 if (fcu->grp) {
144 continue;
145 }
146 bag.fcurve_array[fcurve_index++] = fcu;
147 }
148
149 BLI_assert(fcurve_index == fcu_count);
150
151 action.curves = {nullptr, nullptr};
152 action.groups = {nullptr, nullptr};
153}
154
159
161{
162 /* This function is only called when the blend-file is old enough to NOT use
163 * slotted Actions, so we can safely tag anything that uses an Action. */
164
165 auto flag_adt = [](ID &animated_id,
166 bAction *& /*action_ptr_ref*/,
167 slot_handle_t & /*slot_handle_ref*/,
168 char * /*last_slot_identifier*/) -> bool {
170
171 /* Once tagged, the foreach loop can stop, because more tagging of the same
172 * ID doesn't do anything. */
173 return false;
174 };
175
176 ID *id;
177 FOREACH_MAIN_ID_BEGIN (&bmain, id) {
179
180 /* Process embedded IDs, as these are not listed in bmain, but still can
181 * have their own Action+Slot. Unfortunately there is no generic looper
182 * for embedded IDs. At this moment the only animatable embedded ID is a
183 * node tree. */
185 if (node_tree) {
186 foreach_action_slot_use_with_references(node_tree->id, flag_adt);
187 }
188 }
190}
191
193{
194 auto version_slot_assignment = [&](ID &animated_id,
195 bAction *dna_action,
196 PointerRNA &action_slot_owner_ptr,
197 PropertyRNA &action_slot_prop,
198 char *last_used_slot_identifier) {
199 BLI_assert(dna_action); /* Ensured by the foreach loop. */
200 Action &action = dna_action->wrap();
201
202 if (action.slot_array_num == 0) {
203 /* There's a few reasons why this Action doesn't have a slot. It could simply be a slotted
204 * Action without slots, or a legacy-but-not-yet-versioned Action, or it could be it is a
205 * _really_ old (pre-2.50) Action. The latter are upgraded in do_versions_after_setup(), but
206 * this function can be called earlier than that. So better gracefully skip those. */
207 return true;
208 }
209
210 /* If there is already a slot assigned, there's nothing to do here. */
211 PointerRNA current_slot_ptr = RNA_property_pointer_get(&action_slot_owner_ptr,
212 &action_slot_prop);
213 if (current_slot_ptr.data) {
214 return true;
215 }
216
217 /* Reset the "last used slot identifier" to the default "Legacy Slot". That way
218 * generic_slot_for_autoassign() will pick up on legacy slots automatically.
219 *
220 * Note that this function should only run on legacy users of Actions, i.e. they are not
221 * expected to have any last-used slot at all. The field in DNA can still be set, though,
222 * because the 4.3 code already has the data model for slotted Actions. */
223
224 /* Ensure that the identifier has the correct ID type prefix. */
225 *reinterpret_cast<short *>(last_used_slot_identifier) = GS(animated_id.name);
226
227 static_assert(Slot::identifier_length_max > 2); /* Because of the -2 below. */
228 BLI_strncpy_utf8(last_used_slot_identifier + 2,
231
232 Slot *slot_to_assign = generic_slot_for_autoassign(
233 animated_id, action, last_used_slot_identifier);
234 if (!slot_to_assign) {
235 /* This means that there is no slot that can be found by name, not even the "Legacy Slot"
236 * name. Keep the ID unanimated, as this means that the referenced Action has changed
237 * significantly since this file was opened. */
240 "\"%s\" is using Action \"%s\", which does not have a slot with identifier "
241 "\"%s\" or \"%s\". Manually assign the right action slot to \"%s\".\n",
242 animated_id.name,
243 action.id.name + 2,
244 last_used_slot_identifier,
245 animated_id.name,
246 animated_id.name + 2);
247 return true;
248 }
249
250 PointerRNA slot_to_assign_ptr = RNA_pointer_create_discrete(
251 &action.id, &RNA_ActionSlot, slot_to_assign);
253 &action_slot_owner_ptr, &action_slot_prop, slot_to_assign_ptr, reports);
254 RNA_property_update_main(&bmain, nullptr, &action_slot_owner_ptr, &action_slot_prop);
255
256 return true;
257 };
258
259 /* Note that the code below does not remove the `action_assignment_needs_slot` tag. One ID can
260 * use multiple Actions (via NLA, Action constraints, etc.); if one of those Action is an ancient
261 * one from before 2.50 (just to name one example case) this ID may needs to be re-visited
262 * after those were versioned. Rather than trying to figure out if re-visiting is necessary, this
263 * function is safe to call multiple times, and all that's lost is a little bit of CPU time. */
264
265 ID *id;
266 FOREACH_MAIN_ID_BEGIN (&bmain, id) {
267 /* Process the ID itself. */
269 foreach_action_slot_use_with_rna(*id, version_slot_assignment);
270 }
271
272 /* Process embedded IDs, as these are not listed in bmain, but still can
273 * have their own Action+Slot. Unfortunately there is no generic looper
274 * for embedded IDs. At this moment the only animatable embedded ID is a
275 * node tree. */
277 if (node_tree && BLO_readfile_id_runtime_tags(node_tree->id).action_assignment_needs_slot) {
278 foreach_action_slot_use_with_rna(node_tree->id, version_slot_assignment);
279 }
280 }
282}
283
284} // namespace blender::animrig::versioning
Functions and classes to work with Actions.
Functionality to iterate an Action in various ways.
Functions for backward compatibility with the legacy Action API.
Versioning of old animation data. Most animation versioning code lives in the versioning_xxx....
#define FOREACH_MAIN_ID_END
Definition BKE_main.hh:563
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition BKE_main.hh:557
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
char * BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
external readfile function prototypes.
ID_Readfile_Data::Tags BLO_readfile_id_runtime_tags(ID &id)
Definition readfile.cc:2231
#define DATA_(msgid)
#define DNA_DEFAULT_ACTION_LAST_SLOT_HANDLE
ReportList * reports
Definition WM_types.hh:1025
void slot_identifier_define(Slot &slot, StringRefNull new_identifier)
Layer & layer_add(std::optional< StringRefNull > name)
Strip & strip_add(Action &owning_action, Strip::Type strip_type)
std::string idtype_string() const
static constexpr int identifier_length_max
const T & data(const Action &owning_action) const
#define GS(a)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
constexpr const char * DEFAULT_LEGACY_LAYER_NAME
constexpr const char * DEFAULT_LEGACY_SLOT_NAME
void convert_legacy_animato_action(bAction &dna_action)
Definition versioning.cc:81
void tag_action_user_for_slotted_actions_conversion(ID &animated_id)
bool action_is_layered(const bAction &dna_action)
Definition versioning.cc:37
void convert_legacy_action_assignments(Main &bmain, ReportList *reports)
void convert_legacy_animato_actions(Main &bmain)
Definition versioning.cc:57
void tag_action_users_for_slotted_actions_conversion(Main &bmain)
decltype(::ActionSlot::handle) slot_handle_t
bool foreach_action_slot_use_with_rna(ID &animated_id, FunctionRef< bool(ID &animated_id, bAction *action, PointerRNA &action_slot_owner_ptr, PropertyRNA &action_slot_prop, char *last_slot_identifier)> callback)
bool foreach_action_slot_use_with_references(ID &animated_id, FunctionRef< bool(ID &animated_id, bAction *&action_ptr_ref, slot_handle_t &slot_handle_ref, char *last_slot_identifier)> callback)
Slot * generic_slot_for_autoassign(const ID &animated_id, Action &action, StringRefNull last_slot_identifier)
bNodeTree * node_tree_from_id(ID *id)
Definition node.cc:4840
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value, ReportList *reports)
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_update_main(Main *bmain, Scene *scene, PointerRNA *ptr, PropertyRNA *prop)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
struct bActionGroup ** group_array
struct FCurve ** fcurve_array
struct ID_Readfile_Data::Tags tags
struct ID_Readfile_Data * readfile_data
Definition DNA_ID.h:401
Definition DNA_ID.h:404
char name[66]
Definition DNA_ID.h:415
struct ID_Runtime runtime
Definition DNA_ID.h:493
ListBase actions
Definition BKE_main.hh:269
void * data
Definition RNA_types.hh:53
struct ActionChannelbag * channelbag
ListBase curves
int32_t last_slot_handle
ListBase groups