Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/anim_sys.c
| Show First 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | |||||
| #include "DEG_depsgraph_query.h" | #include "DEG_depsgraph_query.h" | ||||
| #include "RNA_access.h" | #include "RNA_access.h" | ||||
| #include "nla_private.h" | #include "nla_private.h" | ||||
| #include "atomic_ops.h" | #include "atomic_ops.h" | ||||
| #include "CLG_log.h" | |||||
| static CLG_LogRef LOG = {"bke.anim_sys"}; | |||||
| /* ***************************************** */ | /* ***************************************** */ | ||||
| /* AnimData API */ | /* AnimData API */ | ||||
| /* Getter/Setter -------------------------------------------- */ | /* Getter/Setter -------------------------------------------- */ | ||||
| /* Check if ID can have AnimData */ | /* Check if ID can have AnimData */ | ||||
| bool id_type_can_have_animdata(const short id_type) | bool id_type_can_have_animdata(const short id_type) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 267 Lines • ▼ Show 20 Lines | void BKE_animdata_merge_copy( | ||||
| AnimData *dst = BKE_animdata_from_id(dst_id); | AnimData *dst = BKE_animdata_from_id(dst_id); | ||||
| /* sanity checks */ | /* sanity checks */ | ||||
| if (ELEM(NULL, dst, src)) | if (ELEM(NULL, dst, src)) | ||||
| return; | return; | ||||
| // TODO: we must unset all "tweakmode" flags | // TODO: we must unset all "tweakmode" flags | ||||
| if ((src->flag & ADT_NLA_EDIT_ON) || (dst->flag & ADT_NLA_EDIT_ON)) { | if ((src->flag & ADT_NLA_EDIT_ON) || (dst->flag & ADT_NLA_EDIT_ON)) { | ||||
| printf("ERROR: Merging AnimData blocks while editing NLA is dangerous as it may cause data corruption\n"); | CLOG_ERROR(&LOG, "Merging AnimData blocks while editing NLA is dangerous as it may cause data corruption"); | ||||
| return; | return; | ||||
| } | } | ||||
| /* handle actions... */ | /* handle actions... */ | ||||
| if (action_mode == ADT_MERGECOPY_SRC_COPY) { | if (action_mode == ADT_MERGECOPY_SRC_COPY) { | ||||
| /* make a copy of the actions */ | /* make a copy of the actions */ | ||||
| dst->action = BKE_action_copy(bmain, src->action); | dst->action = BKE_action_copy(bmain, src->action); | ||||
| dst->tmpact = BKE_action_copy(bmain, src->tmpact); | dst->tmpact = BKE_action_copy(bmain, src->tmpact); | ||||
| ▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | |||||
| */ | */ | ||||
| void action_move_fcurves_by_basepath(bAction *srcAct, bAction *dstAct, const char basepath[]) | void action_move_fcurves_by_basepath(bAction *srcAct, bAction *dstAct, const char basepath[]) | ||||
| { | { | ||||
| FCurve *fcu, *fcn = NULL; | FCurve *fcu, *fcn = NULL; | ||||
| /* sanity checks */ | /* sanity checks */ | ||||
| if (ELEM(NULL, srcAct, dstAct, basepath)) { | if (ELEM(NULL, srcAct, dstAct, basepath)) { | ||||
| if (G.debug & G_DEBUG) { | if (G.debug & G_DEBUG) { | ||||
| printf("ERROR: action_partition_fcurves_by_basepath(%p, %p, %p) has insufficient info to work with\n", | CLOG_ERROR(&LOG, "srcAct: %p, dstAct: %p, basepath: %p has insufficient info to work with", | ||||
| (void *)srcAct, (void *)dstAct, (void *)basepath); | (void *)srcAct, (void *)dstAct, (void *)basepath); | ||||
| } | } | ||||
| return; | return; | ||||
| } | } | ||||
| /* clear 'temp' flags on all groups in src, as we'll be needing them later | /* 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 | * to identify groups that we've managed to empty out here | ||||
| */ | */ | ||||
| action_groups_clear_tempflags(srcAct); | action_groups_clear_tempflags(srcAct); | ||||
| ▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | void BKE_animdata_separate_by_basepath( | ||||
| Main *bmain, ID *srcID, ID *dstID, ListBase *basepaths) | Main *bmain, ID *srcID, ID *dstID, ListBase *basepaths) | ||||
| { | { | ||||
| AnimData *srcAdt = NULL, *dstAdt = NULL; | AnimData *srcAdt = NULL, *dstAdt = NULL; | ||||
| LinkData *ld; | LinkData *ld; | ||||
| /* sanity checks */ | /* sanity checks */ | ||||
| if (ELEM(NULL, srcID, dstID)) { | if (ELEM(NULL, srcID, dstID)) { | ||||
| if (G.debug & G_DEBUG) | if (G.debug & G_DEBUG) | ||||
| printf("ERROR: no source or destination ID to separate AnimData with\n"); | CLOG_ERROR(&LOG, "no source or destination ID to separate AnimData with"); | ||||
| return; | return; | ||||
| } | } | ||||
| /* get animdata from src, and create for destination (if needed) */ | /* get animdata from src, and create for destination (if needed) */ | ||||
| srcAdt = BKE_animdata_from_id(srcID); | srcAdt = BKE_animdata_from_id(srcID); | ||||
| dstAdt = BKE_animdata_add_id(dstID); | dstAdt = BKE_animdata_add_id(dstID); | ||||
| if (ELEM(NULL, srcAdt, dstAdt)) { | if (ELEM(NULL, srcAdt, dstAdt)) { | ||||
| if (G.debug & G_DEBUG) | if (G.debug & G_DEBUG) | ||||
| printf("ERROR: no AnimData for this pair of ID's\n"); | CLOG_ERROR(&LOG, "no AnimData for this pair of ID's"); | ||||
| return; | return; | ||||
| } | } | ||||
| /* active action */ | /* active action */ | ||||
| if (srcAdt->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 */ | /* 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) { | if (dstAdt->action == NULL) { | ||||
| dstAdt->action = BKE_action_add(bmain, srcAdt->action->id.name + 2); | dstAdt->action = BKE_action_add(bmain, srcAdt->action->id.name + 2); | ||||
| } | } | ||||
| else if (dstAdt->action == srcAdt->action) { | else if (dstAdt->action == srcAdt->action) { | ||||
| printf("Argh! Source and Destination share animation! ('%s' and '%s' both use '%s') Making new empty action\n", | 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); | srcID->name, dstID->name, srcAdt->action->id.name); | ||||
| /* TODO: review this... */ | /* TODO: review this... */ | ||||
| id_us_min(&dstAdt->action->id); | id_us_min(&dstAdt->action->id); | ||||
| dstAdt->action = BKE_action_add(bmain, dstAdt->action->id.name + 2); | dstAdt->action = BKE_action_add(bmain, dstAdt->action->id.name + 2); | ||||
| } | } | ||||
| /* loop over base paths, trying to fix for each one... */ | /* loop over base paths, trying to fix for each one... */ | ||||
| for (ld = basepaths->first; ld; ld = ld->next) { | for (ld = basepaths->first; ld; ld = ld->next) { | ||||
| ▲ Show 20 Lines • Show All 249 Lines • ▼ Show 20 Lines | |||||
| char *BKE_animsys_fix_rna_path_rename(ID *owner_id, char *old_path, const char *prefix, const char *oldName, | 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) | const char *newName, int oldSubscript, int newSubscript, bool verify_paths) | ||||
| { | { | ||||
| char *oldN, *newN; | char *oldN, *newN; | ||||
| char *result; | char *result; | ||||
| /* if no action, no need to proceed */ | /* if no action, no need to proceed */ | ||||
| if (ELEM(NULL, owner_id, old_path)) { | if (ELEM(NULL, owner_id, old_path)) { | ||||
| if (G.debug & G_DEBUG) printf("%s: early abort\n", __func__); | if (G.debug & G_DEBUG) CLOG_WARN(&LOG, "early abort"); | ||||
| return old_path; | return old_path; | ||||
| } | } | ||||
| /* Name sanitation logic - copied from BKE_animdata_fix_paths_rename() */ | /* Name sanitation logic - copied from BKE_animdata_fix_paths_rename() */ | ||||
| if ((oldName != NULL) && (newName != NULL)) { | if ((oldName != NULL) && (newName != NULL)) { | ||||
| /* pad the names with [" "] so that only exact matches are made */ | /* pad the names with [" "] so that only exact matches are made */ | ||||
| const size_t name_old_len = strlen(oldName); | const size_t name_old_len = strlen(oldName); | ||||
| const size_t name_new_len = strlen(newName); | const size_t name_new_len = strlen(newName); | ||||
| ▲ Show 20 Lines • Show All 540 Lines • ▼ Show 20 Lines | |||||
| * Checks are performed to ensure that destination is appropriate for the KeyingSet in question | * 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 *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; | KS_Path *ksp; | ||||
| /* sanity checks */ | /* sanity checks */ | ||||
| if (ELEM(NULL, ks, rna_path)) { | if (ELEM(NULL, ks, rna_path)) { | ||||
| printf("ERROR: no Keying Set and/or RNA Path to add path with\n"); | CLOG_ERROR(&LOG, "no Keying Set and/or RNA Path to add path with"); | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| /* ID is required for all types of KeyingSets */ | /* ID is required for all types of KeyingSets */ | ||||
| if (id == NULL) { | if (id == NULL) { | ||||
| printf("ERROR: No ID provided for Keying Set Path\n"); | CLOG_ERROR(&LOG, "No ID provided for Keying Set Path"); | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| /* don't add if there is already a matching KS_Path in the KeyingSet */ | /* 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 (BKE_keyingset_find_path(ks, id, group_name, rna_path, array_index, groupmode)) { | ||||
| if (G.debug & G_DEBUG) | if (G.debug & G_DEBUG) | ||||
| printf("ERROR: destination already exists in Keying Set\n"); | CLOG_ERROR(&LOG, "destination already exists in Keying Set"); | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| /* allocate a new KeyingSet Path */ | /* allocate a new KeyingSet Path */ | ||||
| ksp = MEM_callocN(sizeof(KS_Path), "KeyingSet Path"); | ksp = MEM_callocN(sizeof(KS_Path), "KeyingSet Path"); | ||||
| /* just store absolute info */ | /* just store absolute info */ | ||||
| ksp->id = id; | ksp->id = id; | ||||
| ▲ Show 20 Lines • Show All 106 Lines • ▼ Show 20 Lines | static bool animsys_store_rna_setting( | ||||
| if (path) { | if (path) { | ||||
| /* get property to write to */ | /* get property to write to */ | ||||
| if (RNA_path_resolve_property(ptr, path, &r_result->ptr, &r_result->prop)) { | 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)) { | 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); | int array_len = RNA_property_array_length(&r_result->ptr, r_result->prop); | ||||
| if (array_len && array_index >= array_len) { | if (array_len && array_index >= array_len) { | ||||
| if (G.debug & G_DEBUG) { | if (G.debug & G_DEBUG) { | ||||
| printf("Animato: Invalid array index. ID = '%s', '%s[%d]', array length is %d\n", | 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>", | (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>", | ||||
| path, array_index, array_len - 1); | path, array_index, array_len - 1); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| r_result->prop_index = array_len ? array_index : -1; | r_result->prop_index = array_len ? array_index : -1; | ||||
| success = true; | success = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* failed to get path */ | /* failed to get path */ | ||||
| /* XXX don't tag as failed yet though, as there are some legit situations (Action Constraint) | /* 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 */ | * where some channels will not exist, but shouldn't lock up Action */ | ||||
| if (G.debug & G_DEBUG) { | if (G.debug & G_DEBUG) { | ||||
| printf("Animato: Invalid path. ID = '%s', '%s[%d]'\n", | CLOG_WARN(&LOG, "Animato: Invalid path. ID = '%s', '%s[%d]'", | ||||
| (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>", | (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>", | ||||
| path, array_index); | path, array_index); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return success; | return success; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 882 Lines • ▼ Show 20 Lines | static NlaEvalChannel *nlaevalchan_verify(PointerRNA *ptr, NlaEvalData *nlaeval, const char *path) | ||||
| } | } | ||||
| /* Resolve the property and look it up in the key hash. */ | /* Resolve the property and look it up in the key hash. */ | ||||
| NlaEvalChannelKey key; | NlaEvalChannelKey key; | ||||
| if (!RNA_path_resolve_property(ptr, path, &key.ptr, &key.prop)) { | if (!RNA_path_resolve_property(ptr, path, &key.ptr, &key.prop)) { | ||||
| /* Report failure to resolve the path. */ | /* Report failure to resolve the path. */ | ||||
| if (G.debug & G_DEBUG) { | if (G.debug & G_DEBUG) { | ||||
| printf("Animato: Invalid path. ID = '%s', '%s'\n", | CLOG_WARN(&LOG, "Animato: Invalid path. ID = '%s', '%s'", | ||||
| (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>", path); | (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>", path); | ||||
| } | } | ||||
| /* Cache NULL result. */ | /* Cache NULL result. */ | ||||
| *p_path_nec = NULL; | *p_path_nec = NULL; | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| NlaEvalChannel *nec = nlaevalchan_verify_key(nlaeval, path, &key); | NlaEvalChannel *nec = nlaevalchan_verify_key(nlaeval, path, &key); | ||||
| ▲ Show 20 Lines • Show All 204 Lines • ▼ Show 20 Lines | if (nec == NULL) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| int index = nlaevalchan_validate_index(nec, array_index); | int index = nlaevalchan_validate_index(nec, array_index); | ||||
| if (index < 0) { | if (index < 0) { | ||||
| if (G.debug & G_DEBUG) { | if (G.debug & G_DEBUG) { | ||||
| ID *id = nec->key.ptr.id.data; | ID *id = nec->key.ptr.id.data; | ||||
| printf("Animato: Invalid array index. ID = '%s', '%s[%d]', array length is %d\n", | 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); | id ? (id->name + 2) : "<No ID>", nec->rna_path, array_index, nec->base_snapshot.length); | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (nec->mix_mode == NEC_MIX_QUATERNION) { | if (nec->mix_mode == NEC_MIX_QUATERNION) { | ||||
| /* For quaternion properties, always output all sub-channels. */ | /* For quaternion properties, always output all sub-channels. */ | ||||
| BLI_bitmap_set_all(nec->valid.ptr, true, 4); | BLI_bitmap_set_all(nec->valid.ptr, true, 4); | ||||
| ▲ Show 20 Lines • Show All 157 Lines • ▼ Show 20 Lines | static void nlastrip_evaluate_actionclip(PointerRNA *ptr, NlaEvalData *channels, ListBase *modifiers, NlaEvalStrip *nes, NlaEvalSnapshot *snapshot) | ||||
| FCurve *fcu; | FCurve *fcu; | ||||
| float evaltime; | float evaltime; | ||||
| /* sanity checks for action */ | /* sanity checks for action */ | ||||
| if (strip == NULL) | if (strip == NULL) | ||||
| return; | return; | ||||
| if (strip->act == NULL) { | if (strip->act == NULL) { | ||||
| printf("NLA-Strip Eval Error: Strip '%s' has no Action\n", strip->name); | CLOG_ERROR(&LOG, "NLA-Strip Eval Error: Strip '%s' has no Action", strip->name); | ||||
| return; | 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) */ | /* join this strip's modifiers to the parent's modifiers (own modifiers first) */ | ||||
| nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &strip->modifiers, modifiers); | nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &strip->modifiers, modifiers); | ||||
| ▲ Show 20 Lines • Show All 442 Lines • ▼ Show 20 Lines | if (animsys_evaluate_nla(depsgraph, &echannels, ptr, adt, ctime, NULL)) { | ||||
| animsys_evaluate_nla_domain(ptr, &echannels, adt); | animsys_evaluate_nla_domain(ptr, &echannels, adt); | ||||
| /* flush effects of accumulating channels in NLA to the actual data they affect */ | /* flush effects of accumulating channels in NLA to the actual data they affect */ | ||||
| nladata_flush_channels(depsgraph, ptr, &echannels, &echannels.eval_snapshot); | nladata_flush_channels(depsgraph, ptr, &echannels, &echannels.eval_snapshot); | ||||
| } | } | ||||
| else { | else { | ||||
| /* special case - evaluate as if there isn't any NLA data */ | /* special case - evaluate as if there isn't any NLA data */ | ||||
| /* TODO: this is really just a stop-gap measure... */ | /* TODO: this is really just a stop-gap measure... */ | ||||
| if (G.debug & G_DEBUG) printf("NLA Eval: Stopgap for active action on NLA Stack - no strips case\n"); | 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 */ | /* free temp data */ | ||||
| nlaeval_free(&echannels); | nlaeval_free(&echannels); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 501 Lines • ▼ Show 20 Lines | if ((driver_orig) && !(driver_orig->flag & DRIVER_FLAG_INVALID) /*&& (driver_orig->flag & DRIVER_FLAG_RECALC)*/) { | ||||
| //printf("\tnew val = %f\n", fcu->curval); | //printf("\tnew val = %f\n", fcu->curval); | ||||
| /* clear recalc flag */ | /* clear recalc flag */ | ||||
| driver_orig->flag &= ~DRIVER_FLAG_RECALC; | driver_orig->flag &= ~DRIVER_FLAG_RECALC; | ||||
| /* set error-flag if evaluation failed */ | /* set error-flag if evaluation failed */ | ||||
| if (ok == 0) { | if (ok == 0) { | ||||
| printf("invalid driver - %s[%d]\n", fcu->rna_path, fcu->array_index); | CLOG_ERROR(&LOG, "invalid driver - %s[%d]", fcu->rna_path, fcu->array_index); | ||||
| driver_orig->flag |= DRIVER_FLAG_INVALID; | driver_orig->flag |= DRIVER_FLAG_INVALID; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||