Py-Driver: add 'self' option
authorCampbell Barton <ideasman42@gmail.com>
Sat, 30 Jul 2016 06:34:01 +0000 (16:34 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Sat, 30 Jul 2016 06:46:13 +0000 (16:46 +1000)
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.

16 files changed:
source/blender/blenkernel/BKE_animsys.h
source/blender/blenkernel/BKE_fcurve.h
source/blender/blenkernel/intern/anim_sys.c
source/blender/blenkernel/intern/fcurve.c
source/blender/editors/animation/keyframing.c
source/blender/editors/space_graph/graph_buttons.c
source/blender/makesdna/DNA_anim_types.h
source/blender/makesrna/RNA_access.h
source/blender/makesrna/RNA_types.h
source/blender/makesrna/intern/rna_access.c
source/blender/makesrna/intern/rna_fcurve.c
source/blender/python/BPY_extern.h
source/blender/python/intern/bpy_driver.c
source/blender/python/intern/bpy_driver.h
source/blender/python/intern/bpy_rna_driver.c
source/blender/python/intern/bpy_rna_driver.h

index 983f3ce22b87458e2414d0edd1cf954d5f03de71..00ea323f9343a554ec148ae7173198c27b86094b 100644 (file)
@@ -37,6 +37,7 @@ struct Main;
 struct AnimData;
 struct KeyingSet;
 struct KS_Path;
+struct PathResolvedRNA;
 struct bContext;
 
 struct PointerRNA;
index bb4eb652ae26bba7c3d10c1c6730430c9e2e8567..3a45097efc5fbbb777402ba1d44e6da9740dcc34 100644 (file)
@@ -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 ******************** */
 
index d04b950c0434a3064c0b755ed2d73787350fa0da..0d184b70ce3c49ce70faf291f9d8f00cf45e2e0f 100644 (file)
@@ -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) : "<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) {
+                               printf("Animato: Invalid path. ID = '%s',  '%s[%d]'\n",
+                                      (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>",
+                                      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) : "<No ID>",
-                                              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) : "<No ID>",
-                              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 */
index 395161aa6edf8b6937d1544818b1f12651dca9bb..a89d423e7a63539f5170d2deb033b8b0eedfd246 100644 (file)
@@ -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;
        }
index 0c0f54f01793fffb6099d684d45e2f8a39b0a7e5..98be77b491f33068ede0ea7e6241a77a14efb40b 100644 (file)
@@ -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 */
index a9ab1502e16794969dc33d06e645c6f60e8d3d0c..4cbf04f9d42c66712b6ba82f232a610369e79a19 100644 (file)
@@ -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);
                
index 6bd7b3a499906f6a181e4cfdbcacaf0b66c95353..31fe8fe563e0f700f625c30f42ad8df6180bd4c9 100644 (file)
@@ -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 -------------------------------------- */
index c3d25ed297235cfe7a7df8b5f91a000e58ca916e..e884d769afefde418ab4427c0010c6d6f68f4610 100644 (file)
@@ -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);
 
index 1d5f46a18142aa2f248ea620df3d274a89d0862c..276531992f97959760dc7eced8df1d21eb866436 100644 (file)
@@ -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 {
index 5a93e18a7dd7e95c9ba3a773351c6350ac6c1bf3..047e5ea17ab72488ac0f5d1702a8769ddc67e0d2 100644 (file)
@@ -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;
+       }
+}
index 5fb581eb74a847cda555b797e577b098071c8924..08c0f98e45b184e09b2d8f89478ba0b489594e77 100644 (file)
@@ -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);
index 4006816e78851bc2a561fd28262d6104e03c69d8..3148dab3c50a45cabec09f9b9b22880edcb83146 100644 (file)
@@ -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);
index 65b6bd501ced68a35b0826df828c858b0ca92e33..2f0c054e3815985a292f979b35f07cbc34dec85f 100644 (file)
@@ -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;
index 1fccec7e1b2b9f7e70a8342df4b7700041860055..017a6fe89c50ff8db8609afaedbf6c9d67b6b4d5 100644 (file)
 #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__ */
index 482508a8d857e340d80c8c147e49a00d108981f1..98fc372f2fcdfa57aeb61b943734c7d4a20eabc3 100644 (file)
@@ -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);
+}
index 8deac2e4384b203f44474012654be0dc7a98c08e..2021575537d18b4e16a0b2796676376320862038 100644 (file)
@@ -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__ */