Blender V4.3
anim_data.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009 Blender Authors, Joshua Leung. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8#include "MEM_guardedalloc.h"
9
10#include <cstring>
11#include <optional>
12
13#include "ANIM_action.hh"
14
15#include "BKE_action.hh"
16#include "BKE_anim_data.hh"
17#include "BKE_animsys.h"
18#include "BKE_context.hh"
19#include "BKE_fcurve.hh"
20#include "BKE_fcurve_driver.h"
21#include "BKE_global.hh"
22#include "BKE_idtype.hh"
23#include "BKE_lib_id.hh"
24#include "BKE_lib_query.hh"
25#include "BKE_main.hh"
26#include "BKE_nla.hh"
27#include "BKE_node.hh"
28#include "BKE_report.hh"
29
30#include "DNA_ID.h"
31#include "DNA_anim_types.h"
32#include "DNA_light_types.h"
33#include "DNA_material_types.h"
34#include "DNA_node_types.h"
35#include "DNA_space_types.h"
37#include "DNA_world_types.h"
38
39#include "BLI_alloca.h"
40#include "BLI_dynstr.h"
41#include "BLI_listbase.h"
42#include "BLI_string.h"
43#include "BLI_utildefines.h"
44
45#include "DEG_depsgraph.hh"
46
47#include "BLO_read_write.hh"
48
49#include "RNA_access.hh"
50#include "RNA_path.hh"
51
53#include "ANIM_action_legacy.hh"
54
55#include "CLG_log.h"
56
57#ifdef WITH_ANIM_BAKLAVA
58# include "ANIM_action.hh"
59#endif // WITH_ANIM_BAKLAVA
60
61static CLG_LogRef LOG = {"bke.anim_sys"};
62
63using namespace blender;
64
65/* ***************************************** */
66/* AnimData API */
67
68/* Getter/Setter -------------------------------------------- */
69
70bool id_type_can_have_animdata(const short id_type)
71{
72 const IDTypeInfo *typeinfo = BKE_idtype_get_info_from_idcode(id_type);
73 if (typeinfo != nullptr) {
74 return (typeinfo->flags & IDTYPE_FLAGS_NO_ANIMDATA) == 0;
75 }
76 return false;
77}
78
79bool id_can_have_animdata(const ID *id)
80{
81 /* sanity check */
82 if (id == nullptr) {
83 return false;
84 }
85
86 return id_type_can_have_animdata(GS(id->name));
87}
88
90{
91 /* In order for this to work, we assume that the #AnimData pointer is stored
92 * immediately after the given ID-block in the struct, as per IdAdtTemplate. */
93
94 /* Only some ID-blocks have this info for now, so we cast the types that do
95 * to be of type IdAdtTemplate, and add the AnimData to it using the template. */
96 if (id_can_have_animdata(id)) {
97 IdAdtTemplate *iat = (IdAdtTemplate *)id;
98 return iat->adt;
99 }
100 return nullptr;
101}
102
104{
105 /* In order for this to work, we assume that the #AnimData pointer is stored
106 * immediately after the given ID-block in the struct, as per IdAdtTemplate. */
107
108 /* Only some ID-blocks have this info for now, so we cast the types that do
109 * to be of type IdAdtTemplate, and add the AnimData to it using the template. */
110 if (id_can_have_animdata(id)) {
111 IdAdtTemplate *iat = (IdAdtTemplate *)id;
112
113 /* check if there's already AnimData, in which case, don't add */
114 if (iat->adt == nullptr) {
115 AnimData *adt;
116
117 /* add animdata */
118 adt = iat->adt = static_cast<AnimData *>(MEM_callocN(sizeof(AnimData), "AnimData"));
119
120 /* set default settings */
121 adt->act_influence = 1.0f;
122 }
123
124 return iat->adt;
125 }
126 return nullptr;
127}
128
129/* Action / `tmpact` Setter shared code -------------------------
130 *
131 * Both the action and `tmpact` setter functions have essentially
132 * identical semantics, because `tmpact` is just a place to temporarily
133 * store the main action during tweaking. This function contains the
134 * shared code between those two setter functions, setting the action
135 * of the passed `act_slot` to `act`.
136 *
137 * Preconditions:
138 * - `id` and `act_slot` must be non-null (but the pointer `act_slot`
139 * points to can be null).
140 * - `id` must have animation data.
141 * - `act_slot` must be a pointer to either the `action` or `tmpact`
142 * field of `id`'s animation data.
143 */
144static bool animdata_set_action(ReportList *reports, ID *id, bAction **act_slot, bAction *act)
145{
146 /* Action must have same type as owner. */
147 if (!BKE_animdata_action_ensure_idroot(id, act)) {
148 /* Cannot set to this type. */
150 reports,
151 RPT_ERROR,
152 "Could not set action '%s' onto ID '%s', as it does not have suitably rooted paths "
153 "for this purpose",
154 act->id.name + 2,
155 id->name);
156 return false;
157 }
158
159 if (*act_slot == act) {
160 /* Don't bother reducing and increasing the user count when there is nothing changing. */
161 return true;
162 }
163
164 /* Unassign current action. */
165 if (*act_slot) {
166 id_us_min((ID *)*act_slot);
167 *act_slot = nullptr;
168 }
169
170 if (act == nullptr) {
171 return true;
172 }
173
174 *act_slot = act;
175 id_us_plus((ID *)*act_slot);
176
177 return true;
178}
179
180/* Tmpact Setter --------------------------------------- */
182{
184
185 if (adt == nullptr) {
186 BKE_report(reports, RPT_WARNING, "No AnimData to set tmpact on");
187 return false;
188 }
189
190 return animdata_set_action(reports, id, &adt->tmpact, act);
191}
192
193/* Action Setter --------------------------------------- */
195{
196 using namespace blender;
197
198 /* If we're unassigning (null action pointer) and there's no animdata, we can
199 * skip the whole song and dance of creating animdata just to "unassign" the
200 * action from it. */
201 if (act == nullptr && BKE_animdata_from_id(id) == nullptr) {
202 return true;
203 }
204
206 if (adt == nullptr) {
207 BKE_report(reports, RPT_WARNING, "Attempt to set action on non-animatable ID");
208 return false;
209 }
210
212 /* Cannot remove, otherwise things turn to custard. */
213 BKE_report(reports, RPT_ERROR, "Cannot change action, as it is still being edited in NLA");
214 return false;
215 }
216
217#ifdef WITH_ANIM_BAKLAVA
218 return animrig::assign_action(act, {*id, *adt});
219#else
220 return animdata_set_action(reports, id, &adt->action, act);
221#endif // WITH_ANIM_BAKLAVA
222}
223
225{
226 /* Active action is only editable when it is not a tweaking strip. */
227 const bool is_tweaking_strip = (adt->flag & ADT_NLA_EDIT_ON) || adt->actstrip != nullptr ||
228 adt->tmpact != nullptr;
229 return !is_tweaking_strip;
230}
231
233{
234 const int idcode = GS(owner->name);
235
236 if (action == nullptr) {
237 /* A nullptr action is usable by any ID type. */
238 return true;
239 }
240
241#ifdef WITH_ANIM_BAKLAVA
243 /* TODO: for layered Actions, this function doesn't make sense. Once all Actions are
244 * auto-versioned to layered Actions, this entire function can be removed. */
245 action->idroot = 0;
246 /* Layered Actions can always be assigned to any ID type. It's the slots
247 * that are specialized. */
248 return true;
249 }
250#endif
251
252 if (action->idroot == 0) {
253 /* First time this Action is assigned, lock it to this ID type. */
254 action->idroot = idcode;
255 return true;
256 }
257
258 return (action->idroot == idcode);
259}
260
261/* Freeing -------------------------------------------- */
262
263void BKE_animdata_free(ID *id, const bool do_id_user)
264{
265 if (!id_can_have_animdata(id)) {
266 return;
267 }
268
269 IdAdtTemplate *iat = (IdAdtTemplate *)id;
270 AnimData *adt = iat->adt;
271 if (!adt) {
272 return;
273 }
274
275 if (do_id_user) {
276 /* The ADT is going to be freed, which means that if it's in tweak mode, it'll have to exit
277 * that first. Otherwise we cannot un-assign its Action. */
278 BKE_nla_tweakmode_exit({*id, *adt});
279
280 if (adt->action) {
281#ifdef WITH_ANIM_BAKLAVA
282 const bool unassign_ok = blender::animrig::unassign_action(*id);
283 BLI_assert_msg(unassign_ok,
284 "Expecting action un-assignment to always work when not in NLA tweak mode");
285 UNUSED_VARS_NDEBUG(unassign_ok);
286#else
287 id_us_min(&adt->action->id);
288#endif
289 }
290 /* same goes for the temporarily displaced action */
291 if (adt->tmpact) {
292#ifdef WITH_ANIM_BAKLAVA
293 /* This should never happen, as we _just_ exited tweak mode. */
295 const bool unassign_ok = blender::animrig::assign_tmpaction(nullptr, {*id, *adt});
296 BLI_assert_msg(unassign_ok, "Expecting tmpaction un-assignment to always work");
297 UNUSED_VARS_NDEBUG(unassign_ok);
298#else
299 id_us_min(&adt->tmpact->id);
300#endif
301 }
302 }
303
304 /* free nla data */
305 BKE_nla_tracks_free(&adt->nla_tracks, do_id_user);
306
307 /* free drivers - stored as a list of F-Curves */
309
310 /* free driver array cache */
312
313 /* free overrides */
314 /* TODO... */
315
316 /* free animdata now */
317 MEM_freeN(adt);
318 iat->adt = nullptr;
319}
320
322{
323 if (id == nullptr) {
324 return false;
325 }
326
327 const AnimData *adt = BKE_animdata_from_id((ID *)id);
328 if (adt == nullptr) {
329 return false;
330 }
331
332 if (adt->action) {
333 const blender::animrig::Action &action = adt->action->wrap();
334 if (action.is_action_layered() && action.is_slot_animated(adt->slot_handle)) {
335 return true;
336 }
337 if (action.is_action_legacy() && !BLI_listbase_is_empty(&action.curves)) {
338 return true;
339 }
340 }
341
344}
345
347{
348 LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
350 }
351
354
355 LISTBASE_FOREACH (NlaTrack *, nla_track, &adt->nla_tracks) {
356 LISTBASE_FOREACH (NlaStrip *, nla_strip, &nla_track->strips) {
357 BKE_nla_strip_foreach_id(nla_strip, data);
358 }
359 }
360}
361
362/* Copying -------------------------------------------- */
363
365 std::optional<Library *> owner_library,
366 AnimData *adt,
367 const int flag)
368{
369 AnimData *dadt;
370
371 const bool do_action = (flag & LIB_ID_COPY_ACTIONS) != 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0;
372 const bool do_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0;
373
374 /* sanity check before duplicating struct */
375 if (adt == nullptr) {
376 return nullptr;
377 }
378 dadt = static_cast<AnimData *>(MEM_dupallocN(adt));
379
380 /* make a copy of action - at worst, user has to delete copies... */
381 if (do_action) {
382 /* Recursive copy of 'real' IDs is a bit hairy. Even if do not want to deal with user-count
383 * when copying ID's data itself, we still need to do so with sub-IDs, since those will not be
384 * handled by later 'update user-counts of used IDs' code as used e.g. at end of
385 * #BKE_id_copy_ex().
386 * So in case we do copy the ID and its sub-IDs in bmain, silence the 'no user-count' flag for
387 * the sub-IDs copying.
388 * NOTE: This is a bit weak, as usually when it comes to recursive ID copy. Should work for
389 * now, but we may have to revisit this at some point and add a proper extra flag to deal with
390 * that situation. Or refactor completely the way we handle such recursion, by flattening it
391 * e.g. */
392 const int id_copy_flag = (flag & LIB_ID_CREATE_NO_MAIN) == 0 ?
394 flag;
395 BLI_assert(bmain != nullptr);
396 BLI_assert(dadt->action == nullptr || dadt->action != dadt->tmpact);
397 dadt->action = reinterpret_cast<bAction *>(
398 BKE_id_copy_in_lib(bmain,
399 owner_library,
400 reinterpret_cast<ID *>(dadt->action),
401 nullptr,
402 nullptr,
403 id_copy_flag));
404 dadt->tmpact = reinterpret_cast<bAction *>(
405 BKE_id_copy_in_lib(bmain,
406 owner_library,
407 reinterpret_cast<ID *>(dadt->tmpact),
408 nullptr,
409 nullptr,
410 id_copy_flag));
411 }
412 else if (do_id_user) {
413 id_us_plus((ID *)dadt->action);
414 id_us_plus((ID *)dadt->tmpact);
415 }
416
417 /* duplicate NLA data */
418 BKE_nla_tracks_copy_from_adt(bmain, dadt, adt, flag);
419
420 /* duplicate drivers (F-Curves) */
421 BKE_fcurves_copy(&dadt->drivers, &adt->drivers);
422 dadt->driver_array = nullptr;
423
424 /* don't copy overrides */
426
427 const bool is_main = (flag & LIB_ID_CREATE_NO_MAIN) == 0;
428 if (is_main) {
429 /* Action references were changed, so the Slot-to-user map is incomplete now. Only necessary
430 * when this happens in the main database though, as the user cache only tracks original IDs,
431 * not evaluated copies.
432 *
433 * This function does not have access to the animated ID, so it cannot just add that ID to the
434 * slot's users, hence the invalidation of the users map.
435 *
436 * TODO: refactor to pass the owner ID to this function, and just add it to the Slot's
437 * users. */
438 if (bmain) {
440 }
441 }
442
443 /* return */
444 return dadt;
445}
446
447AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag)
448{
449 return BKE_animdata_copy_in_lib(bmain, std::nullopt, adt, flag);
450}
451
452bool BKE_animdata_copy_id(Main *bmain, ID *id_to, ID *id_from, const int flag)
453{
454 AnimData *adt;
455
456 if ((id_to && id_from) && (GS(id_to->name) != GS(id_from->name))) {
457 return false;
458 }
459
461
462 adt = BKE_animdata_from_id(id_from);
463 if (adt) {
464 IdAdtTemplate *iat = (IdAdtTemplate *)id_to;
465 iat->adt = BKE_animdata_copy(bmain, adt, flag);
466 }
467
468 return true;
469}
470
471static void animdata_copy_id_action(Main *bmain,
472 ID *id,
473 const bool set_newid,
474 const bool do_linked_id)
475{
476 using namespace blender::animrig;
477
479 if (adt) {
480 if (adt->action && (do_linked_id || !ID_IS_LINKED(adt->action))) {
481 bAction *cloned_action = reinterpret_cast<bAction *>(BKE_id_copy(bmain, &adt->action->id));
482 if (set_newid) {
483 ID_NEW_SET(adt->action, cloned_action);
484 }
485
486 /* The Action was cloned, so this should find the same-named slot automatically. */
487 const slot_handle_t orig_slot_handle = adt->slot_handle;
488 const bool assign_ok = assign_action(&cloned_action->wrap(), *id);
489 BLI_assert_msg(assign_ok, "Expected action assignment to work when copying animdata");
490 BLI_assert(orig_slot_handle == adt->slot_handle);
491 UNUSED_VARS_NDEBUG(assign_ok, orig_slot_handle);
492 }
493 if (adt->tmpact && (do_linked_id || !ID_IS_LINKED(adt->tmpact))) {
494 bAction *cloned_action = reinterpret_cast<bAction *>(BKE_id_copy(bmain, &adt->tmpact->id));
495 if (set_newid) {
496 ID_NEW_SET(adt->tmpact, cloned_action);
497 }
498
499 /* The Action was cloned, so this should find the same-named slot automatically. */
500 const slot_handle_t orig_slot_handle = adt->tmp_slot_handle;
501 const bool assign_ok = assign_tmpaction(&cloned_action->wrap(), {*id, *adt});
502 BLI_assert_msg(assign_ok, "Expected tmp-action assignment to work when copying animdata");
503 BLI_assert(orig_slot_handle == adt->tmp_slot_handle);
504 UNUSED_VARS_NDEBUG(assign_ok, orig_slot_handle);
505 }
506 }
508 if (ntree) {
509 animdata_copy_id_action(bmain, &ntree->id, set_newid, do_linked_id);
510 }
511 /* Note that collections are not animatable currently, so no need to handle scenes' master
512 * collection here. */
513}
514
516{
517 const bool is_id_liboverride = ID_IS_OVERRIDE_LIBRARY(id);
518 animdata_copy_id_action(bmain, id, false, !is_id_liboverride);
519}
520
522 ID *id,
523 const /*eDupli_ID_Flags*/ uint duplicate_flags)
524{
525 if (duplicate_flags & USER_DUP_ACT) {
526 animdata_copy_id_action(bmain, id, true, (duplicate_flags & USER_DUP_LINKED_ID) != 0);
527 }
528}
529
531 Main *bmain, ID *dst_id, ID *src_id, eAnimData_MergeCopy_Modes action_mode, bool fix_drivers)
532{
533 AnimData *src = BKE_animdata_from_id(src_id);
534 AnimData *dst = BKE_animdata_from_id(dst_id);
535
536 /* sanity checks */
537 if (ELEM(nullptr, dst, src)) {
538 return;
539 }
540
541 /* TODO: we must unset all "tweak-mode" flags. */
542 if ((src->flag & ADT_NLA_EDIT_ON) || (dst->flag & ADT_NLA_EDIT_ON)) {
544 &LOG,
545 "Merging AnimData blocks while editing NLA is dangerous as it may cause data corruption");
546 return;
547 }
548
549 /* handle actions... */
550 if (action_mode == ADT_MERGECOPY_SRC_COPY) {
551 /* make a copy of the actions */
552 dst->action = (bAction *)BKE_id_copy(bmain, &src->action->id);
553 dst->tmpact = (bAction *)BKE_id_copy(bmain, &src->tmpact->id);
554 }
555 else if (action_mode == ADT_MERGECOPY_SRC_REF) {
556 /* make a reference to it */
557 dst->action = src->action;
558 id_us_plus((ID *)dst->action);
559
560 dst->tmpact = src->tmpact;
561 id_us_plus((ID *)dst->tmpact);
562 }
563 dst->slot_handle = src->slot_handle;
565 STRNCPY(dst->slot_name, src->slot_name);
567
568 /* duplicate NLA data */
569 if (src->nla_tracks.first) {
570 ListBase tracks = {nullptr, nullptr};
571
572 BKE_nla_tracks_copy(bmain, &tracks, &src->nla_tracks, 0);
573 BLI_movelisttolist(&dst->nla_tracks, &tracks);
574 }
575
576 /* duplicate drivers (F-Curves) */
577 if (src->drivers.first) {
578 ListBase drivers = {nullptr, nullptr};
579
580 BKE_fcurves_copy(&drivers, &src->drivers);
581
582 /* Fix up all driver targets using the old target id
583 * - This assumes that the src ID is being merged into the dst ID
584 */
585 if (fix_drivers) {
586 LISTBASE_FOREACH (FCurve *, fcu, &drivers) {
587 ChannelDriver *driver = fcu->driver;
588 LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
590 if (dtar->id == src_id) {
591 dtar->id = dst_id;
592 }
593 }
595 }
596 }
597 }
598
599 BLI_movelisttolist(&dst->drivers, &drivers);
600 }
601}
602
603/* Sub-ID Regrouping ------------------------------------------- */
604
612static bool animpath_matches_basepath(const char path[], const char basepath[])
613{
614 /* we need start of path to be basepath */
615 return (path && basepath) && STRPREFIX(path, basepath);
616}
617
619 const char *old_basepath,
620 const char *new_basepath)
621{
622 BLI_assert(animpath_matches_basepath(fcu->rna_path, old_basepath));
623 if (STREQ(old_basepath, new_basepath)) {
624 return;
625 }
626
627 char *new_path = BLI_sprintfN("%s%s", new_basepath, fcu->rna_path + strlen(old_basepath));
628 MEM_freeN(fcu->rna_path);
629 fcu->rna_path = new_path;
630}
631
632/* Move F-Curves in src action to dst action, setting up all the necessary groups
633 * for this to happen, but only if the F-Curves being moved have the appropriate
634 * "base path".
635 * - This is used when data moves from one data-block to another, causing the
636 * F-Curves to need to be moved over too
637 */
639 const animrig::slot_handle_t src_slot_handle,
640 bAction *dstAct,
641 const animrig::slot_handle_t dst_slot_handle,
642 const char *src_basepath,
643 const char *dst_basepath)
644{
645 /* sanity checks */
646 if (ELEM(nullptr, srcAct, dstAct, src_basepath, dst_basepath)) {
647 if (G.debug & G_DEBUG) {
649 "srcAct: %p, dstAct: %p, src_basepath: %p, dst_basepath: %p has insufficient "
650 "info to work with",
651 (void *)srcAct,
652 (void *)dstAct,
653 (void *)src_basepath,
654 (void *)dst_basepath);
655 }
656 return;
657 }
658
659 animrig::Action &source_action = srcAct->wrap();
660 animrig::Action &dest_action = dstAct->wrap();
661
662 /* Get a list of all F-Curves to move. This is done in a separate step so we
663 * don't move the curves while iterating over them at the same time. */
664 Vector<FCurve *> fcurves_to_move;
665 animrig::foreach_fcurve_in_action_slot(source_action, src_slot_handle, [&](FCurve &fcurve) {
666 if (animpath_matches_basepath(fcurve.rna_path, src_basepath)) {
667 fcurves_to_move.append(&fcurve);
668 }
669 });
670
671 /* Move the curves from one Action to the other, and change its path to match the destination. */
672 for (FCurve *fcurve_to_move : fcurves_to_move) {
673 animpath_update_basepath(fcurve_to_move, src_basepath, dst_basepath);
674 animrig::action_fcurve_move(dest_action, dst_slot_handle, source_action, *fcurve_to_move);
675 }
676}
677
679 AnimData *dstAdt,
680 const char *src_basepath,
681 const char *dst_basepath)
682{
683 LISTBASE_FOREACH_MUTABLE (FCurve *, fcu, &srcAdt->drivers) {
684 if (animpath_matches_basepath(fcu->rna_path, src_basepath)) {
685 animpath_update_basepath(fcu, src_basepath, dst_basepath);
686 BLI_remlink(&srcAdt->drivers, fcu);
687 BLI_addtail(&dstAdt->drivers, fcu);
688
689 /* TODO: add depsgraph flushing calls? */
690 }
691 }
692}
693
694void BKE_animdata_transfer_by_basepath(Main *bmain, ID *srcID, ID *dstID, ListBase *basepaths)
695{
696 AnimData *srcAdt = nullptr, *dstAdt = nullptr;
697
698 /* sanity checks */
699 if (ELEM(nullptr, srcID, dstID)) {
700 if (G.debug & G_DEBUG) {
701 CLOG_ERROR(&LOG, "no source or destination ID to separate AnimData with");
702 }
703 return;
704 }
705
706 /* get animdata from src, and create for destination (if needed) */
707 srcAdt = BKE_animdata_from_id(srcID);
708 dstAdt = BKE_animdata_ensure_id(dstID);
709
710 if (ELEM(nullptr, srcAdt, dstAdt)) {
711 if (G.debug & G_DEBUG) {
712 CLOG_ERROR(&LOG, "no AnimData for this pair of ID's");
713 }
714 return;
715 }
716
717 /* active action */
718 if (srcAdt->action) {
719 const OwnedAnimData dst_owned_adt = {*dstID, *dstAdt};
720 if (dstAdt->action == srcAdt->action) {
721 CLOG_WARN(&LOG,
722 "Source and Destination share animation! "
723 "('%s' and '%s' both use '%s') Making new empty action",
724 srcID->name,
725 dstID->name,
726 srcAdt->action->id.name);
727
728 /* This sets dstAdt->action to nullptr. */
729 const bool unassign_ok = animrig::unassign_action(dst_owned_adt);
730 BLI_assert_msg(unassign_ok, "Expected Action unassignment to work");
731 UNUSED_VARS_NDEBUG(unassign_ok);
732 }
733
734 /* Set up an action if necessary, and name it in a similar way so that it
735 * can be easily found again. */
736 if (!dstAdt->action) {
737 animrig::Action &new_action = animrig::action_add(*bmain, srcAdt->action->id.name + 2);
738 if (USER_EXPERIMENTAL_TEST(&U, use_animation_baklava)) {
739 new_action.slot_add_for_id(*dstID);
740 }
741 const bool assign_ok = animrig::assign_action(&new_action, dst_owned_adt);
742 BLI_assert_msg(assign_ok, "Expected Action assignment to work");
743 UNUSED_VARS_NDEBUG(assign_ok);
744 if (USER_EXPERIMENTAL_TEST(&U, use_animation_baklava)) {
745 BLI_assert(dstAdt->slot_handle != animrig::Slot::unassigned);
746 }
747 }
748
749 /* loop over base paths, trying to fix for each one... */
750 LISTBASE_FOREACH (const AnimationBasePathChange *, basepath_change, basepaths) {
752 srcAdt->slot_handle,
753 dstAdt->action,
754 dstAdt->slot_handle,
755 basepath_change->src_basepath,
756 basepath_change->dst_basepath);
757 }
758 }
759
760 /* drivers */
761 if (srcAdt->drivers.first) {
762 LISTBASE_FOREACH (const AnimationBasePathChange *, basepath_change, basepaths) {
764 srcAdt, dstAdt, basepath_change->src_basepath, basepath_change->dst_basepath);
765 }
766 }
767 /* Tag source action because list of fcurves changed. */
769}
770
771/* Path Validation -------------------------------------------- */
772
773/* Check if a given RNA Path is valid, by tracing it from the given ID,
774 * and seeing if we can resolve it. */
775static bool check_rna_path_is_valid(ID *owner_id, const char *path)
776{
778 PropertyRNA *prop = nullptr;
779
780 /* make initial RNA pointer to start resolving from */
781 PointerRNA id_ptr = RNA_id_pointer_create(owner_id);
782
783 /* try to resolve */
784 return RNA_path_resolve_property(&id_ptr, path, &ptr, &prop);
785}
786
787/* Check if some given RNA Path needs fixing - free the given path and set a new one as appropriate
788 * NOTE: we assume that oldName and newName have [" "] padding around them
789 */
790static char *rna_path_rename_fix(ID *owner_id,
791 const char *prefix,
792 const char *oldName,
793 const char *newName,
794 char *oldpath,
795 bool verify_paths)
796{
797 char *prefixPtr = strstr(oldpath, prefix);
798 if (prefixPtr == nullptr) {
799 return oldpath;
800 }
801
802 char *oldNamePtr = strstr(oldpath, oldName);
803 if (oldNamePtr == nullptr) {
804 return oldpath;
805 }
806
807 int prefixLen = strlen(prefix);
808 int oldNameLen = strlen(oldName);
809
810 /* only start fixing the path if the prefix and oldName feature in the path,
811 * and prefix occurs immediately before oldName
812 */
813 if (prefixPtr + prefixLen == oldNamePtr) {
814 /* if we haven't aren't able to resolve the path now, try again after fixing it */
815 if (!verify_paths || check_rna_path_is_valid(owner_id, oldpath) == 0) {
816 DynStr *ds = BLI_dynstr_new();
817 const char *postfixPtr = oldNamePtr + oldNameLen;
818 char *newPath = nullptr;
819
820 /* add the part of the string that goes up to the start of the prefix */
821 if (prefixPtr > oldpath) {
822 BLI_dynstr_nappend(ds, oldpath, prefixPtr - oldpath);
823 }
824
825 /* add the prefix */
826 BLI_dynstr_append(ds, prefix);
827
828 /* add the new name (complete with brackets) */
829 BLI_dynstr_append(ds, newName);
830
831 /* add the postfix */
832 BLI_dynstr_append(ds, postfixPtr);
833
834 /* create new path, and cleanup old data */
835 newPath = BLI_dynstr_get_cstring(ds);
836 BLI_dynstr_free(ds);
837
838 /* check if the new path will solve our problems */
839 /* TODO: will need to check whether this step really helps in practice */
840 if (!verify_paths || check_rna_path_is_valid(owner_id, newPath)) {
841 /* free the old path, and return the new one, since we've solved the issues */
842 MEM_freeN(oldpath);
843 return newPath;
844 }
845
846 /* still couldn't resolve the path... so, might as well just leave it alone */
847 MEM_freeN(newPath);
848 }
849 }
850
851 /* the old path doesn't need to be changed */
852 return oldpath;
853}
854
855/* Check RNA-Paths for a list of F-Curves */
856static bool fcurves_path_rename_fix(ID *owner_id,
857 const char *prefix,
858 const char *oldName,
859 const char *newName,
860 const char *oldKey,
861 const char *newKey,
863 bool verify_paths)
864{
865 bool is_changed = false;
866 /* We need to check every curve. */
867 for (FCurve *fcu : curves) {
868 if (fcu->rna_path == nullptr) {
869 continue;
870 }
871 const char *old_path = fcu->rna_path;
872 /* Firstly, handle the F-Curve's own path. */
873 fcu->rna_path = rna_path_rename_fix(
874 owner_id, prefix, oldKey, newKey, fcu->rna_path, verify_paths);
875 /* if path changed and the F-Curve is grouped, check if its group also needs renaming
876 * (i.e. F-Curve is first of a bone's F-Curves;
877 * hence renaming this should also trigger rename) */
878 if (fcu->rna_path != old_path) {
879 bActionGroup *agrp = fcu->grp;
880 is_changed = true;
881 if (oldName != nullptr && (agrp != nullptr) && STREQ(oldName, agrp->name)) {
882 STRNCPY(agrp->name, newName);
883 }
884 }
885 }
886 return is_changed;
887}
888
889/* Check RNA-Paths for a list of Drivers */
890static bool drivers_path_rename_fix(ID *owner_id,
891 ID *ref_id,
892 const char *prefix,
893 const char *oldName,
894 const char *newName,
895 const char *oldKey,
896 const char *newKey,
897 ListBase *curves,
898 bool verify_paths)
899{
900 bool is_changed = false;
901 /* We need to check every curve - drivers are F-Curves too. */
902 LISTBASE_FOREACH (FCurve *, fcu, curves) {
903 /* firstly, handle the F-Curve's own path */
904 if (fcu->rna_path != nullptr) {
905 const char *old_rna_path = fcu->rna_path;
906 fcu->rna_path = rna_path_rename_fix(
907 owner_id, prefix, oldKey, newKey, fcu->rna_path, verify_paths);
908 is_changed |= (fcu->rna_path != old_rna_path);
909 }
910 if (fcu->driver == nullptr) {
911 continue;
912 }
913 ChannelDriver *driver = fcu->driver;
914 /* driver variables */
915 LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
916 /* only change the used targets, since the others will need fixing manually anyway */
918 /* rename RNA path */
919 if (dtar->rna_path && dtar->id) {
920 const char *old_rna_path = dtar->rna_path;
921 dtar->rna_path = rna_path_rename_fix(
922 dtar->id, prefix, oldKey, newKey, dtar->rna_path, verify_paths);
923 is_changed |= (dtar->rna_path != old_rna_path);
924 }
925 /* also fix the bone-name (if applicable) */
926 if (strstr(prefix, "bones")) {
927 if (((dtar->id) && (GS(dtar->id->name) == ID_OB) &&
928 (!ref_id || ((Object *)(dtar->id))->data == ref_id)) &&
929 (dtar->pchan_name[0]) && STREQ(oldName, dtar->pchan_name))
930 {
931 is_changed = true;
932 STRNCPY(dtar->pchan_name, newName);
933 }
934 }
935 }
937 }
938 }
939 return is_changed;
940}
941
942/* Fix all RNA-Paths for Actions linked to NLA Strips */
943static bool nlastrips_path_rename_fix(ID *owner_id,
944 const char *prefix,
945 const char *oldName,
946 const char *newName,
947 const char *oldKey,
948 const char *newKey,
949 ListBase *strips,
950 bool verify_paths)
951{
952 bool is_changed = false;
953 /* Recursively check strips, fixing only actions. */
954 LISTBASE_FOREACH (NlaStrip *, strip, strips) {
955 /* fix strip's action */
956 if (strip->act != nullptr) {
957 const bool is_changed_action = fcurves_path_rename_fix(
958 owner_id,
959 prefix,
960 oldName,
961 newName,
962 oldKey,
963 newKey,
965 verify_paths);
966 if (is_changed_action) {
967 DEG_id_tag_update(&strip->act->id, ID_RECALC_ANIMATION);
968 }
969 is_changed |= is_changed_action;
970 }
971 /* Ignore own F-Curves, since those are local. */
972 /* Check sub-strips (if meta-strips). */
973 is_changed |= nlastrips_path_rename_fix(
974 owner_id, prefix, oldName, newName, oldKey, newKey, &strip->strips, verify_paths);
975 }
976 return is_changed;
977}
978
979/* Rename Sub-ID Entities in RNA Paths ----------------------- */
980
982 char *old_path,
983 const char *prefix,
984 const char *oldName,
985 const char *newName,
986 int oldSubscript,
987 int newSubscript,
988 bool verify_paths)
989{
990 char *oldN, *newN;
991 char *result;
992
993 /* if no action, no need to proceed */
994 if (ELEM(nullptr, owner_id, old_path)) {
995 if (G.debug & G_DEBUG) {
996 CLOG_WARN(&LOG, "early abort");
997 }
998 return old_path;
999 }
1000
1001 /* Name sanitation logic - copied from BKE_animdata_fix_paths_rename() */
1002 if ((oldName != nullptr) && (newName != nullptr)) {
1003 /* pad the names with [" "] so that only exact matches are made */
1004 const size_t name_old_len = strlen(oldName);
1005 const size_t name_new_len = strlen(newName);
1006 char *name_old_esc = static_cast<char *>(
1007 BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1));
1008 char *name_new_esc = static_cast<char *>(
1009 BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1));
1010
1011 BLI_str_escape(name_old_esc, oldName, (name_old_len * 2) + 1);
1012 BLI_str_escape(name_new_esc, newName, (name_new_len * 2) + 1);
1013 oldN = BLI_sprintfN("[\"%s\"]", name_old_esc);
1014 newN = BLI_sprintfN("[\"%s\"]", name_new_esc);
1015 }
1016 else {
1017 oldN = BLI_sprintfN("[%d]", oldSubscript);
1018 newN = BLI_sprintfN("[%d]", newSubscript);
1019 }
1020
1021 /* fix given path */
1022 if (G.debug & G_DEBUG) {
1023 printf("%s | %s | oldpath = %p ", oldN, newN, old_path);
1024 }
1025 result = rna_path_rename_fix(owner_id, prefix, oldN, newN, old_path, verify_paths);
1026 if (G.debug & G_DEBUG) {
1027 printf("path rename result = %p\n", result);
1028 }
1029
1030 /* free the temp names */
1031 MEM_freeN(oldN);
1032 MEM_freeN(newN);
1033
1034 /* return the resulting path - may be the same path again if nothing changed */
1035 return result;
1036}
1037
1039 bAction *act,
1040 const char *prefix,
1041 const char *oldName,
1042 const char *newName,
1043 int oldSubscript,
1044 int newSubscript,
1045 bool verify_paths)
1046{
1047 char *oldN, *newN;
1048
1049 /* if no action, no need to proceed */
1050 if (ELEM(nullptr, owner_id, act)) {
1051 return;
1052 }
1053
1054 /* Name sanitation logic - copied from BKE_animdata_fix_paths_rename() */
1055 if ((oldName != nullptr) && (newName != nullptr)) {
1056 /* pad the names with [" "] so that only exact matches are made */
1057 const size_t name_old_len = strlen(oldName);
1058 const size_t name_new_len = strlen(newName);
1059 char *name_old_esc = static_cast<char *>(
1060 BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1));
1061 char *name_new_esc = static_cast<char *>(
1062 BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1));
1063
1064 BLI_str_escape(name_old_esc, oldName, (name_old_len * 2) + 1);
1065 BLI_str_escape(name_new_esc, newName, (name_new_len * 2) + 1);
1066 oldN = BLI_sprintfN("[\"%s\"]", name_old_esc);
1067 newN = BLI_sprintfN("[\"%s\"]", name_new_esc);
1068 }
1069 else {
1070 oldN = BLI_sprintfN("[%d]", oldSubscript);
1071 newN = BLI_sprintfN("[%d]", newSubscript);
1072 }
1073
1074 /* fix paths in action */
1075 fcurves_path_rename_fix(owner_id,
1076 prefix,
1077 oldName,
1078 newName,
1079 oldN,
1080 newN,
1082 verify_paths);
1083
1084 /* free the temp names */
1085 MEM_freeN(oldN);
1086 MEM_freeN(newN);
1087}
1088
1090 AnimData *adt,
1091 ID *ref_id,
1092 const char *prefix,
1093 const char *oldName,
1094 const char *newName,
1095 int oldSubscript,
1096 int newSubscript,
1097 bool verify_paths)
1098{
1099 char *oldN, *newN;
1100 /* If no AnimData, no need to proceed. */
1101 if (ELEM(nullptr, owner_id, adt)) {
1102 return;
1103 }
1104 bool is_self_changed = false;
1105 /* Name sanitation logic - shared with BKE_action_fix_paths_rename(). */
1106 if ((oldName != nullptr) && (newName != nullptr)) {
1107 /* Pad the names with [" "] so that only exact matches are made. */
1108 const size_t name_old_len = strlen(oldName);
1109 const size_t name_new_len = strlen(newName);
1110 char *name_old_esc = static_cast<char *>(
1111 BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1));
1112 char *name_new_esc = static_cast<char *>(
1113 BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1));
1114
1115 BLI_str_escape(name_old_esc, oldName, (name_old_len * 2) + 1);
1116 BLI_str_escape(name_new_esc, newName, (name_new_len * 2) + 1);
1117 oldN = BLI_sprintfN("[\"%s\"]", name_old_esc);
1118 newN = BLI_sprintfN("[\"%s\"]", name_new_esc);
1119 }
1120 else {
1121 oldN = BLI_sprintfN("[%d]", oldSubscript);
1122 newN = BLI_sprintfN("[%d]", newSubscript);
1123 }
1124 /* Active action and temp action. */
1125 if (adt->action != nullptr) {
1126 if (fcurves_path_rename_fix(owner_id,
1127 prefix,
1128 oldName,
1129 newName,
1130 oldN,
1131 newN,
1133 verify_paths))
1134 {
1136 }
1137 }
1138 if (adt->tmpact) {
1139 if (fcurves_path_rename_fix(owner_id,
1140 prefix,
1141 oldName,
1142 newName,
1143 oldN,
1144 newN,
1146 verify_paths))
1147 {
1149 }
1150 }
1151 /* Drivers - Drivers are really F-Curves */
1152 is_self_changed |= drivers_path_rename_fix(
1153 owner_id, ref_id, prefix, oldName, newName, oldN, newN, &adt->drivers, verify_paths);
1154 /* NLA Data - Animation Data for Strips */
1155 LISTBASE_FOREACH (NlaTrack *, nlt, &adt->nla_tracks) {
1156 is_self_changed |= nlastrips_path_rename_fix(
1157 owner_id, prefix, oldName, newName, oldN, newN, &nlt->strips, verify_paths);
1158 }
1159 /* Tag owner ID if it */
1160 if (is_self_changed) {
1162 }
1163 /* free the temp names */
1164 MEM_freeN(oldN);
1165 MEM_freeN(newN);
1166}
1167
1168/* Remove FCurves with Prefix -------------------------------------- */
1169
1171static bool fcurves_path_remove_from_listbase(const char *prefix, ListBase *curves)
1172{
1173 FCurve *fcu, *fcn;
1174 bool any_removed = false;
1175 if (!prefix) {
1176 return any_removed;
1177 }
1178
1179 /* we need to check every curve... */
1180 for (fcu = static_cast<FCurve *>(curves->first); fcu; fcu = fcn) {
1181 fcn = fcu->next;
1182
1183 if (fcu->rna_path) {
1184 if (STRPREFIX(fcu->rna_path, prefix)) {
1185 BLI_remlink(curves, fcu);
1186 BKE_fcurve_free(fcu);
1187 any_removed = true;
1188 }
1189 }
1190 }
1191 return any_removed;
1192}
1193
1194/* Check RNA-Paths for a list of F-Curves */
1195static bool nlastrips_path_remove_fix(const char *prefix, ListBase *strips)
1196{
1197 bool any_removed = false;
1198
1199 /* recursively check strips, fixing only actions... */
1200 LISTBASE_FOREACH (NlaStrip *, strip, strips) {
1201 /* fix strip's action */
1202 if (strip->act) {
1204 *strip->act, strip->action_slot_handle, prefix);
1205 }
1206
1207 /* Check sub-strips (if meta-strips). */
1208 any_removed |= nlastrips_path_remove_fix(prefix, &strip->strips);
1209 }
1210
1211 return any_removed;
1212}
1213
1214bool BKE_animdata_fix_paths_remove(ID *id, const char *prefix)
1215{
1216 AnimData *adt = BKE_animdata_from_id(id);
1217 if (!adt) {
1218 return false;
1219 }
1220
1221 bool any_removed = false;
1222
1223 /* Actions. */
1224 if (adt->action) {
1225 any_removed |= animrig::legacy::action_fcurves_remove(*adt->action, adt->slot_handle, prefix);
1226 }
1227 if (adt->tmpact) {
1229 *adt->action, adt->tmp_slot_handle, prefix);
1230 }
1231
1232 /* Drivers. */
1233 any_removed |= fcurves_path_remove_from_listbase(prefix, &adt->drivers);
1234
1235 /* NLA strips. */
1236 LISTBASE_FOREACH (NlaTrack *, nlt, &adt->nla_tracks) {
1237 any_removed |= nlastrips_path_remove_fix(prefix, &nlt->strips);
1238 }
1239
1240 return any_removed;
1241}
1242
1243/* Apply Op to All FCurves in Database --------------------------- */
1244
1245/* Helper for adt_apply_all_fcurves_cb() - Apply wrapped operator to list of F-Curves */
1246static void fcurves_apply_cb(ID *id,
1248 const FunctionRef<void(ID *, FCurve *)> func)
1249{
1250 for (FCurve *fcu : fcurves) {
1251 func(id, fcu);
1252 }
1253}
1255 ListBase *fcurves,
1256
1257 const FunctionRef<void(ID *, FCurve *)> func)
1258{
1259 LISTBASE_FOREACH (FCurve *, fcu, fcurves) {
1260 func(id, fcu);
1261 }
1262}
1263
1264/* Helper for adt_apply_all_fcurves_cb() - Recursively go through each NLA strip */
1266 ListBase *strips,
1267 const FunctionRef<void(ID *, FCurve *)> func)
1268{
1269 LISTBASE_FOREACH (NlaStrip *, strip, strips) {
1270 /* fix strip's action */
1271 if (strip->act) {
1273 }
1274
1275 /* Check sub-strips (if meta-strips). */
1276 nlastrips_apply_all_curves_cb(id, &strip->strips, func);
1277 }
1278}
1279
1280/* Helper for BKE_fcurves_main_cb() - Dispatch wrapped operator to all F-Curves */
1282 AnimData *adt,
1283 const FunctionRef<void(ID *, FCurve *)> func)
1284{
1285 if (adt->action) {
1287 }
1288
1289 if (adt->tmpact) {
1291 }
1292
1293 /* free drivers - stored as a list of F-Curves */
1294 fcurves_listbase_apply_cb(id, &adt->drivers, func);
1295
1296 /* NLA Data - Animation Data for Strips */
1297 LISTBASE_FOREACH (NlaTrack *, nlt, &adt->nla_tracks) {
1298 nlastrips_apply_all_curves_cb(id, &nlt->strips, func);
1299 }
1300}
1301
1302void BKE_fcurves_id_cb(ID *id, const FunctionRef<void(ID *, FCurve *)> func)
1303{
1304 AnimData *adt = BKE_animdata_from_id(id);
1305 if (adt != nullptr) {
1306 adt_apply_all_fcurves_cb(id, adt, func);
1307 }
1308}
1309
1310void BKE_fcurves_main_cb(Main *bmain, const FunctionRef<void(ID *, FCurve *)> func)
1311{
1312 /* Use the AnimData-based function so that we don't have to reimplement all that stuff */
1314 [&](ID *id, AnimData *adt) { adt_apply_all_fcurves_cb(id, adt, func); });
1315}
1316
1317/* Whole Database Ops -------------------------------------------- */
1318
1319void BKE_animdata_main_cb(Main *bmain, const FunctionRef<void(ID *, AnimData *)> func)
1320{
1321 ID *id;
1322
1323/* standard data version */
1324#define ANIMDATA_IDS_CB(first) \
1325 for (id = static_cast<ID *>(first); id; id = static_cast<ID *>(id->next)) { \
1326 AnimData *adt = BKE_animdata_from_id(id); \
1327 if (adt) { \
1328 func(id, adt); \
1329 } \
1330 } \
1331 (void)0
1332
1333/* "embedded" nodetree cases (i.e. scene/material/texture->nodetree) */
1334#define ANIMDATA_NODETREE_IDS_CB(first, NtId_Type) \
1335 for (id = static_cast<ID *>(first); id; id = static_cast<ID *>(id->next)) { \
1336 AnimData *adt = BKE_animdata_from_id(id); \
1337 NtId_Type *ntp = (NtId_Type *)id; \
1338 if (ntp->nodetree) { \
1339 AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \
1340 if (adt2) { \
1341 func(id, adt2); \
1342 } \
1343 } \
1344 if (adt) { \
1345 func(id, adt); \
1346 } \
1347 } \
1348 (void)0
1349
1350 /* nodes */
1352
1353 /* textures */
1355
1356 /* lights */
1358
1359 /* materials */
1361
1362 /* cameras */
1364
1365 /* shapekeys */
1367
1368 /* metaballs */
1370
1371 /* curves */
1373
1374 /* armatures */
1376
1377 /* lattices */
1379
1380 /* meshes */
1382
1383 /* particles */
1385
1386 /* speakers */
1388
1389 /* movie clips */
1391
1392 /* objects */
1394
1395 /* masks */
1396 ANIMDATA_IDS_CB(bmain->masks.first);
1397
1398 /* worlds */
1400
1401 /* scenes */
1403
1404 /* line styles */
1406
1407 /* grease pencil */
1409
1410 /* grease pencil */
1412
1413 /* palettes */
1415
1416 /* cache files */
1418
1419 /* Hair Curves. */
1421
1422 /* pointclouds */
1424
1425 /* volumes */
1427}
1428
1430 const char *prefix,
1431 const char *oldName,
1432 const char *newName)
1433{
1434 Main *bmain = G.main; /* XXX UGLY! */
1435 BKE_animdata_fix_paths_rename_all_ex(bmain, ref_id, prefix, oldName, newName, 0, 0, true);
1436}
1437
1439 ID *ref_id,
1440 const char *prefix,
1441 const char *oldName,
1442 const char *newName,
1443 const int oldSubscript,
1444 const int newSubscript,
1445 const bool verify_paths)
1446{
1447 BKE_animdata_main_cb(bmain, [&](ID *id, AnimData *adt) {
1449 id, adt, ref_id, prefix, oldName, newName, oldSubscript, newSubscript, verify_paths);
1450 });
1451}
1452
1453/* .blend file API -------------------------------------------- */
1454
1456{
1457 AnimData *adt = BKE_animdata_from_id(id);
1458 if (!adt) {
1459 return;
1460 }
1461
1462 /* firstly, just write the AnimData block */
1463 BLO_write_struct(writer, AnimData, adt);
1464
1465 /* write drivers */
1467
1468 /* write overrides */
1469 /* FIXME: are these needed? */
1470 LISTBASE_FOREACH (AnimOverride *, aor, &adt->overrides) {
1471 /* overrides consist of base data + rna_path */
1472 BLO_write_struct(writer, AnimOverride, aor);
1473 BLO_write_string(writer, aor->rna_path);
1474 }
1475
1476 /* TODO: write the remaps (if they are needed). */
1477
1478 /* write NLA data */
1479 BKE_nla_blend_write(writer, &adt->nla_tracks);
1480}
1481
1483{
1484 IdAdtTemplate *iat = id_can_have_animdata(id) ? reinterpret_cast<IdAdtTemplate *>(id) : nullptr;
1485 if (!iat || !iat->adt) {
1486 return;
1487 }
1488
1489 AnimData *adt = static_cast<AnimData *>(BLO_read_struct(reader, AnimData, &iat->adt));
1490 if (adt == nullptr) {
1491 return;
1492 }
1493
1494 /* link drivers */
1495 BLO_read_struct_list(reader, FCurve, &adt->drivers);
1497 adt->driver_array = nullptr;
1498
1499 /* link overrides */
1500 /* TODO... */
1501
1502 /* link NLA-data */
1504 BKE_nla_blend_read_data(reader, id, &adt->nla_tracks);
1505
1506 /* relink active track/strip - even though strictly speaking this should only be used
1507 * if we're in 'tweaking mode', we need to be able to have this loaded back for
1508 * undo, but also since users may not exit tweak-mode before saving (#24535).
1509 */
1510 /* TODO: it's not really nice that anyone should be able to save the file in this
1511 * state, but it's going to be too hard to enforce this single case. */
1512 BLO_read_struct(reader, NlaTrack, &adt->act_track);
1513 BLO_read_struct(reader, NlaStrip, &adt->actstrip);
1514
1515 if (ID_IS_LINKED(id)) {
1516 /* Linked NLAs should never be in tweak mode, as you cannot exit that on linked data. */
1518 }
1519}
1520
1522{
1523 AnimData *adt = BKE_animdata_from_id(id);
1524 if (!adt) {
1525 return;
1526 }
1527
1529}
Functions and classes to work with Actions.
Functionality to iterate an Action in various ways.
Functions for backward compatibility with the legacy Action API.
Blender kernel action and pose functionality.
eAnimData_MergeCopy_Modes
@ ADT_MERGECOPY_SRC_COPY
@ ADT_MERGECOPY_SRC_REF
void BKE_fcurve_foreach_id(FCurve *fcu, LibraryForeachIDData *data)
void BKE_fcurve_blend_write_listbase(BlendWriter *writer, ListBase *fcurves)
void BKE_fcurve_blend_read_data_listbase(BlendDataReader *reader, ListBase *fcurves)
void BKE_fcurves_free(ListBase *list)
void BKE_fcurves_copy(ListBase *dst, ListBase *src)
void BKE_fcurve_free(FCurve *fcu)
#define DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar)
#define DRIVER_TARGETS_LOOPER_END
@ G_DEBUG
@ IDTYPE_FLAGS_NO_ANIMDATA
Definition BKE_idtype.hh:41
const IDTypeInfo * BKE_idtype_get_info_from_idcode(short id_code)
Definition idtype.cc:145
@ LIB_ID_COPY_ACTIONS
@ LIB_ID_CREATE_NO_USER_REFCOUNT
@ LIB_ID_CREATE_NO_MAIN
void id_us_plus(ID *id)
Definition lib_id.cc:351
struct ID * BKE_id_copy_in_lib(Main *bmain, std::optional< Library * > owner_library, const ID *id, const ID *new_owner_id, ID **new_id_p, int flag)
Definition lib_id.cc:656
ID * BKE_id_copy(Main *bmain, const ID *id)
Definition lib_id.cc:765
void id_us_min(ID *id)
Definition lib_id.cc:359
#define BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data_, func_call_)
#define BKE_LIB_FOREACHID_PROCESS_IDSUPER(data_, id_super_, cb_flag_)
@ IDWALK_CB_USER
void BKE_nla_tracks_copy_from_adt(Main *bmain, AnimData *adt_dest, const AnimData *adt_source, int flag)
void BKE_nla_tweakmode_exit(OwnedAnimData owned_adt)
void BKE_nla_tweakmode_exit_nofollowptr(AnimData *adt)
void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, const ListBase *src, int flag)
void BKE_nla_blend_write(BlendWriter *writer, ListBase *tracks)
void BKE_nla_tracks_free(ListBase *tracks, bool do_id_user)
void BKE_nla_liboverride_post_process(ID *id, AnimData *adt)
void BKE_nla_blend_read_data(BlendDataReader *reader, ID *id_owner, ListBase *tracks)
void BKE_nla_strip_foreach_id(NlaStrip *strip, LibraryForeachIDData *data)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
#define BLI_array_alloca(arr, realsize)
Definition BLI_alloca.h:25
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
A dynamically sized string ADT.
char * BLI_dynstr_get_cstring(const DynStr *ds) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition BLI_dynstr.c:149
void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len) ATTR_NONNULL()
Definition BLI_dynstr.c:81
DynStr * BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_dynstr.c:37
void BLI_dynstr_free(DynStr *ds) ATTR_NONNULL()
Definition BLI_dynstr.c:174
void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr) ATTR_NONNULL()
Definition BLI_dynstr.c:62
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void void void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
char * BLI_sprintfN(const char *__restrict format,...) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1
#define STRNCPY(dst, src)
Definition BLI_string.h:593
size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
unsigned int uint
#define STRPREFIX(a, b)
#define UNUSED_VARS_NDEBUG(...)
#define ELEM(...)
#define STREQ(a, b)
#define BLO_write_struct(writer, struct_name, data_ptr)
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
#define BLO_read_struct_list(reader, struct_name, list)
#define BLO_read_struct(reader, struct_name, ptr_p)
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:182
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:181
void DEG_id_tag_update(ID *id, unsigned int flags)
ID and Library types, which are fundamental for SDNA.
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1085
@ ID_RECALC_ANIMATION
Definition DNA_ID.h:1044
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:654
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:683
#define ID_NEW_SET(_id, _idn)
Definition DNA_ID.h:707
@ ID_OB
@ ADT_NLA_EDIT_ON
@ USER_DUP_LINKED_ID
@ USER_DUP_ACT
#define USER_EXPERIMENTAL_TEST(userdef, member)
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
static bool fcurves_path_remove_from_listbase(const char *prefix, ListBase *curves)
void BKE_animdata_main_cb(Main *bmain, const FunctionRef< void(ID *, AnimData *)> func)
bool BKE_animdata_copy_id(Main *bmain, ID *id_to, ID *id_from, const int flag)
Definition anim_data.cc:452
bool BKE_animdata_id_is_animated(const ID *id)
Definition anim_data.cc:321
static void animdata_copy_id_action(Main *bmain, ID *id, const bool set_newid, const bool do_linked_id)
Definition anim_data.cc:471
static void adt_apply_all_fcurves_cb(ID *id, AnimData *adt, const FunctionRef< void(ID *, FCurve *)> func)
bool BKE_animdata_action_ensure_idroot(const ID *owner, bAction *action)
Definition anim_data.cc:232
bool BKE_animdata_fix_paths_remove(ID *id, const char *prefix)
static void nlastrips_apply_all_curves_cb(ID *id, ListBase *strips, const FunctionRef< void(ID *, FCurve *)> func)
void BKE_animdata_fix_paths_rename_all_ex(Main *bmain, ID *ref_id, const char *prefix, const char *oldName, const char *newName, const int oldSubscript, const int newSubscript, const bool verify_paths)
void BKE_animdata_merge_copy(Main *bmain, ID *dst_id, ID *src_id, eAnimData_MergeCopy_Modes action_mode, bool fix_drivers)
Definition anim_data.cc:530
void BKE_animdata_blend_write(BlendWriter *writer, ID *id)
static bool drivers_path_rename_fix(ID *owner_id, ID *ref_id, const char *prefix, const char *oldName, const char *newName, const char *oldKey, const char *newKey, ListBase *curves, bool verify_paths)
Definition anim_data.cc:890
static bool check_rna_path_is_valid(ID *owner_id, const char *path)
Definition anim_data.cc:775
AnimData * BKE_animdata_ensure_id(ID *id)
Definition anim_data.cc:103
static bool nlastrips_path_rename_fix(ID *owner_id, const char *prefix, const char *oldName, const char *newName, const char *oldKey, const char *newKey, ListBase *strips, bool verify_paths)
Definition anim_data.cc:943
bool id_can_have_animdata(const ID *id)
Definition anim_data.cc:79
void BKE_action_fix_paths_rename(ID *owner_id, bAction *act, const char *prefix, const char *oldName, const char *newName, int oldSubscript, int newSubscript, bool verify_paths)
void BKE_animdata_foreach_id(AnimData *adt, LibraryForeachIDData *data)
Definition anim_data.cc:346
#define ANIMDATA_NODETREE_IDS_CB(first, NtId_Type)
bool id_type_can_have_animdata(const short id_type)
Definition anim_data.cc:70
static void fcurves_listbase_apply_cb(ID *id, ListBase *fcurves, const FunctionRef< void(ID *, FCurve *)> func)
void BKE_fcurves_id_cb(ID *id, const FunctionRef< void(ID *, FCurve *)> func)
bool BKE_animdata_action_editable(const AnimData *adt)
Definition anim_data.cc:224
bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act)
Definition anim_data.cc:194
void BKE_animdata_free(ID *id, const bool do_id_user)
Definition anim_data.cc:263
static bool animpath_matches_basepath(const char path[], const char basepath[])
Definition anim_data.cc:612
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:89
void BKE_fcurves_main_cb(Main *bmain, const FunctionRef< void(ID *, FCurve *)> func)
static bool nlastrips_path_remove_fix(const char *prefix, ListBase *strips)
void BKE_animdata_blend_read_data(BlendDataReader *reader, ID *id)
static char * rna_path_rename_fix(ID *owner_id, const char *prefix, const char *oldName, const char *newName, char *oldpath, bool verify_paths)
Definition anim_data.cc:790
AnimData * BKE_animdata_copy_in_lib(Main *bmain, std::optional< Library * > owner_library, AnimData *adt, const int flag)
Definition anim_data.cc:364
static bool animdata_set_action(ReportList *reports, ID *id, bAction **act_slot, bAction *act)
Definition anim_data.cc:144
static void fcurves_apply_cb(ID *id, blender::Span< FCurve * > fcurves, const FunctionRef< void(ID *, FCurve *)> func)
void BKE_animdata_liboverride_post_process(ID *id)
void BKE_animdata_duplicate_id_action(Main *bmain, ID *id, const uint duplicate_flags)
Definition anim_data.cc:521
static void animpath_update_basepath(FCurve *fcu, const char *old_basepath, const char *new_basepath)
Definition anim_data.cc:618
static CLG_LogRef LOG
Definition anim_data.cc:61
#define ANIMDATA_IDS_CB(first)
void BKE_animdata_transfer_by_basepath(Main *bmain, ID *srcID, ID *dstID, ListBase *basepaths)
Definition anim_data.cc:694
void BKE_animdata_fix_paths_rename_all(ID *ref_id, const char *prefix, const char *oldName, const char *newName)
bool BKE_animdata_set_tmpact(ReportList *reports, ID *id, bAction *act)
Definition anim_data.cc:181
void BKE_animdata_copy_id_action(Main *bmain, ID *id)
Definition anim_data.cc:515
static void action_move_fcurves_by_basepath(bAction *srcAct, const animrig::slot_handle_t src_slot_handle, bAction *dstAct, const animrig::slot_handle_t dst_slot_handle, const char *src_basepath, const char *dst_basepath)
Definition anim_data.cc:638
char * BKE_animsys_fix_rna_path_rename(ID *owner_id, char *old_path, const char *prefix, const char *oldName, const char *newName, int oldSubscript, int newSubscript, bool verify_paths)
Definition anim_data.cc:981
AnimData * BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag)
Definition anim_data.cc:447
static void animdata_move_drivers_by_basepath(AnimData *srcAdt, AnimData *dstAdt, const char *src_basepath, const char *dst_basepath)
Definition anim_data.cc:678
void BKE_animdata_fix_paths_rename(ID *owner_id, AnimData *adt, ID *ref_id, const char *prefix, const char *oldName, const char *newName, int oldSubscript, int newSubscript, bool verify_paths)
static bool fcurves_path_rename_fix(ID *owner_id, const char *prefix, const char *oldName, const char *newName, const char *oldKey, const char *newKey, blender::Span< FCurve * > curves, bool verify_paths)
Definition anim_data.cc:856
unsigned int U
Definition btGjkEpa3.h:78
Slot & slot_add_for_id(const ID &animated_id)
bool is_slot_animated(slot_handle_t slot_handle) const
static void users_invalidate(Main &bmain)
static constexpr slot_handle_t unassigned
#define printf
#define GS(x)
Definition iris.cc:202
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
#define G(x, y, z)
Vector< const FCurve * > fcurves_all(const bAction *action)
bool action_fcurves_remove(bAction &action, slot_handle_t slot_handle, StringRefNull rna_path_prefix)
bool action_treat_as_legacy(const bAction &action)
void foreach_fcurve_in_action_slot(Action &action, slot_handle_t handle, FunctionRef< void(FCurve &fcurve)> callback)
void action_fcurve_move(Action &action_dst, slot_handle_t action_slot_dst, Action &action_src, FCurve &fcurve)
Action & action_add(Main &bmain, StringRefNull name)
decltype(::ActionSlot::handle) slot_handle_t
bool assign_tmpaction(bAction *action, OwnedAnimData owned_adt)
bool unassign_action(ID &animated_id)
bool assign_action(bAction *action, ID &animated_id)
bNodeTree * node_tree_from_id(ID *id)
Definition node.cc:3732
PointerRNA RNA_id_pointer_create(ID *id)
bool RNA_path_resolve_property(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
Definition rna_path.cc:553
bAction * action
NlaStrip * actstrip
ListBase overrides
float act_influence
int32_t slot_handle
FCurve ** driver_array
char tmp_slot_name[66]
NlaTrack * act_track
int32_t tmp_slot_handle
bAction * tmpact
ListBase drivers
ListBase nla_tracks
char slot_name[66]
struct FCurve * next
char * rna_path
uint32_t flags
Definition DNA_ID.h:413
char name[66]
Definition DNA_ID.h:425
void * first
ListBase volumes
Definition BKE_main.hh:253
ListBase masks
Definition BKE_main.hh:243
ListBase scenes
Definition BKE_main.hh:210
ListBase grease_pencils
Definition BKE_main.hh:241
ListBase textures
Definition BKE_main.hh:217
ListBase meshes
Definition BKE_main.hh:213
ListBase movieclips
Definition BKE_main.hh:242
ListBase hair_curves
Definition BKE_main.hh:251
ListBase lights
Definition BKE_main.hh:220
ListBase nodetrees
Definition BKE_main.hh:234
ListBase particles
Definition BKE_main.hh:236
ListBase materials
Definition BKE_main.hh:216
ListBase linestyles
Definition BKE_main.hh:244
ListBase pointclouds
Definition BKE_main.hh:252
ListBase lattices
Definition BKE_main.hh:219
ListBase shapekeys
Definition BKE_main.hh:223
ListBase cameras
Definition BKE_main.hh:221
ListBase armatures
Definition BKE_main.hh:232
ListBase speakers
Definition BKE_main.hh:228
ListBase curves
Definition BKE_main.hh:214
ListBase worlds
Definition BKE_main.hh:224
ListBase palettes
Definition BKE_main.hh:237
ListBase metaballs
Definition BKE_main.hh:215
ListBase gpencils
Definition BKE_main.hh:240
ListBase objects
Definition BKE_main.hh:212
ListBase cachefiles
Definition BKE_main.hh:245
ListBase strips
ListBase curves
PointerRNA * ptr
Definition wm_files.cc:4126
uint8_t flag
Definition wm_window.cc:138