diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:17:24 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:21:24 +0300 |
commit | e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch) | |
tree | 8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/blenkernel/intern/anim_sys.c | |
parent | b3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff) |
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211.
For details on usage and instructions for migrating branches
without conflicts, see:
https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/blenkernel/intern/anim_sys.c')
-rw-r--r-- | source/blender/blenkernel/intern/anim_sys.c | 5794 |
1 files changed, 3001 insertions, 2793 deletions
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 33f19caf1cc..75244a8ba8a 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -21,7 +21,6 @@ * \ingroup bke */ - #include <stdio.h> #include <string.h> #include <stddef.h> @@ -84,39 +83,47 @@ static CLG_LogRef LOG = {"bke.anim_sys"}; /* Check if ID can have AnimData */ bool id_type_can_have_animdata(const short id_type) { - /* Only some ID-blocks have this info for now */ - /* TODO: finish adding this for the other blocktypes */ - switch (id_type) { - /* has AnimData */ - case ID_OB: - case ID_ME: case ID_MB: case ID_CU: case ID_AR: case ID_LT: - case ID_KE: - case ID_PA: - case ID_MA: case ID_TE: case ID_NT: - case ID_LA: case ID_CA: case ID_WO: - case ID_LS: - case ID_LP: - case ID_SPK: - case ID_SCE: - case ID_MC: - case ID_MSK: - case ID_GD: - case ID_CF: - return true; - - /* no AnimData */ - default: - return false; - } + /* Only some ID-blocks have this info for now */ + /* TODO: finish adding this for the other blocktypes */ + switch (id_type) { + /* has AnimData */ + case ID_OB: + case ID_ME: + case ID_MB: + case ID_CU: + case ID_AR: + case ID_LT: + case ID_KE: + case ID_PA: + case ID_MA: + case ID_TE: + case ID_NT: + case ID_LA: + case ID_CA: + case ID_WO: + case ID_LS: + case ID_LP: + case ID_SPK: + case ID_SCE: + case ID_MC: + case ID_MSK: + case ID_GD: + case ID_CF: + return true; + + /* no AnimData */ + default: + return false; + } } bool id_can_have_animdata(const ID *id) { - /* sanity check */ - if (id == NULL) - return false; + /* sanity check */ + if (id == NULL) + return false; - return id_type_can_have_animdata(GS(id->name)); + return id_type_can_have_animdata(GS(id->name)); } /* Get AnimData from the given ID-block. In order for this to work, we assume that @@ -125,16 +132,16 @@ bool id_can_have_animdata(const ID *id) */ AnimData *BKE_animdata_from_id(ID *id) { - /* only some ID-blocks have this info for now, so we cast the - * types that do to be of type IdAdtTemplate, and extract the - * AnimData that way - */ - if (id_can_have_animdata(id)) { - IdAdtTemplate *iat = (IdAdtTemplate *)id; - return iat->adt; - } - else - return NULL; + /* only some ID-blocks have this info for now, so we cast the + * types that do to be of type IdAdtTemplate, and extract the + * AnimData that way + */ + if (id_can_have_animdata(id)) { + IdAdtTemplate *iat = (IdAdtTemplate *)id; + return iat->adt; + } + else + return NULL; } /* Add AnimData to the given ID-block. In order for this to work, we assume that @@ -143,28 +150,28 @@ AnimData *BKE_animdata_from_id(ID *id) */ AnimData *BKE_animdata_add_id(ID *id) { - /* Only some ID-blocks have this info for now, so we cast the - * types that do to be of type IdAdtTemplate, and add the AnimData - * to it using the template - */ - if (id_can_have_animdata(id)) { - IdAdtTemplate *iat = (IdAdtTemplate *)id; + /* Only some ID-blocks have this info for now, so we cast the + * types that do to be of type IdAdtTemplate, and add the AnimData + * to it using the template + */ + if (id_can_have_animdata(id)) { + IdAdtTemplate *iat = (IdAdtTemplate *)id; - /* check if there's already AnimData, in which case, don't add */ - if (iat->adt == NULL) { - AnimData *adt; + /* check if there's already AnimData, in which case, don't add */ + if (iat->adt == NULL) { + AnimData *adt; - /* add animdata */ - adt = iat->adt = MEM_callocN(sizeof(AnimData), "AnimData"); + /* add animdata */ + adt = iat->adt = MEM_callocN(sizeof(AnimData), "AnimData"); - /* set default settings */ - adt->act_influence = 1.0f; - } + /* set default settings */ + adt->act_influence = 1.0f; + } - return iat->adt; - } - else - return NULL; + return iat->adt; + } + else + return NULL; } /* Action Setter --------------------------------------- */ @@ -172,52 +179,56 @@ AnimData *BKE_animdata_add_id(ID *id) /* Called when user tries to change the active action of an AnimData block (via RNA, Outliner, etc.) */ bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act) { - AnimData *adt = BKE_animdata_from_id(id); - bool ok = false; - - /* animdata validity check */ - if (adt == NULL) { - BKE_report(reports, RPT_WARNING, "No AnimData to set action on"); - return ok; - } - - /* active action is only editable when it is not a tweaking strip - * see rna_AnimData_action_editable() in rna_animation.c - */ - if ((adt->flag & ADT_NLA_EDIT_ON) || (adt->actstrip) || (adt->tmpact)) { - /* cannot remove, otherwise things turn to custard */ - BKE_report(reports, RPT_ERROR, "Cannot change action, as it is still being edited in NLA"); - return ok; - } - - /* manage usercount for current action */ - if (adt->action) - id_us_min((ID *)adt->action); - - /* assume that AnimData's action can in fact be edited... */ - if (act) { - /* action must have same type as owner */ - if (ELEM(act->idroot, 0, GS(id->name))) { - /* can set */ - adt->action = act; - id_us_plus((ID *)adt->action); - ok = true; - } - else { - /* cannot set */ - BKE_reportf(reports, RPT_ERROR, - "Could not set action '%s' onto ID '%s', as it does not have suitably rooted paths " - "for this purpose", act->id.name + 2, id->name); - /* ok = false; */ - } - } - else { - /* just clearing the action... */ - adt->action = NULL; - ok = true; - } - - return ok; + AnimData *adt = BKE_animdata_from_id(id); + bool ok = false; + + /* animdata validity check */ + if (adt == NULL) { + BKE_report(reports, RPT_WARNING, "No AnimData to set action on"); + return ok; + } + + /* active action is only editable when it is not a tweaking strip + * see rna_AnimData_action_editable() in rna_animation.c + */ + if ((adt->flag & ADT_NLA_EDIT_ON) || (adt->actstrip) || (adt->tmpact)) { + /* cannot remove, otherwise things turn to custard */ + BKE_report(reports, RPT_ERROR, "Cannot change action, as it is still being edited in NLA"); + return ok; + } + + /* manage usercount for current action */ + if (adt->action) + id_us_min((ID *)adt->action); + + /* assume that AnimData's action can in fact be edited... */ + if (act) { + /* action must have same type as owner */ + if (ELEM(act->idroot, 0, GS(id->name))) { + /* can set */ + adt->action = act; + id_us_plus((ID *)adt->action); + ok = true; + } + else { + /* cannot set */ + BKE_reportf( + reports, + RPT_ERROR, + "Could not set action '%s' onto ID '%s', as it does not have suitably rooted paths " + "for this purpose", + act->id.name + 2, + id->name); + /* ok = false; */ + } + } + else { + /* just clearing the action... */ + adt->action = NULL; + ok = true; + } + + return ok; } /* Freeing -------------------------------------------- */ @@ -225,41 +236,41 @@ bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act) /* Free AnimData used by the nominated ID-block, and clear ID-block's AnimData pointer */ void BKE_animdata_free(ID *id, const bool do_id_user) { - /* Only some ID-blocks have this info for now, so we cast the - * types that do to be of type IdAdtTemplate - */ - if (id_can_have_animdata(id)) { - IdAdtTemplate *iat = (IdAdtTemplate *)id; - AnimData *adt = iat->adt; + /* Only some ID-blocks have this info for now, so we cast the + * types that do to be of type IdAdtTemplate + */ + if (id_can_have_animdata(id)) { + IdAdtTemplate *iat = (IdAdtTemplate *)id; + AnimData *adt = iat->adt; - /* check if there's any AnimData to start with */ - if (adt) { - if (do_id_user) { - /* unlink action (don't free, as it's in its own list) */ - if (adt->action) - id_us_min(&adt->action->id); - /* same goes for the temporarily displaced action */ - if (adt->tmpact) - id_us_min(&adt->tmpact->id); - } + /* check if there's any AnimData to start with */ + if (adt) { + if (do_id_user) { + /* unlink action (don't free, as it's in its own list) */ + if (adt->action) + id_us_min(&adt->action->id); + /* same goes for the temporarily displaced action */ + if (adt->tmpact) + id_us_min(&adt->tmpact->id); + } - /* free nla data */ - BKE_nla_tracks_free(&adt->nla_tracks, do_id_user); + /* free nla data */ + BKE_nla_tracks_free(&adt->nla_tracks, do_id_user); - /* free drivers - stored as a list of F-Curves */ - free_fcurves(&adt->drivers); + /* free drivers - stored as a list of F-Curves */ + free_fcurves(&adt->drivers); - /* free driver array cache */ - MEM_SAFE_FREE(adt->driver_array); + /* free driver array cache */ + MEM_SAFE_FREE(adt->driver_array); - /* free overrides */ - /* TODO... */ + /* free overrides */ + /* TODO... */ - /* free animdata now */ - MEM_freeN(adt); - iat->adt = NULL; - } - } + /* free animdata now */ + MEM_freeN(adt); + iat->adt = NULL; + } + } } /* Copying -------------------------------------------- */ @@ -271,39 +282,39 @@ void BKE_animdata_free(ID *id, const bool do_id_user) */ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag) { - AnimData *dadt; + AnimData *dadt; - const bool do_action = (flag & LIB_ID_COPY_ACTIONS) != 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0; - const bool do_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0; + const bool do_action = (flag & LIB_ID_COPY_ACTIONS) != 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0; + const bool do_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0; - /* sanity check before duplicating struct */ - if (adt == NULL) - return NULL; - dadt = MEM_dupallocN(adt); + /* sanity check before duplicating struct */ + if (adt == NULL) + return NULL; + dadt = MEM_dupallocN(adt); - /* make a copy of action - at worst, user has to delete copies... */ - if (do_action) { - BLI_assert(bmain != NULL); - BKE_id_copy(bmain, (ID *)dadt->action, (ID **)&dadt->action); - BKE_id_copy(bmain, (ID *)dadt->tmpact, (ID **)&dadt->tmpact); - } - else if (do_id_user) { - id_us_plus((ID *)dadt->action); - id_us_plus((ID *)dadt->tmpact); - } + /* make a copy of action - at worst, user has to delete copies... */ + if (do_action) { + BLI_assert(bmain != NULL); + BKE_id_copy(bmain, (ID *)dadt->action, (ID **)&dadt->action); + BKE_id_copy(bmain, (ID *)dadt->tmpact, (ID **)&dadt->tmpact); + } + else if (do_id_user) { + id_us_plus((ID *)dadt->action); + id_us_plus((ID *)dadt->tmpact); + } - /* duplicate NLA data */ - BKE_nla_tracks_copy(bmain, &dadt->nla_tracks, &adt->nla_tracks, flag); + /* duplicate NLA data */ + BKE_nla_tracks_copy(bmain, &dadt->nla_tracks, &adt->nla_tracks, flag); - /* duplicate drivers (F-Curves) */ - copy_fcurves(&dadt->drivers, &adt->drivers); - dadt->driver_array = NULL; + /* duplicate drivers (F-Curves) */ + copy_fcurves(&dadt->drivers, &adt->drivers); + dadt->driver_array = NULL; - /* don't copy overrides */ - BLI_listbase_clear(&dadt->overrides); + /* don't copy overrides */ + BLI_listbase_clear(&dadt->overrides); - /* return */ - return dadt; + /* return */ + return dadt; } /** @@ -312,110 +323,110 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag) */ bool BKE_animdata_copy_id(Main *bmain, ID *id_to, ID *id_from, const int flag) { - AnimData *adt; + AnimData *adt; - if ((id_to && id_from) && (GS(id_to->name) != GS(id_from->name))) - return false; + if ((id_to && id_from) && (GS(id_to->name) != GS(id_from->name))) + return false; - BKE_animdata_free(id_to, (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0); + BKE_animdata_free(id_to, (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0); - adt = BKE_animdata_from_id(id_from); - if (adt) { - IdAdtTemplate *iat = (IdAdtTemplate *)id_to; - iat->adt = BKE_animdata_copy(bmain, adt, flag); - } + adt = BKE_animdata_from_id(id_from); + if (adt) { + IdAdtTemplate *iat = (IdAdtTemplate *)id_to; + iat->adt = BKE_animdata_copy(bmain, adt, flag); + } - return true; + return true; } void BKE_animdata_copy_id_action(Main *bmain, ID *id, const bool set_newid) { - AnimData *adt = BKE_animdata_from_id(id); - if (adt) { - if (adt->action) { - id_us_min((ID *)adt->action); - adt->action = set_newid ? ID_NEW_SET(adt->action, BKE_action_copy(bmain, adt->action)) : - BKE_action_copy(bmain, adt->action); - } - if (adt->tmpact) { - id_us_min((ID *)adt->tmpact); - adt->tmpact = set_newid ? ID_NEW_SET(adt->tmpact, BKE_action_copy(bmain, adt->tmpact)) : - BKE_action_copy(bmain, adt->tmpact); - } - } + AnimData *adt = BKE_animdata_from_id(id); + if (adt) { + if (adt->action) { + id_us_min((ID *)adt->action); + adt->action = set_newid ? ID_NEW_SET(adt->action, BKE_action_copy(bmain, adt->action)) : + BKE_action_copy(bmain, adt->action); + } + if (adt->tmpact) { + id_us_min((ID *)adt->tmpact); + adt->tmpact = set_newid ? ID_NEW_SET(adt->tmpact, BKE_action_copy(bmain, adt->tmpact)) : + BKE_action_copy(bmain, adt->tmpact); + } + } } /* Merge copies of the data from the src AnimData into the destination AnimData */ void BKE_animdata_merge_copy( - Main *bmain, ID *dst_id, ID *src_id, - eAnimData_MergeCopy_Modes action_mode, bool fix_drivers) -{ - AnimData *src = BKE_animdata_from_id(src_id); - AnimData *dst = BKE_animdata_from_id(dst_id); - - /* sanity checks */ - if (ELEM(NULL, dst, src)) - return; - - // TODO: we must unset all "tweakmode" flags - if ((src->flag & ADT_NLA_EDIT_ON) || (dst->flag & ADT_NLA_EDIT_ON)) { - CLOG_ERROR(&LOG, "Merging AnimData blocks while editing NLA is dangerous as it may cause data corruption"); - return; - } - - /* handle actions... */ - if (action_mode == ADT_MERGECOPY_SRC_COPY) { - /* make a copy of the actions */ - dst->action = BKE_action_copy(bmain, src->action); - dst->tmpact = BKE_action_copy(bmain, src->tmpact); - } - else if (action_mode == ADT_MERGECOPY_SRC_REF) { - /* make a reference to it */ - dst->action = src->action; - id_us_plus((ID *)dst->action); - - dst->tmpact = src->tmpact; - id_us_plus((ID *)dst->tmpact); - } - - /* duplicate NLA data */ - if (src->nla_tracks.first) { - ListBase tracks = {NULL, NULL}; - - BKE_nla_tracks_copy(bmain, &tracks, &src->nla_tracks, 0); - BLI_movelisttolist(&dst->nla_tracks, &tracks); - } - - /* duplicate drivers (F-Curves) */ - if (src->drivers.first) { - ListBase drivers = {NULL, NULL}; - - copy_fcurves(&drivers, &src->drivers); - - /* Fix up all driver targets using the old target id - * - This assumes that the src ID is being merged into the dst ID - */ - if (fix_drivers) { - FCurve *fcu; - - for (fcu = drivers.first; fcu; fcu = fcu->next) { - ChannelDriver *driver = fcu->driver; - DriverVar *dvar; - - for (dvar = driver->variables.first; dvar; dvar = dvar->next) { - DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar) - { - if (dtar->id == src_id) { - dtar->id = dst_id; - } - } - DRIVER_TARGETS_LOOPER_END; - } - } - } - - BLI_movelisttolist(&dst->drivers, &drivers); - } + Main *bmain, ID *dst_id, ID *src_id, eAnimData_MergeCopy_Modes action_mode, bool fix_drivers) +{ + AnimData *src = BKE_animdata_from_id(src_id); + AnimData *dst = BKE_animdata_from_id(dst_id); + + /* sanity checks */ + if (ELEM(NULL, dst, src)) + return; + + // TODO: we must unset all "tweakmode" flags + if ((src->flag & ADT_NLA_EDIT_ON) || (dst->flag & ADT_NLA_EDIT_ON)) { + CLOG_ERROR( + &LOG, + "Merging AnimData blocks while editing NLA is dangerous as it may cause data corruption"); + return; + } + + /* handle actions... */ + if (action_mode == ADT_MERGECOPY_SRC_COPY) { + /* make a copy of the actions */ + dst->action = BKE_action_copy(bmain, src->action); + dst->tmpact = BKE_action_copy(bmain, src->tmpact); + } + else if (action_mode == ADT_MERGECOPY_SRC_REF) { + /* make a reference to it */ + dst->action = src->action; + id_us_plus((ID *)dst->action); + + dst->tmpact = src->tmpact; + id_us_plus((ID *)dst->tmpact); + } + + /* duplicate NLA data */ + if (src->nla_tracks.first) { + ListBase tracks = {NULL, NULL}; + + BKE_nla_tracks_copy(bmain, &tracks, &src->nla_tracks, 0); + BLI_movelisttolist(&dst->nla_tracks, &tracks); + } + + /* duplicate drivers (F-Curves) */ + if (src->drivers.first) { + ListBase drivers = {NULL, NULL}; + + copy_fcurves(&drivers, &src->drivers); + + /* Fix up all driver targets using the old target id + * - This assumes that the src ID is being merged into the dst ID + */ + if (fix_drivers) { + FCurve *fcu; + + for (fcu = drivers.first; fcu; fcu = fcu->next) { + ChannelDriver *driver = fcu->driver; + DriverVar *dvar; + + for (dvar = driver->variables.first; dvar; dvar = dvar->next) { + DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { + if (dtar->id == src_id) { + dtar->id = dst_id; + } + } + DRIVER_TARGETS_LOOPER_END; + } + } + } + + BLI_movelisttolist(&dst->drivers, &drivers); + } } /* Sub-ID Regrouping ------------------------------------------- */ @@ -429,8 +440,8 @@ void BKE_animdata_merge_copy( */ static bool animpath_matches_basepath(const char path[], const char basepath[]) { - /* we need start of path to be basepath */ - return (path && basepath) && STRPREFIX(path, basepath); + /* we need start of path to be basepath */ + return (path && basepath) && STRPREFIX(path, basepath); } /* Move F-Curves in src action to dst action, setting up all the necessary groups @@ -441,155 +452,160 @@ static bool animpath_matches_basepath(const char path[], const char basepath[]) */ void action_move_fcurves_by_basepath(bAction *srcAct, bAction *dstAct, const char basepath[]) { - FCurve *fcu, *fcn = NULL; - - /* sanity checks */ - if (ELEM(NULL, srcAct, dstAct, basepath)) { - if (G.debug & G_DEBUG) { - CLOG_ERROR(&LOG, "srcAct: %p, dstAct: %p, basepath: %p has insufficient info to work with", - (void *)srcAct, (void *)dstAct, (void *)basepath); - } - return; - } - - /* clear 'temp' flags on all groups in src, as we'll be needing them later - * to identify groups that we've managed to empty out here - */ - action_groups_clear_tempflags(srcAct); - - /* iterate over all src F-Curves, moving over the ones that need to be moved */ - for (fcu = srcAct->curves.first; fcu; fcu = fcn) { - /* store next pointer in case we move stuff */ - fcn = fcu->next; - - /* should F-Curve be moved over? - * - we only need the start of the path to match basepath - */ - if (animpath_matches_basepath(fcu->rna_path, basepath)) { - bActionGroup *agrp = NULL; - - /* if grouped... */ - if (fcu->grp) { - /* make sure there will be a matching group on the other side for the migrants */ - agrp = BKE_action_group_find_name(dstAct, fcu->grp->name); - - if (agrp == NULL) { - /* add a new one with a similar name (usually will be the same though) */ - agrp = action_groups_add_new(dstAct, fcu->grp->name); - } - - /* old groups should be tagged with 'temp' flags so they can be removed later - * if we remove everything from them - */ - fcu->grp->flag |= AGRP_TEMP; - } - - /* perform the migration now */ - action_groups_remove_channel(srcAct, fcu); - - if (agrp) - action_groups_add_channel(dstAct, agrp, fcu); - else - BLI_addtail(&dstAct->curves, fcu); - } - } - - /* cleanup groups (if present) */ - if (srcAct->groups.first) { - bActionGroup *agrp, *grp = NULL; - - for (agrp = srcAct->groups.first; agrp; agrp = grp) { - grp = agrp->next; - - /* only tagged groups need to be considered - clearing these tags or removing them */ - if (agrp->flag & AGRP_TEMP) { - /* if group is empty and tagged, then we can remove as this operation - * moved out all the channels that were formerly here - */ - if (BLI_listbase_is_empty(&agrp->channels)) - BLI_freelinkN(&srcAct->groups, agrp); - else - agrp->flag &= ~AGRP_TEMP; - } - } - } + FCurve *fcu, *fcn = NULL; + + /* sanity checks */ + if (ELEM(NULL, srcAct, dstAct, basepath)) { + if (G.debug & G_DEBUG) { + CLOG_ERROR(&LOG, + "srcAct: %p, dstAct: %p, basepath: %p has insufficient info to work with", + (void *)srcAct, + (void *)dstAct, + (void *)basepath); + } + return; + } + + /* clear 'temp' flags on all groups in src, as we'll be needing them later + * to identify groups that we've managed to empty out here + */ + action_groups_clear_tempflags(srcAct); + + /* iterate over all src F-Curves, moving over the ones that need to be moved */ + for (fcu = srcAct->curves.first; fcu; fcu = fcn) { + /* store next pointer in case we move stuff */ + fcn = fcu->next; + + /* should F-Curve be moved over? + * - we only need the start of the path to match basepath + */ + if (animpath_matches_basepath(fcu->rna_path, basepath)) { + bActionGroup *agrp = NULL; + + /* if grouped... */ + if (fcu->grp) { + /* make sure there will be a matching group on the other side for the migrants */ + agrp = BKE_action_group_find_name(dstAct, fcu->grp->name); + + if (agrp == NULL) { + /* add a new one with a similar name (usually will be the same though) */ + agrp = action_groups_add_new(dstAct, fcu->grp->name); + } + + /* old groups should be tagged with 'temp' flags so they can be removed later + * if we remove everything from them + */ + fcu->grp->flag |= AGRP_TEMP; + } + + /* perform the migration now */ + action_groups_remove_channel(srcAct, fcu); + + if (agrp) + action_groups_add_channel(dstAct, agrp, fcu); + else + BLI_addtail(&dstAct->curves, fcu); + } + } + + /* cleanup groups (if present) */ + if (srcAct->groups.first) { + bActionGroup *agrp, *grp = NULL; + + for (agrp = srcAct->groups.first; agrp; agrp = grp) { + grp = agrp->next; + + /* only tagged groups need to be considered - clearing these tags or removing them */ + if (agrp->flag & AGRP_TEMP) { + /* if group is empty and tagged, then we can remove as this operation + * moved out all the channels that were formerly here + */ + if (BLI_listbase_is_empty(&agrp->channels)) + BLI_freelinkN(&srcAct->groups, agrp); + else + agrp->flag &= ~AGRP_TEMP; + } + } + } } /* Transfer the animation data from srcID to dstID where the srcID * animation data is based off "basepath", creating new AnimData and * associated data as necessary */ -void BKE_animdata_separate_by_basepath( - Main *bmain, ID *srcID, ID *dstID, ListBase *basepaths) -{ - AnimData *srcAdt = NULL, *dstAdt = NULL; - LinkData *ld; - - /* sanity checks */ - if (ELEM(NULL, srcID, dstID)) { - if (G.debug & G_DEBUG) - CLOG_ERROR(&LOG, "no source or destination ID to separate AnimData with"); - return; - } - - /* get animdata from src, and create for destination (if needed) */ - srcAdt = BKE_animdata_from_id(srcID); - dstAdt = BKE_animdata_add_id(dstID); - - if (ELEM(NULL, srcAdt, dstAdt)) { - if (G.debug & G_DEBUG) - CLOG_ERROR(&LOG, "no AnimData for this pair of ID's"); - return; - } - - /* active action */ - if (srcAdt->action) { - /* set up an action if necessary, and name it in a similar way so that it can be easily found again */ - if (dstAdt->action == NULL) { - dstAdt->action = BKE_action_add(bmain, srcAdt->action->id.name + 2); - } - else if (dstAdt->action == srcAdt->action) { - CLOG_WARN(&LOG, "Argh! Source and Destination share animation! " - "('%s' and '%s' both use '%s') Making new empty action", - srcID->name, dstID->name, srcAdt->action->id.name); - - /* TODO: review this... */ - id_us_min(&dstAdt->action->id); - dstAdt->action = BKE_action_add(bmain, dstAdt->action->id.name + 2); - } - - /* loop over base paths, trying to fix for each one... */ - for (ld = basepaths->first; ld; ld = ld->next) { - const char *basepath = (const char *)ld->data; - action_move_fcurves_by_basepath(srcAdt->action, dstAdt->action, basepath); - } - } - - /* drivers */ - if (srcAdt->drivers.first) { - FCurve *fcu, *fcn = NULL; - - /* check each driver against all the base paths to see if any should go */ - for (fcu = srcAdt->drivers.first; fcu; fcu = fcn) { - fcn = fcu->next; - - /* try each basepath in turn, but stop on the first one which works */ - for (ld = basepaths->first; ld; ld = ld->next) { - const char *basepath = (const char *)ld->data; - - if (animpath_matches_basepath(fcu->rna_path, basepath)) { - /* just need to change lists */ - BLI_remlink(&srcAdt->drivers, fcu); - BLI_addtail(&dstAdt->drivers, fcu); - - /* TODO: add depsgraph flushing calls? */ - - /* can stop now, as moved already */ - break; - } - } - } - } +void BKE_animdata_separate_by_basepath(Main *bmain, ID *srcID, ID *dstID, ListBase *basepaths) +{ + AnimData *srcAdt = NULL, *dstAdt = NULL; + LinkData *ld; + + /* sanity checks */ + if (ELEM(NULL, srcID, dstID)) { + if (G.debug & G_DEBUG) + CLOG_ERROR(&LOG, "no source or destination ID to separate AnimData with"); + return; + } + + /* get animdata from src, and create for destination (if needed) */ + srcAdt = BKE_animdata_from_id(srcID); + dstAdt = BKE_animdata_add_id(dstID); + + if (ELEM(NULL, srcAdt, dstAdt)) { + if (G.debug & G_DEBUG) + CLOG_ERROR(&LOG, "no AnimData for this pair of ID's"); + return; + } + + /* active action */ + if (srcAdt->action) { + /* set up an action if necessary, and name it in a similar way so that it can be easily found again */ + if (dstAdt->action == NULL) { + dstAdt->action = BKE_action_add(bmain, srcAdt->action->id.name + 2); + } + else if (dstAdt->action == srcAdt->action) { + CLOG_WARN(&LOG, + "Argh! Source and Destination share animation! " + "('%s' and '%s' both use '%s') Making new empty action", + srcID->name, + dstID->name, + srcAdt->action->id.name); + + /* TODO: review this... */ + id_us_min(&dstAdt->action->id); + dstAdt->action = BKE_action_add(bmain, dstAdt->action->id.name + 2); + } + + /* loop over base paths, trying to fix for each one... */ + for (ld = basepaths->first; ld; ld = ld->next) { + const char *basepath = (const char *)ld->data; + action_move_fcurves_by_basepath(srcAdt->action, dstAdt->action, basepath); + } + } + + /* drivers */ + if (srcAdt->drivers.first) { + FCurve *fcu, *fcn = NULL; + + /* check each driver against all the base paths to see if any should go */ + for (fcu = srcAdt->drivers.first; fcu; fcu = fcn) { + fcn = fcu->next; + + /* try each basepath in turn, but stop on the first one which works */ + for (ld = basepaths->first; ld; ld = ld->next) { + const char *basepath = (const char *)ld->data; + + if (animpath_matches_basepath(fcu->rna_path, basepath)) { + /* just need to change lists */ + BLI_remlink(&srcAdt->drivers, fcu); + BLI_addtail(&dstAdt->drivers, fcu); + + /* TODO: add depsgraph flushing calls? */ + + /* can stop now, as moved already */ + break; + } + } + } + } } /** @@ -602,36 +618,39 @@ void BKE_animdata_separate_by_basepath( * \param prop: RNA definition of property to add for * \return MEM_alloc'd string representing the path to the property from the given #PointerRNA */ -char *BKE_animdata_driver_path_hack(bContext *C, PointerRNA *ptr, PropertyRNA *prop, char *base_path) +char *BKE_animdata_driver_path_hack(bContext *C, + PointerRNA *ptr, + PropertyRNA *prop, + char *base_path) { - ID *id = (ID *)ptr->id.data; - ScrArea *sa = CTX_wm_area(C); + ID *id = (ID *)ptr->id.data; + ScrArea *sa = CTX_wm_area(C); - /* get standard path which may be extended */ - char *basepath = base_path ? base_path : RNA_path_from_ID_to_property(ptr, prop); - char *path = basepath; /* in case no remapping is needed */ + /* get standard path which may be extended */ + char *basepath = base_path ? base_path : RNA_path_from_ID_to_property(ptr, prop); + char *path = basepath; /* in case no remapping is needed */ - /* Remapping will only be performed in the Properties Editor, as only this - * restricts the subspace of options to the 'active' data (a manageable state) - */ - /* TODO: watch out for pinned context? */ - if ((sa) && (sa->spacetype == SPACE_PROPERTIES)) { - Object *ob = CTX_data_active_object(C); + /* Remapping will only be performed in the Properties Editor, as only this + * restricts the subspace of options to the 'active' data (a manageable state) + */ + /* TODO: watch out for pinned context? */ + if ((sa) && (sa->spacetype == SPACE_PROPERTIES)) { + Object *ob = CTX_data_active_object(C); - if (ob && id) { - /* TODO: after material textures were removed, this function serves - * no purpose anymore, but could be used again so was not removed. */ + if (ob && id) { + /* TODO: after material textures were removed, this function serves + * no purpose anymore, but could be used again so was not removed. */ - /* fix RNA pointer, as we've now changed the ID root by changing the paths */ - if (basepath != path) { - /* rebase provided pointer so that it starts from object... */ - RNA_pointer_create(&ob->id, ptr->type, ptr->data, ptr); - } - } - } + /* fix RNA pointer, as we've now changed the ID root by changing the paths */ + if (basepath != path) { + /* rebase provided pointer so that it starts from object... */ + RNA_pointer_create(&ob->id, ptr->type, ptr->data, ptr); + } + } + } - /* the path should now have been corrected for use */ - return path; + /* the path should now have been corrected for use */ + return path; } /* Path Validation -------------------------------------------- */ @@ -639,164 +658,190 @@ char *BKE_animdata_driver_path_hack(bContext *C, PointerRNA *ptr, PropertyRNA *p /* Check if a given RNA Path is valid, by tracing it from the given ID, and seeing if we can resolve it */ static bool check_rna_path_is_valid(ID *owner_id, const char *path) { - PointerRNA id_ptr, ptr; - PropertyRNA *prop = NULL; + PointerRNA id_ptr, ptr; + PropertyRNA *prop = NULL; - /* make initial RNA pointer to start resolving from */ - RNA_id_pointer_create(owner_id, &id_ptr); + /* make initial RNA pointer to start resolving from */ + RNA_id_pointer_create(owner_id, &id_ptr); - /* try to resolve */ - return RNA_path_resolve_property(&id_ptr, path, &ptr, &prop); + /* try to resolve */ + return RNA_path_resolve_property(&id_ptr, path, &ptr, &prop); } /* Check if some given RNA Path needs fixing - free the given path and set a new one as appropriate * NOTE: we assume that oldName and newName have [" "] padding around them */ -static char *rna_path_rename_fix(ID *owner_id, const char *prefix, const char *oldName, const char *newName, char *oldpath, bool verify_paths) -{ - char *prefixPtr = strstr(oldpath, prefix); - char *oldNamePtr = strstr(oldpath, oldName); - int prefixLen = strlen(prefix); - int oldNameLen = strlen(oldName); - - /* only start fixing the path if the prefix and oldName feature in the path, - * and prefix occurs immediately before oldName - */ - if ( (prefixPtr && oldNamePtr) && (prefixPtr + prefixLen == oldNamePtr) ) { - /* if we haven't aren't able to resolve the path now, try again after fixing it */ - if (!verify_paths || check_rna_path_is_valid(owner_id, oldpath) == 0) { - DynStr *ds = BLI_dynstr_new(); - const char *postfixPtr = oldNamePtr + oldNameLen; - char *newPath = NULL; - - /* add the part of the string that goes up to the start of the prefix */ - if (prefixPtr > oldpath) { - BLI_dynstr_nappend(ds, oldpath, prefixPtr - oldpath); - } - - /* add the prefix */ - BLI_dynstr_append(ds, prefix); - - /* add the new name (complete with brackets) */ - BLI_dynstr_append(ds, newName); - - /* add the postfix */ - BLI_dynstr_append(ds, postfixPtr); - - /* create new path, and cleanup old data */ - newPath = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - - /* check if the new path will solve our problems */ - /* TODO: will need to check whether this step really helps in practice */ - if (!verify_paths || check_rna_path_is_valid(owner_id, newPath)) { - /* free the old path, and return the new one, since we've solved the issues */ - MEM_freeN(oldpath); - return newPath; - } - else { - /* still couldn't resolve the path... so, might as well just leave it alone */ - MEM_freeN(newPath); - } - } - } - - /* the old path doesn't need to be changed */ - return oldpath; +static char *rna_path_rename_fix(ID *owner_id, + const char *prefix, + const char *oldName, + const char *newName, + char *oldpath, + bool verify_paths) +{ + char *prefixPtr = strstr(oldpath, prefix); + char *oldNamePtr = strstr(oldpath, oldName); + int prefixLen = strlen(prefix); + int oldNameLen = strlen(oldName); + + /* only start fixing the path if the prefix and oldName feature in the path, + * and prefix occurs immediately before oldName + */ + if ((prefixPtr && oldNamePtr) && (prefixPtr + prefixLen == oldNamePtr)) { + /* if we haven't aren't able to resolve the path now, try again after fixing it */ + if (!verify_paths || check_rna_path_is_valid(owner_id, oldpath) == 0) { + DynStr *ds = BLI_dynstr_new(); + const char *postfixPtr = oldNamePtr + oldNameLen; + char *newPath = NULL; + + /* add the part of the string that goes up to the start of the prefix */ + if (prefixPtr > oldpath) { + BLI_dynstr_nappend(ds, oldpath, prefixPtr - oldpath); + } + + /* add the prefix */ + BLI_dynstr_append(ds, prefix); + + /* add the new name (complete with brackets) */ + BLI_dynstr_append(ds, newName); + + /* add the postfix */ + BLI_dynstr_append(ds, postfixPtr); + + /* create new path, and cleanup old data */ + newPath = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + + /* check if the new path will solve our problems */ + /* TODO: will need to check whether this step really helps in practice */ + if (!verify_paths || check_rna_path_is_valid(owner_id, newPath)) { + /* free the old path, and return the new one, since we've solved the issues */ + MEM_freeN(oldpath); + return newPath; + } + else { + /* still couldn't resolve the path... so, might as well just leave it alone */ + MEM_freeN(newPath); + } + } + } + + /* the old path doesn't need to be changed */ + return oldpath; } /* Check RNA-Paths for a list of F-Curves */ -static bool fcurves_path_rename_fix(ID *owner_id, const char *prefix, const char *oldName, const char *newName, - const char *oldKey, const char *newKey, ListBase *curves, bool verify_paths) -{ - FCurve *fcu; - bool is_changed = false; - /* We need to check every curve. */ - for (fcu = curves->first; fcu; fcu = fcu->next) { - if (fcu->rna_path == NULL) { - continue; - } - const char *old_path = fcu->rna_path; - /* Firstly, handle the F-Curve's own path. */ - fcu->rna_path = rna_path_rename_fix(owner_id, prefix, oldKey, newKey, fcu->rna_path, verify_paths); - /* if path changed and the F-Curve is grouped, check if its group also needs renaming - * (i.e. F-Curve is first of a bone's F-Curves; hence renaming this should also trigger rename) */ - if (fcu->rna_path != old_path) { - bActionGroup *agrp = fcu->grp; - is_changed = true; - if ((agrp != NULL) && STREQ(oldName, agrp->name)) { - BLI_strncpy(agrp->name, newName, sizeof(agrp->name)); - } - } - } - return is_changed; +static bool fcurves_path_rename_fix(ID *owner_id, + const char *prefix, + const char *oldName, + const char *newName, + const char *oldKey, + const char *newKey, + ListBase *curves, + bool verify_paths) +{ + FCurve *fcu; + bool is_changed = false; + /* We need to check every curve. */ + for (fcu = curves->first; fcu; fcu = fcu->next) { + if (fcu->rna_path == NULL) { + continue; + } + const char *old_path = fcu->rna_path; + /* Firstly, handle the F-Curve's own path. */ + fcu->rna_path = rna_path_rename_fix( + owner_id, prefix, oldKey, newKey, fcu->rna_path, verify_paths); + /* if path changed and the F-Curve is grouped, check if its group also needs renaming + * (i.e. F-Curve is first of a bone's F-Curves; hence renaming this should also trigger rename) */ + if (fcu->rna_path != old_path) { + bActionGroup *agrp = fcu->grp; + is_changed = true; + if ((agrp != NULL) && STREQ(oldName, agrp->name)) { + BLI_strncpy(agrp->name, newName, sizeof(agrp->name)); + } + } + } + return is_changed; } /* Check RNA-Paths for a list of Drivers */ -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) -{ - bool is_changed = false; - FCurve *fcu; - /* We need to check every curve - drivers are F-Curves too. */ - for (fcu = curves->first; fcu; fcu = fcu->next) { - /* firstly, handle the F-Curve's own path */ - if (fcu->rna_path != NULL) { - const char *old_rna_path = fcu->rna_path; - fcu->rna_path = rna_path_rename_fix(owner_id, prefix, oldKey, newKey, fcu->rna_path, verify_paths); - is_changed |= (fcu->rna_path != old_rna_path); - } - if (fcu->driver == NULL) { - continue; - } - ChannelDriver *driver = fcu->driver; - DriverVar *dvar; - /* driver variables */ - for (dvar = driver->variables.first; dvar; dvar = dvar->next) { - /* only change the used targets, since the others will need fixing manually anyway */ - DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar) - { - /* rename RNA path */ - if (dtar->rna_path && dtar->id) { - const char *old_rna_path = dtar->rna_path; - dtar->rna_path = rna_path_rename_fix(dtar->id, prefix, oldKey, newKey, dtar->rna_path, verify_paths); - is_changed |= (dtar->rna_path != old_rna_path); - } - /* also fix the bone-name (if applicable) */ - if (strstr(prefix, "bones")) { - if ( ((dtar->id) && (GS(dtar->id->name) == ID_OB) && (!ref_id || ((Object *)(dtar->id))->data == ref_id)) && - (dtar->pchan_name[0]) && STREQ(oldName, dtar->pchan_name) ) - { - is_changed = true; - BLI_strncpy(dtar->pchan_name, newName, sizeof(dtar->pchan_name)); - } - } - } - DRIVER_TARGETS_LOOPER_END; - } - } - return is_changed; +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) +{ + bool is_changed = false; + FCurve *fcu; + /* We need to check every curve - drivers are F-Curves too. */ + for (fcu = curves->first; fcu; fcu = fcu->next) { + /* firstly, handle the F-Curve's own path */ + if (fcu->rna_path != NULL) { + const char *old_rna_path = fcu->rna_path; + fcu->rna_path = rna_path_rename_fix( + owner_id, prefix, oldKey, newKey, fcu->rna_path, verify_paths); + is_changed |= (fcu->rna_path != old_rna_path); + } + if (fcu->driver == NULL) { + continue; + } + ChannelDriver *driver = fcu->driver; + DriverVar *dvar; + /* driver variables */ + for (dvar = driver->variables.first; dvar; dvar = dvar->next) { + /* only change the used targets, since the others will need fixing manually anyway */ + DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { + /* rename RNA path */ + if (dtar->rna_path && dtar->id) { + const char *old_rna_path = dtar->rna_path; + dtar->rna_path = rna_path_rename_fix( + dtar->id, prefix, oldKey, newKey, dtar->rna_path, verify_paths); + is_changed |= (dtar->rna_path != old_rna_path); + } + /* also fix the bone-name (if applicable) */ + if (strstr(prefix, "bones")) { + if (((dtar->id) && (GS(dtar->id->name) == ID_OB) && + (!ref_id || ((Object *)(dtar->id))->data == ref_id)) && + (dtar->pchan_name[0]) && STREQ(oldName, dtar->pchan_name)) { + is_changed = true; + BLI_strncpy(dtar->pchan_name, newName, sizeof(dtar->pchan_name)); + } + } + } + DRIVER_TARGETS_LOOPER_END; + } + } + return is_changed; } /* Fix all RNA-Paths for Actions linked to NLA Strips */ -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) -{ - NlaStrip *strip; - bool is_changed = false; - /* Recursively check strips, fixing only actions. */ - for (strip = strips->first; strip; strip = strip->next) { - /* fix strip's action */ - if (strip->act != NULL) { - is_changed |= fcurves_path_rename_fix( - owner_id, prefix, oldName, newName, oldKey, newKey, &strip->act->curves, verify_paths); - } - /* Ignore own F-Curves, since those are local. */ - /* Check sub-strips (if metas) */ - is_changed |= nlastrips_path_rename_fix( - owner_id, prefix, oldName, newName, oldKey, newKey, &strip->strips, verify_paths); - } - return is_changed; +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) +{ + NlaStrip *strip; + bool is_changed = false; + /* Recursively check strips, fixing only actions. */ + for (strip = strips->first; strip; strip = strip->next) { + /* fix strip's action */ + if (strip->act != NULL) { + is_changed |= fcurves_path_rename_fix( + owner_id, prefix, oldName, newName, oldKey, newKey, &strip->act->curves, verify_paths); + } + /* Ignore own F-Curves, since those are local. */ + /* Check sub-strips (if metas) */ + is_changed |= nlastrips_path_rename_fix( + owner_id, prefix, oldName, newName, oldKey, newKey, &strip->strips, verify_paths); + } + return is_changed; } /* Rename Sub-ID Entities in RNA Paths ----------------------- */ @@ -809,47 +854,56 @@ static bool nlastrips_path_rename_fix(ID *owner_id, const char *prefix, const ch * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]> * i.e. pose.bones["Bone"] */ -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) -{ - char *oldN, *newN; - char *result; - - /* if no action, no need to proceed */ - if (ELEM(NULL, owner_id, old_path)) { - if (G.debug & G_DEBUG) CLOG_WARN(&LOG, "early abort"); - return old_path; - } - - /* Name sanitation logic - copied from BKE_animdata_fix_paths_rename() */ - if ((oldName != NULL) && (newName != NULL)) { - /* pad the names with [" "] so that only exact matches are made */ - const size_t name_old_len = strlen(oldName); - const size_t name_new_len = strlen(newName); - char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1); - char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1); - - BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1); - BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1); - oldN = BLI_sprintfN("[\"%s\"]", name_old_esc); - newN = BLI_sprintfN("[\"%s\"]", name_new_esc); - } - else { - oldN = BLI_sprintfN("[%d]", oldSubscript); - newN = BLI_sprintfN("[%d]", newSubscript); - } - - /* fix given path */ - if (G.debug & G_DEBUG) printf("%s | %s | oldpath = %p ", oldN, newN, old_path); - result = rna_path_rename_fix(owner_id, prefix, oldN, newN, old_path, verify_paths); - if (G.debug & G_DEBUG) printf("path rename result = %p\n", result); - - /* free the temp names */ - MEM_freeN(oldN); - MEM_freeN(newN); - - /* return the resulting path - may be the same path again if nothing changed */ - return result; +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) +{ + char *oldN, *newN; + char *result; + + /* if no action, no need to proceed */ + if (ELEM(NULL, owner_id, old_path)) { + if (G.debug & G_DEBUG) + CLOG_WARN(&LOG, "early abort"); + return old_path; + } + + /* Name sanitation logic - copied from BKE_animdata_fix_paths_rename() */ + if ((oldName != NULL) && (newName != NULL)) { + /* pad the names with [" "] so that only exact matches are made */ + const size_t name_old_len = strlen(oldName); + const size_t name_new_len = strlen(newName); + char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1); + char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1); + + BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1); + BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1); + oldN = BLI_sprintfN("[\"%s\"]", name_old_esc); + newN = BLI_sprintfN("[\"%s\"]", name_new_esc); + } + else { + oldN = BLI_sprintfN("[%d]", oldSubscript); + newN = BLI_sprintfN("[%d]", newSubscript); + } + + /* fix given path */ + if (G.debug & G_DEBUG) + printf("%s | %s | oldpath = %p ", oldN, newN, old_path); + result = rna_path_rename_fix(owner_id, prefix, oldN, newN, old_path, verify_paths); + if (G.debug & G_DEBUG) + printf("path rename result = %p\n", result); + + /* free the temp names */ + MEM_freeN(oldN); + MEM_freeN(newN); + + /* return the resulting path - may be the same path again if nothing changed */ + return result; } /* Fix all RNA_Paths in the given Action, relative to the given ID block @@ -860,102 +914,114 @@ char *BKE_animsys_fix_rna_path_rename(ID *owner_id, char *old_path, const char * * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]> * i.e. pose.bones["Bone"] */ -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) -{ - char *oldN, *newN; - - /* if no action, no need to proceed */ - if (ELEM(NULL, owner_id, act)) - return; - - /* Name sanitation logic - copied from BKE_animdata_fix_paths_rename() */ - if ((oldName != NULL) && (newName != NULL)) { - /* pad the names with [" "] so that only exact matches are made */ - const size_t name_old_len = strlen(oldName); - const size_t name_new_len = strlen(newName); - char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1); - char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1); - - BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1); - BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1); - oldN = BLI_sprintfN("[\"%s\"]", name_old_esc); - newN = BLI_sprintfN("[\"%s\"]", name_new_esc); - } - else { - oldN = BLI_sprintfN("[%d]", oldSubscript); - newN = BLI_sprintfN("[%d]", newSubscript); - } - - /* fix paths in action */ - fcurves_path_rename_fix(owner_id, prefix, oldName, newName, oldN, newN, &act->curves, verify_paths); - - /* free the temp names */ - MEM_freeN(oldN); - MEM_freeN(newN); +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) +{ + char *oldN, *newN; + + /* if no action, no need to proceed */ + if (ELEM(NULL, owner_id, act)) + return; + + /* Name sanitation logic - copied from BKE_animdata_fix_paths_rename() */ + if ((oldName != NULL) && (newName != NULL)) { + /* pad the names with [" "] so that only exact matches are made */ + const size_t name_old_len = strlen(oldName); + const size_t name_new_len = strlen(newName); + char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1); + char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1); + + BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1); + BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1); + oldN = BLI_sprintfN("[\"%s\"]", name_old_esc); + newN = BLI_sprintfN("[\"%s\"]", name_new_esc); + } + else { + oldN = BLI_sprintfN("[%d]", oldSubscript); + newN = BLI_sprintfN("[%d]", newSubscript); + } + + /* fix paths in action */ + fcurves_path_rename_fix( + owner_id, prefix, oldName, newName, oldN, newN, &act->curves, verify_paths); + + /* free the temp names */ + MEM_freeN(oldN); + MEM_freeN(newN); } /* Fix all RNA-Paths in the AnimData block used by the given ID block * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]> * i.e. pose.bones["Bone"] */ -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) -{ - NlaTrack *nlt; - char *oldN, *newN; - /* If no AnimData, no need to proceed. */ - if (ELEM(NULL, owner_id, adt)) { - return; - } - bool is_self_changed = false; - /* Name sanitation logic - shared with BKE_action_fix_paths_rename(). */ - if ((oldName != NULL) && (newName != NULL)) { - /* Pad the names with [" "] so that only exact matches are made. */ - const size_t name_old_len = strlen(oldName); - const size_t name_new_len = strlen(newName); - char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1); - char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1); - - BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1); - BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1); - oldN = BLI_sprintfN("[\"%s\"]", name_old_esc); - newN = BLI_sprintfN("[\"%s\"]", name_new_esc); - } - else { - oldN = BLI_sprintfN("[%d]", oldSubscript); - newN = BLI_sprintfN("[%d]", newSubscript); - } - /* Active action and temp action. */ - if (adt->action != NULL) { - if (fcurves_path_rename_fix(owner_id, prefix, oldName, newName, - oldN, newN, &adt->action->curves, verify_paths)) - { - DEG_id_tag_update(&adt->action->id, ID_RECALC_COPY_ON_WRITE); - } - } - if (adt->tmpact) { - if (fcurves_path_rename_fix(owner_id, prefix, oldName, newName, - oldN, newN, &adt->tmpact->curves, verify_paths)) - { - DEG_id_tag_update(&adt->tmpact->id, ID_RECALC_COPY_ON_WRITE); - } - } - /* Drivers - Drivers are really F-Curves */ - is_self_changed |= drivers_path_rename_fix( - owner_id, ref_id, prefix, oldName, newName, oldN, newN, &adt->drivers, verify_paths); - /* NLA Data - Animation Data for Strips */ - for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { - is_self_changed |= nlastrips_path_rename_fix( - owner_id, prefix, oldName, newName, oldN, newN, &nlt->strips, verify_paths); - } - /* Tag owner ID if it */ - if (is_self_changed) { - DEG_id_tag_update(owner_id, ID_RECALC_COPY_ON_WRITE); - } - /* free the temp names */ - MEM_freeN(oldN); - MEM_freeN(newN); +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) +{ + NlaTrack *nlt; + char *oldN, *newN; + /* If no AnimData, no need to proceed. */ + if (ELEM(NULL, owner_id, adt)) { + return; + } + bool is_self_changed = false; + /* Name sanitation logic - shared with BKE_action_fix_paths_rename(). */ + if ((oldName != NULL) && (newName != NULL)) { + /* Pad the names with [" "] so that only exact matches are made. */ + const size_t name_old_len = strlen(oldName); + const size_t name_new_len = strlen(newName); + char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1); + char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1); + + BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1); + BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1); + oldN = BLI_sprintfN("[\"%s\"]", name_old_esc); + newN = BLI_sprintfN("[\"%s\"]", name_new_esc); + } + else { + oldN = BLI_sprintfN("[%d]", oldSubscript); + newN = BLI_sprintfN("[%d]", newSubscript); + } + /* Active action and temp action. */ + if (adt->action != NULL) { + if (fcurves_path_rename_fix( + owner_id, prefix, oldName, newName, oldN, newN, &adt->action->curves, verify_paths)) { + DEG_id_tag_update(&adt->action->id, ID_RECALC_COPY_ON_WRITE); + } + } + if (adt->tmpact) { + if (fcurves_path_rename_fix( + owner_id, prefix, oldName, newName, oldN, newN, &adt->tmpact->curves, verify_paths)) { + DEG_id_tag_update(&adt->tmpact->id, ID_RECALC_COPY_ON_WRITE); + } + } + /* Drivers - Drivers are really F-Curves */ + is_self_changed |= drivers_path_rename_fix( + owner_id, ref_id, prefix, oldName, newName, oldN, newN, &adt->drivers, verify_paths); + /* NLA Data - Animation Data for Strips */ + for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { + is_self_changed |= nlastrips_path_rename_fix( + owner_id, prefix, oldName, newName, oldN, newN, &nlt->strips, verify_paths); + } + /* Tag owner ID if it */ + if (is_self_changed) { + DEG_id_tag_update(owner_id, ID_RECALC_COPY_ON_WRITE); + } + /* free the temp names */ + MEM_freeN(oldN); + MEM_freeN(newN); } /* Remove FCurves with Prefix -------------------------------------- */ @@ -963,242 +1029,250 @@ void BKE_animdata_fix_paths_rename(ID *owner_id, AnimData *adt, ID *ref_id, cons /* Check RNA-Paths for a list of F-Curves */ static bool fcurves_path_remove_fix(const char *prefix, ListBase *curves) { - FCurve *fcu, *fcn; - bool any_removed = false; - if (!prefix) return any_removed; + FCurve *fcu, *fcn; + bool any_removed = false; + if (!prefix) + return any_removed; - /* we need to check every curve... */ - for (fcu = curves->first; fcu; fcu = fcn) { - fcn = fcu->next; + /* we need to check every curve... */ + for (fcu = curves->first; fcu; fcu = fcn) { + fcn = fcu->next; - if (fcu->rna_path) { - if (STRPREFIX(fcu->rna_path, prefix)) { - BLI_remlink(curves, fcu); - free_fcurve(fcu); - any_removed = true; - } - } - } - return any_removed; + if (fcu->rna_path) { + if (STRPREFIX(fcu->rna_path, prefix)) { + BLI_remlink(curves, fcu); + free_fcurve(fcu); + any_removed = true; + } + } + } + return any_removed; } /* Check RNA-Paths for a list of F-Curves */ static bool nlastrips_path_remove_fix(const char *prefix, ListBase *strips) { - NlaStrip *strip; - bool any_removed = false; + NlaStrip *strip; + bool any_removed = false; - /* recursively check strips, fixing only actions... */ - for (strip = strips->first; strip; strip = strip->next) { - /* fix strip's action */ - if (strip->act) { - any_removed |= fcurves_path_remove_fix(prefix, &strip->act->curves); - } + /* recursively check strips, fixing only actions... */ + for (strip = strips->first; strip; strip = strip->next) { + /* fix strip's action */ + if (strip->act) { + any_removed |= fcurves_path_remove_fix(prefix, &strip->act->curves); + } - /* check sub-strips (if metas) */ - any_removed |= nlastrips_path_remove_fix(prefix, &strip->strips); - } - return any_removed; + /* check sub-strips (if metas) */ + any_removed |= nlastrips_path_remove_fix(prefix, &strip->strips); + } + return any_removed; } bool BKE_animdata_fix_paths_remove(ID *id, const char *prefix) { - /* Only some ID-blocks have this info for now, so we cast the - * types that do to be of type IdAdtTemplate - */ - if (!id_can_have_animdata(id)) { - return false; - } - bool any_removed = false; - IdAdtTemplate *iat = (IdAdtTemplate *)id; - AnimData *adt = iat->adt; - /* check if there's any AnimData to start with */ - if (adt) { - /* free fcurves */ - if (adt->action != NULL) { - any_removed |= fcurves_path_remove_fix(prefix, &adt->action->curves); - } - if (adt->tmpact != NULL) { - any_removed |= fcurves_path_remove_fix(prefix, &adt->tmpact->curves); - } - /* free drivers - stored as a list of F-Curves */ - any_removed |= fcurves_path_remove_fix(prefix, &adt->drivers); - /* NLA Data - Animation Data for Strips */ - for (NlaTrack *nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { - any_removed |= nlastrips_path_remove_fix(prefix, &nlt->strips); - } - } - return any_removed; + /* Only some ID-blocks have this info for now, so we cast the + * types that do to be of type IdAdtTemplate + */ + if (!id_can_have_animdata(id)) { + return false; + } + bool any_removed = false; + IdAdtTemplate *iat = (IdAdtTemplate *)id; + AnimData *adt = iat->adt; + /* check if there's any AnimData to start with */ + if (adt) { + /* free fcurves */ + if (adt->action != NULL) { + any_removed |= fcurves_path_remove_fix(prefix, &adt->action->curves); + } + if (adt->tmpact != NULL) { + any_removed |= fcurves_path_remove_fix(prefix, &adt->tmpact->curves); + } + /* free drivers - stored as a list of F-Curves */ + any_removed |= fcurves_path_remove_fix(prefix, &adt->drivers); + /* NLA Data - Animation Data for Strips */ + for (NlaTrack *nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { + any_removed |= nlastrips_path_remove_fix(prefix, &nlt->strips); + } + } + return any_removed; } /* Apply Op to All FCurves in Database --------------------------- */ /* "User-Data" wrapper used by BKE_fcurves_main_cb() */ typedef struct AllFCurvesCbWrapper { - ID_FCurve_Edit_Callback func; /* Operation to apply on F-Curve */ - void *user_data; /* Custom data for that operation */ + ID_FCurve_Edit_Callback func; /* Operation to apply on F-Curve */ + void *user_data; /* Custom data for that operation */ } AllFCurvesCbWrapper; /* Helper for adt_apply_all_fcurves_cb() - Apply wrapped operator to list of F-Curves */ -static void fcurves_apply_cb(ID *id, ListBase *fcurves, ID_FCurve_Edit_Callback func, void *user_data) +static void fcurves_apply_cb(ID *id, + ListBase *fcurves, + ID_FCurve_Edit_Callback func, + void *user_data) { - FCurve *fcu; + FCurve *fcu; - for (fcu = fcurves->first; fcu; fcu = fcu->next) { - func(id, fcu, user_data); - } + for (fcu = fcurves->first; fcu; fcu = fcu->next) { + func(id, fcu, user_data); + } } /* Helper for adt_apply_all_fcurves_cb() - Recursively go through each NLA strip */ static void nlastrips_apply_all_curves_cb(ID *id, ListBase *strips, AllFCurvesCbWrapper *wrapper) { - NlaStrip *strip; + NlaStrip *strip; - for (strip = strips->first; strip; strip = strip->next) { - /* fix strip's action */ - if (strip->act) { - fcurves_apply_cb(id, &strip->act->curves, wrapper->func, wrapper->user_data); - } + for (strip = strips->first; strip; strip = strip->next) { + /* fix strip's action */ + if (strip->act) { + fcurves_apply_cb(id, &strip->act->curves, wrapper->func, wrapper->user_data); + } - /* check sub-strips (if metas) */ - nlastrips_apply_all_curves_cb(id, &strip->strips, wrapper); - } + /* check sub-strips (if metas) */ + nlastrips_apply_all_curves_cb(id, &strip->strips, wrapper); + } } /* Helper for BKE_fcurves_main_cb() - Dispatch wrapped operator to all F-Curves */ static void adt_apply_all_fcurves_cb(ID *id, AnimData *adt, void *wrapper_data) { - AllFCurvesCbWrapper *wrapper = wrapper_data; - NlaTrack *nlt; + AllFCurvesCbWrapper *wrapper = wrapper_data; + NlaTrack *nlt; - if (adt->action) { - fcurves_apply_cb(id, &adt->action->curves, wrapper->func, wrapper->user_data); - } + if (adt->action) { + fcurves_apply_cb(id, &adt->action->curves, wrapper->func, wrapper->user_data); + } - if (adt->tmpact) { - fcurves_apply_cb(id, &adt->tmpact->curves, wrapper->func, wrapper->user_data); - } + if (adt->tmpact) { + fcurves_apply_cb(id, &adt->tmpact->curves, wrapper->func, wrapper->user_data); + } - /* free drivers - stored as a list of F-Curves */ - fcurves_apply_cb(id, &adt->drivers, wrapper->func, wrapper->user_data); + /* free drivers - stored as a list of F-Curves */ + fcurves_apply_cb(id, &adt->drivers, wrapper->func, wrapper->user_data); - /* NLA Data - Animation Data for Strips */ - for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { - nlastrips_apply_all_curves_cb(id, &nlt->strips, wrapper); - } + /* NLA Data - Animation Data for Strips */ + for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { + nlastrips_apply_all_curves_cb(id, &nlt->strips, wrapper); + } } void BKE_fcurves_id_cb(ID *id, ID_FCurve_Edit_Callback func, void *user_data) { - AnimData *adt = BKE_animdata_from_id(id); - if (adt != NULL) { - AllFCurvesCbWrapper wrapper = {func, user_data}; - adt_apply_all_fcurves_cb(id, adt, &wrapper); - } + AnimData *adt = BKE_animdata_from_id(id); + if (adt != NULL) { + AllFCurvesCbWrapper wrapper = {func, user_data}; + adt_apply_all_fcurves_cb(id, adt, &wrapper); + } } /* apply the given callback function on all F-Curves attached to data in main database */ void BKE_fcurves_main_cb(Main *bmain, ID_FCurve_Edit_Callback func, void *user_data) { - /* Wrap F-Curve operation stuff to pass to the general AnimData-level func */ - AllFCurvesCbWrapper wrapper = {func, user_data}; + /* Wrap F-Curve operation stuff to pass to the general AnimData-level func */ + AllFCurvesCbWrapper wrapper = {func, user_data}; - /* Use the AnimData-based function so that we don't have to reimplement all that stuff */ - BKE_animdata_main_cb(bmain, adt_apply_all_fcurves_cb, &wrapper); + /* Use the AnimData-based function so that we don't have to reimplement all that stuff */ + BKE_animdata_main_cb(bmain, adt_apply_all_fcurves_cb, &wrapper); } - /* Whole Database Ops -------------------------------------------- */ /* apply the given callback function on all data in main database */ void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *user_data) { - ID *id; + ID *id; - /* standard data version */ + /* standard data version */ #define ANIMDATA_IDS_CB(first) \ - for (id = first; id; id = id->next) { \ - AnimData *adt = BKE_animdata_from_id(id); \ - if (adt) func(id, adt, user_data); \ - } (void)0 - - /* "embedded" nodetree cases (i.e. scene/material/texture->nodetree) */ + for (id = first; id; id = id->next) { \ + AnimData *adt = BKE_animdata_from_id(id); \ + if (adt) \ + func(id, adt, user_data); \ + } \ + (void)0 + + /* "embedded" nodetree cases (i.e. scene/material/texture->nodetree) */ #define ANIMDATA_NODETREE_IDS_CB(first, NtId_Type) \ - for (id = first; id; id = id->next) { \ - AnimData *adt = BKE_animdata_from_id(id); \ - NtId_Type *ntp = (NtId_Type *)id; \ - if (ntp->nodetree) { \ - AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \ - if (adt2) func(id, adt2, user_data); \ - } \ - if (adt) func(id, adt, user_data); \ - } (void)0 + for (id = first; id; id = id->next) { \ + AnimData *adt = BKE_animdata_from_id(id); \ + NtId_Type *ntp = (NtId_Type *)id; \ + if (ntp->nodetree) { \ + AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \ + if (adt2) \ + func(id, adt2, user_data); \ + } \ + if (adt) \ + func(id, adt, user_data); \ + } \ + (void)0 - /* nodes */ - ANIMDATA_IDS_CB(bmain->nodetrees.first); + /* nodes */ + ANIMDATA_IDS_CB(bmain->nodetrees.first); - /* textures */ - ANIMDATA_NODETREE_IDS_CB(bmain->textures.first, Tex); + /* textures */ + ANIMDATA_NODETREE_IDS_CB(bmain->textures.first, Tex); - /* lights */ - ANIMDATA_NODETREE_IDS_CB(bmain->lights.first, Light); + /* lights */ + ANIMDATA_NODETREE_IDS_CB(bmain->lights.first, Light); - /* materials */ - ANIMDATA_NODETREE_IDS_CB(bmain->materials.first, Material); + /* materials */ + ANIMDATA_NODETREE_IDS_CB(bmain->materials.first, Material); - /* cameras */ - ANIMDATA_IDS_CB(bmain->cameras.first); + /* cameras */ + ANIMDATA_IDS_CB(bmain->cameras.first); - /* shapekeys */ - ANIMDATA_IDS_CB(bmain->shapekeys.first); + /* shapekeys */ + ANIMDATA_IDS_CB(bmain->shapekeys.first); - /* metaballs */ - ANIMDATA_IDS_CB(bmain->metaballs.first); + /* metaballs */ + ANIMDATA_IDS_CB(bmain->metaballs.first); - /* curves */ - ANIMDATA_IDS_CB(bmain->curves.first); + /* curves */ + ANIMDATA_IDS_CB(bmain->curves.first); - /* armatures */ - ANIMDATA_IDS_CB(bmain->armatures.first); + /* armatures */ + ANIMDATA_IDS_CB(bmain->armatures.first); - /* lattices */ - ANIMDATA_IDS_CB(bmain->lattices.first); + /* lattices */ + ANIMDATA_IDS_CB(bmain->lattices.first); - /* meshes */ - ANIMDATA_IDS_CB(bmain->meshes.first); + /* meshes */ + ANIMDATA_IDS_CB(bmain->meshes.first); - /* particles */ - ANIMDATA_IDS_CB(bmain->particles.first); + /* particles */ + ANIMDATA_IDS_CB(bmain->particles.first); - /* speakers */ - ANIMDATA_IDS_CB(bmain->speakers.first); + /* speakers */ + ANIMDATA_IDS_CB(bmain->speakers.first); - /* movie clips */ - ANIMDATA_IDS_CB(bmain->movieclips.first); + /* movie clips */ + ANIMDATA_IDS_CB(bmain->movieclips.first); - /* objects */ - ANIMDATA_IDS_CB(bmain->objects.first); + /* objects */ + ANIMDATA_IDS_CB(bmain->objects.first); - /* masks */ - ANIMDATA_IDS_CB(bmain->masks.first); + /* masks */ + ANIMDATA_IDS_CB(bmain->masks.first); - /* worlds */ - ANIMDATA_NODETREE_IDS_CB(bmain->worlds.first, World); + /* worlds */ + ANIMDATA_NODETREE_IDS_CB(bmain->worlds.first, World); - /* scenes */ - ANIMDATA_NODETREE_IDS_CB(bmain->scenes.first, Scene); + /* scenes */ + ANIMDATA_NODETREE_IDS_CB(bmain->scenes.first, Scene); - /* line styles */ - ANIMDATA_IDS_CB(bmain->linestyles.first); + /* line styles */ + ANIMDATA_IDS_CB(bmain->linestyles.first); - /* grease pencil */ - ANIMDATA_IDS_CB(bmain->gpencils.first); + /* grease pencil */ + ANIMDATA_IDS_CB(bmain->gpencils.first); - /* palettes */ - ANIMDATA_IDS_CB(bmain->palettes.first); + /* palettes */ + ANIMDATA_IDS_CB(bmain->palettes.first); - /* cache files */ - ANIMDATA_IDS_CB(bmain->cachefiles.first); + /* cache files */ + ANIMDATA_IDS_CB(bmain->cachefiles.first); } /* Fix all RNA-Paths throughout the database (directly access the Global.main version) @@ -1206,95 +1280,101 @@ void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *use * i.e. pose.bones["Bone"] */ /* TODO: use BKE_animdata_main_cb for looping over all data */ -void BKE_animdata_fix_paths_rename_all(ID *ref_id, const char *prefix, const char *oldName, const char *newName) -{ - Main *bmain = G.main; /* XXX UGLY! */ - ID *id; - - /* macro for less typing - * - whether animdata exists is checked for by the main renaming callback, though taking - * this outside of the function may make things slightly faster? - */ +void BKE_animdata_fix_paths_rename_all(ID *ref_id, + const char *prefix, + const char *oldName, + const char *newName) +{ + Main *bmain = G.main; /* XXX UGLY! */ + ID *id; + + /* macro for less typing + * - whether animdata exists is checked for by the main renaming callback, though taking + * this outside of the function may make things slightly faster? + */ #define RENAMEFIX_ANIM_IDS(first) \ - for (id = first; id; id = id->next) { \ - AnimData *adt = BKE_animdata_from_id(id); \ - BKE_animdata_fix_paths_rename(id, adt, ref_id, prefix, oldName, newName, 0, 0, 1); \ - } (void)0 + for (id = first; id; id = id->next) { \ + AnimData *adt = BKE_animdata_from_id(id); \ + BKE_animdata_fix_paths_rename(id, adt, ref_id, prefix, oldName, newName, 0, 0, 1); \ + } \ + (void)0 - /* another version of this macro for nodetrees */ + /* another version of this macro for nodetrees */ #define RENAMEFIX_ANIM_NODETREE_IDS(first, NtId_Type) \ - for (id = first; id; id = id->next) { \ - AnimData *adt = BKE_animdata_from_id(id); \ - NtId_Type *ntp = (NtId_Type *)id; \ - if (ntp->nodetree) { \ - AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \ - BKE_animdata_fix_paths_rename((ID *)ntp->nodetree, adt2, ref_id, prefix, oldName, newName, 0, 0, 1); \ - } \ - BKE_animdata_fix_paths_rename(id, adt, ref_id, prefix, oldName, newName, 0, 0, 1); \ - } (void)0 + for (id = first; id; id = id->next) { \ + AnimData *adt = BKE_animdata_from_id(id); \ + NtId_Type *ntp = (NtId_Type *)id; \ + if (ntp->nodetree) { \ + AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \ + BKE_animdata_fix_paths_rename( \ + (ID *)ntp->nodetree, adt2, ref_id, prefix, oldName, newName, 0, 0, 1); \ + } \ + BKE_animdata_fix_paths_rename(id, adt, ref_id, prefix, oldName, newName, 0, 0, 1); \ + } \ + (void)0 - /* nodes */ - RENAMEFIX_ANIM_IDS(bmain->nodetrees.first); + /* nodes */ + RENAMEFIX_ANIM_IDS(bmain->nodetrees.first); - /* textures */ - RENAMEFIX_ANIM_NODETREE_IDS(bmain->textures.first, Tex); + /* textures */ + RENAMEFIX_ANIM_NODETREE_IDS(bmain->textures.first, Tex); - /* lights */ - RENAMEFIX_ANIM_NODETREE_IDS(bmain->lights.first, Light); + /* lights */ + RENAMEFIX_ANIM_NODETREE_IDS(bmain->lights.first, Light); - /* materials */ - RENAMEFIX_ANIM_NODETREE_IDS(bmain->materials.first, Material); + /* materials */ + RENAMEFIX_ANIM_NODETREE_IDS(bmain->materials.first, Material); - /* cameras */ - RENAMEFIX_ANIM_IDS(bmain->cameras.first); + /* cameras */ + RENAMEFIX_ANIM_IDS(bmain->cameras.first); - /* shapekeys */ - RENAMEFIX_ANIM_IDS(bmain->shapekeys.first); + /* shapekeys */ + RENAMEFIX_ANIM_IDS(bmain->shapekeys.first); - /* metaballs */ - RENAMEFIX_ANIM_IDS(bmain->metaballs.first); + /* metaballs */ + RENAMEFIX_ANIM_IDS(bmain->metaballs.first); - /* curves */ - RENAMEFIX_ANIM_IDS(bmain->curves.first); + /* curves */ + RENAMEFIX_ANIM_IDS(bmain->curves.first); - /* armatures */ - RENAMEFIX_ANIM_IDS(bmain->armatures.first); + /* armatures */ + RENAMEFIX_ANIM_IDS(bmain->armatures.first); - /* lattices */ - RENAMEFIX_ANIM_IDS(bmain->lattices.first); + /* lattices */ + RENAMEFIX_ANIM_IDS(bmain->lattices.first); - /* meshes */ - RENAMEFIX_ANIM_IDS(bmain->meshes.first); + /* meshes */ + RENAMEFIX_ANIM_IDS(bmain->meshes.first); - /* particles */ - RENAMEFIX_ANIM_IDS(bmain->particles.first); + /* particles */ + RENAMEFIX_ANIM_IDS(bmain->particles.first); - /* speakers */ - RENAMEFIX_ANIM_IDS(bmain->speakers.first); + /* speakers */ + RENAMEFIX_ANIM_IDS(bmain->speakers.first); - /* movie clips */ - RENAMEFIX_ANIM_IDS(bmain->movieclips.first); + /* movie clips */ + RENAMEFIX_ANIM_IDS(bmain->movieclips.first); - /* objects */ - RENAMEFIX_ANIM_IDS(bmain->objects.first); + /* objects */ + RENAMEFIX_ANIM_IDS(bmain->objects.first); - /* masks */ - RENAMEFIX_ANIM_IDS(bmain->masks.first); + /* masks */ + RENAMEFIX_ANIM_IDS(bmain->masks.first); - /* worlds */ - RENAMEFIX_ANIM_NODETREE_IDS(bmain->worlds.first, World); + /* worlds */ + RENAMEFIX_ANIM_NODETREE_IDS(bmain->worlds.first, World); - /* linestyles */ - RENAMEFIX_ANIM_IDS(bmain->linestyles.first); + /* linestyles */ + RENAMEFIX_ANIM_IDS(bmain->linestyles.first); - /* grease pencil */ - RENAMEFIX_ANIM_IDS(bmain->gpencils.first); + /* grease pencil */ + RENAMEFIX_ANIM_IDS(bmain->gpencils.first); - /* cache files */ - RENAMEFIX_ANIM_IDS(bmain->cachefiles.first); + /* cache files */ + RENAMEFIX_ANIM_IDS(bmain->cachefiles.first); - /* scenes */ - RENAMEFIX_ANIM_NODETREE_IDS(bmain->scenes.first, Scene); + /* scenes */ + RENAMEFIX_ANIM_NODETREE_IDS(bmain->scenes.first, Scene); } /* *********************************** */ @@ -1304,161 +1384,176 @@ void BKE_animdata_fix_paths_rename_all(ID *ref_id, const char *prefix, const cha /* Find the first path that matches the given criteria */ /* TODO: do we want some method to perform partial matches too? */ -KS_Path *BKE_keyingset_find_path(KeyingSet *ks, ID *id, const char group_name[], const char rna_path[], int array_index, int UNUSED(group_mode)) +KS_Path *BKE_keyingset_find_path(KeyingSet *ks, + ID *id, + const char group_name[], + const char rna_path[], + int array_index, + int UNUSED(group_mode)) { - KS_Path *ksp; + KS_Path *ksp; - /* sanity checks */ - if (ELEM(NULL, ks, rna_path, id)) - return NULL; + /* sanity checks */ + if (ELEM(NULL, ks, rna_path, id)) + return NULL; - /* loop over paths in the current KeyingSet, finding the first one where all settings match - * (i.e. the first one where none of the checks fail and equal 0) - */ - for (ksp = ks->paths.first; ksp; ksp = ksp->next) { - short eq_id = 1, eq_path = 1, eq_index = 1, eq_group = 1; + /* loop over paths in the current KeyingSet, finding the first one where all settings match + * (i.e. the first one where none of the checks fail and equal 0) + */ + for (ksp = ks->paths.first; ksp; ksp = ksp->next) { + short eq_id = 1, eq_path = 1, eq_index = 1, eq_group = 1; - /* id */ - if (id != ksp->id) - eq_id = 0; + /* id */ + if (id != ksp->id) + eq_id = 0; - /* path */ - if ((ksp->rna_path == NULL) || !STREQ(rna_path, ksp->rna_path)) - eq_path = 0; + /* path */ + if ((ksp->rna_path == NULL) || !STREQ(rna_path, ksp->rna_path)) + eq_path = 0; - /* index - need to compare whole-array setting too... */ - if (ksp->array_index != array_index) - eq_index = 0; + /* index - need to compare whole-array setting too... */ + if (ksp->array_index != array_index) + eq_index = 0; - /* group */ - if (group_name) { - /* FIXME: these checks need to be coded... for now, it's not too important though */ - } + /* group */ + if (group_name) { + /* FIXME: these checks need to be coded... for now, it's not too important though */ + } - /* if all aspects are ok, return */ - if (eq_id && eq_path && eq_index && eq_group) - return ksp; - } + /* if all aspects are ok, return */ + if (eq_id && eq_path && eq_index && eq_group) + return ksp; + } - /* none found */ - return NULL; + /* none found */ + return NULL; } /* Defining Tools --------------------------- */ /* Used to create a new 'custom' KeyingSet for the user, that will be automatically added to the stack */ -KeyingSet *BKE_keyingset_add(ListBase *list, const char idname[], const char name[], short flag, short keyingflag) +KeyingSet *BKE_keyingset_add( + ListBase *list, const char idname[], const char name[], short flag, short keyingflag) { - KeyingSet *ks; + KeyingSet *ks; - /* allocate new KeyingSet */ - ks = MEM_callocN(sizeof(KeyingSet), "KeyingSet"); + /* allocate new KeyingSet */ + ks = MEM_callocN(sizeof(KeyingSet), "KeyingSet"); - BLI_strncpy(ks->idname, (idname) ? idname : (name) ? name : DATA_("KeyingSet"), sizeof(ks->idname)); - BLI_strncpy(ks->name, (name) ? name : (idname) ? idname : DATA_("Keying Set"), sizeof(ks->name)); + BLI_strncpy( + ks->idname, (idname) ? idname : (name) ? name : DATA_("KeyingSet"), sizeof(ks->idname)); + BLI_strncpy(ks->name, (name) ? name : (idname) ? idname : DATA_("Keying Set"), sizeof(ks->name)); - ks->flag = flag; - ks->keyingflag = keyingflag; - ks->keyingoverride = keyingflag; /* NOTE: assume that if one is set one way, the other should be too, so that it'll work */ + ks->flag = flag; + ks->keyingflag = keyingflag; + ks->keyingoverride = + keyingflag; /* NOTE: assume that if one is set one way, the other should be too, so that it'll work */ - /* add KeyingSet to list */ - BLI_addtail(list, ks); + /* add KeyingSet to list */ + BLI_addtail(list, ks); - /* Make sure KeyingSet has a unique idname */ - BLI_uniquename(list, ks, DATA_("KeyingSet"), '.', offsetof(KeyingSet, idname), sizeof(ks->idname)); + /* Make sure KeyingSet has a unique idname */ + BLI_uniquename( + list, ks, DATA_("KeyingSet"), '.', offsetof(KeyingSet, idname), sizeof(ks->idname)); - /* Make sure KeyingSet has a unique label (this helps with identification) */ - BLI_uniquename(list, ks, DATA_("Keying Set"), '.', offsetof(KeyingSet, name), sizeof(ks->name)); + /* Make sure KeyingSet has a unique label (this helps with identification) */ + BLI_uniquename(list, ks, DATA_("Keying Set"), '.', offsetof(KeyingSet, name), sizeof(ks->name)); - /* return new KeyingSet for further editing */ - return ks; + /* return new KeyingSet for further editing */ + return ks; } /* Add a path to a KeyingSet. Nothing is returned for now... * Checks are performed to ensure that destination is appropriate for the KeyingSet in question */ -KS_Path *BKE_keyingset_add_path(KeyingSet *ks, ID *id, const char group_name[], const char rna_path[], int array_index, short flag, short groupmode) -{ - KS_Path *ksp; - - /* sanity checks */ - if (ELEM(NULL, ks, rna_path)) { - CLOG_ERROR(&LOG, "no Keying Set and/or RNA Path to add path with"); - return NULL; - } - - /* ID is required for all types of KeyingSets */ - if (id == NULL) { - CLOG_ERROR(&LOG, "No ID provided for Keying Set Path"); - return NULL; - } - - /* don't add if there is already a matching KS_Path in the KeyingSet */ - if (BKE_keyingset_find_path(ks, id, group_name, rna_path, array_index, groupmode)) { - if (G.debug & G_DEBUG) - CLOG_ERROR(&LOG, "destination already exists in Keying Set"); - return NULL; - } - - /* allocate a new KeyingSet Path */ - ksp = MEM_callocN(sizeof(KS_Path), "KeyingSet Path"); - - /* just store absolute info */ - ksp->id = id; - if (group_name) - BLI_strncpy(ksp->group, group_name, sizeof(ksp->group)); - else - ksp->group[0] = '\0'; - - /* store additional info for relative paths (just in case user makes the set relative) */ - if (id) - ksp->idtype = GS(id->name); - - /* just copy path info */ - /* TODO: should array index be checked too? */ - ksp->rna_path = BLI_strdup(rna_path); - ksp->array_index = array_index; - - /* store flags */ - ksp->flag = flag; - ksp->groupmode = groupmode; - - /* add KeyingSet path to KeyingSet */ - BLI_addtail(&ks->paths, ksp); - - /* return this path */ - return ksp; +KS_Path *BKE_keyingset_add_path(KeyingSet *ks, + ID *id, + const char group_name[], + const char rna_path[], + int array_index, + short flag, + short groupmode) +{ + KS_Path *ksp; + + /* sanity checks */ + if (ELEM(NULL, ks, rna_path)) { + CLOG_ERROR(&LOG, "no Keying Set and/or RNA Path to add path with"); + return NULL; + } + + /* ID is required for all types of KeyingSets */ + if (id == NULL) { + CLOG_ERROR(&LOG, "No ID provided for Keying Set Path"); + return NULL; + } + + /* don't add if there is already a matching KS_Path in the KeyingSet */ + if (BKE_keyingset_find_path(ks, id, group_name, rna_path, array_index, groupmode)) { + if (G.debug & G_DEBUG) + CLOG_ERROR(&LOG, "destination already exists in Keying Set"); + return NULL; + } + + /* allocate a new KeyingSet Path */ + ksp = MEM_callocN(sizeof(KS_Path), "KeyingSet Path"); + + /* just store absolute info */ + ksp->id = id; + if (group_name) + BLI_strncpy(ksp->group, group_name, sizeof(ksp->group)); + else + ksp->group[0] = '\0'; + + /* store additional info for relative paths (just in case user makes the set relative) */ + if (id) + ksp->idtype = GS(id->name); + + /* just copy path info */ + /* TODO: should array index be checked too? */ + ksp->rna_path = BLI_strdup(rna_path); + ksp->array_index = array_index; + + /* store flags */ + ksp->flag = flag; + ksp->groupmode = groupmode; + + /* add KeyingSet path to KeyingSet */ + BLI_addtail(&ks->paths, ksp); + + /* return this path */ + return ksp; } /* Free the given Keying Set path */ void BKE_keyingset_free_path(KeyingSet *ks, KS_Path *ksp) { - /* sanity check */ - if (ELEM(NULL, ks, ksp)) - return; + /* sanity check */ + if (ELEM(NULL, ks, ksp)) + return; - /* free RNA-path info */ - if (ksp->rna_path) - MEM_freeN(ksp->rna_path); + /* free RNA-path info */ + if (ksp->rna_path) + MEM_freeN(ksp->rna_path); - /* free path itself */ - BLI_freelinkN(&ks->paths, ksp); + /* free path itself */ + BLI_freelinkN(&ks->paths, ksp); } /* Copy all KeyingSets in the given list */ void BKE_keyingsets_copy(ListBase *newlist, const ListBase *list) { - KeyingSet *ksn; - KS_Path *kspn; + KeyingSet *ksn; + KS_Path *kspn; - BLI_duplicatelist(newlist, list); + BLI_duplicatelist(newlist, list); - for (ksn = newlist->first; ksn; ksn = ksn->next) { - BLI_duplicatelist(&ksn->paths, &ksn->paths); + for (ksn = newlist->first; ksn; ksn = ksn->next) { + BLI_duplicatelist(&ksn->paths, &ksn->paths); - for (kspn = ksn->paths.first; kspn; kspn = kspn->next) - kspn->rna_path = MEM_dupallocN(kspn->rna_path); - } + for (kspn = ksn->paths.first; kspn; kspn = kspn->next) + kspn->rna_path = MEM_dupallocN(kspn->rna_path); + } } /* Freeing Tools --------------------------- */ @@ -1466,289 +1561,286 @@ void BKE_keyingsets_copy(ListBase *newlist, const ListBase *list) /* Free data for KeyingSet but not set itself */ void BKE_keyingset_free(KeyingSet *ks) { - KS_Path *ksp, *kspn; + KS_Path *ksp, *kspn; - /* sanity check */ - if (ks == NULL) - return; + /* sanity check */ + if (ks == NULL) + return; - /* free each path as we go to avoid looping twice */ - for (ksp = ks->paths.first; ksp; ksp = kspn) { - kspn = ksp->next; - BKE_keyingset_free_path(ks, ksp); - } + /* free each path as we go to avoid looping twice */ + for (ksp = ks->paths.first; ksp; ksp = kspn) { + kspn = ksp->next; + BKE_keyingset_free_path(ks, ksp); + } } /* Free all the KeyingSets in the given list */ void BKE_keyingsets_free(ListBase *list) { - KeyingSet *ks, *ksn; + KeyingSet *ks, *ksn; - /* sanity check */ - if (list == NULL) - return; + /* sanity check */ + if (list == NULL) + return; - /* loop over KeyingSets freeing them - * - BKE_keyingset_free() doesn't free the set itself, but it frees its sub-data - */ - for (ks = list->first; ks; ks = ksn) { - ksn = ks->next; - BKE_keyingset_free(ks); - BLI_freelinkN(list, ks); - } + /* loop over KeyingSets freeing them + * - BKE_keyingset_free() doesn't free the set itself, but it frees its sub-data + */ + for (ks = list->first; ks; ks = ksn) { + ksn = ks->next; + BKE_keyingset_free(ks); + BLI_freelinkN(list, ks); + } } /* ***************************************** */ /* Evaluation Data-Setting Backend */ -static bool animsys_store_rna_setting( - PointerRNA *ptr, - /* typically 'fcu->rna_path', 'fcu->array_index' */ - const char *rna_path, const int array_index, - PathResolvedRNA *r_result) -{ - bool success = false; - const char *path = rna_path; - - /* write value to setting */ - if (path) { - /* get property to write to */ - if (RNA_path_resolve_property(ptr, path, &r_result->ptr, &r_result->prop)) { - if ((ptr->id.data == NULL) || RNA_property_animateable(&r_result->ptr, r_result->prop)) { - int array_len = RNA_property_array_length(&r_result->ptr, r_result->prop); - - if (array_len && array_index >= array_len) { - if (G.debug & G_DEBUG) { - CLOG_WARN(&LOG, "Animato: Invalid array index. ID = '%s', '%s[%d]', array length is %d", - (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>", - path, array_index, array_len - 1); - } - } - else { - r_result->prop_index = array_len ? array_index : -1; - success = true; - } - } - } - else { - /* failed to get path */ - /* XXX don't tag as failed yet though, as there are some legit situations (Action Constraint) - * where some channels will not exist, but shouldn't lock up Action */ - if (G.debug & G_DEBUG) { - CLOG_WARN(&LOG, "Animato: Invalid path. ID = '%s', '%s[%d]'", - (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>", - path, array_index); - } - } - } - - return success; +static bool animsys_store_rna_setting(PointerRNA *ptr, + /* typically 'fcu->rna_path', 'fcu->array_index' */ + const char *rna_path, + const int array_index, + PathResolvedRNA *r_result) +{ + bool success = false; + const char *path = rna_path; + + /* write value to setting */ + if (path) { + /* get property to write to */ + if (RNA_path_resolve_property(ptr, path, &r_result->ptr, &r_result->prop)) { + if ((ptr->id.data == NULL) || RNA_property_animateable(&r_result->ptr, r_result->prop)) { + int array_len = RNA_property_array_length(&r_result->ptr, r_result->prop); + + if (array_len && array_index >= array_len) { + if (G.debug & G_DEBUG) { + CLOG_WARN(&LOG, + "Animato: Invalid array index. ID = '%s', '%s[%d]', array length is %d", + (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>", + path, + array_index, + array_len - 1); + } + } + else { + r_result->prop_index = array_len ? array_index : -1; + success = true; + } + } + } + else { + /* failed to get path */ + /* XXX don't tag as failed yet though, as there are some legit situations (Action Constraint) + * where some channels will not exist, but shouldn't lock up Action */ + if (G.debug & G_DEBUG) { + CLOG_WARN(&LOG, + "Animato: Invalid path. ID = '%s', '%s[%d]'", + (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>", + path, + array_index); + } + } + } + + return success; } - /* less than 1.0 evaluates to false, use epsilon to avoid float error */ #define ANIMSYS_FLOAT_AS_BOOL(value) ((value) > ((1.0f - FLT_EPSILON))) static bool animsys_read_rna_setting(PathResolvedRNA *anim_rna, float *r_value) { - PropertyRNA *prop = anim_rna->prop; - PointerRNA *ptr = &anim_rna->ptr; - int array_index = anim_rna->prop_index; - float orig_value; - - /* caller must ensure this is animatable */ - BLI_assert(RNA_property_animateable(ptr, prop) || ptr->id.data == NULL); - - switch (RNA_property_type(prop)) { - case PROP_BOOLEAN: - { - if (array_index != -1) { - const int orig_value_coerce = RNA_property_boolean_get_index(ptr, prop, array_index); - orig_value = (float)orig_value_coerce; - } - else { - const int orig_value_coerce = RNA_property_boolean_get(ptr, prop); - orig_value = (float)orig_value_coerce; - } - break; - } - case PROP_INT: - { - if (array_index != -1) { - const int orig_value_coerce = RNA_property_int_get_index(ptr, prop, array_index); - orig_value = (float)orig_value_coerce; - } - else { - const int orig_value_coerce = RNA_property_int_get(ptr, prop); - orig_value = (float)orig_value_coerce; - } - break; - } - case PROP_FLOAT: - { - if (array_index != -1) { - const float orig_value_coerce = RNA_property_float_get_index(ptr, prop, array_index); - orig_value = (float)orig_value_coerce; - } - else { - const float orig_value_coerce = RNA_property_float_get(ptr, prop); - orig_value = (float)orig_value_coerce; - } - break; - } - case PROP_ENUM: - { - const int orig_value_coerce = RNA_property_enum_get(ptr, prop); - orig_value = (float)orig_value_coerce; - break; - } - default: - /* nothing can be done here... so it is unsuccessful? */ - return false; - } - - if (r_value != NULL) { - *r_value = orig_value; - } - - /* successful */ - return true; + PropertyRNA *prop = anim_rna->prop; + PointerRNA *ptr = &anim_rna->ptr; + int array_index = anim_rna->prop_index; + float orig_value; + + /* caller must ensure this is animatable */ + BLI_assert(RNA_property_animateable(ptr, prop) || ptr->id.data == NULL); + + switch (RNA_property_type(prop)) { + case PROP_BOOLEAN: { + if (array_index != -1) { + const int orig_value_coerce = RNA_property_boolean_get_index(ptr, prop, array_index); + orig_value = (float)orig_value_coerce; + } + else { + const int orig_value_coerce = RNA_property_boolean_get(ptr, prop); + orig_value = (float)orig_value_coerce; + } + break; + } + case PROP_INT: { + if (array_index != -1) { + const int orig_value_coerce = RNA_property_int_get_index(ptr, prop, array_index); + orig_value = (float)orig_value_coerce; + } + else { + const int orig_value_coerce = RNA_property_int_get(ptr, prop); + orig_value = (float)orig_value_coerce; + } + break; + } + case PROP_FLOAT: { + if (array_index != -1) { + const float orig_value_coerce = RNA_property_float_get_index(ptr, prop, array_index); + orig_value = (float)orig_value_coerce; + } + else { + const float orig_value_coerce = RNA_property_float_get(ptr, prop); + orig_value = (float)orig_value_coerce; + } + break; + } + case PROP_ENUM: { + const int orig_value_coerce = RNA_property_enum_get(ptr, prop); + orig_value = (float)orig_value_coerce; + break; + } + default: + /* nothing can be done here... so it is unsuccessful? */ + return false; + } + + if (r_value != NULL) { + *r_value = orig_value; + } + + /* successful */ + return true; } /* Write the given value to a setting using RNA, and return success */ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float value) { - PropertyRNA *prop = anim_rna->prop; - PointerRNA *ptr = &anim_rna->ptr; - int array_index = anim_rna->prop_index; - - /* caller must ensure this is animatable */ - BLI_assert(RNA_property_animateable(ptr, prop) || ptr->id.data == NULL); - - /* Check whether value is new. Otherwise we skip all the updates. */ - float old_value; - if (!animsys_read_rna_setting(anim_rna, &old_value)) { - return false; - } - if (old_value == value) { - return true; - } - - switch (RNA_property_type(prop)) { - case PROP_BOOLEAN: - { - const int value_coerce = ANIMSYS_FLOAT_AS_BOOL(value); - if (array_index != -1) { - RNA_property_boolean_set_index(ptr, prop, array_index, value_coerce); - } - else { - RNA_property_boolean_set(ptr, prop, value_coerce); - } - break; - } - case PROP_INT: - { - int value_coerce = (int)value; - RNA_property_int_clamp(ptr, prop, &value_coerce); - if (array_index != -1) { - RNA_property_int_set_index(ptr, prop, array_index, value_coerce); - } - else { - RNA_property_int_set(ptr, prop, value_coerce); - } - break; - } - case PROP_FLOAT: - { - float value_coerce = value; - RNA_property_float_clamp(ptr, prop, &value_coerce); - if (array_index != -1) { - RNA_property_float_set_index(ptr, prop, array_index, value_coerce); - } - else { - RNA_property_float_set(ptr, prop, value_coerce); - } - break; - } - case PROP_ENUM: - { - const int value_coerce = (int)value; - RNA_property_enum_set(ptr, prop, value_coerce); - break; - } - default: - /* nothing can be done here... so it is unsuccessful? */ - return false; - } - - /* successful */ - return true; + PropertyRNA *prop = anim_rna->prop; + PointerRNA *ptr = &anim_rna->ptr; + int array_index = anim_rna->prop_index; + + /* caller must ensure this is animatable */ + BLI_assert(RNA_property_animateable(ptr, prop) || ptr->id.data == NULL); + + /* Check whether value is new. Otherwise we skip all the updates. */ + float old_value; + if (!animsys_read_rna_setting(anim_rna, &old_value)) { + return false; + } + if (old_value == value) { + return true; + } + + switch (RNA_property_type(prop)) { + case PROP_BOOLEAN: { + const int value_coerce = ANIMSYS_FLOAT_AS_BOOL(value); + if (array_index != -1) { + RNA_property_boolean_set_index(ptr, prop, array_index, value_coerce); + } + else { + RNA_property_boolean_set(ptr, prop, value_coerce); + } + break; + } + case PROP_INT: { + int value_coerce = (int)value; + RNA_property_int_clamp(ptr, prop, &value_coerce); + if (array_index != -1) { + RNA_property_int_set_index(ptr, prop, array_index, value_coerce); + } + else { + RNA_property_int_set(ptr, prop, value_coerce); + } + break; + } + case PROP_FLOAT: { + float value_coerce = value; + RNA_property_float_clamp(ptr, prop, &value_coerce); + if (array_index != -1) { + RNA_property_float_set_index(ptr, prop, array_index, value_coerce); + } + else { + RNA_property_float_set(ptr, prop, value_coerce); + } + break; + } + case PROP_ENUM: { + const int value_coerce = (int)value; + RNA_property_enum_set(ptr, prop, value_coerce); + break; + } + default: + /* nothing can be done here... so it is unsuccessful? */ + return false; + } + + /* successful */ + return true; } /* Simple replacement based data-setting of the FCurve using RNA */ bool BKE_animsys_execute_fcurve(PointerRNA *ptr, FCurve *fcu, float curval) { - PathResolvedRNA anim_rna; - bool ok = false; - - if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { - ok = animsys_write_rna_setting(&anim_rna, curval); - } - - /* return whether we were successful */ - return ok; -} - -static void animsys_write_orig_anim_rna( - PointerRNA *ptr, - const char *rna_path, - int array_index, - float value) -{ - /* Pointer is expected to be an ID pointer, if it's not -- we are doomed. - * - * NOTE: It is possible to have animation data on NLA strip, see T57360. - * TODO(sergey): Find solution for those cases. - */ - if (ptr->id.data == NULL) { - return; - } - PointerRNA orig_ptr = *ptr; - orig_ptr.id.data = ((ID *)orig_ptr.id.data)->orig_id; - orig_ptr.data = orig_ptr.id.data; - PathResolvedRNA orig_anim_rna; - /* TODO(sergey): Is there a faster way to get anim_rna of original ID? */ - if (animsys_store_rna_setting(&orig_ptr, rna_path, array_index, &orig_anim_rna)) { - animsys_write_rna_setting(&orig_anim_rna, value); - } + PathResolvedRNA anim_rna; + bool ok = false; + + if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { + ok = animsys_write_rna_setting(&anim_rna, curval); + } + + /* return whether we were successful */ + return ok; +} + +static void animsys_write_orig_anim_rna(PointerRNA *ptr, + const char *rna_path, + int array_index, + float value) +{ + /* Pointer is expected to be an ID pointer, if it's not -- we are doomed. + * + * NOTE: It is possible to have animation data on NLA strip, see T57360. + * TODO(sergey): Find solution for those cases. + */ + if (ptr->id.data == NULL) { + return; + } + PointerRNA orig_ptr = *ptr; + orig_ptr.id.data = ((ID *)orig_ptr.id.data)->orig_id; + orig_ptr.data = orig_ptr.id.data; + PathResolvedRNA orig_anim_rna; + /* TODO(sergey): Is there a faster way to get anim_rna of original ID? */ + if (animsys_store_rna_setting(&orig_ptr, rna_path, array_index, &orig_anim_rna)) { + animsys_write_rna_setting(&orig_anim_rna, value); + } } /* Evaluate all the F-Curves in the given list * This performs a set of standard checks. If extra checks are required, separate code should be used */ -static void animsys_evaluate_fcurves( - Depsgraph *depsgraph, PointerRNA *ptr, ListBase *list, float ctime) -{ - const bool is_active_depsgraph = DEG_is_active(depsgraph); - /* Calculate then execute each curve. */ - for (FCurve *fcu = list->first; fcu; fcu = fcu->next) { - /* Check if this F-Curve doesn't belong to a muted group. */ - if ((fcu->grp != NULL) && (fcu->grp->flag & AGRP_MUTED)) { - continue; - } - /* Check if this curve should be skipped. */ - if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED))) { - continue; - } - PathResolvedRNA anim_rna; - if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { - const float curval = calculate_fcurve(&anim_rna, fcu, ctime); - animsys_write_rna_setting(&anim_rna, curval); - if (is_active_depsgraph) { - animsys_write_orig_anim_rna(ptr, fcu->rna_path, fcu->array_index, curval); - } - } - } +static void animsys_evaluate_fcurves(Depsgraph *depsgraph, + PointerRNA *ptr, + ListBase *list, + float ctime) +{ + const bool is_active_depsgraph = DEG_is_active(depsgraph); + /* Calculate then execute each curve. */ + for (FCurve *fcu = list->first; fcu; fcu = fcu->next) { + /* Check if this F-Curve doesn't belong to a muted group. */ + if ((fcu->grp != NULL) && (fcu->grp->flag & AGRP_MUTED)) { + continue; + } + /* Check if this curve should be skipped. */ + if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED))) { + continue; + } + PathResolvedRNA anim_rna; + if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { + const float curval = calculate_fcurve(&anim_rna, fcu, ctime); + animsys_write_rna_setting(&anim_rna, curval); + if (is_active_depsgraph) { + animsys_write_orig_anim_rna(ptr, fcu->rna_path, fcu->array_index, curval); + } + } + } } /* ***************************************** */ @@ -1757,36 +1849,36 @@ static void animsys_evaluate_fcurves( /* Evaluate Drivers */ static void animsys_evaluate_drivers(PointerRNA *ptr, AnimData *adt, float ctime) { - FCurve *fcu; - - /* drivers are stored as F-Curves, but we cannot use the standard code, as we need to check if - * the depsgraph requested that this driver be evaluated... - */ - for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { - ChannelDriver *driver = fcu->driver; - bool ok = false; - - /* check if this driver's curve should be skipped */ - if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) { - /* check if driver itself is tagged for recalculation */ - /* XXX driver recalc flag is not set yet by depsgraph! */ - if ((driver) && !(driver->flag & DRIVER_FLAG_INVALID)) { - /* evaluate this using values set already in other places - * NOTE: for 'layering' option later on, we should check if we should remove old value before adding - * new to only be done when drivers only changed */ - - PathResolvedRNA anim_rna; - if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { - const float curval = calculate_fcurve(&anim_rna, fcu, ctime); - ok = animsys_write_rna_setting(&anim_rna, curval); - } - - /* set error-flag if evaluation failed */ - if (ok == 0) - driver->flag |= DRIVER_FLAG_INVALID; - } - } - } + FCurve *fcu; + + /* drivers are stored as F-Curves, but we cannot use the standard code, as we need to check if + * the depsgraph requested that this driver be evaluated... + */ + for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { + ChannelDriver *driver = fcu->driver; + bool ok = false; + + /* check if this driver's curve should be skipped */ + if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) { + /* check if driver itself is tagged for recalculation */ + /* XXX driver recalc flag is not set yet by depsgraph! */ + if ((driver) && !(driver->flag & DRIVER_FLAG_INVALID)) { + /* evaluate this using values set already in other places + * NOTE: for 'layering' option later on, we should check if we should remove old value before adding + * new to only be done when drivers only changed */ + + PathResolvedRNA anim_rna; + if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { + const float curval = calculate_fcurve(&anim_rna, fcu, ctime); + ok = animsys_write_rna_setting(&anim_rna, curval); + } + + /* set error-flag if evaluation failed */ + if (ok == 0) + driver->flag |= DRIVER_FLAG_INVALID; + } + } + } } /* ***************************************** */ @@ -1798,29 +1890,33 @@ static void animsys_evaluate_drivers(PointerRNA *ptr, AnimData *adt, float ctime */ static void action_idcode_patch_check(ID *id, bAction *act) { - int idcode = 0; - - /* just in case */ - if (ELEM(NULL, id, act)) - return; - else - idcode = GS(id->name); - - /* the actual checks... hopefully not too much of a performance hit in the long run... */ - if (act->idroot == 0) { - /* use the current root if not set already (i.e. newly created actions and actions from 2.50-2.57 builds) - * - this has problems if there are 2 users, and the first one encountered is the invalid one - * in which case, the user will need to manually fix this (?) - */ - act->idroot = idcode; - } - else if (act->idroot != idcode) { - /* only report this error if debug mode is enabled (to save performance everywhere else) */ - if (G.debug & G_DEBUG) { - printf("AnimSys Safety Check Failed: Action '%s' is not meant to be used from ID-Blocks of type %d such as '%s'\n", - act->id.name + 2, idcode, id->name); - } - } + int idcode = 0; + + /* just in case */ + if (ELEM(NULL, id, act)) + return; + else + idcode = GS(id->name); + + /* the actual checks... hopefully not too much of a performance hit in the long run... */ + if (act->idroot == 0) { + /* use the current root if not set already (i.e. newly created actions and actions from 2.50-2.57 builds) + * - this has problems if there are 2 users, and the first one encountered is the invalid one + * in which case, the user will need to manually fix this (?) + */ + act->idroot = idcode; + } + else if (act->idroot != idcode) { + /* only report this error if debug mode is enabled (to save performance everywhere else) */ + if (G.debug & G_DEBUG) { + printf( + "AnimSys Safety Check Failed: Action '%s' is not meant to be used from ID-Blocks of " + "type %d such as '%s'\n", + act->id.name + 2, + idcode, + id->name); + } + } } /* ----------------------------------------- */ @@ -1828,46 +1924,50 @@ static void action_idcode_patch_check(ID *id, bAction *act) /* Evaluate Action Group */ void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup *agrp, float ctime) { - FCurve *fcu; + FCurve *fcu; - /* check if mapper is appropriate for use here (we set to NULL if it's inappropriate) */ - if (ELEM(NULL, act, agrp)) return; + /* check if mapper is appropriate for use here (we set to NULL if it's inappropriate) */ + if (ELEM(NULL, act, agrp)) + return; - action_idcode_patch_check(ptr->id.data, act); + action_idcode_patch_check(ptr->id.data, act); - /* if group is muted, don't evaluated any of the F-Curve */ - if (agrp->flag & AGRP_MUTED) - return; + /* if group is muted, don't evaluated any of the F-Curve */ + if (agrp->flag & AGRP_MUTED) + return; - /* calculate then execute each curve */ - for (fcu = agrp->channels.first; (fcu) && (fcu->grp == agrp); fcu = fcu->next) { - /* check if this curve should be skipped */ - if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) { - PathResolvedRNA anim_rna; - if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { - const float curval = calculate_fcurve(&anim_rna, fcu, ctime); - animsys_write_rna_setting(&anim_rna, curval); - } - } - } + /* calculate then execute each curve */ + for (fcu = agrp->channels.first; (fcu) && (fcu->grp == agrp); fcu = fcu->next) { + /* check if this curve should be skipped */ + if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) { + PathResolvedRNA anim_rna; + if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { + const float curval = calculate_fcurve(&anim_rna, fcu, ctime); + animsys_write_rna_setting(&anim_rna, curval); + } + } + } } /* Evaluate Action (F-Curve Bag) */ -static void animsys_evaluate_action_ex( - Depsgraph *depsgraph, PointerRNA *ptr, bAction *act, float ctime) +static void animsys_evaluate_action_ex(Depsgraph *depsgraph, + PointerRNA *ptr, + bAction *act, + float ctime) { - /* check if mapper is appropriate for use here (we set to NULL if it's inappropriate) */ - if (act == NULL) return; + /* check if mapper is appropriate for use here (we set to NULL if it's inappropriate) */ + if (act == NULL) + return; - action_idcode_patch_check(ptr->id.data, act); + action_idcode_patch_check(ptr->id.data, act); - /* calculate then execute each curve */ - animsys_evaluate_fcurves(depsgraph, ptr, &act->curves, ctime); + /* calculate then execute each curve */ + animsys_evaluate_fcurves(depsgraph, ptr, &act->curves, ctime); } void animsys_evaluate_action(Depsgraph *depsgraph, PointerRNA *ptr, bAction *act, float ctime) { - animsys_evaluate_action_ex(depsgraph, ptr, act, ctime); + animsys_evaluate_action_ex(depsgraph, ptr, act, ctime); } /* ***************************************** */ @@ -1876,178 +1976,180 @@ void animsys_evaluate_action(Depsgraph *depsgraph, PointerRNA *ptr, bAction *act /* calculate influence of strip based for given frame based on blendin/out values */ static float nlastrip_get_influence(NlaStrip *strip, float cframe) { - /* sanity checks - normalize the blendin/out values? */ - strip->blendin = fabsf(strip->blendin); - strip->blendout = fabsf(strip->blendout); - - /* result depends on where frame is in respect to blendin/out values */ - if (IS_EQF(strip->blendin, 0.0f) == false && (cframe <= (strip->start + strip->blendin))) { - /* there is some blend-in */ - return fabsf(cframe - strip->start) / (strip->blendin); - } - else if (IS_EQF(strip->blendout, 0.0f) == false && (cframe >= (strip->end - strip->blendout))) { - /* there is some blend-out */ - return fabsf(strip->end - cframe) / (strip->blendout); - } - else { - /* in the middle of the strip, we should be full strength */ - return 1.0f; - } + /* sanity checks - normalize the blendin/out values? */ + strip->blendin = fabsf(strip->blendin); + strip->blendout = fabsf(strip->blendout); + + /* result depends on where frame is in respect to blendin/out values */ + if (IS_EQF(strip->blendin, 0.0f) == false && (cframe <= (strip->start + strip->blendin))) { + /* there is some blend-in */ + return fabsf(cframe - strip->start) / (strip->blendin); + } + else if (IS_EQF(strip->blendout, 0.0f) == false && (cframe >= (strip->end - strip->blendout))) { + /* there is some blend-out */ + return fabsf(strip->end - cframe) / (strip->blendout); + } + else { + /* in the middle of the strip, we should be full strength */ + return 1.0f; + } } /* evaluate the evaluation time and influence for the strip, storing the results in the strip */ static void nlastrip_evaluate_controls(Depsgraph *depsgraph, NlaStrip *strip, float ctime) { - /* now strip's evaluate F-Curves for these settings (if applicable) */ - if (strip->fcurves.first) { - PointerRNA strip_ptr; + /* now strip's evaluate F-Curves for these settings (if applicable) */ + if (strip->fcurves.first) { + PointerRNA strip_ptr; - /* create RNA-pointer needed to set values */ - RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr); + /* create RNA-pointer needed to set values */ + RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr); - /* execute these settings as per normal */ - animsys_evaluate_fcurves(depsgraph, &strip_ptr, &strip->fcurves, ctime); - } + /* execute these settings as per normal */ + animsys_evaluate_fcurves(depsgraph, &strip_ptr, &strip->fcurves, ctime); + } - /* analytically generate values for influence and time (if applicable) - * - we do this after the F-Curves have been evaluated to override the effects of those - * in case the override has been turned off. - */ - if ((strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) == 0) - strip->influence = nlastrip_get_influence(strip, ctime); + /* analytically generate values for influence and time (if applicable) + * - we do this after the F-Curves have been evaluated to override the effects of those + * in case the override has been turned off. + */ + if ((strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) == 0) + strip->influence = nlastrip_get_influence(strip, ctime); - /* Bypass evaluation time computation if time mapping is disabled. */ - if ((strip->flag & NLASTRIP_FLAG_NO_TIME_MAP) != 0) { - strip->strip_time = ctime; - return; - } + /* Bypass evaluation time computation if time mapping is disabled. */ + if ((strip->flag & NLASTRIP_FLAG_NO_TIME_MAP) != 0) { + strip->strip_time = ctime; + return; + } - if ((strip->flag & NLASTRIP_FLAG_USR_TIME) == 0) - strip->strip_time = nlastrip_get_frame(strip, ctime, NLATIME_CONVERT_EVAL); + if ((strip->flag & NLASTRIP_FLAG_USR_TIME) == 0) + strip->strip_time = nlastrip_get_frame(strip, ctime, NLATIME_CONVERT_EVAL); - /* if user can control the evaluation time (using F-Curves), consider the option which allows this time to be clamped - * to lie within extents of the action-clip, so that a steady changing rate of progress through several cycles of the clip - * can be achieved easily - */ - /* NOTE: if we add any more of these special cases, we better group them up nicely... */ - if ((strip->flag & NLASTRIP_FLAG_USR_TIME) && (strip->flag & NLASTRIP_FLAG_USR_TIME_CYCLIC)) - strip->strip_time = fmod(strip->strip_time - strip->actstart, strip->actend - strip->actstart); + /* if user can control the evaluation time (using F-Curves), consider the option which allows this time to be clamped + * to lie within extents of the action-clip, so that a steady changing rate of progress through several cycles of the clip + * can be achieved easily + */ + /* NOTE: if we add any more of these special cases, we better group them up nicely... */ + if ((strip->flag & NLASTRIP_FLAG_USR_TIME) && (strip->flag & NLASTRIP_FLAG_USR_TIME_CYCLIC)) + strip->strip_time = fmod(strip->strip_time - strip->actstart, strip->actend - strip->actstart); } /* gets the strip active at the current time for a list of strips for evaluation purposes */ -NlaEvalStrip *nlastrips_ctime_get_strip(Depsgraph *depsgraph, ListBase *list, ListBase *strips, short index, float ctime) -{ - NlaStrip *strip, *estrip = NULL; - NlaEvalStrip *nes; - short side = 0; - - /* loop over strips, checking if they fall within the range */ - for (strip = strips->first; strip; strip = strip->next) { - /* check if current time occurs within this strip */ - if (IN_RANGE_INCL(ctime, strip->start, strip->end) || (strip->flag & NLASTRIP_FLAG_NO_TIME_MAP)) { - /* this strip is active, so try to use it */ - estrip = strip; - side = NES_TIME_WITHIN; - break; - } - - /* if time occurred before current strip... */ - if (ctime < strip->start) { - if (strip == strips->first) { - /* before first strip - only try to use it if it extends backwards in time too */ - if (strip->extendmode == NLASTRIP_EXTEND_HOLD) - estrip = strip; - - /* side is 'before' regardless of whether there's a useful strip */ - side = NES_TIME_BEFORE; - } - else { - /* before next strip - previous strip has ended, but next hasn't begun, - * so blending mode depends on whether strip is being held or not... - * - only occurs when no transition strip added, otherwise the transition would have - * been picked up above... - */ - strip = strip->prev; - - if (strip->extendmode != NLASTRIP_EXTEND_NOTHING) - estrip = strip; - side = NES_TIME_AFTER; - } - break; - } - - /* if time occurred after current strip... */ - if (ctime > strip->end) { - /* only if this is the last strip should we do anything, and only if that is being held */ - if (strip == strips->last) { - if (strip->extendmode != NLASTRIP_EXTEND_NOTHING) - estrip = strip; - - side = NES_TIME_AFTER; - break; - } - - /* otherwise, skip... as the 'before' case will catch it more elegantly! */ - } - } - - /* check if a valid strip was found - * - must not be muted (i.e. will have contribution - */ - if ((estrip == NULL) || (estrip->flag & NLASTRIP_FLAG_MUTED)) - return NULL; - - /* if ctime was not within the boundaries of the strip, clamp! */ - switch (side) { - case NES_TIME_BEFORE: /* extend first frame only */ - ctime = estrip->start; - break; - case NES_TIME_AFTER: /* extend last frame only */ - ctime = estrip->end; - break; - } - - /* evaluate strip's evaluation controls - * - skip if no influence (i.e. same effect as muting the strip) - * - negative influence is not supported yet... how would that be defined? - */ - /* TODO: this sounds a bit hacky having a few isolated F-Curves stuck on some data it operates on... */ - nlastrip_evaluate_controls(depsgraph, estrip, ctime); - if (estrip->influence <= 0.0f) - return NULL; - - /* check if strip has valid data to evaluate, - * and/or perform any additional type-specific actions - */ - switch (estrip->type) { - case NLASTRIP_TYPE_CLIP: - /* clip must have some action to evaluate */ - if (estrip->act == NULL) - return NULL; - break; - case NLASTRIP_TYPE_TRANSITION: - /* there must be strips to transition from and to (i.e. prev and next required) */ - if (ELEM(NULL, estrip->prev, estrip->next)) - return NULL; - - /* evaluate controls for the relevant extents of the bordering strips... */ - nlastrip_evaluate_controls(depsgraph, estrip->prev, estrip->start); - nlastrip_evaluate_controls(depsgraph, estrip->next, estrip->end); - break; - } - - /* add to list of strips we need to evaluate */ - nes = MEM_callocN(sizeof(NlaEvalStrip), "NlaEvalStrip"); - - nes->strip = estrip; - nes->strip_mode = side; - nes->track_index = index; - nes->strip_time = estrip->strip_time; - - if (list) - BLI_addtail(list, nes); - - return nes; +NlaEvalStrip *nlastrips_ctime_get_strip( + Depsgraph *depsgraph, ListBase *list, ListBase *strips, short index, float ctime) +{ + NlaStrip *strip, *estrip = NULL; + NlaEvalStrip *nes; + short side = 0; + + /* loop over strips, checking if they fall within the range */ + for (strip = strips->first; strip; strip = strip->next) { + /* check if current time occurs within this strip */ + if (IN_RANGE_INCL(ctime, strip->start, strip->end) || + (strip->flag & NLASTRIP_FLAG_NO_TIME_MAP)) { + /* this strip is active, so try to use it */ + estrip = strip; + side = NES_TIME_WITHIN; + break; + } + + /* if time occurred before current strip... */ + if (ctime < strip->start) { + if (strip == strips->first) { + /* before first strip - only try to use it if it extends backwards in time too */ + if (strip->extendmode == NLASTRIP_EXTEND_HOLD) + estrip = strip; + + /* side is 'before' regardless of whether there's a useful strip */ + side = NES_TIME_BEFORE; + } + else { + /* before next strip - previous strip has ended, but next hasn't begun, + * so blending mode depends on whether strip is being held or not... + * - only occurs when no transition strip added, otherwise the transition would have + * been picked up above... + */ + strip = strip->prev; + + if (strip->extendmode != NLASTRIP_EXTEND_NOTHING) + estrip = strip; + side = NES_TIME_AFTER; + } + break; + } + + /* if time occurred after current strip... */ + if (ctime > strip->end) { + /* only if this is the last strip should we do anything, and only if that is being held */ + if (strip == strips->last) { + if (strip->extendmode != NLASTRIP_EXTEND_NOTHING) + estrip = strip; + + side = NES_TIME_AFTER; + break; + } + + /* otherwise, skip... as the 'before' case will catch it more elegantly! */ + } + } + + /* check if a valid strip was found + * - must not be muted (i.e. will have contribution + */ + if ((estrip == NULL) || (estrip->flag & NLASTRIP_FLAG_MUTED)) + return NULL; + + /* if ctime was not within the boundaries of the strip, clamp! */ + switch (side) { + case NES_TIME_BEFORE: /* extend first frame only */ + ctime = estrip->start; + break; + case NES_TIME_AFTER: /* extend last frame only */ + ctime = estrip->end; + break; + } + + /* evaluate strip's evaluation controls + * - skip if no influence (i.e. same effect as muting the strip) + * - negative influence is not supported yet... how would that be defined? + */ + /* TODO: this sounds a bit hacky having a few isolated F-Curves stuck on some data it operates on... */ + nlastrip_evaluate_controls(depsgraph, estrip, ctime); + if (estrip->influence <= 0.0f) + return NULL; + + /* check if strip has valid data to evaluate, + * and/or perform any additional type-specific actions + */ + switch (estrip->type) { + case NLASTRIP_TYPE_CLIP: + /* clip must have some action to evaluate */ + if (estrip->act == NULL) + return NULL; + break; + case NLASTRIP_TYPE_TRANSITION: + /* there must be strips to transition from and to (i.e. prev and next required) */ + if (ELEM(NULL, estrip->prev, estrip->next)) + return NULL; + + /* evaluate controls for the relevant extents of the bordering strips... */ + nlastrip_evaluate_controls(depsgraph, estrip->prev, estrip->start); + nlastrip_evaluate_controls(depsgraph, estrip->next, estrip->end); + break; + } + + /* add to list of strips we need to evaluate */ + nes = MEM_callocN(sizeof(NlaEvalStrip), "NlaEvalStrip"); + + nes->strip = estrip; + nes->strip_mode = side; + nes->track_index = index; + nes->strip_time = estrip->strip_time; + + if (list) + BLI_addtail(list, nes); + + return nes; } /* ---------------------- */ @@ -2055,20 +2157,20 @@ NlaEvalStrip *nlastrips_ctime_get_strip(Depsgraph *depsgraph, ListBase *list, Li /* Initialize a valid mask, allocating memory if necessary. */ static void nlavalidmask_init(NlaValidMask *mask, int bits) { - if (BLI_BITMAP_SIZE(bits) > sizeof(mask->buffer)) { - mask->ptr = BLI_BITMAP_NEW(bits, "NlaValidMask"); - } - else { - mask->ptr = mask->buffer; - } + if (BLI_BITMAP_SIZE(bits) > sizeof(mask->buffer)) { + mask->ptr = BLI_BITMAP_NEW(bits, "NlaValidMask"); + } + else { + mask->ptr = mask->buffer; + } } /* Free allocated memory for the mask. */ static void nlavalidmask_free(NlaValidMask *mask) { - if (mask->ptr != mask->buffer) { - MEM_freeN(mask->ptr); - } + if (mask->ptr != mask->buffer) { + MEM_freeN(mask->ptr); + } } /* ---------------------- */ @@ -2076,18 +2178,17 @@ static void nlavalidmask_free(NlaValidMask *mask) /* Hashing functions for NlaEvalChannelKey. */ static uint nlaevalchan_keyhash(const void *ptr) { - const NlaEvalChannelKey *key = ptr; - uint hash = BLI_ghashutil_ptrhash(key->ptr.data); - return hash ^ BLI_ghashutil_ptrhash(key->prop); + const NlaEvalChannelKey *key = ptr; + uint hash = BLI_ghashutil_ptrhash(key->ptr.data); + return hash ^ BLI_ghashutil_ptrhash(key->prop); } static bool nlaevalchan_keycmp(const void *a, const void *b) { - const NlaEvalChannelKey *A = a; - const NlaEvalChannelKey *B = b; + const NlaEvalChannelKey *A = a; + const NlaEvalChannelKey *B = b; - return ((A->ptr.data != B->ptr.data) || - (A->prop != B->prop)); + return ((A->ptr.data != B->ptr.data) || (A->prop != B->prop)); } /* ---------------------- */ @@ -2095,119 +2196,127 @@ static bool nlaevalchan_keycmp(const void *a, const void *b) /* Allocate a new blending value snapshot for the channel. */ static NlaEvalChannelSnapshot *nlaevalchan_snapshot_new(NlaEvalChannel *nec) { - int length = nec->base_snapshot.length; + int length = nec->base_snapshot.length; - size_t byte_size = sizeof(NlaEvalChannelSnapshot) + sizeof(float) * length; - NlaEvalChannelSnapshot *nec_snapshot = MEM_callocN(byte_size, "NlaEvalChannelSnapshot"); + size_t byte_size = sizeof(NlaEvalChannelSnapshot) + sizeof(float) * length; + NlaEvalChannelSnapshot *nec_snapshot = MEM_callocN(byte_size, "NlaEvalChannelSnapshot"); - nec_snapshot->channel = nec; - nec_snapshot->length = length; + nec_snapshot->channel = nec; + nec_snapshot->length = length; - return nec_snapshot; + return nec_snapshot; } /* Free a channel's blending value snapshot. */ static void nlaevalchan_snapshot_free(NlaEvalChannelSnapshot *nec_snapshot) { - BLI_assert(!nec_snapshot->is_base); + BLI_assert(!nec_snapshot->is_base); - MEM_freeN(nec_snapshot); + MEM_freeN(nec_snapshot); } /* Copy all data in the snapshot. */ -static void nlaevalchan_snapshot_copy(NlaEvalChannelSnapshot *dst, const NlaEvalChannelSnapshot *src) +static void nlaevalchan_snapshot_copy(NlaEvalChannelSnapshot *dst, + const NlaEvalChannelSnapshot *src) { - BLI_assert(dst->channel == src->channel); + BLI_assert(dst->channel == src->channel); - memcpy(dst->values, src->values, sizeof(float) * dst->length); + memcpy(dst->values, src->values, sizeof(float) * dst->length); } /* ---------------------- */ /* Initialize a blending state snapshot structure. */ -static void nlaeval_snapshot_init(NlaEvalSnapshot *snapshot, NlaEvalData *nlaeval, NlaEvalSnapshot *base) +static void nlaeval_snapshot_init(NlaEvalSnapshot *snapshot, + NlaEvalData *nlaeval, + NlaEvalSnapshot *base) { - snapshot->base = base; - snapshot->size = MAX2(16, nlaeval->num_channels); - snapshot->channels = MEM_callocN(sizeof(*snapshot->channels) * snapshot->size, "NlaEvalSnapshot::channels"); + snapshot->base = base; + snapshot->size = MAX2(16, nlaeval->num_channels); + snapshot->channels = MEM_callocN(sizeof(*snapshot->channels) * snapshot->size, + "NlaEvalSnapshot::channels"); } /* Retrieve the individual channel snapshot. */ static NlaEvalChannelSnapshot *nlaeval_snapshot_get(NlaEvalSnapshot *snapshot, int index) { - return (index < snapshot->size) ? snapshot->channels[index] : NULL; + return (index < snapshot->size) ? snapshot->channels[index] : NULL; } /* Ensure at least this number of slots exists. */ static void nlaeval_snapshot_ensure_size(NlaEvalSnapshot *snapshot, int size) { - if (size > snapshot->size) { - snapshot->size *= 2; - CLAMP_MIN(snapshot->size, size); - CLAMP_MIN(snapshot->size, 16); + if (size > snapshot->size) { + snapshot->size *= 2; + CLAMP_MIN(snapshot->size, size); + CLAMP_MIN(snapshot->size, 16); - size_t byte_size = sizeof(*snapshot->channels) * snapshot->size; - snapshot->channels = MEM_recallocN_id(snapshot->channels, byte_size, "NlaEvalSnapshot::channels"); - } + size_t byte_size = sizeof(*snapshot->channels) * snapshot->size; + snapshot->channels = MEM_recallocN_id( + snapshot->channels, byte_size, "NlaEvalSnapshot::channels"); + } } /* Retrieve the address of a slot in the blending state snapshot for this channel (may realloc). */ -static NlaEvalChannelSnapshot **nlaeval_snapshot_ensure_slot(NlaEvalSnapshot *snapshot, NlaEvalChannel *nec) +static NlaEvalChannelSnapshot **nlaeval_snapshot_ensure_slot(NlaEvalSnapshot *snapshot, + NlaEvalChannel *nec) { - nlaeval_snapshot_ensure_size(snapshot, nec->owner->num_channels); - return &snapshot->channels[nec->index]; + nlaeval_snapshot_ensure_size(snapshot, nec->owner->num_channels); + return &snapshot->channels[nec->index]; } /* Retrieve the blending snapshot for the specified channel, with fallback to base. */ -static NlaEvalChannelSnapshot *nlaeval_snapshot_find_channel(NlaEvalSnapshot *snapshot, NlaEvalChannel *nec) +static NlaEvalChannelSnapshot *nlaeval_snapshot_find_channel(NlaEvalSnapshot *snapshot, + NlaEvalChannel *nec) { - while (snapshot != NULL) { - NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_get(snapshot, nec->index); - if (nec_snapshot != NULL) { - return nec_snapshot; - } - snapshot = snapshot->base; - } + while (snapshot != NULL) { + NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_get(snapshot, nec->index); + if (nec_snapshot != NULL) { + return nec_snapshot; + } + snapshot = snapshot->base; + } - return &nec->base_snapshot; + return &nec->base_snapshot; } /* Retrieve or create the channel value snapshot, copying from the other snapshot (or default values) */ -static NlaEvalChannelSnapshot *nlaeval_snapshot_ensure_channel(NlaEvalSnapshot *snapshot, NlaEvalChannel *nec) +static NlaEvalChannelSnapshot *nlaeval_snapshot_ensure_channel(NlaEvalSnapshot *snapshot, + NlaEvalChannel *nec) { - NlaEvalChannelSnapshot **slot = nlaeval_snapshot_ensure_slot(snapshot, nec); + NlaEvalChannelSnapshot **slot = nlaeval_snapshot_ensure_slot(snapshot, nec); - if (*slot == NULL) { - NlaEvalChannelSnapshot *base_snapshot, *nec_snapshot; + if (*slot == NULL) { + NlaEvalChannelSnapshot *base_snapshot, *nec_snapshot; - nec_snapshot = nlaevalchan_snapshot_new(nec); - base_snapshot = nlaeval_snapshot_find_channel(snapshot->base, nec); + nec_snapshot = nlaevalchan_snapshot_new(nec); + base_snapshot = nlaeval_snapshot_find_channel(snapshot->base, nec); - nlaevalchan_snapshot_copy(nec_snapshot, base_snapshot); + nlaevalchan_snapshot_copy(nec_snapshot, base_snapshot); - *slot = nec_snapshot; - } + *slot = nec_snapshot; + } - return *slot; + return *slot; } /* Free all memory owned by this blending snapshot structure. */ static void nlaeval_snapshot_free_data(NlaEvalSnapshot *snapshot) { - if (snapshot->channels != NULL) { - for (int i = 0; i < snapshot->size; i++) { - NlaEvalChannelSnapshot *nec_snapshot = snapshot->channels[i]; - if (nec_snapshot != NULL) { - nlaevalchan_snapshot_free(nec_snapshot); - } - } + if (snapshot->channels != NULL) { + for (int i = 0; i < snapshot->size; i++) { + NlaEvalChannelSnapshot *nec_snapshot = snapshot->channels[i]; + if (nec_snapshot != NULL) { + nlaevalchan_snapshot_free(nec_snapshot); + } + } - MEM_freeN(snapshot->channels); - } + MEM_freeN(snapshot->channels); + } - snapshot->base = NULL; - snapshot->size = 0; - snapshot->channels = NULL; + snapshot->base = NULL; + snapshot->size = 0; + snapshot->channels = NULL; } /* ---------------------- */ @@ -2215,240 +2324,247 @@ static void nlaeval_snapshot_free_data(NlaEvalSnapshot *snapshot) /* Free memory owned by this evaluation channel. */ static void nlaevalchan_free_data(NlaEvalChannel *nec) { - nlavalidmask_free(&nec->valid); + nlavalidmask_free(&nec->valid); - if (nec->blend_snapshot != NULL) { - nlaevalchan_snapshot_free(nec->blend_snapshot); - } + if (nec->blend_snapshot != NULL) { + nlaevalchan_snapshot_free(nec->blend_snapshot); + } } /* Initialize a full NLA evaluation state structure. */ static void nlaeval_init(NlaEvalData *nlaeval) { - memset(nlaeval, 0, sizeof(*nlaeval)); + memset(nlaeval, 0, sizeof(*nlaeval)); - nlaeval->path_hash = BLI_ghash_str_new("NlaEvalData::path_hash"); - nlaeval->key_hash = BLI_ghash_new(nlaevalchan_keyhash, nlaevalchan_keycmp, "NlaEvalData::key_hash"); + nlaeval->path_hash = BLI_ghash_str_new("NlaEvalData::path_hash"); + nlaeval->key_hash = BLI_ghash_new( + nlaevalchan_keyhash, nlaevalchan_keycmp, "NlaEvalData::key_hash"); } static void nlaeval_free(NlaEvalData *nlaeval) { - /* Delete base snapshot - its channels are part of NlaEvalChannel and shouldn't be freed. */ - MEM_SAFE_FREE(nlaeval->base_snapshot.channels); + /* Delete base snapshot - its channels are part of NlaEvalChannel and shouldn't be freed. */ + MEM_SAFE_FREE(nlaeval->base_snapshot.channels); - /* Delete result snapshot. */ - nlaeval_snapshot_free_data(&nlaeval->eval_snapshot); + /* Delete result snapshot. */ + nlaeval_snapshot_free_data(&nlaeval->eval_snapshot); - /* Delete channels. */ - for (NlaEvalChannel *nec = nlaeval->channels.first; nec; nec = nec->next) { - nlaevalchan_free_data(nec); - } + /* Delete channels. */ + for (NlaEvalChannel *nec = nlaeval->channels.first; nec; nec = nec->next) { + nlaevalchan_free_data(nec); + } - BLI_freelistN(&nlaeval->channels); - BLI_ghash_free(nlaeval->path_hash, NULL, NULL); - BLI_ghash_free(nlaeval->key_hash, NULL, NULL); + BLI_freelistN(&nlaeval->channels); + BLI_ghash_free(nlaeval->path_hash, NULL, NULL); + BLI_ghash_free(nlaeval->key_hash, NULL, NULL); } /* ---------------------- */ static int nlaevalchan_validate_index(NlaEvalChannel *nec, int index) { - if (nec->is_array) { - if (index >= 0 && index < nec->base_snapshot.length) { - return index; - } + if (nec->is_array) { + if (index >= 0 && index < nec->base_snapshot.length) { + return index; + } - return -1; - } - else { - return 0; - } + return -1; + } + else { + return 0; + } } /* Initialise default values for NlaEvalChannel from the property data. */ static void nlaevalchan_get_default_values(NlaEvalChannel *nec, float *r_values) { - PointerRNA *ptr = &nec->key.ptr; - PropertyRNA *prop = nec->key.prop; - int length = nec->base_snapshot.length; - - /* Use unit quaternion for quaternion properties. */ - if (nec->mix_mode == NEC_MIX_QUATERNION) { - unit_qt(r_values); - return; - } - /* Use all zero for Axis-Angle properties. */ - if (nec->mix_mode == NEC_MIX_AXIS_ANGLE) { - zero_v4(r_values); - return; - } - - /* NOTE: while this doesn't work for all RNA properties as default values aren't in fact - * set properly for most of them, at least the common ones (which also happen to get used - * in NLA strips a lot, e.g. scale) are set correctly. - */ - if (RNA_property_array_check(prop)) { - BLI_assert(length == RNA_property_array_length(ptr, prop)); - bool *tmp_bool; - int *tmp_int; - - switch (RNA_property_type(prop)) { - case PROP_BOOLEAN: - tmp_bool = MEM_malloc_arrayN(sizeof(*tmp_bool), length, __func__); - RNA_property_boolean_get_default_array(ptr, prop, tmp_bool); - for (int i = 0; i < length; i++) { - r_values[i] = (float)tmp_bool[i]; - } - MEM_freeN(tmp_bool); - break; - case PROP_INT: - tmp_int = MEM_malloc_arrayN(sizeof(*tmp_int), length, __func__); - RNA_property_int_get_default_array(ptr, prop, tmp_int); - for (int i = 0; i < length; i++) { - r_values[i] = (float)tmp_int[i]; - } - MEM_freeN(tmp_int); - break; - case PROP_FLOAT: - RNA_property_float_get_default_array(ptr, prop, r_values); - break; - default: - memset(r_values, 0, sizeof(float) * length); - } - } - else { - BLI_assert(length == 1); - - switch (RNA_property_type(prop)) { - case PROP_BOOLEAN: - *r_values = (float)RNA_property_boolean_get_default(ptr, prop); - break; - case PROP_INT: - *r_values = (float)RNA_property_int_get_default(ptr, prop); - break; - case PROP_FLOAT: - *r_values = RNA_property_float_get_default(ptr, prop); - break; - case PROP_ENUM: - *r_values = (float)RNA_property_enum_get_default(ptr, prop); - break; - default: - *r_values = 0.0f; - } - } - - /* Ensure multiplicative properties aren't reset to 0. */ - if (nec->mix_mode == NEC_MIX_MULTIPLY) { - for (int i = 0; i < length; i++) { - if (r_values[i] == 0.0f) { - r_values[i] = 1.0f; - } - } - } + PointerRNA *ptr = &nec->key.ptr; + PropertyRNA *prop = nec->key.prop; + int length = nec->base_snapshot.length; + + /* Use unit quaternion for quaternion properties. */ + if (nec->mix_mode == NEC_MIX_QUATERNION) { + unit_qt(r_values); + return; + } + /* Use all zero for Axis-Angle properties. */ + if (nec->mix_mode == NEC_MIX_AXIS_ANGLE) { + zero_v4(r_values); + return; + } + + /* NOTE: while this doesn't work for all RNA properties as default values aren't in fact + * set properly for most of them, at least the common ones (which also happen to get used + * in NLA strips a lot, e.g. scale) are set correctly. + */ + if (RNA_property_array_check(prop)) { + BLI_assert(length == RNA_property_array_length(ptr, prop)); + bool *tmp_bool; + int *tmp_int; + + switch (RNA_property_type(prop)) { + case PROP_BOOLEAN: + tmp_bool = MEM_malloc_arrayN(sizeof(*tmp_bool), length, __func__); + RNA_property_boolean_get_default_array(ptr, prop, tmp_bool); + for (int i = 0; i < length; i++) { + r_values[i] = (float)tmp_bool[i]; + } + MEM_freeN(tmp_bool); + break; + case PROP_INT: + tmp_int = MEM_malloc_arrayN(sizeof(*tmp_int), length, __func__); + RNA_property_int_get_default_array(ptr, prop, tmp_int); + for (int i = 0; i < length; i++) { + r_values[i] = (float)tmp_int[i]; + } + MEM_freeN(tmp_int); + break; + case PROP_FLOAT: + RNA_property_float_get_default_array(ptr, prop, r_values); + break; + default: + memset(r_values, 0, sizeof(float) * length); + } + } + else { + BLI_assert(length == 1); + + switch (RNA_property_type(prop)) { + case PROP_BOOLEAN: + *r_values = (float)RNA_property_boolean_get_default(ptr, prop); + break; + case PROP_INT: + *r_values = (float)RNA_property_int_get_default(ptr, prop); + break; + case PROP_FLOAT: + *r_values = RNA_property_float_get_default(ptr, prop); + break; + case PROP_ENUM: + *r_values = (float)RNA_property_enum_get_default(ptr, prop); + break; + default: + *r_values = 0.0f; + } + } + + /* Ensure multiplicative properties aren't reset to 0. */ + if (nec->mix_mode == NEC_MIX_MULTIPLY) { + for (int i = 0; i < length; i++) { + if (r_values[i] == 0.0f) { + r_values[i] = 1.0f; + } + } + } } static char nlaevalchan_detect_mix_mode(NlaEvalChannelKey *key, int length) { - PropertySubType subtype = RNA_property_subtype(key->prop); + PropertySubType subtype = RNA_property_subtype(key->prop); - if (subtype == PROP_QUATERNION && length == 4) { - return NEC_MIX_QUATERNION; - } - else if (subtype == PROP_AXISANGLE && length == 4) { - return NEC_MIX_AXIS_ANGLE; - } - else if (RNA_property_flag(key->prop) & PROP_PROPORTIONAL) { - return NEC_MIX_MULTIPLY; - } - else { - return NEC_MIX_ADD; - } + if (subtype == PROP_QUATERNION && length == 4) { + return NEC_MIX_QUATERNION; + } + else if (subtype == PROP_AXISANGLE && length == 4) { + return NEC_MIX_AXIS_ANGLE; + } + else if (RNA_property_flag(key->prop) & PROP_PROPORTIONAL) { + return NEC_MIX_MULTIPLY; + } + else { + return NEC_MIX_ADD; + } } /* Verify that an appropriate NlaEvalChannel for this property exists. */ -static NlaEvalChannel *nlaevalchan_verify_key(NlaEvalData *nlaeval, const char *path, NlaEvalChannelKey *key) +static NlaEvalChannel *nlaevalchan_verify_key(NlaEvalData *nlaeval, + const char *path, + NlaEvalChannelKey *key) { - /* Look it up in the key hash. */ - NlaEvalChannel **p_key_nec; - NlaEvalChannelKey **p_key; - bool found_key = BLI_ghash_ensure_p_ex(nlaeval->key_hash, key, (void ***)&p_key, (void ***)&p_key_nec); + /* Look it up in the key hash. */ + NlaEvalChannel **p_key_nec; + NlaEvalChannelKey **p_key; + bool found_key = BLI_ghash_ensure_p_ex( + nlaeval->key_hash, key, (void ***)&p_key, (void ***)&p_key_nec); - if (found_key) { - return *p_key_nec; - } + if (found_key) { + return *p_key_nec; + } - /* Create the channel. */ - bool is_array = RNA_property_array_check(key->prop); - int length = is_array ? RNA_property_array_length(&key->ptr, key->prop) : 1; + /* Create the channel. */ + bool is_array = RNA_property_array_check(key->prop); + int length = is_array ? RNA_property_array_length(&key->ptr, key->prop) : 1; - NlaEvalChannel *nec = MEM_callocN(sizeof(NlaEvalChannel) + sizeof(float) * length, "NlaEvalChannel"); + NlaEvalChannel *nec = MEM_callocN(sizeof(NlaEvalChannel) + sizeof(float) * length, + "NlaEvalChannel"); - /* Initialize the channel. */ - nec->rna_path = path; - nec->key = *key; + /* Initialize the channel. */ + nec->rna_path = path; + nec->key = *key; - nec->owner = nlaeval; - nec->index = nlaeval->num_channels++; - nec->is_array = is_array; + nec->owner = nlaeval; + nec->index = nlaeval->num_channels++; + nec->is_array = is_array; - nec->mix_mode = nlaevalchan_detect_mix_mode(key, length); + nec->mix_mode = nlaevalchan_detect_mix_mode(key, length); - nlavalidmask_init(&nec->valid, length); + nlavalidmask_init(&nec->valid, length); - nec->base_snapshot.channel = nec; - nec->base_snapshot.length = length; - nec->base_snapshot.is_base = true; + nec->base_snapshot.channel = nec; + nec->base_snapshot.length = length; + nec->base_snapshot.is_base = true; - nlaevalchan_get_default_values(nec, nec->base_snapshot.values); + nlaevalchan_get_default_values(nec, nec->base_snapshot.values); - /* Store channel in data structures. */ - BLI_addtail(&nlaeval->channels, nec); + /* Store channel in data structures. */ + BLI_addtail(&nlaeval->channels, nec); - *nlaeval_snapshot_ensure_slot(&nlaeval->base_snapshot, nec) = &nec->base_snapshot; + *nlaeval_snapshot_ensure_slot(&nlaeval->base_snapshot, nec) = &nec->base_snapshot; - *p_key_nec = nec; - *p_key = &nec->key; + *p_key_nec = nec; + *p_key = &nec->key; - return nec; + return nec; } /* Verify that an appropriate NlaEvalChannel for this path exists. */ static NlaEvalChannel *nlaevalchan_verify(PointerRNA *ptr, NlaEvalData *nlaeval, const char *path) { - if (path == NULL) { - return NULL; - } + if (path == NULL) { + return NULL; + } - /* Lookup the path in the path based hash. */ - NlaEvalChannel **p_path_nec; - bool found_path = BLI_ghash_ensure_p(nlaeval->path_hash, (void *)path, (void ***)&p_path_nec); + /* Lookup the path in the path based hash. */ + NlaEvalChannel **p_path_nec; + bool found_path = BLI_ghash_ensure_p(nlaeval->path_hash, (void *)path, (void ***)&p_path_nec); - if (found_path) { - return *p_path_nec; - } + if (found_path) { + return *p_path_nec; + } - /* Resolve the property and look it up in the key hash. */ - NlaEvalChannelKey key; + /* Resolve the property and look it up in the key hash. */ + NlaEvalChannelKey key; - if (!RNA_path_resolve_property(ptr, path, &key.ptr, &key.prop)) { - /* Report failure to resolve the path. */ - if (G.debug & G_DEBUG) { - CLOG_WARN(&LOG, "Animato: Invalid path. ID = '%s', '%s'", - (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>", path); - } + if (!RNA_path_resolve_property(ptr, path, &key.ptr, &key.prop)) { + /* Report failure to resolve the path. */ + if (G.debug & G_DEBUG) { + CLOG_WARN(&LOG, + "Animato: Invalid path. ID = '%s', '%s'", + (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>", + path); + } - /* Cache NULL result. */ - *p_path_nec = NULL; - return NULL; - } + /* Cache NULL result. */ + *p_path_nec = NULL; + return NULL; + } - NlaEvalChannel *nec = nlaevalchan_verify_key(nlaeval, path, &key); + NlaEvalChannel *nec = nlaevalchan_verify_key(nlaeval, path, &key); - if (nec->rna_path == NULL) { - nec->rna_path = path; - } + if (nec->rna_path == NULL) { + nec->rna_path = path; + } - return *p_path_nec = nec; + return *p_path_nec = nec; } /* ---------------------- */ @@ -2456,307 +2572,333 @@ static NlaEvalChannel *nlaevalchan_verify(PointerRNA *ptr, NlaEvalData *nlaeval, /* accumulate the old and new values of a channel according to mode and influence */ static float nla_blend_value(int blendmode, float old_value, float value, float inf) { - /* optimisation: no need to try applying if there is no influence */ - if (IS_EQF(inf, 0.0f)) { - return old_value; - } - - /* perform blending */ - switch (blendmode) { - case NLASTRIP_MODE_ADD: - /* simply add the scaled value on to the stack */ - return old_value + (value * inf); - - case NLASTRIP_MODE_SUBTRACT: - /* simply subtract the scaled value from the stack */ - return old_value - (value * inf); - - case NLASTRIP_MODE_MULTIPLY: - /* multiply the scaled value with the stack */ - /* Formula Used: - * result = fac * (a * b) + (1 - fac) * a - */ - return inf * (old_value * value) + (1 - inf) * old_value; - - case NLASTRIP_MODE_COMBINE: - BLI_assert(!"combine mode"); - ATTR_FALLTHROUGH; - - case NLASTRIP_MODE_REPLACE: - default: /* TODO: do we really want to blend by default? it seems more uses might prefer add... */ - /* do linear interpolation - * - the influence of the accumulated data (elsewhere, that is called dstweight) - * is 1 - influence, since the strip's influence is srcweight - */ - return old_value * (1.0f - inf) + (value * inf); - } + /* optimisation: no need to try applying if there is no influence */ + if (IS_EQF(inf, 0.0f)) { + return old_value; + } + + /* perform blending */ + switch (blendmode) { + case NLASTRIP_MODE_ADD: + /* simply add the scaled value on to the stack */ + return old_value + (value * inf); + + case NLASTRIP_MODE_SUBTRACT: + /* simply subtract the scaled value from the stack */ + return old_value - (value * inf); + + case NLASTRIP_MODE_MULTIPLY: + /* multiply the scaled value with the stack */ + /* Formula Used: + * result = fac * (a * b) + (1 - fac) * a + */ + return inf * (old_value * value) + (1 - inf) * old_value; + + case NLASTRIP_MODE_COMBINE: + BLI_assert(!"combine mode"); + ATTR_FALLTHROUGH; + + case NLASTRIP_MODE_REPLACE: + default + : /* TODO: do we really want to blend by default? it seems more uses might prefer add... */ + /* do linear interpolation + * - the influence of the accumulated data (elsewhere, that is called dstweight) + * is 1 - influence, since the strip's influence is srcweight + */ + return old_value * (1.0f - inf) + (value * inf); + } } /* accumulate the old and new values of a channel according to mode and influence */ -static float nla_combine_value(int mix_mode, float base_value, float old_value, float value, float inf) +static float nla_combine_value( + int mix_mode, float base_value, float old_value, float value, float inf) { - /* optimisation: no need to try applying if there is no influence */ - if (IS_EQF(inf, 0.0f)) { - return old_value; - } + /* optimisation: no need to try applying if there is no influence */ + if (IS_EQF(inf, 0.0f)) { + return old_value; + } - /* perform blending */ - switch (mix_mode) { - case NEC_MIX_ADD: - case NEC_MIX_AXIS_ANGLE: - return old_value + (value - base_value) * inf; + /* perform blending */ + switch (mix_mode) { + case NEC_MIX_ADD: + case NEC_MIX_AXIS_ANGLE: + return old_value + (value - base_value) * inf; - case NEC_MIX_MULTIPLY: - if (base_value == 0.0f) { - base_value = 1.0f; - } - return old_value * powf(value / base_value, inf); + case NEC_MIX_MULTIPLY: + if (base_value == 0.0f) { + base_value = 1.0f; + } + return old_value * powf(value / base_value, inf); - case NEC_MIX_QUATERNION: - default: - BLI_assert(!"invalid mix mode"); - return old_value; - } + case NEC_MIX_QUATERNION: + default: + BLI_assert(!"invalid mix mode"); + return old_value; + } } /* compute the value that would blend to the desired target value using nla_blend_value */ -static bool nla_invert_blend_value(int blend_mode, float old_value, float target_value, float influence, float *r_value) -{ - switch (blend_mode) { - case NLASTRIP_MODE_ADD: - *r_value = (target_value - old_value) / influence; - return true; - - case NLASTRIP_MODE_SUBTRACT: - *r_value = (old_value - target_value) / influence; - return true; - - case NLASTRIP_MODE_MULTIPLY: - if (old_value == 0.0f) { - /* Resolve 0/0 to 1. */ - if (target_value == 0.0f) { - *r_value = 1.0f; - return true; - } - /* Division by zero. */ - return false; - } - else { - *r_value = (target_value - old_value) / influence / old_value + 1.0f; - return true; - } - - case NLASTRIP_MODE_COMBINE: - BLI_assert(!"combine mode"); - ATTR_FALLTHROUGH; - - case NLASTRIP_MODE_REPLACE: - default: - *r_value = (target_value - old_value) / influence + old_value; - return true; - } +static bool nla_invert_blend_value( + int blend_mode, float old_value, float target_value, float influence, float *r_value) +{ + switch (blend_mode) { + case NLASTRIP_MODE_ADD: + *r_value = (target_value - old_value) / influence; + return true; + + case NLASTRIP_MODE_SUBTRACT: + *r_value = (old_value - target_value) / influence; + return true; + + case NLASTRIP_MODE_MULTIPLY: + if (old_value == 0.0f) { + /* Resolve 0/0 to 1. */ + if (target_value == 0.0f) { + *r_value = 1.0f; + return true; + } + /* Division by zero. */ + return false; + } + else { + *r_value = (target_value - old_value) / influence / old_value + 1.0f; + return true; + } + + case NLASTRIP_MODE_COMBINE: + BLI_assert(!"combine mode"); + ATTR_FALLTHROUGH; + + case NLASTRIP_MODE_REPLACE: + default: + *r_value = (target_value - old_value) / influence + old_value; + return true; + } } /* compute the value that would blend to the desired target value using nla_combine_value */ -static bool nla_invert_combine_value(int mix_mode, float base_value, float old_value, float target_value, float influence, float *r_value) -{ - switch (mix_mode) { - case NEC_MIX_ADD: - case NEC_MIX_AXIS_ANGLE: - *r_value = base_value + (target_value - old_value) / influence; - return true; - - case NEC_MIX_MULTIPLY: - if (base_value == 0.0f) { - base_value = 1.0f; - } - if (old_value == 0.0f) { - /* Resolve 0/0 to 1. */ - if (target_value == 0.0f) { - *r_value = base_value; - return true; - } - /* Division by zero. */ - return false; - } - else { - *r_value = base_value * powf(target_value / old_value, 1.0f / influence); - return true; - } - - case NEC_MIX_QUATERNION: - default: - BLI_assert(!"invalid mix mode"); - return false; - } +static bool nla_invert_combine_value(int mix_mode, + float base_value, + float old_value, + float target_value, + float influence, + float *r_value) +{ + switch (mix_mode) { + case NEC_MIX_ADD: + case NEC_MIX_AXIS_ANGLE: + *r_value = base_value + (target_value - old_value) / influence; + return true; + + case NEC_MIX_MULTIPLY: + if (base_value == 0.0f) { + base_value = 1.0f; + } + if (old_value == 0.0f) { + /* Resolve 0/0 to 1. */ + if (target_value == 0.0f) { + *r_value = base_value; + return true; + } + /* Division by zero. */ + return false; + } + else { + *r_value = base_value * powf(target_value / old_value, 1.0f / influence); + return true; + } + + case NEC_MIX_QUATERNION: + default: + BLI_assert(!"invalid mix mode"); + return false; + } } /* accumulate quaternion channels for Combine mode according to influence */ -static void nla_combine_quaternion(const float old_values[4], const float values[4], float influence, float result[4]) +static void nla_combine_quaternion(const float old_values[4], + const float values[4], + float influence, + float result[4]) { - float tmp_old[4], tmp_new[4]; + float tmp_old[4], tmp_new[4]; - normalize_qt_qt(tmp_old, old_values); - normalize_qt_qt(tmp_new, values); + normalize_qt_qt(tmp_old, old_values); + normalize_qt_qt(tmp_new, values); - pow_qt_fl_normalized(tmp_new, influence); - mul_qt_qtqt(result, tmp_old, tmp_new); + pow_qt_fl_normalized(tmp_new, influence); + mul_qt_qtqt(result, tmp_old, tmp_new); } /* invert accumulation of quaternion channels for Combine mode according to influence */ -static void nla_invert_combine_quaternion(const float old_values[4], const float values[4], float influence, float result[4]) +static void nla_invert_combine_quaternion(const float old_values[4], + const float values[4], + float influence, + float result[4]) { - float tmp_old[4], tmp_new[4]; + float tmp_old[4], tmp_new[4]; - normalize_qt_qt(tmp_old, old_values); - normalize_qt_qt(tmp_new, values); - invert_qt_normalized(tmp_old); + normalize_qt_qt(tmp_old, old_values); + normalize_qt_qt(tmp_new, values); + invert_qt_normalized(tmp_old); - mul_qt_qtqt(result, tmp_old, tmp_new); - pow_qt_fl_normalized(result, 1.0f / influence); + mul_qt_qtqt(result, tmp_old, tmp_new); + pow_qt_fl_normalized(result, 1.0f / influence); } /* Data about the current blend mode. */ typedef struct NlaBlendData { - NlaEvalSnapshot *snapshot; - int mode; - float influence; + NlaEvalSnapshot *snapshot; + int mode; + float influence; - NlaEvalChannel *blend_queue; + NlaEvalChannel *blend_queue; } NlaBlendData; /* Queue the channel for deferred blending. */ static NlaEvalChannelSnapshot *nlaevalchan_queue_blend(NlaBlendData *blend, NlaEvalChannel *nec) { - if (!nec->in_blend) { - if (nec->blend_snapshot == NULL) { - nec->blend_snapshot = nlaevalchan_snapshot_new(nec); - } + if (!nec->in_blend) { + if (nec->blend_snapshot == NULL) { + nec->blend_snapshot = nlaevalchan_snapshot_new(nec); + } - nec->in_blend = true; - nlaevalchan_snapshot_copy(nec->blend_snapshot, &nec->base_snapshot); + nec->in_blend = true; + nlaevalchan_snapshot_copy(nec->blend_snapshot, &nec->base_snapshot); - nec->next_blend = blend->blend_queue; - blend->blend_queue = nec; - } + nec->next_blend = blend->blend_queue; + blend->blend_queue = nec; + } - return nec->blend_snapshot; + return nec->blend_snapshot; } /* Accumulate (i.e. blend) the given value on to the channel it affects. */ -static bool nlaeval_blend_value(NlaBlendData *blend, NlaEvalChannel *nec, int array_index, float value) -{ - if (nec == NULL) { - return false; - } - - int index = nlaevalchan_validate_index(nec, array_index); - - if (index < 0) { - if (G.debug & G_DEBUG) { - ID *id = nec->key.ptr.id.data; - CLOG_WARN(&LOG, "Animato: Invalid array index. ID = '%s', '%s[%d]', array length is %d", - id ? (id->name + 2) : "<No ID>", nec->rna_path, array_index, nec->base_snapshot.length); - } - - return false; - } - - if (nec->mix_mode == NEC_MIX_QUATERNION) { - /* For quaternion properties, always output all sub-channels. */ - BLI_bitmap_set_all(nec->valid.ptr, true, 4); - } - else { - BLI_BITMAP_ENABLE(nec->valid.ptr, index); - } - - NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_ensure_channel(blend->snapshot, nec); - float *p_value = &nec_snapshot->values[index]; - - if (blend->mode == NLASTRIP_MODE_COMBINE) { - /* Quaternion blending is deferred until all sub-channel values are known. */ - if (nec->mix_mode == NEC_MIX_QUATERNION) { - NlaEvalChannelSnapshot *blend_snapshot = nlaevalchan_queue_blend(blend, nec); - - blend_snapshot->values[index] = value; - } - else { - float base_value = nec->base_snapshot.values[index]; - - *p_value = nla_combine_value(nec->mix_mode, base_value, *p_value, value, blend->influence); - } - } - else { - *p_value = nla_blend_value(blend->mode, *p_value, value, blend->influence); - } - - return true; +static bool nlaeval_blend_value(NlaBlendData *blend, + NlaEvalChannel *nec, + int array_index, + float value) +{ + if (nec == NULL) { + return false; + } + + int index = nlaevalchan_validate_index(nec, array_index); + + if (index < 0) { + if (G.debug & G_DEBUG) { + ID *id = nec->key.ptr.id.data; + CLOG_WARN(&LOG, + "Animato: Invalid array index. ID = '%s', '%s[%d]', array length is %d", + id ? (id->name + 2) : "<No ID>", + nec->rna_path, + array_index, + nec->base_snapshot.length); + } + + return false; + } + + if (nec->mix_mode == NEC_MIX_QUATERNION) { + /* For quaternion properties, always output all sub-channels. */ + BLI_bitmap_set_all(nec->valid.ptr, true, 4); + } + else { + BLI_BITMAP_ENABLE(nec->valid.ptr, index); + } + + NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_ensure_channel(blend->snapshot, nec); + float *p_value = &nec_snapshot->values[index]; + + if (blend->mode == NLASTRIP_MODE_COMBINE) { + /* Quaternion blending is deferred until all sub-channel values are known. */ + if (nec->mix_mode == NEC_MIX_QUATERNION) { + NlaEvalChannelSnapshot *blend_snapshot = nlaevalchan_queue_blend(blend, nec); + + blend_snapshot->values[index] = value; + } + else { + float base_value = nec->base_snapshot.values[index]; + + *p_value = nla_combine_value(nec->mix_mode, base_value, *p_value, value, blend->influence); + } + } + else { + *p_value = nla_blend_value(blend->mode, *p_value, value, blend->influence); + } + + return true; } /* Finish deferred quaternion blending. */ static void nlaeval_blend_flush(NlaBlendData *blend) { - NlaEvalChannel *nec; + NlaEvalChannel *nec; - while ((nec = blend->blend_queue)) { - blend->blend_queue = nec->next_blend; - nec->in_blend = false; + while ((nec = blend->blend_queue)) { + blend->blend_queue = nec->next_blend; + nec->in_blend = false; - NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_ensure_channel(blend->snapshot, nec); - NlaEvalChannelSnapshot *blend_snapshot = nec->blend_snapshot; + NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_ensure_channel(blend->snapshot, nec); + NlaEvalChannelSnapshot *blend_snapshot = nec->blend_snapshot; - if (nec->mix_mode == NEC_MIX_QUATERNION) { - nla_combine_quaternion(nec_snapshot->values, blend_snapshot->values, blend->influence, nec_snapshot->values); - } - else { - BLI_assert(!"mix quaternion"); - } - } + if (nec->mix_mode == NEC_MIX_QUATERNION) { + nla_combine_quaternion( + nec_snapshot->values, blend_snapshot->values, blend->influence, nec_snapshot->values); + } + else { + BLI_assert(!"mix quaternion"); + } + } } /* Blend the specified snapshots into the target, and free the input snapshots. */ -static void nlaeval_snapshot_mix_and_free(NlaEvalData *nlaeval, NlaEvalSnapshot *out, NlaEvalSnapshot *in1, NlaEvalSnapshot *in2, float alpha) -{ - BLI_assert(in1->base == out && in2->base == out); - - nlaeval_snapshot_ensure_size(out, nlaeval->num_channels); - - for (int i = 0; i < nlaeval->num_channels; i++) { - NlaEvalChannelSnapshot *c_in1 = nlaeval_snapshot_get(in1, i); - NlaEvalChannelSnapshot *c_in2 = nlaeval_snapshot_get(in2, i); - - if (c_in1 || c_in2) { - NlaEvalChannelSnapshot *c_out = out->channels[i]; - - /* Steal the entry from one of the input snapshots. */ - if (c_out == NULL) { - if (c_in1 != NULL) { - c_out = c_in1; - in1->channels[i] = NULL; - } - else { - c_out = c_in2; - in2->channels[i] = NULL; - } - } - - if (c_in1 == NULL) { - c_in1 = nlaeval_snapshot_find_channel(in1->base, c_out->channel); - } - if (c_in2 == NULL) { - c_in2 = nlaeval_snapshot_find_channel(in2->base, c_out->channel); - } - - out->channels[i] = c_out; - - for (int j = 0; j < c_out->length; j++) { - c_out->values[j] = c_in1->values[j] * (1.0f - alpha) + c_in2->values[j] * alpha; - } - } - } - - nlaeval_snapshot_free_data(in1); - nlaeval_snapshot_free_data(in2); +static void nlaeval_snapshot_mix_and_free(NlaEvalData *nlaeval, + NlaEvalSnapshot *out, + NlaEvalSnapshot *in1, + NlaEvalSnapshot *in2, + float alpha) +{ + BLI_assert(in1->base == out && in2->base == out); + + nlaeval_snapshot_ensure_size(out, nlaeval->num_channels); + + for (int i = 0; i < nlaeval->num_channels; i++) { + NlaEvalChannelSnapshot *c_in1 = nlaeval_snapshot_get(in1, i); + NlaEvalChannelSnapshot *c_in2 = nlaeval_snapshot_get(in2, i); + + if (c_in1 || c_in2) { + NlaEvalChannelSnapshot *c_out = out->channels[i]; + + /* Steal the entry from one of the input snapshots. */ + if (c_out == NULL) { + if (c_in1 != NULL) { + c_out = c_in1; + in1->channels[i] = NULL; + } + else { + c_out = c_in2; + in2->channels[i] = NULL; + } + } + + if (c_in1 == NULL) { + c_in1 = nlaeval_snapshot_find_channel(in1->base, c_out->channel); + } + if (c_in2 == NULL) { + c_in2 = nlaeval_snapshot_find_channel(in2->base, c_out->channel); + } + + out->channels[i] = c_out; + + for (int j = 0; j < c_out->length; j++) { + c_out->values[j] = c_in1->values[j] * (1.0f - alpha) + c_in2->values[j] * alpha; + } + } + } + + nlaeval_snapshot_free_data(in1); + nlaeval_snapshot_free_data(in2); } /* ---------------------- */ @@ -2765,330 +2907,356 @@ static void nlaeval_snapshot_mix_and_free(NlaEvalData *nlaeval, NlaEvalSnapshot /* Temporarily join two lists of modifiers together, storing the result in a third list */ static void nlaeval_fmodifiers_join_stacks(ListBase *result, ListBase *list1, ListBase *list2) { - FModifier *fcm1, *fcm2; - - /* if list1 is invalid... */ - if (ELEM(NULL, list1, list1->first)) { - if (list2 && list2->first) { - result->first = list2->first; - result->last = list2->last; - } - } - /* if list 2 is invalid... */ - else if (ELEM(NULL, list2, list2->first)) { - result->first = list1->first; - result->last = list1->last; - } - else { - /* list1 should be added first, and list2 second, with the endpoints of these being the endpoints for result - * - the original lists must be left unchanged though, as we need that fact for restoring - */ - result->first = list1->first; - result->last = list2->last; - - fcm1 = list1->last; - fcm2 = list2->first; - - fcm1->next = fcm2; - fcm2->prev = fcm1; - } + FModifier *fcm1, *fcm2; + + /* if list1 is invalid... */ + if (ELEM(NULL, list1, list1->first)) { + if (list2 && list2->first) { + result->first = list2->first; + result->last = list2->last; + } + } + /* if list 2 is invalid... */ + else if (ELEM(NULL, list2, list2->first)) { + result->first = list1->first; + result->last = list1->last; + } + else { + /* list1 should be added first, and list2 second, with the endpoints of these being the endpoints for result + * - the original lists must be left unchanged though, as we need that fact for restoring + */ + result->first = list1->first; + result->last = list2->last; + + fcm1 = list1->last; + fcm2 = list2->first; + + fcm1->next = fcm2; + fcm2->prev = fcm1; + } } /* Split two temporary lists of modifiers */ static void nlaeval_fmodifiers_split_stacks(ListBase *list1, ListBase *list2) { - FModifier *fcm1, *fcm2; + FModifier *fcm1, *fcm2; - /* if list1/2 is invalid... just skip */ - if (ELEM(NULL, list1, list2)) - return; - if (ELEM(NULL, list1->first, list2->first)) - return; + /* if list1/2 is invalid... just skip */ + if (ELEM(NULL, list1, list2)) + return; + if (ELEM(NULL, list1->first, list2->first)) + return; - /* get endpoints */ - fcm1 = list1->last; - fcm2 = list2->first; + /* get endpoints */ + fcm1 = list1->last; + fcm2 = list2->first; - /* clear their links */ - fcm1->next = NULL; - fcm2->prev = NULL; + /* clear their links */ + fcm1->next = NULL; + fcm2->prev = NULL; } /* ---------------------- */ /* evaluate action-clip strip */ -static void nlastrip_evaluate_actionclip(PointerRNA *ptr, NlaEvalData *channels, ListBase *modifiers, NlaEvalStrip *nes, NlaEvalSnapshot *snapshot) +static void nlastrip_evaluate_actionclip(PointerRNA *ptr, + NlaEvalData *channels, + ListBase *modifiers, + NlaEvalStrip *nes, + NlaEvalSnapshot *snapshot) { - FModifierStackStorage *storage; - ListBase tmp_modifiers = {NULL, NULL}; - NlaStrip *strip = nes->strip; - FCurve *fcu; - float evaltime; + FModifierStackStorage *storage; + ListBase tmp_modifiers = {NULL, NULL}; + NlaStrip *strip = nes->strip; + FCurve *fcu; + float evaltime; - /* sanity checks for action */ - if (strip == NULL) - return; + /* sanity checks for action */ + if (strip == NULL) + return; - if (strip->act == NULL) { - CLOG_ERROR(&LOG, "NLA-Strip Eval Error: Strip '%s' has no Action", strip->name); - return; - } + if (strip->act == NULL) { + CLOG_ERROR(&LOG, "NLA-Strip Eval Error: Strip '%s' has no Action", strip->name); + return; + } - action_idcode_patch_check(ptr->id.data, strip->act); + action_idcode_patch_check(ptr->id.data, strip->act); - /* join this strip's modifiers to the parent's modifiers (own modifiers first) */ - nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &strip->modifiers, modifiers); + /* join this strip's modifiers to the parent's modifiers (own modifiers first) */ + nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &strip->modifiers, modifiers); - /* evaluate strip's modifiers which modify time to evaluate the base curves at */ - storage = evaluate_fmodifiers_storage_new(&tmp_modifiers); - evaltime = evaluate_time_fmodifiers(storage, &tmp_modifiers, NULL, 0.0f, strip->strip_time); + /* evaluate strip's modifiers which modify time to evaluate the base curves at */ + storage = evaluate_fmodifiers_storage_new(&tmp_modifiers); + evaltime = evaluate_time_fmodifiers(storage, &tmp_modifiers, NULL, 0.0f, strip->strip_time); - NlaBlendData blend = { - .snapshot = snapshot, - .mode = strip->blendmode, - .influence = strip->influence, - }; + NlaBlendData blend = { + .snapshot = snapshot, + .mode = strip->blendmode, + .influence = strip->influence, + }; - /* evaluate all the F-Curves in the action, saving the relevant pointers to data that will need to be used */ - for (fcu = strip->act->curves.first; fcu; fcu = fcu->next) { - float value = 0.0f; + /* evaluate all the F-Curves in the action, saving the relevant pointers to data that will need to be used */ + for (fcu = strip->act->curves.first; fcu; fcu = fcu->next) { + float value = 0.0f; - /* check if this curve should be skipped */ - if (fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) - continue; - if ((fcu->grp) && (fcu->grp->flag & AGRP_MUTED)) - continue; + /* check if this curve should be skipped */ + if (fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) + continue; + if ((fcu->grp) && (fcu->grp->flag & AGRP_MUTED)) + continue; - /* evaluate the F-Curve's value for the time given in the strip - * NOTE: we use the modified time here, since strip's F-Curve Modifiers are applied on top of this - */ - value = evaluate_fcurve(fcu, evaltime); + /* evaluate the F-Curve's value for the time given in the strip + * NOTE: we use the modified time here, since strip's F-Curve Modifiers are applied on top of this + */ + value = evaluate_fcurve(fcu, evaltime); - /* apply strip's F-Curve Modifiers on this value - * NOTE: we apply the strip's original evaluation time not the modified one (as per standard F-Curve eval) - */ - evaluate_value_fmodifiers(storage, &tmp_modifiers, fcu, &value, strip->strip_time); + /* apply strip's F-Curve Modifiers on this value + * NOTE: we apply the strip's original evaluation time not the modified one (as per standard F-Curve eval) + */ + evaluate_value_fmodifiers(storage, &tmp_modifiers, fcu, &value, strip->strip_time); - /* get an NLA evaluation channel to work with, and accumulate the evaluated value with the value(s) - * stored in this channel if it has been used already - */ - NlaEvalChannel *nec = nlaevalchan_verify(ptr, channels, fcu->rna_path); + /* get an NLA evaluation channel to work with, and accumulate the evaluated value with the value(s) + * stored in this channel if it has been used already + */ + NlaEvalChannel *nec = nlaevalchan_verify(ptr, channels, fcu->rna_path); - nlaeval_blend_value(&blend, nec, fcu->array_index, value); - } + nlaeval_blend_value(&blend, nec, fcu->array_index, value); + } - nlaeval_blend_flush(&blend); + nlaeval_blend_flush(&blend); - /* free temporary storage */ - evaluate_fmodifiers_storage_free(storage); + /* free temporary storage */ + evaluate_fmodifiers_storage_free(storage); - /* unlink this strip's modifiers from the parent's modifiers again */ - nlaeval_fmodifiers_split_stacks(&strip->modifiers, modifiers); + /* unlink this strip's modifiers from the parent's modifiers again */ + nlaeval_fmodifiers_split_stacks(&strip->modifiers, modifiers); } /* evaluate transition strip */ -static void nlastrip_evaluate_transition( - Depsgraph *depsgraph, PointerRNA *ptr, NlaEvalData *channels, ListBase *modifiers, NlaEvalStrip *nes, NlaEvalSnapshot *snapshot) -{ - ListBase tmp_modifiers = {NULL, NULL}; - NlaEvalSnapshot snapshot1, snapshot2; - NlaEvalStrip tmp_nes; - NlaStrip *s1, *s2; - - /* join this strip's modifiers to the parent's modifiers (own modifiers first) */ - nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &nes->strip->modifiers, modifiers); - - /* get the two strips to operate on - * - we use the endpoints of the strips directly flanking our strip - * using these as the endpoints of the transition (destination and source) - * - these should have already been determined to be valid... - * - if this strip is being played in reverse, we need to swap these endpoints - * otherwise they will be interpolated wrong - */ - if (nes->strip->flag & NLASTRIP_FLAG_REVERSE) { - s1 = nes->strip->next; - s2 = nes->strip->prev; - } - else { - s1 = nes->strip->prev; - s2 = nes->strip->next; - } - - /* prepare template for 'evaluation strip' - * - based on the transition strip's evaluation strip data - * - strip_mode is NES_TIME_TRANSITION_* based on which endpoint - * - strip_time is the 'normalized' (i.e. in-strip) time for evaluation, - * which doubles up as an additional weighting factor for the strip influences - * which allows us to appear to be 'interpolating' between the two extremes - */ - tmp_nes = *nes; - - /* evaluate these strips into a temp-buffer (tmp_channels) */ - /* FIXME: modifier evaluation here needs some work... */ - /* first strip */ - tmp_nes.strip_mode = NES_TIME_TRANSITION_START; - tmp_nes.strip = s1; - nlaeval_snapshot_init(&snapshot1, channels, snapshot); - nlastrip_evaluate(depsgraph, ptr, channels, &tmp_modifiers, &tmp_nes, &snapshot1); - - /* second strip */ - tmp_nes.strip_mode = NES_TIME_TRANSITION_END; - tmp_nes.strip = s2; - nlaeval_snapshot_init(&snapshot2, channels, snapshot); - nlastrip_evaluate(depsgraph, ptr, channels, &tmp_modifiers, &tmp_nes, &snapshot2); - - /* accumulate temp-buffer and full-buffer, using the 'real' strip */ - nlaeval_snapshot_mix_and_free(channels, snapshot, &snapshot1, &snapshot2, nes->strip_time); - - /* unlink this strip's modifiers from the parent's modifiers again */ - nlaeval_fmodifiers_split_stacks(&nes->strip->modifiers, modifiers); +static void nlastrip_evaluate_transition(Depsgraph *depsgraph, + PointerRNA *ptr, + NlaEvalData *channels, + ListBase *modifiers, + NlaEvalStrip *nes, + NlaEvalSnapshot *snapshot) +{ + ListBase tmp_modifiers = {NULL, NULL}; + NlaEvalSnapshot snapshot1, snapshot2; + NlaEvalStrip tmp_nes; + NlaStrip *s1, *s2; + + /* join this strip's modifiers to the parent's modifiers (own modifiers first) */ + nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &nes->strip->modifiers, modifiers); + + /* get the two strips to operate on + * - we use the endpoints of the strips directly flanking our strip + * using these as the endpoints of the transition (destination and source) + * - these should have already been determined to be valid... + * - if this strip is being played in reverse, we need to swap these endpoints + * otherwise they will be interpolated wrong + */ + if (nes->strip->flag & NLASTRIP_FLAG_REVERSE) { + s1 = nes->strip->next; + s2 = nes->strip->prev; + } + else { + s1 = nes->strip->prev; + s2 = nes->strip->next; + } + + /* prepare template for 'evaluation strip' + * - based on the transition strip's evaluation strip data + * - strip_mode is NES_TIME_TRANSITION_* based on which endpoint + * - strip_time is the 'normalized' (i.e. in-strip) time for evaluation, + * which doubles up as an additional weighting factor for the strip influences + * which allows us to appear to be 'interpolating' between the two extremes + */ + tmp_nes = *nes; + + /* evaluate these strips into a temp-buffer (tmp_channels) */ + /* FIXME: modifier evaluation here needs some work... */ + /* first strip */ + tmp_nes.strip_mode = NES_TIME_TRANSITION_START; + tmp_nes.strip = s1; + nlaeval_snapshot_init(&snapshot1, channels, snapshot); + nlastrip_evaluate(depsgraph, ptr, channels, &tmp_modifiers, &tmp_nes, &snapshot1); + + /* second strip */ + tmp_nes.strip_mode = NES_TIME_TRANSITION_END; + tmp_nes.strip = s2; + nlaeval_snapshot_init(&snapshot2, channels, snapshot); + nlastrip_evaluate(depsgraph, ptr, channels, &tmp_modifiers, &tmp_nes, &snapshot2); + + /* accumulate temp-buffer and full-buffer, using the 'real' strip */ + nlaeval_snapshot_mix_and_free(channels, snapshot, &snapshot1, &snapshot2, nes->strip_time); + + /* unlink this strip's modifiers from the parent's modifiers again */ + nlaeval_fmodifiers_split_stacks(&nes->strip->modifiers, modifiers); } /* evaluate meta-strip */ -static void nlastrip_evaluate_meta( - Depsgraph *depsgraph, PointerRNA *ptr, NlaEvalData *channels, ListBase *modifiers, NlaEvalStrip *nes, NlaEvalSnapshot *snapshot) -{ - ListBase tmp_modifiers = {NULL, NULL}; - NlaStrip *strip = nes->strip; - NlaEvalStrip *tmp_nes; - float evaltime; - - /* meta-strip was calculated normally to have some time to be evaluated at - * and here we 'look inside' the meta strip, treating it as a decorated window to - * it's child strips, which get evaluated as if they were some tracks on a strip - * (but with some extra modifiers to apply). - * - * NOTE: keep this in sync with animsys_evaluate_nla() - */ - - /* join this strip's modifiers to the parent's modifiers (own modifiers first) */ - nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &strip->modifiers, modifiers); - - /* find the child-strip to evaluate */ - evaltime = (nes->strip_time * (strip->end - strip->start)) + strip->start; - tmp_nes = nlastrips_ctime_get_strip(depsgraph, NULL, &strip->strips, -1, evaltime); - - /* directly evaluate child strip into accumulation buffer... - * - there's no need to use a temporary buffer (as it causes issues [T40082]) - */ - if (tmp_nes) { - nlastrip_evaluate(depsgraph, ptr, channels, &tmp_modifiers, tmp_nes, snapshot); - - /* free temp eval-strip */ - MEM_freeN(tmp_nes); - } - - /* unlink this strip's modifiers from the parent's modifiers again */ - nlaeval_fmodifiers_split_stacks(&strip->modifiers, modifiers); +static void nlastrip_evaluate_meta(Depsgraph *depsgraph, + PointerRNA *ptr, + NlaEvalData *channels, + ListBase *modifiers, + NlaEvalStrip *nes, + NlaEvalSnapshot *snapshot) +{ + ListBase tmp_modifiers = {NULL, NULL}; + NlaStrip *strip = nes->strip; + NlaEvalStrip *tmp_nes; + float evaltime; + + /* meta-strip was calculated normally to have some time to be evaluated at + * and here we 'look inside' the meta strip, treating it as a decorated window to + * it's child strips, which get evaluated as if they were some tracks on a strip + * (but with some extra modifiers to apply). + * + * NOTE: keep this in sync with animsys_evaluate_nla() + */ + + /* join this strip's modifiers to the parent's modifiers (own modifiers first) */ + nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &strip->modifiers, modifiers); + + /* find the child-strip to evaluate */ + evaltime = (nes->strip_time * (strip->end - strip->start)) + strip->start; + tmp_nes = nlastrips_ctime_get_strip(depsgraph, NULL, &strip->strips, -1, evaltime); + + /* directly evaluate child strip into accumulation buffer... + * - there's no need to use a temporary buffer (as it causes issues [T40082]) + */ + if (tmp_nes) { + nlastrip_evaluate(depsgraph, ptr, channels, &tmp_modifiers, tmp_nes, snapshot); + + /* free temp eval-strip */ + MEM_freeN(tmp_nes); + } + + /* unlink this strip's modifiers from the parent's modifiers again */ + nlaeval_fmodifiers_split_stacks(&strip->modifiers, modifiers); } /* evaluates the given evaluation strip */ -void nlastrip_evaluate(Depsgraph *depsgraph, PointerRNA *ptr, NlaEvalData *channels, ListBase *modifiers, NlaEvalStrip *nes, NlaEvalSnapshot *snapshot) -{ - NlaStrip *strip = nes->strip; - - /* to prevent potential infinite recursion problems (i.e. transition strip, beside meta strip containing a transition - * several levels deep inside it), we tag the current strip as being evaluated, and clear this when we leave - */ - /* TODO: be careful with this flag, since some edit tools may be running and have set this while animplayback was running */ - if (strip->flag & NLASTRIP_FLAG_EDIT_TOUCHED) - return; - strip->flag |= NLASTRIP_FLAG_EDIT_TOUCHED; - - /* actions to take depend on the type of strip */ - switch (strip->type) { - case NLASTRIP_TYPE_CLIP: /* action-clip */ - nlastrip_evaluate_actionclip(ptr, channels, modifiers, nes, snapshot); - break; - case NLASTRIP_TYPE_TRANSITION: /* transition */ - nlastrip_evaluate_transition(depsgraph, ptr, channels, modifiers, nes, snapshot); - break; - case NLASTRIP_TYPE_META: /* meta */ - nlastrip_evaluate_meta(depsgraph, ptr, channels, modifiers, nes, snapshot); - break; - - default: /* do nothing */ - break; - } - - /* clear temp recursion safe-check */ - strip->flag &= ~NLASTRIP_FLAG_EDIT_TOUCHED; +void nlastrip_evaluate(Depsgraph *depsgraph, + PointerRNA *ptr, + NlaEvalData *channels, + ListBase *modifiers, + NlaEvalStrip *nes, + NlaEvalSnapshot *snapshot) +{ + NlaStrip *strip = nes->strip; + + /* to prevent potential infinite recursion problems (i.e. transition strip, beside meta strip containing a transition + * several levels deep inside it), we tag the current strip as being evaluated, and clear this when we leave + */ + /* TODO: be careful with this flag, since some edit tools may be running and have set this while animplayback was running */ + if (strip->flag & NLASTRIP_FLAG_EDIT_TOUCHED) + return; + strip->flag |= NLASTRIP_FLAG_EDIT_TOUCHED; + + /* actions to take depend on the type of strip */ + switch (strip->type) { + case NLASTRIP_TYPE_CLIP: /* action-clip */ + nlastrip_evaluate_actionclip(ptr, channels, modifiers, nes, snapshot); + break; + case NLASTRIP_TYPE_TRANSITION: /* transition */ + nlastrip_evaluate_transition(depsgraph, ptr, channels, modifiers, nes, snapshot); + break; + case NLASTRIP_TYPE_META: /* meta */ + nlastrip_evaluate_meta(depsgraph, ptr, channels, modifiers, nes, snapshot); + break; + + default: /* do nothing */ + break; + } + + /* clear temp recursion safe-check */ + strip->flag &= ~NLASTRIP_FLAG_EDIT_TOUCHED; } /* write the accumulated settings to */ -void nladata_flush_channels(Depsgraph *depsgraph, PointerRNA *ptr, NlaEvalData *channels, NlaEvalSnapshot *snapshot) -{ - /* sanity checks */ - if (channels == NULL) - return; - - const bool is_active_depsgraph = DEG_is_active(depsgraph); - - /* for each channel with accumulated values, write its value on the property it affects */ - for (NlaEvalChannel *nec = channels->channels.first; nec; nec = nec->next) { - NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_find_channel(snapshot, nec); - - PathResolvedRNA rna = { nec->key.ptr, nec->key.prop, -1 }; - - for (int i = 0; i < nec_snapshot->length; i++) { - if (BLI_BITMAP_TEST(nec->valid.ptr, i)) { - float value = nec_snapshot->values[i]; - if (nec->is_array) { - rna.prop_index = i; - } - animsys_write_rna_setting(&rna, value); - if (is_active_depsgraph) { - animsys_write_orig_anim_rna(ptr, nec->rna_path, rna.prop_index, value); - } - } - } - } +void nladata_flush_channels(Depsgraph *depsgraph, + PointerRNA *ptr, + NlaEvalData *channels, + NlaEvalSnapshot *snapshot) +{ + /* sanity checks */ + if (channels == NULL) + return; + + const bool is_active_depsgraph = DEG_is_active(depsgraph); + + /* for each channel with accumulated values, write its value on the property it affects */ + for (NlaEvalChannel *nec = channels->channels.first; nec; nec = nec->next) { + NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_find_channel(snapshot, nec); + + PathResolvedRNA rna = {nec->key.ptr, nec->key.prop, -1}; + + for (int i = 0; i < nec_snapshot->length; i++) { + if (BLI_BITMAP_TEST(nec->valid.ptr, i)) { + float value = nec_snapshot->values[i]; + if (nec->is_array) { + rna.prop_index = i; + } + animsys_write_rna_setting(&rna, value); + if (is_active_depsgraph) { + animsys_write_orig_anim_rna(ptr, nec->rna_path, rna.prop_index, value); + } + } + } + } } /* ---------------------- */ -static void nla_eval_domain_action(PointerRNA *ptr, NlaEvalData *channels, bAction *act, GSet *touched_actions) +static void nla_eval_domain_action(PointerRNA *ptr, + NlaEvalData *channels, + bAction *act, + GSet *touched_actions) { - if (!BLI_gset_add(touched_actions, act)) { - return; - } + if (!BLI_gset_add(touched_actions, act)) { + return; + } - for (FCurve *fcu = act->curves.first; fcu; fcu = fcu->next) { - /* check if this curve should be skipped */ - if (fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) - continue; - if ((fcu->grp) && (fcu->grp->flag & AGRP_MUTED)) - continue; + for (FCurve *fcu = act->curves.first; fcu; fcu = fcu->next) { + /* check if this curve should be skipped */ + if (fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) + continue; + if ((fcu->grp) && (fcu->grp->flag & AGRP_MUTED)) + continue; - NlaEvalChannel *nec = nlaevalchan_verify(ptr, channels, fcu->rna_path); + NlaEvalChannel *nec = nlaevalchan_verify(ptr, channels, fcu->rna_path); - if (nec != NULL) { - /* For quaternion properties, enable all sub-channels. */ - if (nec->mix_mode == NEC_MIX_QUATERNION) { - BLI_bitmap_set_all(nec->valid.ptr, true, 4); - continue; - } + if (nec != NULL) { + /* For quaternion properties, enable all sub-channels. */ + if (nec->mix_mode == NEC_MIX_QUATERNION) { + BLI_bitmap_set_all(nec->valid.ptr, true, 4); + continue; + } - int idx = nlaevalchan_validate_index(nec, fcu->array_index); + int idx = nlaevalchan_validate_index(nec, fcu->array_index); - if (idx >= 0) { - BLI_BITMAP_ENABLE(nec->valid.ptr, idx); - } - } - } + if (idx >= 0) { + BLI_BITMAP_ENABLE(nec->valid.ptr, idx); + } + } + } } -static void nla_eval_domain_strips(PointerRNA *ptr, NlaEvalData *channels, ListBase *strips, GSet *touched_actions) +static void nla_eval_domain_strips(PointerRNA *ptr, + NlaEvalData *channels, + ListBase *strips, + GSet *touched_actions) { - for (NlaStrip *strip = strips->first; strip; strip = strip->next) { - /* check strip's action */ - if (strip->act) { - nla_eval_domain_action(ptr, channels, strip->act, touched_actions); - } + for (NlaStrip *strip = strips->first; strip; strip = strip->next) { + /* check strip's action */ + if (strip->act) { + nla_eval_domain_action(ptr, channels, strip->act, touched_actions); + } - /* check sub-strips (if metas) */ - nla_eval_domain_strips(ptr, channels, &strip->strips, touched_actions); - } + /* check sub-strips (if metas) */ + nla_eval_domain_strips(ptr, channels, &strip->strips, touched_actions); + } } /** @@ -3097,31 +3265,31 @@ static void nla_eval_domain_strips(PointerRNA *ptr, NlaEvalData *channels, ListB */ static void animsys_evaluate_nla_domain(PointerRNA *ptr, NlaEvalData *channels, AnimData *adt) { - GSet *touched_actions = BLI_gset_ptr_new(__func__); + GSet *touched_actions = BLI_gset_ptr_new(__func__); - if (adt->action) { - nla_eval_domain_action(ptr, channels, adt->action, touched_actions); - } + if (adt->action) { + nla_eval_domain_action(ptr, channels, adt->action, touched_actions); + } - /* NLA Data - Animation Data for Strips */ - for (NlaTrack *nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { - /* solo and muting are mutually exclusive... */ - if (adt->flag & ADT_NLA_SOLO_TRACK) { - /* skip if there is a solo track, but this isn't it */ - if ((nlt->flag & NLATRACK_SOLO) == 0) - continue; - /* else - mute doesn't matter */ - } - else { - /* no solo tracks - skip track if muted */ - if (nlt->flag & NLATRACK_MUTED) - continue; - } + /* NLA Data - Animation Data for Strips */ + for (NlaTrack *nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { + /* solo and muting are mutually exclusive... */ + if (adt->flag & ADT_NLA_SOLO_TRACK) { + /* skip if there is a solo track, but this isn't it */ + if ((nlt->flag & NLATRACK_SOLO) == 0) + continue; + /* else - mute doesn't matter */ + } + else { + /* no solo tracks - skip track if muted */ + if (nlt->flag & NLATRACK_MUTED) + continue; + } - nla_eval_domain_strips(ptr, channels, &nlt->strips, touched_actions); - } + nla_eval_domain_strips(ptr, channels, &nlt->strips, touched_actions); + } - BLI_gset_free(touched_actions, NULL); + BLI_gset_free(touched_actions, NULL); } /* ---------------------- */ @@ -3133,169 +3301,185 @@ static void animsys_evaluate_nla_domain(PointerRNA *ptr, NlaEvalData *channels, * \param[out] r_context If not NULL, data about the currently edited strip is stored here and excluded from value calculation. * \return false if NLA evaluation isn't actually applicable */ -static bool animsys_evaluate_nla(Depsgraph *depsgraph, NlaEvalData *echannels, PointerRNA *ptr, AnimData *adt, float ctime, NlaKeyframingContext *r_context) -{ - NlaTrack *nlt; - short track_index = 0; - bool has_strips = false; - - ListBase estrips = {NULL, NULL}; - NlaEvalStrip *nes; - NlaStrip dummy_strip_buf; - - /* dummy strip for active action */ - NlaStrip *dummy_strip = r_context ? &r_context->strip : &dummy_strip_buf; - - memset(dummy_strip, 0, sizeof(*dummy_strip)); - - /* 1. get the stack of strips to evaluate at current time (influence calculated here) */ - for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next, track_index++) { - /* stop here if tweaking is on and this strip is the tweaking track (it will be the first one that's 'disabled')... */ - if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED)) - break; - - /* solo and muting are mutually exclusive... */ - if (adt->flag & ADT_NLA_SOLO_TRACK) { - /* skip if there is a solo track, but this isn't it */ - if ((nlt->flag & NLATRACK_SOLO) == 0) - continue; - /* else - mute doesn't matter */ - } - else { - /* no solo tracks - skip track if muted */ - if (nlt->flag & NLATRACK_MUTED) - continue; - } - - /* if this track has strips (but maybe they won't be suitable), set has_strips - * - used for mainly for still allowing normal action evaluation... - */ - if (nlt->strips.first) - has_strips = true; - - /* otherwise, get strip to evaluate for this channel */ - nes = nlastrips_ctime_get_strip(depsgraph, &estrips, &nlt->strips, track_index, ctime); - if (nes) nes->track = nlt; - } - - /* add 'active' Action (may be tweaking track) as last strip to evaluate in NLA stack - * - only do this if we're not exclusively evaluating the 'solo' NLA-track - * - however, if the 'solo' track houses the current 'tweaking' strip, - * then we should allow this to play, otherwise nothing happens - */ - if ((adt->action) && ((adt->flag & ADT_NLA_SOLO_TRACK) == 0 || (adt->flag & ADT_NLA_EDIT_ON))) { - /* if there are strips, evaluate action as per NLA rules */ - if ((has_strips) || (adt->actstrip)) { - /* make dummy NLA strip, and add that to the stack */ - ListBase dummy_trackslist; - - dummy_trackslist.first = dummy_trackslist.last = dummy_strip; - - /* Strips with a user-defined time curve don't get properly remapped for editing - * at the moment, so mapping them just for display may be confusing. */ - bool is_inplace_tweak = (nlt) && !(adt->flag & ADT_NLA_EDIT_NOMAP) && !(adt->actstrip->flag & NLASTRIP_FLAG_USR_TIME); - - if (is_inplace_tweak) { - /* edit active action in-place according to its active strip, so copy the data */ - memcpy(dummy_strip, adt->actstrip, sizeof(NlaStrip)); - dummy_strip->next = dummy_strip->prev = NULL; - } - else { - /* set settings of dummy NLA strip from AnimData settings */ - dummy_strip->act = adt->action; - - /* action range is calculated taking F-Modifiers into account (which making new strips doesn't do due to the troublesome nature of that) */ - calc_action_range(dummy_strip->act, &dummy_strip->actstart, &dummy_strip->actend, 1); - dummy_strip->start = dummy_strip->actstart; - dummy_strip->end = (IS_EQF(dummy_strip->actstart, dummy_strip->actend)) ? (dummy_strip->actstart + 1.0f) : (dummy_strip->actend); - - /* Always use the blend mode of the strip in tweak mode, even if not in-place. */ - if (nlt && adt->actstrip) { - dummy_strip->blendmode = adt->actstrip->blendmode; - dummy_strip->extendmode = NLASTRIP_EXTEND_HOLD; - } - else { - dummy_strip->blendmode = adt->act_blendmode; - dummy_strip->extendmode = adt->act_extendmode; - } - - /* Unless extendmode is Nothing (might be useful for flattening NLA evaluation), disable range. */ - if (dummy_strip->extendmode != NLASTRIP_EXTEND_NOTHING) { - dummy_strip->flag |= NLASTRIP_FLAG_NO_TIME_MAP; - } - - dummy_strip->influence = adt->act_influence; - - /* NOTE: must set this, or else the default setting overrides, and this setting doesn't work */ - dummy_strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE; - } - - /* add this to our list of evaluation strips */ - if (r_context == NULL) { - nlastrips_ctime_get_strip(depsgraph, &estrips, &dummy_trackslist, -1, ctime); - } - /* If computing the context for keyframing, store data there instead of the list. */ - else { - /* The extend mode here effectively controls whether it is possible to keyframe beyond the ends. */ - dummy_strip->extendmode = is_inplace_tweak ? NLASTRIP_EXTEND_NOTHING : NLASTRIP_EXTEND_HOLD; - - r_context->eval_strip = nes = nlastrips_ctime_get_strip(depsgraph, NULL, &dummy_trackslist, -1, ctime); - - /* These setting combinations require no data from strips below, so exit immediately. */ - if ((nes == NULL) || (dummy_strip->blendmode == NLASTRIP_MODE_REPLACE && dummy_strip->influence == 1.0f)) { - BLI_freelistN(&estrips); - return true; - } - } - } - else { - /* special case - evaluate as if there isn't any NLA data */ - BLI_freelistN(&estrips); - return false; - } - } - - /* only continue if there are strips to evaluate */ - if (BLI_listbase_is_empty(&estrips)) - return true; - - /* 2. for each strip, evaluate then accumulate on top of existing channels, but don't set values yet */ - for (nes = estrips.first; nes; nes = nes->next) - nlastrip_evaluate(depsgraph, ptr, echannels, NULL, nes, &echannels->eval_snapshot); - - /* 3. free temporary evaluation data that's not used elsewhere */ - BLI_freelistN(&estrips); - return true; +static bool animsys_evaluate_nla(Depsgraph *depsgraph, + NlaEvalData *echannels, + PointerRNA *ptr, + AnimData *adt, + float ctime, + NlaKeyframingContext *r_context) +{ + NlaTrack *nlt; + short track_index = 0; + bool has_strips = false; + + ListBase estrips = {NULL, NULL}; + NlaEvalStrip *nes; + NlaStrip dummy_strip_buf; + + /* dummy strip for active action */ + NlaStrip *dummy_strip = r_context ? &r_context->strip : &dummy_strip_buf; + + memset(dummy_strip, 0, sizeof(*dummy_strip)); + + /* 1. get the stack of strips to evaluate at current time (influence calculated here) */ + for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next, track_index++) { + /* stop here if tweaking is on and this strip is the tweaking track (it will be the first one that's 'disabled')... */ + if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED)) + break; + + /* solo and muting are mutually exclusive... */ + if (adt->flag & ADT_NLA_SOLO_TRACK) { + /* skip if there is a solo track, but this isn't it */ + if ((nlt->flag & NLATRACK_SOLO) == 0) + continue; + /* else - mute doesn't matter */ + } + else { + /* no solo tracks - skip track if muted */ + if (nlt->flag & NLATRACK_MUTED) + continue; + } + + /* if this track has strips (but maybe they won't be suitable), set has_strips + * - used for mainly for still allowing normal action evaluation... + */ + if (nlt->strips.first) + has_strips = true; + + /* otherwise, get strip to evaluate for this channel */ + nes = nlastrips_ctime_get_strip(depsgraph, &estrips, &nlt->strips, track_index, ctime); + if (nes) + nes->track = nlt; + } + + /* add 'active' Action (may be tweaking track) as last strip to evaluate in NLA stack + * - only do this if we're not exclusively evaluating the 'solo' NLA-track + * - however, if the 'solo' track houses the current 'tweaking' strip, + * then we should allow this to play, otherwise nothing happens + */ + if ((adt->action) && ((adt->flag & ADT_NLA_SOLO_TRACK) == 0 || (adt->flag & ADT_NLA_EDIT_ON))) { + /* if there are strips, evaluate action as per NLA rules */ + if ((has_strips) || (adt->actstrip)) { + /* make dummy NLA strip, and add that to the stack */ + ListBase dummy_trackslist; + + dummy_trackslist.first = dummy_trackslist.last = dummy_strip; + + /* Strips with a user-defined time curve don't get properly remapped for editing + * at the moment, so mapping them just for display may be confusing. */ + bool is_inplace_tweak = (nlt) && !(adt->flag & ADT_NLA_EDIT_NOMAP) && + !(adt->actstrip->flag & NLASTRIP_FLAG_USR_TIME); + + if (is_inplace_tweak) { + /* edit active action in-place according to its active strip, so copy the data */ + memcpy(dummy_strip, adt->actstrip, sizeof(NlaStrip)); + dummy_strip->next = dummy_strip->prev = NULL; + } + else { + /* set settings of dummy NLA strip from AnimData settings */ + dummy_strip->act = adt->action; + + /* action range is calculated taking F-Modifiers into account (which making new strips doesn't do due to the troublesome nature of that) */ + calc_action_range(dummy_strip->act, &dummy_strip->actstart, &dummy_strip->actend, 1); + dummy_strip->start = dummy_strip->actstart; + dummy_strip->end = (IS_EQF(dummy_strip->actstart, dummy_strip->actend)) ? + (dummy_strip->actstart + 1.0f) : + (dummy_strip->actend); + + /* Always use the blend mode of the strip in tweak mode, even if not in-place. */ + if (nlt && adt->actstrip) { + dummy_strip->blendmode = adt->actstrip->blendmode; + dummy_strip->extendmode = NLASTRIP_EXTEND_HOLD; + } + else { + dummy_strip->blendmode = adt->act_blendmode; + dummy_strip->extendmode = adt->act_extendmode; + } + + /* Unless extendmode is Nothing (might be useful for flattening NLA evaluation), disable range. */ + if (dummy_strip->extendmode != NLASTRIP_EXTEND_NOTHING) { + dummy_strip->flag |= NLASTRIP_FLAG_NO_TIME_MAP; + } + + dummy_strip->influence = adt->act_influence; + + /* NOTE: must set this, or else the default setting overrides, and this setting doesn't work */ + dummy_strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE; + } + + /* add this to our list of evaluation strips */ + if (r_context == NULL) { + nlastrips_ctime_get_strip(depsgraph, &estrips, &dummy_trackslist, -1, ctime); + } + /* If computing the context for keyframing, store data there instead of the list. */ + else { + /* The extend mode here effectively controls whether it is possible to keyframe beyond the ends. */ + dummy_strip->extendmode = is_inplace_tweak ? NLASTRIP_EXTEND_NOTHING : + NLASTRIP_EXTEND_HOLD; + + r_context->eval_strip = nes = nlastrips_ctime_get_strip( + depsgraph, NULL, &dummy_trackslist, -1, ctime); + + /* These setting combinations require no data from strips below, so exit immediately. */ + if ((nes == NULL) || + (dummy_strip->blendmode == NLASTRIP_MODE_REPLACE && dummy_strip->influence == 1.0f)) { + BLI_freelistN(&estrips); + return true; + } + } + } + else { + /* special case - evaluate as if there isn't any NLA data */ + BLI_freelistN(&estrips); + return false; + } + } + + /* only continue if there are strips to evaluate */ + if (BLI_listbase_is_empty(&estrips)) + return true; + + /* 2. for each strip, evaluate then accumulate on top of existing channels, but don't set values yet */ + for (nes = estrips.first; nes; nes = nes->next) + nlastrip_evaluate(depsgraph, ptr, echannels, NULL, nes, &echannels->eval_snapshot); + + /* 3. free temporary evaluation data that's not used elsewhere */ + BLI_freelistN(&estrips); + return true; } /* NLA Evaluation function (mostly for use through do_animdata) * - All channels that will be affected are not cleared anymore. Instead, we just evaluate into * some temp channels, where values can be accumulated in one go. */ -static void animsys_calculate_nla(Depsgraph *depsgraph, PointerRNA *ptr, AnimData *adt, float ctime) +static void animsys_calculate_nla(Depsgraph *depsgraph, + PointerRNA *ptr, + AnimData *adt, + float ctime) { - NlaEvalData echannels; + NlaEvalData echannels; - nlaeval_init(&echannels); + nlaeval_init(&echannels); - /* evaluate the NLA stack, obtaining a set of values to flush */ - if (animsys_evaluate_nla(depsgraph, &echannels, ptr, adt, ctime, NULL)) { - /* reset any channels touched by currently inactive actions to default value */ - animsys_evaluate_nla_domain(ptr, &echannels, adt); + /* evaluate the NLA stack, obtaining a set of values to flush */ + if (animsys_evaluate_nla(depsgraph, &echannels, ptr, adt, ctime, NULL)) { + /* reset any channels touched by currently inactive actions to default value */ + animsys_evaluate_nla_domain(ptr, &echannels, adt); - /* flush effects of accumulating channels in NLA to the actual data they affect */ - nladata_flush_channels(depsgraph, ptr, &echannels, &echannels.eval_snapshot); - } - else { - /* special case - evaluate as if there isn't any NLA data */ - /* TODO: this is really just a stop-gap measure... */ - if (G.debug & G_DEBUG) CLOG_WARN(&LOG, "NLA Eval: Stopgap for active action on NLA Stack - no strips case"); + /* flush effects of accumulating channels in NLA to the actual data they affect */ + nladata_flush_channels(depsgraph, ptr, &echannels, &echannels.eval_snapshot); + } + else { + /* special case - evaluate as if there isn't any NLA data */ + /* TODO: this is really just a stop-gap measure... */ + if (G.debug & G_DEBUG) + CLOG_WARN(&LOG, "NLA Eval: Stopgap for active action on NLA Stack - no strips case"); - animsys_evaluate_action(depsgraph, ptr, adt->action, ctime); - } + animsys_evaluate_action(depsgraph, ptr, adt->action, ctime); + } - /* free temp data */ - nlaeval_free(&echannels); + /* free temp data */ + nlaeval_free(&echannels); } /* ---------------------- */ @@ -3308,35 +3492,40 @@ static void animsys_calculate_nla(Depsgraph *depsgraph, PointerRNA *ptr, AnimDat * @param ptr RNA pointer to the Object with the animation. * @return Keyframing context, or NULL if not necessary. */ -NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context( - struct ListBase *cache, struct Depsgraph *depsgraph, struct PointerRNA *ptr, struct AnimData *adt, float ctime) +NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(struct ListBase *cache, + struct Depsgraph *depsgraph, + struct PointerRNA *ptr, + struct AnimData *adt, + float ctime) { - /* No remapping needed if NLA is off or no action. */ - if ((adt == NULL) || (adt->action == NULL) || (adt->nla_tracks.first == NULL) || (adt->flag & ADT_NLA_EVAL_OFF)) { - return NULL; - } + /* No remapping needed if NLA is off or no action. */ + if ((adt == NULL) || (adt->action == NULL) || (adt->nla_tracks.first == NULL) || + (adt->flag & ADT_NLA_EVAL_OFF)) { + return NULL; + } - /* No remapping if editing an ordinary Replace action with full influence. */ - if (!(adt->flag & ADT_NLA_EDIT_ON) && (adt->act_blendmode == NLASTRIP_MODE_REPLACE && adt->act_influence == 1.0f)) { - return NULL; - } + /* No remapping if editing an ordinary Replace action with full influence. */ + if (!(adt->flag & ADT_NLA_EDIT_ON) && + (adt->act_blendmode == NLASTRIP_MODE_REPLACE && adt->act_influence == 1.0f)) { + return NULL; + } - /* Try to find a cached context. */ - NlaKeyframingContext *ctx = BLI_findptr(cache, adt, offsetof(NlaKeyframingContext, adt)); + /* Try to find a cached context. */ + NlaKeyframingContext *ctx = BLI_findptr(cache, adt, offsetof(NlaKeyframingContext, adt)); - if (ctx == NULL) { - /* Allocate and evaluate a new context. */ - ctx = MEM_callocN(sizeof(*ctx), "NlaKeyframingContext"); - ctx->adt = adt; + if (ctx == NULL) { + /* Allocate and evaluate a new context. */ + ctx = MEM_callocN(sizeof(*ctx), "NlaKeyframingContext"); + ctx->adt = adt; - nlaeval_init(&ctx->nla_channels); - animsys_evaluate_nla(depsgraph, &ctx->nla_channels, ptr, adt, ctime, ctx); + nlaeval_init(&ctx->nla_channels); + animsys_evaluate_nla(depsgraph, &ctx->nla_channels, ptr, adt, ctime, ctx); - BLI_assert(ELEM(ctx->strip.act, NULL, adt->action)); - BLI_addtail(cache, ctx); - } + BLI_assert(ELEM(ctx->strip.act, NULL, adt->action)); + BLI_addtail(cache, ctx); + } - return ctx; + return ctx; } /** @@ -3350,84 +3539,99 @@ NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context( * @param[out] r_force_all Set to true if all channels must be inserted. May be NULL. * @return False if correction fails due to a division by zero, or null r_force_all when all channels are required. */ -bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context, struct PointerRNA *prop_ptr, struct PropertyRNA *prop, float *values, int count, int index, bool *r_force_all) -{ - if (r_force_all != NULL) { - *r_force_all = false; - } - - /* No context means no correction. */ - if (context == NULL || context->strip.act == NULL) { - return true; - } - - /* If the strip is not evaluated, it is the same as zero influence. */ - if (context->eval_strip == NULL) { - return false; - } - - /* Full influence Replace strips also require no correction. */ - int blend_mode = context->strip.blendmode; - float influence = context->strip.influence; - - if (blend_mode == NLASTRIP_MODE_REPLACE && influence == 1.0f) { - return true; - } - - /* Zero influence is division by zero. */ - if (influence <= 0.0f) { - return false; - } - - /* Find the evaluation channel for the NLA stack below current strip. */ - NlaEvalChannelKey key = { .ptr = *prop_ptr, .prop = prop, }; - NlaEvalData *nlaeval = &context->nla_channels; - NlaEvalChannel *nec = nlaevalchan_verify_key(nlaeval, NULL, &key); - - if (nec->base_snapshot.length != count) { - BLI_assert(!"invalid value count"); - return false; - } - - /* Invert the blending operation to compute the desired key values. */ - NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_find_channel(&nlaeval->eval_snapshot, nec); - - float *old_values = nec_snapshot->values; - - if (blend_mode == NLASTRIP_MODE_COMBINE) { - /* Quaternion combine handles all sub-channels as a unit. */ - if (nec->mix_mode == NEC_MIX_QUATERNION) { - if (r_force_all == NULL) { - return false; - } - - *r_force_all = true; - - nla_invert_combine_quaternion(old_values, values, influence, values); - } - else { - float *base_values = nec->base_snapshot.values; - - for (int i = 0; i < count; i++) { - if (ELEM(index, i, -1)) { - if (!nla_invert_combine_value(nec->mix_mode, base_values[i], old_values[i], values[i], influence, &values[i])) { - return false; - } - } - } - } - } - else { - for (int i = 0; i < count; i++) { - if (ELEM(index, i, -1)) { - if (!nla_invert_blend_value(blend_mode, old_values[i], values[i], influence, &values[i])) { - return false; - } - } - } - } - - return true; +bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context, + struct PointerRNA *prop_ptr, + struct PropertyRNA *prop, + float *values, + int count, + int index, + bool *r_force_all) +{ + if (r_force_all != NULL) { + *r_force_all = false; + } + + /* No context means no correction. */ + if (context == NULL || context->strip.act == NULL) { + return true; + } + + /* If the strip is not evaluated, it is the same as zero influence. */ + if (context->eval_strip == NULL) { + return false; + } + + /* Full influence Replace strips also require no correction. */ + int blend_mode = context->strip.blendmode; + float influence = context->strip.influence; + + if (blend_mode == NLASTRIP_MODE_REPLACE && influence == 1.0f) { + return true; + } + + /* Zero influence is division by zero. */ + if (influence <= 0.0f) { + return false; + } + + /* Find the evaluation channel for the NLA stack below current strip. */ + NlaEvalChannelKey key = { + .ptr = *prop_ptr, + .prop = prop, + }; + NlaEvalData *nlaeval = &context->nla_channels; + NlaEvalChannel *nec = nlaevalchan_verify_key(nlaeval, NULL, &key); + + if (nec->base_snapshot.length != count) { + BLI_assert(!"invalid value count"); + return false; + } + + /* Invert the blending operation to compute the desired key values. */ + NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_find_channel(&nlaeval->eval_snapshot, + nec); + + float *old_values = nec_snapshot->values; + + if (blend_mode == NLASTRIP_MODE_COMBINE) { + /* Quaternion combine handles all sub-channels as a unit. */ + if (nec->mix_mode == NEC_MIX_QUATERNION) { + if (r_force_all == NULL) { + return false; + } + + *r_force_all = true; + + nla_invert_combine_quaternion(old_values, values, influence, values); + } + else { + float *base_values = nec->base_snapshot.values; + + for (int i = 0; i < count; i++) { + if (ELEM(index, i, -1)) { + if (!nla_invert_combine_value(nec->mix_mode, + base_values[i], + old_values[i], + values[i], + influence, + &values[i])) { + return false; + } + } + } + } + } + else { + for (int i = 0; i < count; i++) { + if (ELEM(index, i, -1)) { + if (!nla_invert_blend_value(blend_mode, old_values[i], values[i], influence, &values[i])) { + return false; + } + } + } + } + + return true; } /** @@ -3435,12 +3639,12 @@ bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context, */ void BKE_animsys_free_nla_keyframing_context_cache(struct ListBase *cache) { - for (NlaKeyframingContext *ctx = cache->first; ctx; ctx = ctx->next) { - MEM_SAFE_FREE(ctx->eval_strip); - nlaeval_free(&ctx->nla_channels); - } + for (NlaKeyframingContext *ctx = cache->first; ctx; ctx = ctx->next) { + MEM_SAFE_FREE(ctx->eval_strip); + nlaeval_free(&ctx->nla_channels); + } - BLI_freelistN(cache); + BLI_freelistN(cache); } /* ***************************************** */ @@ -3449,15 +3653,15 @@ void BKE_animsys_free_nla_keyframing_context_cache(struct ListBase *cache) /* Evaluate Overrides */ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt) { - AnimOverride *aor; + AnimOverride *aor; - /* for each override, simply execute... */ - for (aor = adt->overrides.first; aor; aor = aor->next) { - PathResolvedRNA anim_rna; - if (animsys_store_rna_setting(ptr, aor->rna_path, aor->array_index, &anim_rna)) { - animsys_write_rna_setting(&anim_rna, aor->value); - } - } + /* for each override, simply execute... */ + for (aor = adt->overrides.first; aor; aor = aor->next) { + PathResolvedRNA anim_rna; + if (animsys_store_rna_setting(ptr, aor->rna_path, aor->array_index, &anim_rna)) { + animsys_write_rna_setting(&anim_rna, aor->value); + } + } } /* ***************************************** */ @@ -3500,58 +3704,59 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt) * and that the flags for which parts of the anim-data settings need to be recalculated * have been set already by the depsgraph. Now, we use the recalc */ -void BKE_animsys_evaluate_animdata(Depsgraph *depsgraph, Scene *scene, ID *id, AnimData *adt, float ctime, short recalc) -{ - PointerRNA id_ptr; - - /* sanity checks */ - if (ELEM(NULL, id, adt)) - return; - - /* get pointer to ID-block for RNA to use */ - RNA_id_pointer_create(id, &id_ptr); - - /* recalculate keyframe data: - * - NLA before Active Action, as Active Action behaves as 'tweaking track' - * that overrides 'rough' work in NLA - */ - /* TODO: need to double check that this all works correctly */ - if (recalc & ADT_RECALC_ANIM) { - /* evaluate NLA data */ - if ((adt->nla_tracks.first) && !(adt->flag & ADT_NLA_EVAL_OFF)) { - /* evaluate NLA-stack - * - active action is evaluated as part of the NLA stack as the last item - */ - animsys_calculate_nla(depsgraph, &id_ptr, adt, ctime); - } - /* evaluate Active Action only */ - else if (adt->action) - animsys_evaluate_action_ex(depsgraph, &id_ptr, adt->action, ctime); - } - - /* recalculate drivers - * - Drivers need to be evaluated afterwards, as they can either override - * or be layered on top of existing animation data. - * - Drivers should be in the appropriate order to be evaluated without problems... - */ - if (recalc & ADT_RECALC_DRIVERS) { - animsys_evaluate_drivers(&id_ptr, adt, ctime); - } - - /* always execute 'overrides' - * - Overrides allow editing, by overwriting the value(s) set from animation-data, with the - * value last set by the user (and not keyframed yet). - * - Overrides are cleared upon frame change and/or keyframing - * - It is best that we execute this every time, so that no errors are likely to occur. - */ - animsys_evaluate_overrides(&id_ptr, adt); - - /* execute and clear all cached property update functions */ - if (scene) { - Main *bmain = G.main; // xxx - to get passed in! - RNA_property_update_cache_flush(bmain, scene); - RNA_property_update_cache_free(); - } +void BKE_animsys_evaluate_animdata( + Depsgraph *depsgraph, Scene *scene, ID *id, AnimData *adt, float ctime, short recalc) +{ + PointerRNA id_ptr; + + /* sanity checks */ + if (ELEM(NULL, id, adt)) + return; + + /* get pointer to ID-block for RNA to use */ + RNA_id_pointer_create(id, &id_ptr); + + /* recalculate keyframe data: + * - NLA before Active Action, as Active Action behaves as 'tweaking track' + * that overrides 'rough' work in NLA + */ + /* TODO: need to double check that this all works correctly */ + if (recalc & ADT_RECALC_ANIM) { + /* evaluate NLA data */ + if ((adt->nla_tracks.first) && !(adt->flag & ADT_NLA_EVAL_OFF)) { + /* evaluate NLA-stack + * - active action is evaluated as part of the NLA stack as the last item + */ + animsys_calculate_nla(depsgraph, &id_ptr, adt, ctime); + } + /* evaluate Active Action only */ + else if (adt->action) + animsys_evaluate_action_ex(depsgraph, &id_ptr, adt->action, ctime); + } + + /* recalculate drivers + * - Drivers need to be evaluated afterwards, as they can either override + * or be layered on top of existing animation data. + * - Drivers should be in the appropriate order to be evaluated without problems... + */ + if (recalc & ADT_RECALC_DRIVERS) { + animsys_evaluate_drivers(&id_ptr, adt, ctime); + } + + /* always execute 'overrides' + * - Overrides allow editing, by overwriting the value(s) set from animation-data, with the + * value last set by the user (and not keyframed yet). + * - Overrides are cleared upon frame change and/or keyframing + * - It is best that we execute this every time, so that no errors are likely to occur. + */ + animsys_evaluate_overrides(&id_ptr, adt); + + /* execute and clear all cached property update functions */ + if (scene) { + Main *bmain = G.main; // xxx - to get passed in! + RNA_property_update_cache_flush(bmain, scene); + RNA_property_update_cache_free(); + } } /* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only @@ -3561,129 +3766,135 @@ void BKE_animsys_evaluate_animdata(Depsgraph *depsgraph, Scene *scene, ID *id, A * 'local' (i.e. belonging in the nearest ID-block that setting is related to, not a * standard 'root') block are overridden by a larger 'user' */ -void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, Scene *scene, float ctime) +void BKE_animsys_evaluate_all_animation(Main *main, + Depsgraph *depsgraph, + Scene *scene, + float ctime) { - ID *id; + ID *id; - if (G.debug & G_DEBUG) - printf("Evaluate all animation - %f\n", ctime); + if (G.debug & G_DEBUG) + printf("Evaluate all animation - %f\n", ctime); - /* macros for less typing - * - only evaluate animation data for id if it has users (and not just fake ones) - * - whether animdata exists is checked for by the evaluation function, though taking - * this outside of the function may make things slightly faster? - */ + /* macros for less typing + * - only evaluate animation data for id if it has users (and not just fake ones) + * - whether animdata exists is checked for by the evaluation function, though taking + * this outside of the function may make things slightly faster? + */ #define EVAL_ANIM_IDS(first, aflag) \ - for (id = first; id; id = id->next) { \ - if (ID_REAL_USERS(id) > 0) { \ - AnimData *adt = BKE_animdata_from_id(id); \ - BKE_animsys_evaluate_animdata(depsgraph, scene, id, adt, ctime, aflag); \ - } \ - } (void)0 - - /* another macro for the "embedded" nodetree cases - * - this is like EVAL_ANIM_IDS, but this handles the case "embedded nodetrees" - * (i.e. scene/material/texture->nodetree) which we need a special exception - * for, otherwise they'd get skipped - * - ntp = "node tree parent" = datablock where node tree stuff resides - */ + for (id = first; id; id = id->next) { \ + if (ID_REAL_USERS(id) > 0) { \ + AnimData *adt = BKE_animdata_from_id(id); \ + BKE_animsys_evaluate_animdata(depsgraph, scene, id, adt, ctime, aflag); \ + } \ + } \ + (void)0 + + /* another macro for the "embedded" nodetree cases + * - this is like EVAL_ANIM_IDS, but this handles the case "embedded nodetrees" + * (i.e. scene/material/texture->nodetree) which we need a special exception + * for, otherwise they'd get skipped + * - ntp = "node tree parent" = datablock where node tree stuff resides + */ #define EVAL_ANIM_NODETREE_IDS(first, NtId_Type, aflag) \ - for (id = first; id; id = id->next) { \ - if (ID_REAL_USERS(id) > 0) { \ - AnimData *adt = BKE_animdata_from_id(id); \ - NtId_Type *ntp = (NtId_Type *)id; \ - if (ntp->nodetree) { \ - AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \ - BKE_animsys_evaluate_animdata(depsgraph, scene, (ID *)ntp->nodetree, adt2, ctime, ADT_RECALC_ANIM); \ - } \ - BKE_animsys_evaluate_animdata(depsgraph, scene, id, adt, ctime, aflag); \ - } \ - } (void)0 + for (id = first; id; id = id->next) { \ + if (ID_REAL_USERS(id) > 0) { \ + AnimData *adt = BKE_animdata_from_id(id); \ + NtId_Type *ntp = (NtId_Type *)id; \ + if (ntp->nodetree) { \ + AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \ + BKE_animsys_evaluate_animdata( \ + depsgraph, scene, (ID *)ntp->nodetree, adt2, ctime, ADT_RECALC_ANIM); \ + } \ + BKE_animsys_evaluate_animdata(depsgraph, scene, id, adt, ctime, aflag); \ + } \ + } \ + (void)0 - /* optimization: - * when there are no actions, don't go over database and loop over heaps of datablocks, - * which should ultimately be empty, since it is not possible for now to have any animation - * without some actions, and drivers wouldn't get affected by any state changes - * - * however, if there are some curves, we will need to make sure that their 'ctime' property gets - * set correctly, so this optimization must be skipped in that case... - */ - if (BLI_listbase_is_empty(&main->actions) && BLI_listbase_is_empty(&main->curves)) { - if (G.debug & G_DEBUG) - printf("\tNo Actions, so no animation needs to be evaluated...\n"); + /* optimization: + * when there are no actions, don't go over database and loop over heaps of datablocks, + * which should ultimately be empty, since it is not possible for now to have any animation + * without some actions, and drivers wouldn't get affected by any state changes + * + * however, if there are some curves, we will need to make sure that their 'ctime' property gets + * set correctly, so this optimization must be skipped in that case... + */ + if (BLI_listbase_is_empty(&main->actions) && BLI_listbase_is_empty(&main->curves)) { + if (G.debug & G_DEBUG) + printf("\tNo Actions, so no animation needs to be evaluated...\n"); - return; - } + return; + } - /* nodes */ - EVAL_ANIM_IDS(main->nodetrees.first, ADT_RECALC_ANIM); + /* nodes */ + EVAL_ANIM_IDS(main->nodetrees.first, ADT_RECALC_ANIM); - /* textures */ - EVAL_ANIM_NODETREE_IDS(main->textures.first, Tex, ADT_RECALC_ANIM); + /* textures */ + EVAL_ANIM_NODETREE_IDS(main->textures.first, Tex, ADT_RECALC_ANIM); - /* lights */ - EVAL_ANIM_NODETREE_IDS(main->lights.first, Light, ADT_RECALC_ANIM); + /* lights */ + EVAL_ANIM_NODETREE_IDS(main->lights.first, Light, ADT_RECALC_ANIM); - /* materials */ - EVAL_ANIM_NODETREE_IDS(main->materials.first, Material, ADT_RECALC_ANIM); + /* materials */ + EVAL_ANIM_NODETREE_IDS(main->materials.first, Material, ADT_RECALC_ANIM); - /* cameras */ - EVAL_ANIM_IDS(main->cameras.first, ADT_RECALC_ANIM); + /* cameras */ + EVAL_ANIM_IDS(main->cameras.first, ADT_RECALC_ANIM); - /* shapekeys */ - EVAL_ANIM_IDS(main->shapekeys.first, ADT_RECALC_ANIM); + /* shapekeys */ + EVAL_ANIM_IDS(main->shapekeys.first, ADT_RECALC_ANIM); - /* metaballs */ - EVAL_ANIM_IDS(main->metaballs.first, ADT_RECALC_ANIM); + /* metaballs */ + EVAL_ANIM_IDS(main->metaballs.first, ADT_RECALC_ANIM); - /* curves */ - EVAL_ANIM_IDS(main->curves.first, ADT_RECALC_ANIM); + /* curves */ + EVAL_ANIM_IDS(main->curves.first, ADT_RECALC_ANIM); - /* armatures */ - EVAL_ANIM_IDS(main->armatures.first, ADT_RECALC_ANIM); + /* armatures */ + EVAL_ANIM_IDS(main->armatures.first, ADT_RECALC_ANIM); - /* lattices */ - EVAL_ANIM_IDS(main->lattices.first, ADT_RECALC_ANIM); + /* lattices */ + EVAL_ANIM_IDS(main->lattices.first, ADT_RECALC_ANIM); - /* meshes */ - EVAL_ANIM_IDS(main->meshes.first, ADT_RECALC_ANIM); + /* meshes */ + EVAL_ANIM_IDS(main->meshes.first, ADT_RECALC_ANIM); - /* particles */ - EVAL_ANIM_IDS(main->particles.first, ADT_RECALC_ANIM); + /* particles */ + EVAL_ANIM_IDS(main->particles.first, ADT_RECALC_ANIM); - /* speakers */ - EVAL_ANIM_IDS(main->speakers.first, ADT_RECALC_ANIM); + /* speakers */ + EVAL_ANIM_IDS(main->speakers.first, ADT_RECALC_ANIM); - /* movie clips */ - EVAL_ANIM_IDS(main->movieclips.first, ADT_RECALC_ANIM); + /* movie clips */ + EVAL_ANIM_IDS(main->movieclips.first, ADT_RECALC_ANIM); - /* linestyles */ - EVAL_ANIM_IDS(main->linestyles.first, ADT_RECALC_ANIM); + /* linestyles */ + EVAL_ANIM_IDS(main->linestyles.first, ADT_RECALC_ANIM); - /* grease pencil */ - EVAL_ANIM_IDS(main->gpencils.first, ADT_RECALC_ANIM); + /* grease pencil */ + EVAL_ANIM_IDS(main->gpencils.first, ADT_RECALC_ANIM); - /* palettes */ - EVAL_ANIM_IDS(main->palettes.first, ADT_RECALC_ANIM); + /* palettes */ + EVAL_ANIM_IDS(main->palettes.first, ADT_RECALC_ANIM); - /* cache files */ - EVAL_ANIM_IDS(main->cachefiles.first, ADT_RECALC_ANIM); + /* cache files */ + EVAL_ANIM_IDS(main->cachefiles.first, ADT_RECALC_ANIM); - /* objects */ - /* ADT_RECALC_ANIM doesn't need to be supplied here, since object AnimData gets - * this tagged by Depsgraph on framechange. This optimization means that objects - * linked from other (not-visible) scenes will not need their data calculated. - */ - EVAL_ANIM_IDS(main->objects.first, 0); + /* objects */ + /* ADT_RECALC_ANIM doesn't need to be supplied here, since object AnimData gets + * this tagged by Depsgraph on framechange. This optimization means that objects + * linked from other (not-visible) scenes will not need their data calculated. + */ + EVAL_ANIM_IDS(main->objects.first, 0); - /* masks */ - EVAL_ANIM_IDS(main->masks.first, ADT_RECALC_ANIM); + /* masks */ + EVAL_ANIM_IDS(main->masks.first, ADT_RECALC_ANIM); - /* worlds */ - EVAL_ANIM_NODETREE_IDS(main->worlds.first, World, ADT_RECALC_ANIM); + /* worlds */ + EVAL_ANIM_NODETREE_IDS(main->worlds.first, World, ADT_RECALC_ANIM); - /* scenes */ - EVAL_ANIM_NODETREE_IDS(main->scenes.first, Scene, ADT_RECALC_ANIM); + /* scenes */ + EVAL_ANIM_NODETREE_IDS(main->scenes.first, Scene, ADT_RECALC_ANIM); } /* ***************************************** */ @@ -3693,33 +3904,33 @@ void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, Scene void BKE_animsys_eval_animdata(Depsgraph *depsgraph, ID *id) { - float ctime = DEG_get_ctime(depsgraph); - AnimData *adt = BKE_animdata_from_id(id); - Scene *scene = NULL; /* XXX: this is only needed for flushing RNA updates, - * which should get handled as part of the dependency graph instead... - */ - DEG_debug_print_eval_time(depsgraph, __func__, id->name, id, ctime); - BKE_animsys_evaluate_animdata(depsgraph, scene, id, adt, ctime, ADT_RECALC_ANIM); + float ctime = DEG_get_ctime(depsgraph); + AnimData *adt = BKE_animdata_from_id(id); + Scene *scene = NULL; /* XXX: this is only needed for flushing RNA updates, + * which should get handled as part of the dependency graph instead... + */ + DEG_debug_print_eval_time(depsgraph, __func__, id->name, id, ctime); + BKE_animsys_evaluate_animdata(depsgraph, scene, id, adt, ctime, ADT_RECALC_ANIM); } void BKE_animsys_update_driver_array(ID *id) { - AnimData *adt = BKE_animdata_from_id(id); + AnimData *adt = BKE_animdata_from_id(id); - /* Runtime driver map to avoid O(n^2) lookups in BKE_animsys_eval_driver. - * Ideally the depsgraph could pass a pointer to the COW driver directly, - * but this is difficult in the current design. */ - if (adt && adt->drivers.first) { - BLI_assert(!adt->driver_array); + /* Runtime driver map to avoid O(n^2) lookups in BKE_animsys_eval_driver. + * Ideally the depsgraph could pass a pointer to the COW driver directly, + * but this is difficult in the current design. */ + if (adt && adt->drivers.first) { + BLI_assert(!adt->driver_array); - int num_drivers = BLI_listbase_count(&adt->drivers); - adt->driver_array = MEM_mallocN(sizeof(FCurve *) * num_drivers, "adt->driver_array"); + int num_drivers = BLI_listbase_count(&adt->drivers); + adt->driver_array = MEM_mallocN(sizeof(FCurve *) * num_drivers, "adt->driver_array"); - int driver_index = 0; - for (FCurve *fcu = adt->drivers.first; fcu; fcu = fcu->next) { - adt->driver_array[driver_index++] = fcu; - } - } + int driver_index = 0; + for (FCurve *fcu = adt->drivers.first; fcu; fcu = fcu->next) { + adt->driver_array[driver_index++] = fcu; + } + } } void BKE_animsys_eval_driver(Depsgraph *depsgraph, @@ -3727,74 +3938,71 @@ void BKE_animsys_eval_driver(Depsgraph *depsgraph, int driver_index, ChannelDriver *driver_orig) { - /* TODO(sergey): De-duplicate with BKE animsys. */ - PointerRNA id_ptr; - bool ok = false; - - /* Lookup driver, accelerated with driver array map. */ - const AnimData *adt = BKE_animdata_from_id(id); - FCurve *fcu; - - if (adt->driver_array) { - fcu = adt->driver_array[driver_index]; - } - else { - fcu = BLI_findlink(&adt->drivers, driver_index); - } - - DEG_debug_print_eval_subdata_index( - depsgraph, __func__, id->name, id, "fcu", fcu->rna_path, fcu, fcu->array_index); - - RNA_id_pointer_create(id, &id_ptr); - - /* check if this driver's curve should be skipped */ - if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) { - /* check if driver itself is tagged for recalculation */ - /* XXX driver recalc flag is not set yet by depsgraph! */ - if ((driver_orig) && !(driver_orig->flag & DRIVER_FLAG_INVALID)) { - /* evaluate this using values set already in other places - * NOTE: for 'layering' option later on, we should check if we should remove old value before adding - * new to only be done when drivers only changed */ - //printf("\told val = %f\n", fcu->curval); - - PathResolvedRNA anim_rna; - if (animsys_store_rna_setting(&id_ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { - /* Evaluate driver, and write results to COW-domain destination */ - const float ctime = DEG_get_ctime(depsgraph); - const float curval = evaluate_fcurve_driver(&anim_rna, fcu, driver_orig, ctime); - ok = animsys_write_rna_setting(&anim_rna, curval); - - /* Flush results & status codes to original data for UI (T59984) */ - if (ok && DEG_is_active(depsgraph)) { - animsys_write_orig_anim_rna(&id_ptr, fcu->rna_path, fcu->array_index, curval); - - /* curval is displayed in the UI, and flag contains error-status codes */ - driver_orig->curval = fcu->driver->curval; - driver_orig->flag = fcu->driver->flag; - - DriverVar *dvar_orig = driver_orig->variables.first; - DriverVar *dvar = fcu->driver->variables.first; - for (; - dvar_orig && dvar; - dvar_orig = dvar_orig->next, dvar = dvar->next) - { - DriverTarget *dtar_orig = &dvar_orig->targets[0]; - DriverTarget *dtar = &dvar->targets[0]; - for (int i = 0; i < MAX_DRIVER_TARGETS; i++, dtar_orig++, dtar++) { - dtar_orig->flag = dtar->flag; - } - - dvar_orig->curval = dvar->curval; - dvar_orig->flag = dvar->flag; - } - } - } - - /* set error-flag if evaluation failed */ - if (ok == 0) { - CLOG_ERROR(&LOG, "invalid driver - %s[%d]", fcu->rna_path, fcu->array_index); - driver_orig->flag |= DRIVER_FLAG_INVALID; - } - } - } + /* TODO(sergey): De-duplicate with BKE animsys. */ + PointerRNA id_ptr; + bool ok = false; + + /* Lookup driver, accelerated with driver array map. */ + const AnimData *adt = BKE_animdata_from_id(id); + FCurve *fcu; + + if (adt->driver_array) { + fcu = adt->driver_array[driver_index]; + } + else { + fcu = BLI_findlink(&adt->drivers, driver_index); + } + + DEG_debug_print_eval_subdata_index( + depsgraph, __func__, id->name, id, "fcu", fcu->rna_path, fcu, fcu->array_index); + + RNA_id_pointer_create(id, &id_ptr); + + /* check if this driver's curve should be skipped */ + if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) { + /* check if driver itself is tagged for recalculation */ + /* XXX driver recalc flag is not set yet by depsgraph! */ + if ((driver_orig) && !(driver_orig->flag & DRIVER_FLAG_INVALID)) { + /* evaluate this using values set already in other places + * NOTE: for 'layering' option later on, we should check if we should remove old value before adding + * new to only be done when drivers only changed */ + //printf("\told val = %f\n", fcu->curval); + + PathResolvedRNA anim_rna; + if (animsys_store_rna_setting(&id_ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { + /* Evaluate driver, and write results to COW-domain destination */ + const float ctime = DEG_get_ctime(depsgraph); + const float curval = evaluate_fcurve_driver(&anim_rna, fcu, driver_orig, ctime); + ok = animsys_write_rna_setting(&anim_rna, curval); + + /* Flush results & status codes to original data for UI (T59984) */ + if (ok && DEG_is_active(depsgraph)) { + animsys_write_orig_anim_rna(&id_ptr, fcu->rna_path, fcu->array_index, curval); + + /* curval is displayed in the UI, and flag contains error-status codes */ + driver_orig->curval = fcu->driver->curval; + driver_orig->flag = fcu->driver->flag; + + DriverVar *dvar_orig = driver_orig->variables.first; + DriverVar *dvar = fcu->driver->variables.first; + for (; dvar_orig && dvar; dvar_orig = dvar_orig->next, dvar = dvar->next) { + DriverTarget *dtar_orig = &dvar_orig->targets[0]; + DriverTarget *dtar = &dvar->targets[0]; + for (int i = 0; i < MAX_DRIVER_TARGETS; i++, dtar_orig++, dtar++) { + dtar_orig->flag = dtar->flag; + } + + dvar_orig->curval = dvar->curval; + dvar_orig->flag = dvar->flag; + } + } + } + + /* set error-flag if evaluation failed */ + if (ok == 0) { + CLOG_ERROR(&LOG, "invalid driver - %s[%d]", fcu->rna_path, fcu->array_index); + driver_orig->flag |= DRIVER_FLAG_INVALID; + } + } + } } |