From db44a92a11bc1dff94f8aa162c19429a1fdafa5f Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 17 Nov 2011 07:08:09 +0000 Subject: [PATCH] pydrivers: 'frame' is now in the driver namespace, - no need to link to scenes when using a frame from the pydriver, this made linking rigs for eg, quite messy. - advantage that we get subframe values (where scenes from was fixed to a whole number). --- source/blender/blenkernel/intern/fcurve.c | 8 +++-- .../editors/interface/interface_anim.c | 19 +--------- source/blender/python/BPY_extern.h | 2 +- source/blender/python/intern/bpy_driver.c | 35 ++++++++++++++++++- source/blender/python/intern/bpy_driver.h | 2 +- .../bad_level_call_stubs/stubs.c | 2 +- 6 files changed, 43 insertions(+), 25 deletions(-) diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 5ab997d2c54..4bb9dc47fda 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -1576,7 +1576,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 */ -static float evaluate_driver (ChannelDriver *driver, float UNUSED(evaltime)) +static float evaluate_driver (ChannelDriver *driver, const float evaltime) { DriverVar *dvar; @@ -1663,8 +1663,10 @@ static float evaluate_driver (ChannelDriver *driver, float UNUSED(evaltime)) /* this evaluates the expression using Python,and returns its result: * - on errors it reports, then returns 0.0f */ - driver->curval= BPY_driver_exec(driver); + driver->curval= BPY_driver_exec(driver, evaltime); } +#else /* WITH_PYTHON*/ + (void)evaltime; #endif /* WITH_PYTHON*/ } break; @@ -2087,7 +2089,7 @@ 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) +float evaluate_fcurve (FCurve *fcu, float evaltime) { float cvalue= 0.0f; float devaltime; diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index 1edd43d4e01..5e095bae922 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -164,24 +164,7 @@ int ui_but_anim_expression_create(uiBut *but, const char *str) /* set the expression */ // TODO: need some way of identifying variables used BLI_strncpy_utf8(driver->expression, str, sizeof(driver->expression)); - - /* FIXME: for now, assume that - * - for expressions, users are likely to be using "frame" -> current frame" as a variable - * - driver_add_new_variable() adds a single-prop variable by default - */ - { - DriverVar *dvar; - DriverTarget *dtar; - - dvar = driver_add_new_variable(driver); - BLI_strncpy(dvar->name, "frame", sizeof(dvar->name)); - - dtar = &dvar->targets[0]; - dtar->id = (ID *)CTX_data_scene(C); // XXX: should we check that C is valid first? - dtar->idtype= ID_SCE; - dtar->rna_path = BLI_sprintfN("frame_current"); - } - + /* updates */ driver->flag |= DRIVER_FLAG_RECOMPILE; WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME, NULL); diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h index 29e0185c2f2..51f9063c289 100644 --- a/source/blender/python/BPY_extern.h +++ b/source/blender/python/BPY_extern.h @@ -74,7 +74,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); +float BPY_driver_exec(struct ChannelDriver *driver, const float evaltime); int BPY_button_exec(struct bContext *C, const char *expr, double *value, const short verbose); int BPY_string_exec(struct bContext *C, const char *expr); diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c index 12fb5ed43b4..2aad4d8f2fe 100644 --- a/source/blender/python/intern/bpy_driver.c +++ b/source/blender/python/intern/bpy_driver.c @@ -91,6 +91,29 @@ int bpy_pydriver_create_dict(void) return 0; } +/* note, this function should do nothing most runs, only when changing frame */ +static PyObject *bpy_pydriver_InternStr__frame= NULL; + +static void bpy_pydriver_update_dict(const float evaltime) +{ + /* not thread safe but neither is python */ + static float evaltime_prev= FLT_MAX; + + if (evaltime_prev != evaltime) { + + /* currently only update the frame */ + if (bpy_pydriver_InternStr__frame == NULL) { + bpy_pydriver_InternStr__frame= PyUnicode_FromString("frame"); + } + + PyDict_SetItem(bpy_pydriver_Dict, + bpy_pydriver_InternStr__frame, + PyFloat_FromDouble(evaltime)); + + evaltime_prev= evaltime; + } +} + /* 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 @@ -110,6 +133,11 @@ void BPY_driver_reset(void) bpy_pydriver_Dict= NULL; } + if (bpy_pydriver_InternStr__frame) { + Py_DECREF(bpy_pydriver_InternStr__frame); + bpy_pydriver_InternStr__frame= NULL; + } + if (use_gil) PyGILState_Release(gilstate); @@ -139,7 +167,7 @@ static void pydriver_error(ChannelDriver *driver) * now release the GIL on python operator execution instead, using * PyEval_SaveThread() / PyEval_RestoreThread() so we dont lock up blender. */ -float BPY_driver_exec(ChannelDriver *driver) +float BPY_driver_exec(ChannelDriver *driver, const float evaltime) { PyObject *driver_vars=NULL; PyObject *retval= NULL; @@ -183,6 +211,10 @@ float BPY_driver_exec(ChannelDriver *driver) } } + /* update global namespace */ + bpy_pydriver_update_dict(evaltime); + + if (driver->expr_comp==NULL) driver->flag |= DRIVER_FLAG_RECOMPILE; @@ -246,6 +278,7 @@ float BPY_driver_exec(ChannelDriver *driver) } } + #if 0 // slow, with this can avoid all Py_CompileString above. /* execute expression to get a value */ retval= PyRun_String(expr, Py_eval_input, bpy_pydriver_Dict, driver_vars); diff --git a/source/blender/python/intern/bpy_driver.h b/source/blender/python/intern/bpy_driver.h index 3e38cacf6d1..802a3649e20 100644 --- a/source/blender/python/intern/bpy_driver.h +++ b/source/blender/python/intern/bpy_driver.h @@ -33,7 +33,7 @@ int bpy_pydriver_create_dict(void); extern PyObject *bpy_pydriver_Dict; /* externals */ -float BPY_driver_exec(struct ChannelDriver *driver); +float BPY_driver_exec(struct ChannelDriver *driver, const float evaltime); void BPY_driver_reset(void); #endif // BPY_DRIVER_H diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index abc5307b9f6..b299de0d897 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -454,7 +454,7 @@ void BPY_text_free_code(struct Text *text) {} void BPY_id_release(struct Text *text) {} int BPY_context_member_get(struct Context *C, const char *member, struct bContextDataResult *result) { return 0; } void BPY_pyconstraint_target(struct bPythonConstraint *con, struct bConstraintTarget *ct) {} -float BPY_driver_exec(struct ChannelDriver *driver) {return 0.0f;} /* might need this one! */ +float BPY_driver_exec(struct ChannelDriver *driver, const float evaltime) {return 0.0f;} /* might need this one! */ void BPY_DECREF(void *pyob_ptr) {} void BPY_pyconstraint_exec(struct bPythonConstraint *con, struct bConstraintOb *cob, struct ListBase *targets) {} void macro_wrapper(struct wmOperatorType *ot, void *userdata) {} ;