Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/BKE_bad_level_calls.h7
-rw-r--r--source/blender/blenkernel/bad_level_call_stubs/stubs.c10
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c44
-rw-r--r--source/blender/blenkernel/intern/ipo.c13
-rw-r--r--source/blender/makesdna/DNA_curve_types.h8
-rw-r--r--source/blender/python/BPY_extern.h5
-rw-r--r--source/blender/python/BPY_interface.c190
-rw-r--r--source/blender/python/api2_2x/EXPP_interface.c99
-rw-r--r--source/blender/python/api2_2x/EXPP_interface.h13
-rw-r--r--source/blender/python/api2_2x/Object.c13
-rw-r--r--source/blender/src/drawipo.c51
-rw-r--r--source/blender/src/usiblender.c6
12 files changed, 437 insertions, 22 deletions
diff --git a/source/blender/blenkernel/BKE_bad_level_calls.h b/source/blender/blenkernel/BKE_bad_level_calls.h
index f261f786dd4..10248fad220 100644
--- a/source/blender/blenkernel/BKE_bad_level_calls.h
+++ b/source/blender/blenkernel/BKE_bad_level_calls.h
@@ -57,13 +57,20 @@ struct Sequence;
struct ListBase;
void build_seqar(struct ListBase *seqbase, struct Sequence ***seqar, int *totseq);
+/* BPython API */
struct ID;
struct Script;
struct Text;
+struct IpoDriver; /* DNA_curve_types.h */
+struct Object;
void BPY_do_pyscript (struct ID *id, short int event);
void BPY_clear_script (struct Script *script);
void BPY_free_compiled_text (struct Text *text);
void BPY_free_screen_spacehandlers (struct bScreen *sc);
+/* ipo.c: */
+float BPY_pydriver_eval(struct IpoDriver *driver);
+/* depsgraph.c: */
+struct Object **BPY_pydriver_get_objects(struct IpoDriver *driver);
/* writefile.c */
struct Oops;
diff --git a/source/blender/blenkernel/bad_level_call_stubs/stubs.c b/source/blender/blenkernel/bad_level_call_stubs/stubs.c
index 7bc4e664429..3e858aca631 100644
--- a/source/blender/blenkernel/bad_level_call_stubs/stubs.c
+++ b/source/blender/blenkernel/bad_level_call_stubs/stubs.c
@@ -109,6 +109,16 @@ void BPY_do_pyscript(ID *id, short int event){}
void BPY_clear_script(Script *script){}
void BPY_free_compiled_text(struct Text *text){}
void BPY_free_screen_spacehandlers (struct bScreen *sc){}
+float BPY_pydriver_eval(struct IpoDriver *driver)
+{
+ return 0;
+}
+
+/* depsgraph.c: */
+struct Object **BPY_pydriver_get_objects(struct IpoDriver *driver)
+{
+ return 0;
+}
/* writefile.c */
/* struct Oops; */
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index b6a85bbe910..42898bc8976 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -75,7 +75,8 @@
#include "MEM_guardedalloc.h"
#include "blendef.h"
-
+#include "BPY_extern.h"
+
#include "depsgraph_private.h"
/* Queue and stack operations for dag traversal
@@ -302,12 +303,41 @@ static void dag_add_driver_relation(Ipo *ipo, DagForest *dag, DagNode *node, int
DagNode *node1;
for(icu= ipo->curve.first; icu; icu= icu->next) {
- if(icu->driver && icu->driver->ob) {
- node1 = dag_get_node(dag, icu->driver->ob);
- if(icu->driver->blocktype==ID_AR)
- dag_add_relation(dag, node1, node, isdata?DAG_RL_DATA_DATA:DAG_RL_DATA_OB);
- else
- dag_add_relation(dag, node1, node, isdata?DAG_RL_OB_DATA:DAG_RL_OB_OB);
+ if(icu->driver) {
+
+ if (icu->driver->type == IPO_DRIVER_TYPE_PYTHON) {
+
+ if ((icu->driver->flag & IPO_DRIVER_FLAG_INVALID) || (icu->driver->name[0] == '\0'))
+ continue; /* empty or invalid expression */
+ else {
+ /* now we need refs to all objects mentioned in this
+ * pydriver expression, to call 'dag_add_relation'
+ * for each of them */
+ Object **obarray = BPY_pydriver_get_objects(icu->driver);
+ if (obarray) {
+ Object *ob, **oba = obarray;
+
+ while (*oba) {
+ ob = *oba;
+ node1 = dag_get_node(dag, ob);
+ if (ob->type == OB_ARMATURE)
+ dag_add_relation(dag, node1, node, isdata?DAG_RL_DATA_DATA:DAG_RL_DATA_OB);
+ else
+ dag_add_relation(dag, node1, node, isdata?DAG_RL_OB_DATA:DAG_RL_OB_OB);
+ oba++;
+ }
+
+ MEM_freeN(obarray);
+ }
+ }
+ }
+ else if (icu->driver->ob) {
+ node1 = dag_get_node(dag, icu->driver->ob);
+ if(icu->driver->blocktype==ID_AR)
+ dag_add_relation(dag, node1, node, isdata?DAG_RL_DATA_DATA:DAG_RL_DATA_OB);
+ else
+ dag_add_relation(dag, node1, node, isdata?DAG_RL_OB_DATA:DAG_RL_OB_OB);
+ }
}
}
}
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index 9efb74ffa35..27bf9c1744f 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -75,6 +75,7 @@
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_object.h"
+#include "BPY_extern.h" /* for BPY_pydriver_eval() */
#define SMALL -1.0e-10
@@ -739,12 +740,18 @@ void berekenx(float *f, float *o, int b)
static float eval_driver(IpoDriver *driver)
{
- if(driver->flag & IPO_DRIVER_PYTHON) {
- printf("Execute %s\n", driver->name);
+ if(driver->type == IPO_DRIVER_TYPE_PYTHON) {
+ /* check for empty or invalid expression */
+ if ((driver->name[0] == '\0') ||
+ (driver->flag & IPO_DRIVER_FLAG_INVALID))
+ return 0.0f;
+ /* this evals the expression and returns its result:
+ * (on errors it reports, then returns 0.0f) */
+ return BPY_pydriver_eval(driver);
}
else {
Object *ob= driver->ob;
-
+
if(ob==NULL) return 0.0f;
if(driver->blocktype==ID_OB) {
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index a400fad0530..174b17792ce 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -254,9 +254,13 @@ typedef struct IpoCurve {
/* *************** driver ****************** */
-/* driver->flag */
-#define IPO_DRIVER_PYTHON 1
+/* driver->type */
+#define IPO_DRIVER_TYPE_NORMAL 0
+#define IPO_DRIVER_TYPE_PYTHON 1
+/* driver->flag */
+/* invalid flag: currently only used for buggy pydriver expressions: */
+#define IPO_DRIVER_FLAG_INVALID 1
#endif
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h
index ffb5f258d8d..cc187ea3a0d 100644
--- a/source/blender/python/BPY_extern.h
+++ b/source/blender/python/BPY_extern.h
@@ -37,6 +37,8 @@ extern char bprogname[]; /* holds a copy of argv[0], from creator.c */
struct Text; /* defined in DNA_text_types.h */
struct ID; /* DNA_ID.h */
+struct Object; /* DNA_object_types.h */
+struct IpoDriver; /* DNA_curve_types.h */
struct ScriptLink; /* DNA_scriptlink_types.h */
struct ListBase; /* DNA_listBase.h */
struct SpaceText; /* DNA_space_types.h */
@@ -79,6 +81,9 @@ extern "C" {
int BPY_do_spacehandlers(struct ScrArea *sa, unsigned short event,
unsigned short space_event);
+ float BPY_pydriver_eval(struct IpoDriver *driver);
+ struct Object **BPY_pydriver_get_objects(struct IpoDriver *driver);
+
/* format importer hook */
int BPY_call_importloader( char *name );
diff --git a/source/blender/python/BPY_interface.c b/source/blender/python/BPY_interface.c
index ff262b1a581..6a79e673345 100644
--- a/source/blender/python/BPY_interface.c
+++ b/source/blender/python/BPY_interface.c
@@ -43,6 +43,7 @@
#include "BKE_library.h"
#include "BKE_object.h" /* during_scriptlink() */
#include "BKE_text.h"
+#include "DNA_curve_types.h" /* for struct IpoDriver */
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h" /* for U.pythondir */
#include "MEM_guardedalloc.h"
@@ -73,6 +74,9 @@
*/
//#include "api2_2x/Registry.h"
+/* for pydrivers (ipo drivers defined by one-line Python expressions) */
+PyObject *bpy_pydriver_Dict = NULL;
+
/*Declares the modules and their initialization functions
*These are TOP-LEVEL modules e.g. import `module` - there is no
*support for packages here e.g. import `package.module` */
@@ -175,6 +179,11 @@ void BPY_end_python( void )
bpy_registryDict = NULL;
}
+ if( bpy_pydriver_Dict ) {
+ Py_DECREF( bpy_pydriver_Dict );
+ bpy_pydriver_Dict = NULL;
+ }
+
Py_Finalize( );
BPyMenu_RemoveAllEntries( ); /* freeing bpymenu mem */
@@ -919,6 +928,187 @@ void BPY_clear_script( Script * script )
unlink_script( script );
}
+/* PyDrivers */
+
+/* PyDrivers are Ipo Drivers governed by expressions written in Python.
+ * Expressions here are one-liners that evaluate to a float value. */
+
+/* For faster execution we keep a special dictionary for pydrivers, with
+ * the needed modules and aliases. */
+static int bpy_pydriver_create_dict(void)
+{
+ PyObject *d, *mod;
+
+ if (bpy_pydriver_Dict) return -1;
+
+ d = PyDict_New();
+ if (!d) return -1;
+
+ bpy_pydriver_Dict = d;
+
+ /* import some modules: builtins, Blender, math, Blender.noise */
+
+ PyDict_SetItemString(d, "__builtins__", PyEval_GetBuiltins());
+
+ mod = PyImport_ImportModule("Blender");
+ if (mod) {
+ PyDict_SetItemString(d, "Blender", mod);
+ PyDict_SetItemString(d, "b", mod);
+ Py_DECREF(mod);
+ }
+
+ mod = PyImport_ImportModule("math");
+ if (mod) {
+ PyDict_SetItemString(d, "math", mod);
+ PyDict_SetItemString(d, "m", mod);
+ Py_DECREF(mod);
+ }
+
+ mod = PyImport_ImportModule("Blender.Noise");
+ if (mod) {
+ PyDict_SetItemString(d, "noise", mod);
+ PyDict_SetItemString(d, "n", mod);
+ Py_DECREF(mod);
+ }
+
+ /* If there's a Blender text called pydrivers.py, import it.
+ * Users can add their own functions to this module. */
+ mod = importText("pydrivers"); /* can also use PyImport_Import() */
+ if (mod) {
+ PyDict_SetItemString(d, "pydrivers", mod);
+ PyDict_SetItemString(d, "p", mod);
+ Py_DECREF(mod);
+ }
+ else
+ PyErr_Clear();
+
+ /* short aliases for some Get() functions: */
+
+ /* ob(obname) == Blender.Object.Get(obname) */
+ mod = PyImport_ImportModule("Blender.Object");
+ if (mod) {
+ PyObject *fcn = PyObject_GetAttrString(mod, "Get");
+ Py_DECREF(mod);
+ if (fcn)
+ PyDict_SetItemString(d, "ob", fcn);
+ }
+
+ /* me(meshname) == Blender.Mesh.Get(meshname) */
+ mod = PyImport_ImportModule("Blender.Mesh");
+ if (mod) {
+ PyObject *fcn = PyObject_GetAttrString(mod, "Get");
+ Py_DECREF(mod);
+ if (fcn)
+ PyDict_SetItemString(d, "me", fcn);
+ }
+
+ /* ma(matname) == Blender.Material.Get(matname) */
+ mod = PyImport_ImportModule("Blender.Material");
+ if (mod) {
+ PyObject *fcn = PyObject_GetAttrString(mod, "Get");
+ Py_DECREF(mod);
+ if (fcn)
+ PyDict_SetItemString(d, "ma", fcn);
+ }
+
+ return 0;
+}
+
+/* error return function for BPY_eval_pydriver */
+static float pydriver_error(IpoDriver *driver) {
+
+ if (bpy_pydriver_oblist)
+ bpy_pydriver_freeList();
+
+ if (bpy_pydriver_Dict) { /* free the global dict used by pydrivers */
+ Py_DECREF(bpy_pydriver_Dict);
+ bpy_pydriver_Dict = NULL;
+ }
+
+ driver->flag |= IPO_DRIVER_FLAG_INVALID; /* py expression failed */
+
+ fprintf(stderr, "\nError in Ipo Driver: Object %s\nThis is the failed Python expression:\n'%s'\n\n", driver->ob->id.name+2, driver->name);
+
+ PyErr_Print();
+
+ return 0.0f;
+}
+
+/* for depsgraph.c, runs py expr once to collect all refs. made
+ * to objects (self refs. to the object that owns the py driver
+ * are not allowed). */
+struct Object **BPY_pydriver_get_objects(IpoDriver *driver)
+{
+ /*if (!driver || !driver->ob || driver->name[0] == '\0')
+ return NULL;*/
+
+ /*PyErr_Clear();*/
+
+ /* clear the flag that marks invalid python expressions */
+ driver->flag &= ~IPO_DRIVER_FLAG_INVALID;
+
+ /* tell we're running a pydriver, so Get() functions know they need
+ * to add the requested obj to our list */
+ bpy_pydriver_running(1);
+
+ /* append driver owner object as the 1st ob in the list;
+ * we put it there to make sure it is not itself referenced in
+ * its pydriver expression */
+ bpy_pydriver_appendToList(driver->ob);
+
+ /* this will append any other ob referenced in expr (driver->name)
+ * or set the driver's error flag if driver's py expression fails */
+ BPY_pydriver_eval(driver);
+
+ bpy_pydriver_running(0); /* ok, we're done */
+
+ return bpy_pydriver_obArrayFromList(); /* NULL if eval failed */
+}
+
+/* This evals py driver expressions, 'expr' is a Python expression that
+ * should evaluate to a float number, which is returned. */
+float BPY_pydriver_eval(IpoDriver *driver)
+{
+ char *expr = NULL;
+ PyObject *retval, *floatval;
+ float result = 0.0f; /* default return */
+
+ if (!driver) return result;
+
+ expr = driver->name; /* the py expression to be evaluated */
+ if (!expr || expr[0]=='\0') return result;
+
+ if (!bpy_pydriver_Dict) {
+ if (bpy_pydriver_create_dict() != 0) {
+ fprintf(stderr, "Pydriver error: couldn't create Python dictionary");
+ return result;
+ }
+ }
+
+ retval = PyRun_String(expr, Py_eval_input, bpy_pydriver_Dict,
+ bpy_pydriver_Dict);
+
+ if (retval == NULL) {
+ return pydriver_error(driver);
+ }
+ else {
+ floatval = PyNumber_Float(retval);
+ Py_DECREF(retval);
+ }
+
+ if (floatval == NULL)
+ return pydriver_error(driver);
+ else {
+ result = (float)PyFloat_AsDouble(floatval);
+ Py_DECREF(floatval);
+ }
+
+ /* all fine, make sure the "invalid expression" flag is cleared */
+ driver->flag &= ~IPO_DRIVER_FLAG_INVALID;
+
+ return result;
+}
+
/*****************************************************************************/
/* ScriptLinks */
/*****************************************************************************/
diff --git a/source/blender/python/api2_2x/EXPP_interface.c b/source/blender/python/api2_2x/EXPP_interface.c
index 9f20db03c07..ee8b04ebde9 100644
--- a/source/blender/python/api2_2x/EXPP_interface.c
+++ b/source/blender/python/api2_2x/EXPP_interface.c
@@ -34,6 +34,9 @@
#include "EXPP_interface.h"
#include "BLI_blenlib.h"
+#include "MEM_guardedalloc.h"
+#include "BLI_linklist.h" /* linked list: LinkNode struct and functions */
+#include "DNA_object_types.h"
#include "DNA_space_types.h" /* for FILE_MAXDIR, FILE_MAXFILE */
#include "Blender.h"
@@ -129,3 +132,99 @@ char *bpy_gethome(int append_scriptsdir)
return NULL;
}
+
+/* PyDrivers */
+
+/*
+ * Pydrivers are Blender Ipo Drivers defined by Python expressions.
+ * We need to tell DAG about objects used in these expressions, so we
+ * eval each expression to collect the ob refs. in it.
+ */
+
+/* these are checked for example in Object.c: M_Object_Get (Object.Get())
+ * to collect the refs. */
+static int pydriver_running = 0;
+
+int bpy_during_pydriver(void)
+{
+ return pydriver_running;
+}
+
+void bpy_pydriver_running(int state)
+{
+ pydriver_running = state;
+}
+
+/* Obj references are collected in this extern linked list: */
+LinkNode *bpy_pydriver_oblist = NULL;
+
+void bpy_pydriver_freeList(void)
+{
+ BLI_linklist_free(bpy_pydriver_oblist, NULL);
+ bpy_pydriver_oblist = NULL;
+}
+
+void bpy_pydriver_appendToList(struct Object *ob)
+{
+ LinkNode *ln = bpy_pydriver_oblist;
+
+ /* check that the expression is not referencing its owner object */
+
+/* XXX COMMENTED OUT TO TEST IF WE REALLY NEED TO IMPOSE THIS RESTRICTION
+ if (ln && ln->link) {
+ if (ob == (Object *)ln->link) {
+ PyErr_SetString(PyExc_AttributeError,
+ "Python driver expression can't reference its own object");
+ return;
+ }
+ else
+ ln = ln->next;
+ }
+*/
+ while (ln) { /* is ob already in list? ... */
+ if (ob == (Object *)ln->link)
+ break;
+ ln = ln->next;
+ }
+
+ if (!ln) /* ... not yet, append it */
+ BLI_linklist_append(&bpy_pydriver_oblist, (void *)ob);
+
+ return;
+}
+
+/* Get an array from our linked list of objs referenced in the
+ * current pydriver. The first node in the list is discarded,
+ * since it is the actual pydriver owner, which shouldn't be
+ * passed to the depsgraph (no self references). */
+struct Object **bpy_pydriver_obArrayFromList(void)
+{
+ Object **obarray = NULL;
+
+ if (bpy_pydriver_oblist) {
+ int i;
+ short len = BLI_linklist_length(bpy_pydriver_oblist);
+
+ if (len > 1) {
+
+ obarray = (Object **)MEM_mallocN(sizeof(Object*)*len,
+ "pydriver array");
+
+ if (obarray) {
+ LinkNode *ln = bpy_pydriver_oblist;
+ ln = ln->next; /* skip first ob, which is the pydriver owner */
+
+ for (i = 0; i < len-1; i++) {
+ obarray[i] = (Object *)ln->link;
+ ln = ln->next;
+ }
+
+ obarray[len-1] = NULL; /* NULL-terminated array */
+ }
+ }
+ bpy_pydriver_freeList();
+ }
+
+ return obarray;
+}
+
diff --git a/source/blender/python/api2_2x/EXPP_interface.h b/source/blender/python/api2_2x/EXPP_interface.h
index dfcf7abf1da..80767af1c01 100644
--- a/source/blender/python/api2_2x/EXPP_interface.h
+++ b/source/blender/python/api2_2x/EXPP_interface.h
@@ -33,11 +33,24 @@
#ifndef EXPP_INTERFACE_H
#define EXPP_INTERFACE_H
+struct Object;
struct Script;
+struct LinkNode;
+
+extern struct LinkNode *bpy_pydriver_oblist;
void initBlenderApi2_2x( void );
char *bpy_gethome( int append_scriptsdir );
void discardFromBDict( char *key );
void EXPP_Library_Close( void ); /* in Library.c, used by BPY_end_python */
+/* PyDrivers */
+
+void bpy_pydriver_freeList(void);
+void bpy_pydriver_appendToList(struct Object *ob);
+struct Object **bpy_pydriver_obArrayFromList(void);
+
+int bpy_during_pydriver(void);
+void bpy_pydriver_running(int state);
+
#endif /* EXPP_INTERFACE_H */
diff --git a/source/blender/python/api2_2x/Object.c b/source/blender/python/api2_2x/Object.c
index db012729da6..1132f07a511 100644
--- a/source/blender/python/api2_2x/Object.c
+++ b/source/blender/python/api2_2x/Object.c
@@ -110,6 +110,7 @@ struct rctf;
#include "Group.h"
#include "Modifier.h"
#include "gen_utils.h"
+#include "EXPP_interface.h"
#include "BIF_editkey.h"
/* Defines for insertIpoKey */
@@ -787,6 +788,10 @@ PyObject *M_Object_Get( PyObject * self, PyObject * args )
buffer );
}
+ /* objects used in pydriver expressions need this */
+ if (bpy_during_pydriver())
+ bpy_pydriver_appendToList(object);
+
return Object_CreatePyObject( object );
} else {
/* No argument has been given. Return a list of all objects. */
@@ -794,11 +799,17 @@ PyObject *M_Object_Get( PyObject * self, PyObject * args )
Link *link;
int index;
+ /* do not allow Get() (w/o arguments) inside pydriver, otherwise
+ * we'd have to update all objects in the DAG */
+ if (bpy_during_pydriver())
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "Object.Get requires an argument when used in pydrivers" );
+
obj_list = PyList_New( BLI_countlist( &( G.main->object ) ) );
if( !obj_list )
return EXPP_ReturnPyObjError( PyExc_SystemError,
- "List creation failed." );
+ "List creation failed." );
link = G.main->object.first;
index = 0;
diff --git a/source/blender/src/drawipo.c b/source/blender/src/drawipo.c
index 642a7a0602e..ffbc8a67f9d 100644
--- a/source/blender/src/drawipo.c
+++ b/source/blender/src/drawipo.c
@@ -84,6 +84,8 @@
#include "BSE_editipo_types.h"
#include "BSE_editnla_types.h"
+#include "BPY_extern.h"
+
#include "mydevice.h"
#include "blendef.h"
#include "butspace.h" // shouldnt be...
@@ -1561,6 +1563,7 @@ static void draw_key(SpaceIpo *sipo, int visible)
#define B_IPO_DRIVER 3405
#define B_IPO_REDR 3406
#define B_IPO_DEPCHANGE 3407
+#define B_IPO_DRIVERTYPE 3408
static float hspeed= 0;
@@ -1755,7 +1758,12 @@ void do_ipobuts(unsigned short event)
ei= get_active_editipo();
if(ei) {
if(ei->icu->driver) {
- if(G.sipo->blocktype==ID_KE || G.sipo->blocktype==ID_AC)
+ if (ei->icu->driver->type == IPO_DRIVER_TYPE_PYTHON) {
+ /* eval user's expression once for validity */
+ BPY_pydriver_eval(ei->icu->driver);
+ DAG_scene_sort(G.scene);
+ }
+ else if(G.sipo->blocktype==ID_KE || G.sipo->blocktype==ID_AC)
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
else
DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
@@ -1814,14 +1822,39 @@ void do_ipobuts(unsigned short event)
BIF_undo_push("Add/Remove Ipo driver");
}
break;
+ case B_IPO_DRIVERTYPE:
+ ei= get_active_editipo();
+ if(ei) {
+ if(ei->icu->driver) {
+ IpoDriver *driver= ei->icu->driver;
+
+ if(driver->type == IPO_DRIVER_TYPE_PYTHON) {
+ /* pydriver expression shouldn't reference own ob,
+ * so we need to store ob ptr to check against it */
+ driver->ob= ob;
+ }
+ else {
+ driver->ob= NULL;
+ driver->blocktype= ID_OB;
+ driver->adrcode= OB_LOC_X;
+ driver->flag &= ~IPO_DRIVER_FLAG_INVALID;
+ }
+ }
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ DAG_scene_sort(G.scene);
+
+ BIF_undo_push("Change Ipo driver type");
+ }
+ break;
case B_IPO_DEPCHANGE:
ei= get_active_editipo();
if(ei) {
if(ei->icu->driver) {
IpoDriver *driver= ei->icu->driver;
- if(driver->flag & IPO_DRIVER_PYTHON) {
- driver->ob= NULL;
+ if(driver->type == IPO_DRIVER_TYPE_PYTHON) {
}
else {
if(driver->ob) {
@@ -1918,14 +1951,18 @@ static void ipo_panel_properties(short cntrl) // IPO_HANDLER_PROPERTIES
if(ei->icu && ei->icu->driver) {
IpoDriver *driver= ei->icu->driver;
-
+
uiDefBut(block, BUT, B_IPO_DRIVER, "Remove", 210,265,100,20, NULL, 0.0f, 0.0f, 0, 0, "Remove Driver for this Ipo Channel");
uiBlockBeginAlign(block);
- uiDefIconButBitS(block, TOG, IPO_DRIVER_PYTHON, B_IPO_DEPCHANGE, ICON_PYTHON, 10,240,25,20, &driver->flag, 0, 0, 0, 0, "Use a one-line Python Expression as Driver");
-
- if(driver->flag & IPO_DRIVER_PYTHON) {
+ uiDefIconButS(block, TOG, B_IPO_DRIVERTYPE, ICON_PYTHON, 10,240,25,20, &driver->type, (float)IPO_DRIVER_TYPE_NORMAL, (float)IPO_DRIVER_TYPE_PYTHON, 0, 0, "Use a one-line Python Expression as Driver");
+
+ if(driver->type == IPO_DRIVER_TYPE_PYTHON) {
uiDefBut(block, TEX, B_IPO_REDR, "", 35,240,275,20, driver->name, 0, 127, 0, 0, "Python Expression");
+ if(driver->flag & IPO_DRIVER_FLAG_INVALID) {
+ uiDefBut(block, LABEL, 0, "Error: invalid Python expression",
+ 5,215,230,19, NULL, 0, 0, 0, 0, "");
+ }
uiBlockEndAlign(block);
}
else {
diff --git a/source/blender/src/usiblender.c b/source/blender/src/usiblender.c
index e20fbf6fbad..8bfa493364a 100644
--- a/source/blender/src/usiblender.c
+++ b/source/blender/src/usiblender.c
@@ -758,6 +758,10 @@ void exit_usiblender(void)
free_editArmature();
free_posebuf();
+ /* before free_blender so py's gc happens while library still exists */
+ /* needed at least for a rare sigsegv that can happen in pydrivers */
+ BPY_end_python();
+
free_blender(); /* blender.c, does entire library */
free_matcopybuf();
free_ipocopybuf();
@@ -784,8 +788,6 @@ void exit_usiblender(void)
#ifdef WITH_QUICKTIME
quicktime_exit();
#endif
-
- BPY_end_python();
if (!G.background) {
BIF_resources_free();