From 4e845e06704bad3c11297ae8e86b400ef80b2a89 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 30 Jul 2016 16:34:01 +1000 Subject: Py-Driver: add 'self' option Drivers can use this to refer to the data which the driver is applied to, useful for objects, bones, to avoid having to create a variable pointing to its self. --- source/blender/blenkernel/BKE_animsys.h | 1 + source/blender/blenkernel/BKE_fcurve.h | 6 +- source/blender/blenkernel/intern/anim_sys.c | 156 ++++++++++++++++++---------- source/blender/blenkernel/intern/fcurve.c | 98 ++++++++++------- 4 files changed, 166 insertions(+), 95 deletions(-) (limited to 'source/blender/blenkernel') diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index 983f3ce22b8..00ea323f934 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -37,6 +37,7 @@ struct Main; struct AnimData; struct KeyingSet; struct KS_Path; +struct PathResolvedRNA; struct bContext; struct PointerRNA; diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index bb4eb652ae2..3a45097efc5 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -48,6 +48,7 @@ struct AnimData; struct bAction; struct BezTriple; struct StructRNA; +struct PathResolvedRNA; struct PointerRNA; struct PropertyRNA; @@ -107,7 +108,7 @@ bool driver_get_variable_property( struct ChannelDriver *driver, struct DriverTarget *dtar, struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index); -float evaluate_driver(struct ChannelDriver *driver, const float evaltime); +float evaluate_driver(struct PathResolvedRNA *anim_rna, struct ChannelDriver *driver, const float evaltime); /* ************** F-Curve Modifiers *************** */ @@ -278,8 +279,9 @@ void correct_bezpart(float v1[2], float v2[2], float v3[2], float v4[2]); /* evaluate fcurve */ float evaluate_fcurve(struct FCurve *fcu, float evaltime); +float evaluate_fcurve_driver(struct PathResolvedRNA *anim_rna, struct FCurve *fcu, float evaltime); /* evaluate fcurve and store value */ -float calculate_fcurve(struct FCurve *fcu, float evaltime); +float calculate_fcurve(struct PathResolvedRNA *anim_rna, struct FCurve *fcu, float evaltime); /* ************* F-Curve Samples API ******************** */ diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index d04b950c043..0d184b70ce3 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -1482,41 +1482,87 @@ static bool animsys_remap_path(AnimMapper *UNUSED(remap), char *path, char **dst return false; } +static bool animsys_store_rna_setting( + PointerRNA *ptr, AnimMapper *remap, + /* typically 'fcu->rna_path', 'fcu->array_index' */ + const char *rna_path, const int array_index, + PathResolvedRNA *r_result) +{ + bool success = false; + + char *path = NULL; + bool free_path; + + /* get path, remapped as appropriate to work in its new environment */ + free_path = animsys_remap_path(remap, (char *)rna_path, &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) { + printf("Animato: Invalid array index. ID = '%s', '%s[%d]', array length is %d\n", + (ptr && ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "", + 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) { + printf("Animato: Invalid path. ID = '%s', '%s[%d]'\n", + (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "", + path, array_index); + } + } + } + + /* free temp path-info */ + if (free_path) { + MEM_freeN((void *)path); + } + + 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))) /* Write the given value to a setting using RNA, and return success */ -static bool animsys_write_rna_setting(PointerRNA *ptr, char *path, int array_index, float value) +static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, float value) { - PropertyRNA *prop; - PointerRNA new_ptr; + PropertyRNA *prop = anim_rna->prop; + PointerRNA new_ptr = anim_rna->ptr; + int array_index = anim_rna->prop_index; //printf("%p %s %i %f\n", ptr, path, array_index, value); /* get property to write to */ - if (RNA_path_resolve_property(ptr, path, &new_ptr, &prop)) { + // if (RNA_path_resolve_property(ptr, path, &new_ptr, &prop)) + { /* set value for animatable numerical values only * HACK: some local F-Curves (e.g. those on NLA Strips) are evaluated * without an ID provided, which causes the animateable test to fail! */ - if (RNA_property_animateable(&new_ptr, prop) || (ptr->id.data == NULL)) { - int array_len = RNA_property_array_length(&new_ptr, prop); + // if (RNA_property_animateable(&new_ptr, prop) || (ptr->id.data == NULL)) + { bool written = false; - - if (array_len && array_index >= array_len) { - if (G.debug & G_DEBUG) { - printf("Animato: Invalid array index. ID = '%s', '%s[%d]', array length is %d\n", - (ptr && ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "", - path, array_index, array_len - 1); - } - - return false; - } - + switch (RNA_property_type(prop)) { case PROP_BOOLEAN: - if (array_len) { + if (array_index != -1) { if (RNA_property_boolean_get_index(&new_ptr, prop, array_index) != ANIMSYS_FLOAT_AS_BOOL(value)) { RNA_property_boolean_set_index(&new_ptr, prop, array_index, ANIMSYS_FLOAT_AS_BOOL(value)); written = true; @@ -1530,7 +1576,7 @@ static bool animsys_write_rna_setting(PointerRNA *ptr, char *path, int array_ind } break; case PROP_INT: - if (array_len) { + if (array_index != -1) { if (RNA_property_int_get_index(&new_ptr, prop, array_index) != (int)value) { RNA_property_int_set_index(&new_ptr, prop, array_index, (int)value); written = true; @@ -1544,7 +1590,7 @@ static bool animsys_write_rna_setting(PointerRNA *ptr, char *path, int array_ind } break; case PROP_FLOAT: - if (array_len) { + if (array_index != -1) { if (RNA_property_float_get_index(&new_ptr, prop, array_index) != value) { RNA_property_float_set_index(&new_ptr, prop, array_index, value); written = true; @@ -1606,37 +1652,18 @@ static bool animsys_write_rna_setting(PointerRNA *ptr, char *path, int array_ind /* successful */ return 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) { - printf("Animato: Invalid path. ID = '%s', '%s[%d]'\n", - (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "", - path, array_index); - } - return false; - } } /* Simple replacement based data-setting of the FCurve using RNA */ bool BKE_animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu, float curval) { - char *path = NULL; - bool free_path = false; + PathResolvedRNA anim_rna; bool ok = false; - - /* get path, remapped as appropriate to work in its new environment */ - free_path = animsys_remap_path(remap, fcu->rna_path, &path); - - /* write value to setting */ - if (path) - ok = animsys_write_rna_setting(ptr, path, fcu->array_index, curval); - - /* free temp path-info */ - if (free_path) - MEM_freeN(path); - + + if (animsys_store_rna_setting(ptr, remap, fcu->rna_path, fcu->array_index, &anim_rna)) { + ok = animsys_write_rna_setting(&anim_rna, curval); + } + /* return whether we were successful */ return ok; } @@ -1654,8 +1681,11 @@ static void animsys_evaluate_fcurves(PointerRNA *ptr, ListBase *list, AnimMapper if ((fcu->grp == NULL) || (fcu->grp->flag & AGRP_MUTED) == 0) { /* check if this curve should be skipped */ if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) { - const float curval = calculate_fcurve(fcu, ctime); - BKE_animsys_execute_fcurve(ptr, remap, fcu, curval); + PathResolvedRNA anim_rna; + if (animsys_store_rna_setting(ptr, remap, fcu->rna_path, fcu->array_index, &anim_rna)) { + const float curval = calculate_fcurve(&anim_rna, fcu, ctime); + animsys_write_rna_setting(&anim_rna, curval); + } } } } @@ -1684,8 +1714,12 @@ static void animsys_evaluate_drivers(PointerRNA *ptr, AnimData *adt, float ctime /* 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 */ - const float curval = calculate_fcurve(fcu, ctime); - ok = BKE_animsys_execute_fcurve(ptr, NULL, fcu, curval); + + PathResolvedRNA anim_rna; + if (animsys_store_rna_setting(ptr, NULL, 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); + } /* clear recalc flag */ driver->flag &= ~DRIVER_FLAG_RECALC; @@ -1753,8 +1787,11 @@ void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup * 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) { - const float curval = calculate_fcurve(fcu, ctime); - BKE_animsys_execute_fcurve(ptr, remap, fcu, curval); + PathResolvedRNA anim_rna; + if (animsys_store_rna_setting(ptr, remap, fcu->rna_path, fcu->array_index, &anim_rna)) { + const float curval = calculate_fcurve(&anim_rna, fcu, ctime); + animsys_write_rna_setting(&anim_rna, curval); + } } } } @@ -2612,8 +2649,12 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt) AnimOverride *aor; /* for each override, simply execute... */ - for (aor = adt->overrides.first; aor; aor = aor->next) - animsys_write_rna_setting(ptr, aor->rna_path, aor->array_index, aor->value); + for (aor = adt->overrides.first; aor; aor = aor->next) { + PathResolvedRNA anim_rna; + if (animsys_store_rna_setting(ptr, NULL, aor->rna_path, aor->array_index, &anim_rna)) { + animsys_write_rna_setting(&anim_rna, aor->value); + } + } } /* ***************************************** */ @@ -2888,8 +2929,13 @@ void BKE_animsys_eval_driver(EvaluationContext *eval_ctx, * 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); - const float curval = calculate_fcurve(fcu, eval_ctx->ctime); - ok = BKE_animsys_execute_fcurve(&id_ptr, NULL, fcu, curval); + + PathResolvedRNA anim_rna; + if (animsys_store_rna_setting(&id_ptr, NULL, fcu->rna_path, fcu->array_index, &anim_rna)) { + const float curval = calculate_fcurve(&anim_rna, fcu, eval_ctx->ctime); + ok = animsys_write_rna_setting(&anim_rna, curval); + } + //printf("\tnew val = %f\n", fcu->curval); /* clear recalc flag */ diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 395161aa6ed..a89d423e7a6 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -1859,7 +1859,7 @@ float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar) * - "evaltime" is the frame at which F-Curve is being evaluated * - has to return a float value */ -float evaluate_driver(ChannelDriver *driver, const float evaltime) +float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, const float evaltime) { DriverVar *dvar; @@ -1944,7 +1944,9 @@ float evaluate_driver(ChannelDriver *driver, const float evaltime) * - on errors it reports, then returns 0.0f */ BLI_mutex_lock(&python_driver_lock); - driver->curval = BPY_driver_exec(driver, evaltime); + + driver->curval = BPY_driver_exec(anim_rna, driver, evaltime); + BLI_mutex_unlock(&python_driver_lock); } #else /* WITH_PYTHON*/ @@ -2599,25 +2601,64 @@ static float fcurve_eval_samples(FCurve *fcu, FPoint *fpts, float evaltime) /* Evaluate and return the value of the given F-Curve at the specified frame ("evaltime") * Note: this is also used for drivers */ -float evaluate_fcurve(FCurve *fcu, float evaltime) +static float evaluate_fcurve_ex(FCurve *fcu, float evaltime, float cvalue) { FModifierStackStorage *storage; - float cvalue = 0.0f; float devaltime; + + /* evaluate modifiers which modify time to evaluate the base curve at */ + storage = evaluate_fmodifiers_storage_new(&fcu->modifiers); + devaltime = evaluate_time_fmodifiers(storage, &fcu->modifiers, fcu, cvalue, evaltime); + + /* evaluate curve-data + * - 'devaltime' instead of 'evaltime', as this is the time that the last time-modifying + * F-Curve modifier on the stack requested the curve to be evaluated at + */ + if (fcu->bezt) + cvalue = fcurve_eval_keyframes(fcu, fcu->bezt, devaltime); + else if (fcu->fpt) + cvalue = fcurve_eval_samples(fcu, fcu->fpt, devaltime); + + /* evaluate modifiers */ + evaluate_value_fmodifiers(storage, &fcu->modifiers, fcu, &cvalue, devaltime); + + evaluate_fmodifiers_storage_free(storage); + + /* if curve can only have integral values, perform truncation (i.e. drop the decimal part) + * here so that the curve can be sampled correctly + */ + if (fcu->flag & FCURVE_INT_VALUES) + cvalue = floorf(cvalue + 0.5f); - /* if there is a driver (only if this F-Curve is acting as 'driver'), evaluate it to find value to use as "evaltime" + /* return evaluated value */ + return cvalue; +} + +float evaluate_fcurve(FCurve *fcu, float evaltime) +{ + BLI_assert(fcu->driver == NULL); + + return evaluate_fcurve_ex(fcu, evaltime, 0.0); +} + +float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, FCurve *fcu, float evaltime) +{ + BLI_assert(fcu->driver != NULL); + float cvalue = 0.0f; + + /* if there is a driver (only if this F-Curve is acting as 'driver'), evaluate it to find value to use as "evaltime" * since drivers essentially act as alternative input (i.e. in place of 'time') for F-Curves */ if (fcu->driver) { /* evaltime now serves as input for the curve */ - evaltime = evaluate_driver(fcu->driver, evaltime); - + evaltime = evaluate_driver(anim_rna, fcu->driver, evaltime); + /* only do a default 1-1 mapping if it's unlikely that anything else will set a value... */ if (fcu->totvert == 0) { FModifier *fcm; bool do_linear = true; - - /* out-of-range F-Modifiers will block, as will those which just plain overwrite the values + + /* out-of-range F-Modifiers will block, as will those which just plain overwrite the values * XXX: additive is a bit more dicey; it really depends then if things are in range or not... */ for (fcm = fcu->modifiers.first; fcm; fcm = fcm->next) { @@ -2634,7 +2675,7 @@ float evaluate_fcurve(FCurve *fcu, float evaltime) do_linear = false; } } - + /* only copy over results if none of the modifiers disagreed with this */ if (do_linear) { cvalue = evaltime; @@ -2642,36 +2683,11 @@ float evaluate_fcurve(FCurve *fcu, float evaltime) } } - /* evaluate modifiers which modify time to evaluate the base curve at */ - storage = evaluate_fmodifiers_storage_new(&fcu->modifiers); - devaltime = evaluate_time_fmodifiers(storage, &fcu->modifiers, fcu, cvalue, evaltime); - - /* evaluate curve-data - * - 'devaltime' instead of 'evaltime', as this is the time that the last time-modifying - * F-Curve modifier on the stack requested the curve to be evaluated at - */ - if (fcu->bezt) - cvalue = fcurve_eval_keyframes(fcu, fcu->bezt, devaltime); - else if (fcu->fpt) - cvalue = fcurve_eval_samples(fcu, fcu->fpt, devaltime); - - /* evaluate modifiers */ - evaluate_value_fmodifiers(storage, &fcu->modifiers, fcu, &cvalue, devaltime); - - evaluate_fmodifiers_storage_free(storage); - - /* if curve can only have integral values, perform truncation (i.e. drop the decimal part) - * here so that the curve can be sampled correctly - */ - if (fcu->flag & FCURVE_INT_VALUES) - cvalue = floorf(cvalue + 0.5f); - - /* return evaluated value */ - return cvalue; + return evaluate_fcurve_ex(fcu, evaltime, cvalue); } /* Calculate the value of the given F-Curve at the given frame, and set its curval */ -float calculate_fcurve(FCurve *fcu, float evaltime) +float calculate_fcurve(PathResolvedRNA *anim_rna, FCurve *fcu, float evaltime) { /* only calculate + set curval (overriding the existing value) if curve has * any data which warrants this... @@ -2680,7 +2696,13 @@ float calculate_fcurve(FCurve *fcu, float evaltime) list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE)) { /* calculate and set curval (evaluates driver too if necessary) */ - float curval = evaluate_fcurve(fcu, evaltime); + float curval; + if (fcu->driver) { + curval = evaluate_fcurve_driver(anim_rna, fcu, evaltime); + } + else { + curval = evaluate_fcurve(fcu, evaltime); + } fcu->curval = curval; /* debug display only, not thread safe! */ return curval; } -- cgit v1.2.3