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 ++++++++----- source/blender/editors/animation/keyframing.c | 13 +- source/blender/editors/space_graph/graph_buttons.c | 5 + source/blender/makesdna/DNA_anim_types.h | 4 +- source/blender/makesrna/RNA_access.h | 5 + source/blender/makesrna/RNA_types.h | 10 ++ source/blender/makesrna/intern/rna_access.c | 19 +++ source/blender/makesrna/intern/rna_fcurve.c | 8 +- source/blender/python/BPY_extern.h | 3 +- source/blender/python/intern/bpy_driver.c | 21 ++- source/blender/python/intern/bpy_driver.h | 3 +- source/blender/python/intern/bpy_rna_driver.c | 5 + source/blender/python/intern/bpy_rna_driver.h | 2 + 16 files changed, 256 insertions(+), 103 deletions(-) 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; } diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 0c0f54f0179..98be77b491f 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -930,11 +930,18 @@ bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *pr /* update F-Curve flags to ensure proper behaviour for property type */ update_autoflags_fcurve_direct(fcu, prop); - + /* adjust frame on which to add keyframe */ if ((flag & INSERTKEY_DRIVER) && (fcu->driver)) { - /* for making it easier to add corrective drivers... */ - cfra = evaluate_driver(fcu->driver, cfra); + PathResolvedRNA anim_rna; + + if (RNA_path_resolved_create(&ptr, prop, fcu->array_index, &anim_rna)) { + /* for making it easier to add corrective drivers... */ + cfra = evaluate_driver(&anim_rna, fcu->driver, cfra); + } + else { + cfra = 0.0f; + } } /* obtain value to give keyframe */ diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index a9ab1502e16..4cbf04f9d42 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -812,6 +812,11 @@ static void graph_panel_drivers(const bContext *C, Panel *pa) } col = uiLayoutColumn(pa->layout, true); + + if (driver->type == DRIVER_TYPE_PYTHON) { + uiItemR(col, &driver_ptr, "use_self", 0, NULL, ICON_NONE); + } + /* debug setting */ uiItemR(col, &driver_ptr, "show_debug_info", 0, NULL, ICON_NONE); diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h index 6bd7b3a4999..31fe8fe563e 100644 --- a/source/blender/makesdna/DNA_anim_types.h +++ b/source/blender/makesdna/DNA_anim_types.h @@ -450,7 +450,9 @@ typedef enum eDriver_Flags { /* the names are cached so they don't need have python unicode versions created each time */ DRIVER_FLAG_RENAMEVAR = (1<<4), /* intermediate values of driver should be shown in the UI for debugging purposes */ - DRIVER_FLAG_SHOWDEBUG = (1<<5) + DRIVER_FLAG_SHOWDEBUG = (1<<5), + /* include 'self' in the drivers namespace. */ + DRIVER_FLAG_USE_SELF = (1<<6), } eDriver_Flags; /* F-Curves -------------------------------------- */ diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index c3d25ed2972..e884d769afe 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -715,6 +715,11 @@ void RNA_main_pointer_create(struct Main *main, PointerRNA *r_ptr); void RNA_id_pointer_create(struct ID *id, PointerRNA *r_ptr); void RNA_pointer_create(struct ID *id, StructRNA *type, void *data, PointerRNA *r_ptr); +bool RNA_path_resolved_create( + PointerRNA *ptr, struct PropertyRNA *prop, + const int prop_index, + PathResolvedRNA *r_anim_rna); + void RNA_blender_rna_pointer_create(PointerRNA *r_ptr); void RNA_pointer_recast(PointerRNA *ptr, PointerRNA *r_ptr); diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index 1d5f46a1814..276531992f9 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -64,6 +64,16 @@ typedef struct PropertyPointerRNA { struct PropertyRNA *prop; } PropertyPointerRNA; +/** + * Stored result of a RNA path lookup (as used by anim-system) + */ +typedef struct PathResolvedRNA { + struct PointerRNA ptr; + struct PropertyRNA *prop; + /* -1 for non-array access */ + int prop_index; +} PathResolvedRNA; + /* Property */ typedef enum PropertyType { diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 5a93e18a7dd..047e5ea17ab 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -6966,3 +6966,22 @@ bool RNA_struct_equals(PointerRNA *a, PointerRNA *b, eRNAEqualsMode mode) return equals; } + +bool RNA_path_resolved_create( + PointerRNA *ptr, struct PropertyRNA *prop, + const int prop_index, + PathResolvedRNA *r_anim_rna) +{ + int array_len = RNA_property_array_length(ptr, prop); + + if ((array_len == 0) || (prop_index < array_len)) { + r_anim_rna->ptr = *ptr; + r_anim_rna->prop = prop; + r_anim_rna->prop_index = array_len ? prop_index : -1; + + return true; + } + else { + return false; + } +} diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index 5fb581eb74a..08c0f98e45b 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -1600,7 +1600,13 @@ static void rna_def_channeldriver(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", DRIVER_FLAG_SHOWDEBUG); RNA_def_property_ui_text(prop, "Show Debug Info", "Show intermediate values for the driver calculations to allow debugging of drivers"); - + + prop = RNA_def_property(srna, "use_self", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", DRIVER_FLAG_USE_SELF); + RNA_def_property_ui_text(prop, "Use Self", + "Pass 'self' argument to Py-Driver, " + "so it can access the data referenced by the driver (object, bone, etc...)"); + /* State Info (for Debugging) */ prop = RNA_def_property(srna, "is_valid", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", DRIVER_FLAG_INVALID); diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h index 4006816e788..3148dab3c50 100644 --- a/source/blender/python/BPY_extern.h +++ b/source/blender/python/BPY_extern.h @@ -32,6 +32,7 @@ #ifndef __BPY_EXTERN_H__ #define __BPY_EXTERN_H__ +struct PathResolvedRNA; struct Text; /* defined in DNA_text_types.h */ struct ID; /* DNA_ID.h */ struct Object; /* DNA_object_types.h */ @@ -85,7 +86,7 @@ void BPY_modules_load_user(struct bContext *C); void BPY_app_handlers_reset(const short do_all); void BPY_driver_reset(void); -float BPY_driver_exec(struct ChannelDriver *driver, const float evaltime); +float BPY_driver_exec(struct PathResolvedRNA *anim_rna, struct ChannelDriver *driver, const float evaltime); void BPY_DECREF(void *pyob_ptr); /* Py_DECREF() */ void BPY_DECREF_RNA_INVALIDATE(void *pyob_ptr); diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c index 65b6bd501ce..2f0c054e381 100644 --- a/source/blender/python/intern/bpy_driver.c +++ b/source/blender/python/intern/bpy_driver.c @@ -120,6 +120,22 @@ static void bpy_pydriver_update_dict(const float evaltime) } } +static PyObject *bpy_pydriver_InternStr__self = NULL; + +static void bpy_pydriver_update_dict_self(struct PathResolvedRNA *anim_rna) +{ + if (bpy_pydriver_InternStr__self == NULL) { + bpy_pydriver_InternStr__self = PyUnicode_FromString("self"); + } + + PyObject *item = pyrna_driver_self_from_anim_rna(anim_rna); + PyDict_SetItem(bpy_pydriver_Dict, + bpy_pydriver_InternStr__self, + item); + Py_DECREF(item); + +} + /* Update function, it gets rid of pydrivers global dictionary, forcing * BPY_driver_exec to recreate it. This function is used to force * reloading the Blender text module "pydrivers.py", if available, so @@ -174,7 +190,7 @@ static void pydriver_error(ChannelDriver *driver) * now release the GIL on python operator execution instead, using * PyEval_SaveThread() / PyEval_RestoreThread() so we don't lock up blender. */ -float BPY_driver_exec(ChannelDriver *driver, const float evaltime) +float BPY_driver_exec(struct PathResolvedRNA *anim_rna, ChannelDriver *driver, const float evaltime) { PyObject *driver_vars = NULL; PyObject *retval = NULL; @@ -226,6 +242,9 @@ float BPY_driver_exec(ChannelDriver *driver, const float evaltime) /* update global namespace */ bpy_pydriver_update_dict(evaltime); + if (driver->flag & DRIVER_FLAG_USE_SELF) { + bpy_pydriver_update_dict_self(anim_rna); + } if (driver->expr_comp == NULL) driver->flag |= DRIVER_FLAG_RECOMPILE; diff --git a/source/blender/python/intern/bpy_driver.h b/source/blender/python/intern/bpy_driver.h index 1fccec7e1b2..017a6fe89c5 100644 --- a/source/blender/python/intern/bpy_driver.h +++ b/source/blender/python/intern/bpy_driver.h @@ -28,12 +28,13 @@ #define __BPY_DRIVER_H__ struct ChannelDriver; +struct PathResolvedRNA; int bpy_pydriver_create_dict(void); extern PyObject *bpy_pydriver_Dict; /* externals */ -float BPY_driver_exec(struct ChannelDriver *driver, const float evaltime); +float BPY_driver_exec(struct PathResolvedRNA *anim_rna, struct ChannelDriver *driver, const float evaltime); void BPY_driver_reset(void); #endif /* __BPY_DRIVER_H__ */ diff --git a/source/blender/python/intern/bpy_rna_driver.c b/source/blender/python/intern/bpy_rna_driver.c index 482508a8d85..98fc372f2fc 100644 --- a/source/blender/python/intern/bpy_rna_driver.c +++ b/source/blender/python/intern/bpy_rna_driver.c @@ -77,3 +77,8 @@ PyObject *pyrna_driver_get_variable_value( return driver_arg; } + +PyObject *pyrna_driver_self_from_anim_rna(struct PathResolvedRNA *anim_rna) +{ + return pyrna_struct_CreatePyObject(&anim_rna->ptr); +} diff --git a/source/blender/python/intern/bpy_rna_driver.h b/source/blender/python/intern/bpy_rna_driver.h index 8deac2e4384..2021575537d 100644 --- a/source/blender/python/intern/bpy_rna_driver.h +++ b/source/blender/python/intern/bpy_rna_driver.h @@ -27,7 +27,9 @@ struct ChannelDriver; struct DriverTarget; +struct PathResolvedRNA; PyObject *pyrna_driver_get_variable_value(struct ChannelDriver *driver, struct DriverTarget *dtar); +PyObject *pyrna_driver_self_from_anim_rna(struct PathResolvedRNA *anim_rna); #endif /* __BPY_RNA_DRIVER_H__ */ -- cgit v1.2.3