diff options
author | Ian Thompson <quornian@googlemail.com> | 2008-07-26 14:45:11 +0400 |
---|---|---|
committer | Ian Thompson <quornian@googlemail.com> | 2008-07-26 14:45:11 +0400 |
commit | 4a8aa06a1477f044dd41518d4a8ac633f32f653c (patch) | |
tree | a77bd165669a12720e8f096b7b6868e4c96dfb78 /source/blender/python | |
parent | 4c6e0d49c8defaf5bb3efa56e9843965cfed7f92 (diff) |
Merge from trunk
revs. 15635:15771
Diffstat (limited to 'source/blender/python')
-rw-r--r-- | source/blender/python/BPY_interface.c | 2 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Blender.c | 2 | ||||
-rw-r--r-- | source/blender/python/api2_2x/IDProp.c | 57 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Library.c | 69 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Particle.c | 472 | ||||
-rw-r--r-- | source/blender/python/api2_2x/doc/IDProp.py | 4 | ||||
-rw-r--r-- | source/blender/python/api2_2x/doc/Ipo.py | 4 | ||||
-rw-r--r-- | source/blender/python/api2_2x/doc/LibData.py | 42 | ||||
-rw-r--r-- | source/blender/python/api2_2x/doc/Particle.py | 229 | ||||
-rw-r--r-- | source/blender/python/api2_2x/sceneRender.c | 4 |
10 files changed, 503 insertions, 382 deletions
diff --git a/source/blender/python/BPY_interface.c b/source/blender/python/BPY_interface.c index 2a6d28c8cb3..36a8ee27a50 100644 --- a/source/blender/python/BPY_interface.c +++ b/source/blender/python/BPY_interface.c @@ -410,12 +410,14 @@ void BPY_rebuild_syspath( void ) mod = PyImport_ImportModule( "sys" ); if (!mod) { printf("error: could not import python sys module. some modules may not import.\n"); + PyGILState_Release(gilstate); return; } if (!bpy_orig_syspath_List) { /* should never happen */ printf("error refershing python path\n"); Py_DECREF(mod); + PyGILState_Release(gilstate); return; } diff --git a/source/blender/python/api2_2x/Blender.c b/source/blender/python/api2_2x/Blender.c index d8385c1d660..420d292cdce 100644 --- a/source/blender/python/api2_2x/Blender.c +++ b/source/blender/python/api2_2x/Blender.c @@ -708,7 +708,7 @@ static PyObject *Blender_Save( PyObject * self, PyObject * args ) "expected filename and optional int (overwrite flag) as arguments" ); for( li = G.main->library.first; li; li = li->id.next ) { - if( BLI_streq( li->name, fname ) ) { + if( li->parent==NULL && BLI_streq( li->name, fname ) ) { return EXPP_ReturnPyObjError( PyExc_AttributeError, "cannot overwrite used library" ); } diff --git a/source/blender/python/api2_2x/IDProp.c b/source/blender/python/api2_2x/IDProp.c index f60ebf8dee1..4a51619aec4 100644 --- a/source/blender/python/api2_2x/IDProp.c +++ b/source/blender/python/api2_2x/IDProp.c @@ -60,6 +60,8 @@ PyObject *BPy_IDGroup_WrapData( ID *id, IDProperty *prop ) return PyInt_FromLong( (long)prop->data.val ); case IDP_FLOAT: return PyFloat_FromDouble( (double)(*(float*)(&prop->data.val)) ); + case IDP_DOUBLE: + return PyFloat_FromDouble( (*(double*)(&prop->data.val)) ); case IDP_GROUP: /*blegh*/ { @@ -128,7 +130,19 @@ int BPy_IDGroup_SetData(BPy_IDProperty *self, IDProperty *prop, PyObject *value) Py_XDECREF(value); break; } - + case IDP_DOUBLE: + { + double dvalue; + if (!PyNumber_Check(value)) + return EXPP_ReturnIntError(PyExc_TypeError, "expected a float!"); + value = PyNumber_Float(value); + if (!value) + return EXPP_ReturnIntError(PyExc_TypeError, "expected a float!"); + dvalue = (float) PyFloat_AsDouble(value); + *(double*)&self->prop->data.val = dvalue; + Py_XDECREF(value); + break; + } default: return EXPP_ReturnIntError(PyExc_AttributeError, "attempt to set read-only attribute!"); } @@ -204,8 +218,8 @@ char *BPy_IDProperty_Map_ValidateAndCreate(char *name, IDProperty *group, PyObje IDPropertyTemplate val = {0}; if (PyFloat_Check(ob)) { - val.f = (float) PyFloat_AsDouble(ob); - prop = IDP_New(IDP_FLOAT, val, name); + val.d = PyFloat_AsDouble(ob); + prop = IDP_New(IDP_DOUBLE, val, name); } else if (PyInt_Check(ob)) { val.i = (int) PyInt_AsLong(ob); prop = IDP_New(IDP_INT, val, name); @@ -223,7 +237,7 @@ char *BPy_IDProperty_Map_ValidateAndCreate(char *name, IDProperty *group, PyObje val.array.len = PySequence_Length(ob); for (i=0; i<val.array.len; i++) { item = PySequence_GetItem(ob, i); - if (PyFloat_Check(item)) val.array.type = IDP_FLOAT; + if (PyFloat_Check(item)) val.array.type = IDP_DOUBLE; else if (!PyInt_Check(item)) return "only floats and ints are allowed in ID property arrays"; Py_XDECREF(item); } @@ -236,7 +250,7 @@ char *BPy_IDProperty_Map_ValidateAndCreate(char *name, IDProperty *group, PyObje ((int*)prop->data.pointer)[i] = (int)PyInt_AsLong(item); } else { item = PyNumber_Float(item); - ((float*)prop->data.pointer)[i] = (float)PyFloat_AsDouble(item); + ((double*)prop->data.pointer)[i] = (float)PyFloat_AsDouble(item); } Py_XDECREF(item); } @@ -334,6 +348,9 @@ PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop) case IDP_FLOAT: return PyFloat_FromDouble(*((float*)&prop->data.val)); break; + case IDP_DOUBLE: + return PyFloat_FromDouble(*((double*)&prop->data.val)); + break; case IDP_INT: return PyInt_FromLong( (long)prop->data.val ); break; @@ -347,12 +364,15 @@ PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop) "PyList_New() failed" ); for (i=0; i<prop->len; i++) { - if (prop->subtype == IDP_FLOAT) + if (prop->subtype == IDP_FLOAT) { PyList_SetItem(seq, i, PyFloat_FromDouble(((float*)prop->data.pointer)[i])); - - else PyList_SetItem(seq, i, - PyInt_FromLong(((int*)prop->data.pointer)[i])); + } else if (prop->subtype == IDP_DOUBLE) { + PyList_SetItem(seq, i, + PyFloat_FromDouble(((double*)prop->data.pointer)[i])); + } else { PyList_SetItem(seq, i, + PyInt_FromLong(((int*)prop->data.pointer)[i])); + } } return seq; } @@ -451,7 +471,7 @@ PyObject *BPy_IDGroup_GetKeys(BPy_IDProperty *self) /*set correct group length*/ self->prop->len = i; - /*free the old list*/ + /*free the list*/ Py_DECREF(seq); /*call self again*/ @@ -688,6 +708,9 @@ PyObject *BPy_IDArray_GetItem(BPy_IDArray *self, int index) case IDP_FLOAT: return PyFloat_FromDouble( (double)(((float*)self->prop->data.pointer)[index])); break; + case IDP_DOUBLE: + return PyFloat_FromDouble( (((double*)self->prop->data.pointer)[index])); + break; case IDP_INT: return PyInt_FromLong( (long)((int*)self->prop->data.pointer)[index] ); break; @@ -700,7 +723,8 @@ int BPy_IDArray_SetItem(BPy_IDArray *self, int index, PyObject *val) { int i; float f; - + double d; + if (index < 0 || index >= self->prop->len) return EXPP_ReturnIntError( PyExc_RuntimeError, "index out of range!"); @@ -717,6 +741,17 @@ int BPy_IDArray_SetItem(BPy_IDArray *self, int index, PyObject *val) ((float*)self->prop->data.pointer)[index] = f; Py_XDECREF(val); break; + case IDP_DOUBLE: + if (!PyNumber_Check(val)) return EXPP_ReturnIntError( PyExc_TypeError, + "expected a float"); + val = PyNumber_Float(val); + if (!val) return EXPP_ReturnIntError( PyExc_TypeError, + "expected a float"); + + d = (double) PyFloat_AsDouble(val); + ((double*)self->prop->data.pointer)[index] = d; + Py_XDECREF(val); + break; case IDP_INT: if (!PyNumber_Check(val)) return EXPP_ReturnIntError( PyExc_TypeError, "expected an int"); diff --git a/source/blender/python/api2_2x/Library.c b/source/blender/python/api2_2x/Library.c index 799735c2062..468263c4208 100644 --- a/source/blender/python/api2_2x/Library.c +++ b/source/blender/python/api2_2x/Library.c @@ -1135,9 +1135,78 @@ static PyObject *M_Library_Load(PyObject *self, PyObject * args) return (PyObject *)lib; } +static PyObject *M_Library_GetPaths(PyObject *self, PyObject * args) +{ + PyObject *list; + PyObject *name; + int type=0; + Library *lib; + + if( !PyArg_ParseTuple( args, "|i", &type ) || type < 0 || type > 2 ) { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected an int between 0 and 2." ); + } + + list = PyList_New(0); + + for(lib= G.main->library.first; lib; lib= lib->id.next) { + if (type==0) { + /* any type is ok */ + } else if (type==1 && lib->parent == 0) { + /* only direct linked */ + } else if (type==2 && lib->parent != 0) { + /* only indirect */ + } else { + continue; /* incompatible type */ + } + + name = PyString_FromString(lib->name); + PyList_Append(list, name); + Py_DECREF(name); + } + return list; +} + +static PyObject *M_Library_ReplacePath(PyObject *self, PyObject * args) +{ + char *name_from, *name_to; + Library *lib; + + if( !PyArg_ParseTuple( args, "ss", &name_from, &name_to )) { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected the name of a library path" ); + } + + for(lib= G.main->library.first; lib; lib= lib->id.next) { + if (strcmp(lib->name, name_from)==0) { + if (lib->parent) { + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "path is indirectly linked, cannot be changed." ); + } + + if (strlen(name_to) > sizeof(lib->name)) { + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "string length too long, cannot set path." ); + } + + strcpy(lib->name, name_to); + Py_RETURN_NONE; + } + } + + return EXPP_ReturnPyObjError( PyExc_ValueError, + "path given does not exist as a library" ); +} + + + static struct PyMethodDef M_Library_methods[] = { {"load", (PyCFunction)M_Library_Load, METH_VARARGS, "(string) - declare a .blend file for use as a library"}, + {"paths", (PyCFunction)M_Library_GetPaths, METH_VARARGS, + "(type) - return a list of library paths, type 0 for all, 1 only direct links, 2 only indirect links"}, + {"replace", (PyCFunction)M_Library_ReplacePath, METH_VARARGS, + "(from, to) - replace the path of an existing, directly linked library."}, {NULL, NULL, 0, NULL} }; diff --git a/source/blender/python/api2_2x/Particle.c b/source/blender/python/api2_2x/Particle.c index 95de9757b87..2c2e724129e 100644 --- a/source/blender/python/api2_2x/Particle.c +++ b/source/blender/python/api2_2x/Particle.c @@ -40,6 +40,7 @@ #include "BKE_material.h" #include "BKE_utildefines.h" #include "BKE_pointcache.h" +#include "BKE_DerivedMesh.h" #include "BIF_editparticle.h" #include "BIF_space.h" #include "blendef.h" @@ -799,22 +800,27 @@ static PyObject *Part_freeEdit( BPy_PartSys * self, PyObject * args ){ Py_RETURN_NONE; } -static PyObject *Part_GetLoc( BPy_PartSys * self, PyObject * args ){ +static PyObject *Part_GetLoc( BPy_PartSys * self, PyObject * args ) +{ ParticleSystem *psys = 0L; Object *ob = 0L; PyObject *partlist,*seglist; - PyObject* loc = 0L; ParticleCacheKey **cache,*path; + PyObject* loc = 0L; ParticleKey state; - float cfra=bsystem_time(ob,(float)CFRA,0.0); + DerivedMesh* dm; + float cfra; int i,j,k; + float vm[4][4],wm[4][4]; int childexists = 0; int all = 0; int id = 0; + cfra = bsystem_time(ob,(float)CFRA,0.0); + if( !PyArg_ParseTuple( args, "|ii", &all,&id ) ) return EXPP_ReturnPyObjError( PyExc_TypeError, - "expected one optional integer as argument" ); + "expected two optional integers as arguments" ); psys = self->psys; ob = self->object; @@ -822,88 +828,118 @@ static PyObject *Part_GetLoc( BPy_PartSys * self, PyObject * args ){ if (!ob || !psys) Py_RETURN_NONE; - if (psys->part->type == 2){ - cache=psys->pathcache; + G.rendering = 1; - /* little hack to calculate hair steps in render mode */ - psys->renderdata = (void*)(int)1; + /* Just to create a valid rendering context */ + psys_render_set(ob,psys,vm,wm,0,0,0); - psys_cache_paths(ob, psys, cfra, 1); + dm = mesh_create_derived_render(ob,CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL); + dm->release(dm); - psys->renderdata = NULL; + if ( !psys_check_enabled(ob,psys) ){ + G.rendering = 0; + psys_render_restore(ob,psys); + Particle_Recalc(self,1); + Py_RETURN_NONE; + } - partlist = PyList_New( 0 ); - if( !partlist ) - return EXPP_ReturnPyObjError( PyExc_MemoryError, "PyList() failed" ); + partlist = PyList_New( 0 ); + if( !partlist ){ + PyErr_SetString( PyExc_MemoryError, "PyList_New() failed" ); + goto error; + } - for(i = 0; i < psys->totpart; i++){ - path=cache[i]; - seglist = PyList_New( 0 ); - k = path->steps+1; - for( j = 0; j < k ; j++){ - loc = PyTuple_New(3); - - PyTuple_SetItem(loc,0,PyFloat_FromDouble((double)path->co[0])); - PyTuple_SetItem(loc,1,PyFloat_FromDouble((double)path->co[1])); - PyTuple_SetItem(loc,2,PyFloat_FromDouble((double)path->co[2])); - - if ( (PyList_Append(seglist,loc) < 0) ){ - Py_DECREF(seglist); - Py_DECREF(partlist); - Py_XDECREF(loc); - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Couldn't append item to PyList" ); + if (psys->part->type == PART_HAIR){ + cache = psys->pathcache; + + if ( ((self->psys->part->draw & PART_DRAW_PARENT) && (self->psys->part->childtype != 0)) || (self->psys->part->childtype == 0) ){ + + for(i = 0; i < psys->totpart; i++){ + seglist = PyList_New( 0 ); + if (!seglist){ + PyErr_SetString( PyExc_MemoryError, + "PyList_New() failed" ); + goto error; + } + + path=cache[i]; + k = path->steps+1; + for( j = 0; j < k ; j++, path++){ + loc = Py_BuildValue("(fff)",(double)path->co[0], + (double)path->co[1], (double)path->co[2]); + + if (!loc){ + PyErr_SetString( PyExc_RuntimeError, + "Couldn't build tuple" ); + goto error; + } + + if ( (PyList_Append(seglist,loc) < 0) ){ + PyErr_SetString( PyExc_RuntimeError, + "Couldn't append item to PyList" ); + goto error; + } + Py_DECREF(loc); /* PyList_Append increfs */ + loc = NULL; } - Py_DECREF(loc); /* PyList_Append increfs */ - path++; - } - if ( PyList_Append(partlist,seglist) < 0 ){ - Py_DECREF(seglist); - Py_DECREF(partlist); - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Couldn't append item to PyList" ); + if ( PyList_Append(partlist,seglist) < 0 ){ + PyErr_SetString( PyExc_RuntimeError, + "Couldn't append item to PyList" ); + goto error; + } + Py_DECREF(seglist); /* PyList_Append increfs */ + seglist = NULL; } - Py_DECREF(seglist); /* PyList_Append increfs */ } cache=psys->childcache; for(i = 0; i < psys->totchild; i++){ - path=cache[i]; seglist = PyList_New( 0 ); - k = path->steps+1; - for( j = 0; j < k ; j++){ - loc = PyTuple_New(3); + if (!seglist){ + PyErr_SetString( PyExc_MemoryError, + "PyList_New() failed" ); + goto error; + } - PyTuple_SetItem(loc,0,PyFloat_FromDouble((double)path->co[0])); - PyTuple_SetItem(loc,1,PyFloat_FromDouble((double)path->co[1])); - PyTuple_SetItem(loc,2,PyFloat_FromDouble((double)path->co[2])); + path=cache[i]; + k = path->steps+1; + for( j = 0; j < k ; j++, path++ ){ + loc = Py_BuildValue("(fff)",(double)path->co[0], + (double)path->co[1], (double)path->co[2]); + + if (!loc){ + PyErr_SetString( PyExc_RuntimeError, + "Couldn't build tuple" ); + goto error; + } if ( PyList_Append(seglist,loc) < 0){ - Py_DECREF(partlist); - Py_XDECREF(loc); - return EXPP_ReturnPyObjError( PyExc_RuntimeError, + PyErr_SetString( PyExc_RuntimeError, "Couldn't append item to PyList" ); + goto error; } Py_DECREF(loc);/* PyList_Append increfs */ - path++; + loc = NULL; } if ( PyList_Append(partlist,seglist) < 0){ - Py_DECREF(partlist); - Py_XDECREF(loc); - return EXPP_ReturnPyObjError( PyExc_RuntimeError, + PyErr_SetString( PyExc_RuntimeError, "Couldn't append item to PyList" ); + goto error; } Py_DECREF(seglist); /* PyList_Append increfs */ + seglist = NULL; } - } else { int init; - partlist = PyList_New( 0 ); - if( !partlist ) - return EXPP_ReturnPyObjError( PyExc_MemoryError, "PyList() failed" ); + char *fmt = NULL; + + if(id) + fmt = "(fffi)"; + else + fmt = "(fff)"; if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT)) childexists = 1; @@ -919,55 +955,67 @@ static PyObject *Part_GetLoc( BPy_PartSys * self, PyObject * args ){ init = 1; if (init){ - if (!id) - loc = PyTuple_New(3); - else - loc = PyTuple_New(4); - PyTuple_SetItem(loc,0,PyFloat_FromDouble((double)state.co[0])); - PyTuple_SetItem(loc,1,PyFloat_FromDouble((double)state.co[1])); - PyTuple_SetItem(loc,2,PyFloat_FromDouble((double)state.co[2])); - if (id) - PyTuple_SetItem(loc,3,PyInt_FromLong(i)); + loc = Py_BuildValue(fmt,(double)state.co[0], + (double)state.co[1], (double)state.co[2],i); + + if (!loc){ + PyErr_SetString( PyExc_RuntimeError, + "Couldn't build tuple" ); + goto error; + } if ( PyList_Append(partlist,loc) < 0 ){ - Py_DECREF(partlist); - Py_XDECREF(loc); - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Couldn't append item to PyList" ); + PyErr_SetString( PyExc_RuntimeError, + "Couldn't append item to PyList" ); + goto error; } - Py_DECREF(loc);/* PyList_Append increfs */ - } - else { - if ( all ){ - if ( PyList_Append(partlist,Py_None) < 0 ){ - Py_DECREF(partlist); - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Couldn't append item to PyList" ); - } - Py_DECREF(Py_None); /* PyList_Append increfs */ + Py_DECREF(loc); + loc = NULL; + } else { + if ( all && PyList_Append(partlist,Py_None) < 0 ){ + PyErr_SetString( PyExc_RuntimeError, + "Couldn't append item to PyList" ); + goto error; } } } } + + psys_render_restore(ob,psys); + G.rendering = 0; + Particle_Recalc(self,1); return partlist; + +error: + Py_XDECREF(partlist); + Py_XDECREF(seglist); + Py_XDECREF(loc); + psys_render_restore(ob,psys); + G.rendering = 0; + Particle_Recalc(self,1); + return NULL; } -static PyObject *Part_GetRot( BPy_PartSys * self, PyObject * args ){ +static PyObject *Part_GetRot( BPy_PartSys * self, PyObject * args ) +{ ParticleSystem *psys = 0L; Object *ob = 0L; PyObject *partlist = 0L; PyObject* loc = 0L; ParticleKey state; + DerivedMesh* dm; + float vm[4][4],wm[4][4]; int i; int childexists = 0; int all = 0; int id = 0; + char *fmt = NULL; float cfra=bsystem_time(ob,(float)CFRA,0.0); if( !PyArg_ParseTuple( args, "|ii", &all, &id ) ) return EXPP_ReturnPyObjError( PyExc_TypeError, - "expected one optional integer as argument" ); + "expected two optional integers as arguments" ); psys = self->psys; ob = self->object; @@ -975,63 +1023,105 @@ static PyObject *Part_GetRot( BPy_PartSys * self, PyObject * args ){ if (!ob || !psys) Py_RETURN_NONE; - if (psys->part->type != 2){ + G.rendering = 1; + + /* Just to create a valid rendering context */ + psys_render_set(ob,psys,vm,wm,0,0,0); + + dm = mesh_create_derived_render(ob,CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL); + dm->release(dm); + + if ( !psys_check_enabled(ob,psys) ){ + G.rendering = 0; + psys_render_restore(ob,psys); + Particle_Recalc(self,1); + Py_RETURN_NONE; + } + + if (psys->part->type != PART_HAIR){ partlist = PyList_New( 0 ); + if( !partlist ){ + PyErr_SetString( PyExc_MemoryError, "PyList_New() failed" ); + goto error; + } + if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT)) childexists = 1; + if(id) + fmt = "(ffffi)"; + else + fmt = "(ffff)"; + for (i = 0; i < psys->totpart + psys->totchild; i++){ if (childexists && (i < psys->totpart)) continue; state.time = cfra; if(psys_get_particle_state(ob,psys,i,&state,0)==0){ - if ( all ){ - PyList_Append(partlist,Py_None); - Py_DECREF(Py_None); /* PyList_Append increfs */ - continue; - } else { - continue; + if ( all && PyList_Append(partlist,Py_None) < 0){ + PyErr_SetString( PyExc_RuntimeError, + "Couldn't append item to PyList" ); + goto error; + } + } else { + loc = Py_BuildValue(fmt,(double)state.rot[0], (double)state.rot[1], + (double)state.rot[2], (double)state.rot[3], i); + + if (!loc){ + PyErr_SetString( PyExc_RuntimeError, + "Couldn't build tuple" ); + goto error; + } + if (PyList_Append(partlist,loc) < 0){ + PyErr_SetString ( PyExc_RuntimeError, + "Couldn't append item to PyList" ); + goto error; } + Py_DECREF(loc); /* PyList_Append increfs */ + loc = NULL; } - if (!id) - loc = PyTuple_New(4); - else - loc = PyTuple_New(5); - PyTuple_SetItem(loc,0,PyFloat_FromDouble((double)state.rot[0])); - PyTuple_SetItem(loc,1,PyFloat_FromDouble((double)state.rot[1])); - PyTuple_SetItem(loc,2,PyFloat_FromDouble((double)state.rot[2])); - PyTuple_SetItem(loc,3,PyFloat_FromDouble((double)state.rot[3])); - if (id) - PyTuple_SetItem(loc,4,PyInt_FromLong(i)); - PyList_Append(partlist,loc); - Py_DECREF(loc); /* PyList_Append increfs */ } + } else { + partlist = EXPP_incr_ret( Py_None ); } + + psys_render_restore(ob,psys); + G.rendering = 0; + Particle_Recalc(self,1); return partlist; + +error: + Py_XDECREF(partlist); + Py_XDECREF(loc); + psys_render_restore(ob,psys); + G.rendering = 0; + Particle_Recalc(self,1); + return NULL; } -static PyObject *Part_GetSize( BPy_PartSys * self, PyObject * args ){ +static PyObject *Part_GetSize( BPy_PartSys * self, PyObject * args ) +{ ParticleKey state; ParticleSystem *psys = 0L; ParticleData *data; Object *ob = 0L; PyObject *partlist,*tuple; - PyObject* siz = 0L; + DerivedMesh* dm; + float vm[4][4],wm[4][4]; float size; int i; int childexists = 0; int all = 0; int id = 0; + char *fmt = NULL; float cfra=bsystem_time(ob,(float)CFRA,0.0); if( !PyArg_ParseTuple( args, "|ii", &all, &id ) ) return EXPP_ReturnPyObjError( PyExc_TypeError, - "expected one optional integer as argument" ); - - data = self->psys->particles; + "expected two optional integers as arguments" ); psys = self->psys; ob = self->object; @@ -1039,13 +1129,39 @@ static PyObject *Part_GetSize( BPy_PartSys * self, PyObject * args ){ if (!ob || !psys) Py_RETURN_NONE; - partlist = PyList_New( 0 ); + G.rendering = 1; - if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT)) - childexists = 1; + /* Just to create a valid rendering context */ + psys_render_set(ob,psys,vm,wm,0,0,0); + + dm = mesh_create_derived_render(ob,CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL); + dm->release(dm); + data = self->psys->particles; + + if ( !psys_check_enabled(ob,psys) ){ + psys_render_restore(ob,psys); + G.rendering = 0; + Particle_Recalc(self,1); + Py_RETURN_NONE; + } + + partlist = PyList_New( 0 ); + + if( !partlist ){ + PyErr_SetString( PyExc_MemoryError, "PyList_New() failed" ); + goto error; + } + + if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT)) + childexists = 1; + + if(id) + fmt = "(fi)"; + else + fmt = "f"; - for (i = 0; i < psys->totpart + psys->totchild; i++, data++){ - if (psys->part->type != 2){ + for (i = 0; i < psys->totpart + psys->totchild; i++, data++){ + if (psys->part->type != PART_HAIR){ if (childexists && (i < psys->totpart)) continue; @@ -1061,43 +1177,61 @@ static PyObject *Part_GetSize( BPy_PartSys * self, PyObject * args ){ ChildParticle *cpa= &psys->child[i-psys->totpart]; size = psys_get_child_size(psys,cpa,cfra,0); } - if (id){ - tuple = PyTuple_New(2); - PyTuple_SetItem(tuple,0,PyFloat_FromDouble((double)size)); - PyTuple_SetItem(tuple,1,PyInt_FromLong(i)); - PyList_Append(partlist,tuple); - Py_DECREF(tuple); - } else { - siz = PyFloat_FromDouble((double)size); - PyList_Append(partlist,siz); - Py_DECREF(siz); + + tuple = Py_BuildValue(fmt,(double)size,i); + + if (!tuple){ + PyErr_SetString( PyExc_RuntimeError, + "Couldn't build tuple" ); + goto error; + } + + if (PyList_Append(partlist,tuple) < 0){ + PyErr_SetString( PyExc_RuntimeError, + "Couldn't append item to PyList" ); + goto error; } + Py_DECREF(tuple); + tuple = NULL; } } + + psys_render_restore(ob,psys); + G.rendering = 0; + Particle_Recalc(self,1); return partlist; + +error: + Py_XDECREF(partlist); + Py_XDECREF(tuple); + psys_render_restore(ob,psys); + G.rendering = 0; + Particle_Recalc(self,1); + return NULL; } -static PyObject *Part_GetAge( BPy_PartSys * self, PyObject * args ){ +static PyObject *Part_GetAge( BPy_PartSys * self, PyObject * args ) +{ ParticleKey state; ParticleSystem *psys = 0L; ParticleData *data; Object *ob = 0L; PyObject *partlist,*tuple; - PyObject* lif = 0L; + DerivedMesh* dm; + float vm[4][4],wm[4][4]; float life; int i; int childexists = 0; int all = 0; int id = 0; + char *fmt = NULL; float cfra=bsystem_time(ob,(float)CFRA,0.0); if( !PyArg_ParseTuple( args, "|ii", &all, &id ) ) return EXPP_ReturnPyObjError( PyExc_TypeError, - "expected one optional integer as argument" ); - - data = self->psys->particles; + "expected two optional integers as arguments" ); psys = self->psys; ob = self->object; @@ -1105,13 +1239,37 @@ static PyObject *Part_GetAge( BPy_PartSys * self, PyObject * args ){ if (!ob || !psys) Py_RETURN_NONE; - partlist = PyList_New( 0 ); + G.rendering = 1; - if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT)) - childexists = 1; + /* Just to create a valid rendering context */ + psys_render_set(ob,psys,vm,wm,0,0,0); + + dm = mesh_create_derived_render(ob,CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL); + dm->release(dm); + data = self->psys->particles; + + if ( !psys_check_enabled(ob,psys) ){ + psys_render_restore(ob,psys); + G.rendering = 0; + Py_RETURN_NONE; + } + + partlist = PyList_New( 0 ); + if( !partlist ){ + PyErr_SetString( PyExc_MemoryError, "PyList_New() failed" ); + goto error; + } + + if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT)) + childexists = 1; + + if(id) + fmt = "(fi)"; + else + fmt = "f"; - for (i = 0; i < psys->totpart + psys->totchild; i++, data++){ - if (psys->part->type != 2){ + for (i = 0; i < psys->totpart + psys->totchild; i++, data++){ + if (psys->part->type != PART_HAIR){ if (childexists && (i < psys->totpart)) continue; @@ -1128,20 +1286,37 @@ static PyObject *Part_GetAge( BPy_PartSys * self, PyObject * args ){ ChildParticle *cpa= &psys->child[i-psys->totpart]; life = psys_get_child_time(psys,cpa,cfra); } - if (id){ - tuple = PyTuple_New(2); - PyTuple_SetItem(tuple,0,PyFloat_FromDouble((double)life)); - PyTuple_SetItem(tuple,1,PyInt_FromLong(i)); - PyList_Append(partlist,tuple); - Py_DECREF(tuple); - } else { - lif = PyFloat_FromDouble((double)life); - PyList_Append(partlist,lif); - Py_DECREF(lif); + + tuple = Py_BuildValue(fmt,(double)life,i); + + if (!tuple){ + PyErr_SetString( PyExc_RuntimeError, + "Couldn't build tuple" ); + goto error; } + + if (PyList_Append(partlist,tuple) < 0){ + PyErr_SetString( PyExc_RuntimeError, + "Couldn't append item to PyList" ); + goto error; + } + Py_DECREF(tuple); + tuple = NULL; } } + + psys_render_restore(ob,psys); + G.rendering = 0; + Particle_Recalc(self,1); return partlist; + +error: + Py_XDECREF(partlist); + Py_XDECREF(tuple); + psys_render_restore(ob,psys); + G.rendering = 0; + Particle_Recalc(self,1); + return NULL; } @@ -1376,11 +1551,8 @@ static int Part_set2d( BPy_PartSys * self, PyObject * args ) { int number; - if( !PyInt_Check( args ) ) { - char errstr[128]; - sprintf ( errstr, "expected int argument" ); - return EXPP_ReturnIntError( PyExc_TypeError, errstr ); - } + if( !PyInt_Check( args ) ) + return EXPP_ReturnIntError( PyExc_TypeError, "expected int argument" ); number = PyInt_AS_LONG( args ); @@ -1526,7 +1698,7 @@ static int Part_setRandEmission( BPy_PartSys * self, PyObject * args ) static PyObject *Part_getRandEmission( BPy_PartSys * self ) { - return PyInt_FromLong( ((long)( self->psys->part->flag & PART_BOIDS_2D )) > 0 ); + return PyInt_FromLong( ((long)( self->psys->part->flag & PART_TRAND )) > 0 ); } static int Part_setParticleDist( BPy_PartSys * self, PyObject * args ) @@ -1546,7 +1718,7 @@ static int Part_setParticleDist( BPy_PartSys * self, PyObject * args ) return EXPP_ReturnIntError( PyExc_TypeError, errstr ); } - self->psys->part->from = number; + self->psys->part->from = (short)number; Particle_RecalcPsys_distr(self,1); @@ -1603,7 +1775,7 @@ static int Part_setDist( BPy_PartSys * self, PyObject * args ) return EXPP_ReturnIntError( PyExc_TypeError, errstr ); } - self->psys->part->distr = number; + self->psys->part->distr = (short)number; Particle_RecalcPsys_distr(self,1); @@ -1731,7 +1903,7 @@ static int Part_setTargetPsys( BPy_PartSys * self, PyObject * args ){ res = EXPP_setIValueRange( args, &self->psys->target_psys, 0, tottpsys, 'h' ); - if((psys=psys_get_current(ob))){ + if( ( psys = psys_get_current(ob) ) ){ if(psys->keyed_ob==ob || psys->target_ob==ob){ if(psys->keyed_ob==ob) psys->keyed_ob=NULL; diff --git a/source/blender/python/api2_2x/doc/IDProp.py b/source/blender/python/api2_2x/doc/IDProp.py index 0a0df335fa3..01d5136cd70 100644 --- a/source/blender/python/api2_2x/doc/IDProp.py +++ b/source/blender/python/api2_2x/doc/IDProp.py @@ -18,7 +18,9 @@ class IDGroup: Note that for arrays, the array type defaults to int unless a float is found while scanning the template list; if any floats are found, then the whole - array is float. + array is float. Note that double-precision floating point numbers are used for + python-created float ID properties and arrays (though the internal C api does + support single-precision floats, and the python code will read them). You can also delete properties with the del operator. For example: diff --git a/source/blender/python/api2_2x/doc/Ipo.py b/source/blender/python/api2_2x/doc/Ipo.py index c479926ccf3..d1c72f8cb86 100644 --- a/source/blender/python/api2_2x/doc/Ipo.py +++ b/source/blender/python/api2_2x/doc/Ipo.py @@ -250,7 +250,7 @@ class Ipo: OfsZ, SizeX, SizeY, SizeZ, texR, texG, texB, DefVar, Col, Nor, Var, Disp. 3. Object Ipo: LocX, LocY, LocZ, dLocX, dLocY, dLocZ, RotX, RotY, RotZ, - dRotX, dRotY, dRotZ, SizeX, SizeY, SizeZ, dSizeX, dSizeY, dSizeZ, + dRotX, dRotY, dRotZ, ScaleX, ScaleY, ScaleZ, dScaleX, dScaleY, dScaleZ, Layer, Time, ColR, ColG, ColB, ColA, FStreng, FFall, Damping, RDamp, Perm. 4. Lamp Ipo: Energ, R, G, B, Dist, SpoSi, SpoBl, Quad1, Quad2, HaInt. @@ -289,7 +289,7 @@ class Ipo: OfsZ, SizeX, SizeY, SizeZ, texR, texG, texB, DefVar, Col, Nor, Var, Disp. 3. Object Ipo: LocX, LocY, LocZ, dLocX, dLocY, dLocZ, RotX, RotY, RotZ, - dRotX, dRotY, dRotZ, SizeX, SizeY, SizeZ, dSizeX, dSizeY, dSizeZ, + dRotX, dRotY, dRotZ, ScaleX, ScaleY, ScaleZ, dScaleX, dScaleY, dScaleZ, Layer, Time, ColR, ColG, ColB, ColA, FStreng, FFall, Damping, RDamp, Perm. 4. Lamp Ipo: Energ, R, G, B, Dist, SpoSi, SpoBl, Quad1, Quad2, HaInt. diff --git a/source/blender/python/api2_2x/doc/LibData.py b/source/blender/python/api2_2x/doc/LibData.py index 47bd7fdb763..daa6a186531 100644 --- a/source/blender/python/api2_2x/doc/LibData.py +++ b/source/blender/python/api2_2x/doc/LibData.py @@ -27,17 +27,37 @@ Example:: """ def load(filename,relative=False): - """ - Select an existing .blend file for use as a library. Unlike the - Library module, multiple libraries can be defined at the same time. - - @type filename: string - @param filename: The filename of a Blender file. Filenames starting with "//" will be loaded relative to the blend file's location. - @type relative: boolean - @param relative: Convert relative paths to absolute paths (default). Setting this parameter to True will leave paths relative. - @rtype: Library - @return: return a L{Library} object. - """ + """ + Select an existing .blend file for use as a library. Unlike the + Library module, multiple libraries can be defined at the same time. + + @type filename: string + @param filename: The filename of a Blender file. Filenames starting with "//" will be loaded relative to the blend file's location. + @type relative: boolean + @param relative: Convert relative paths to absolute paths (default). Setting this parameter to True will leave paths relative. + @rtype: Library + @return: return a L{Library} object. + """ + +def paths(link=0): + """ + Returns a list of paths used in the current blend file. + + @type link: int + @param link: 0 (default if no args given) for all library paths, 1 for directly linked library paths only, 2 for indirectly linked library paths only. + @rtype: List + @return: return a list of path strings. + """ + +def replace(pathFrom, pathTo): + """ + Replaces an existing directly linked path. + + @type pathFrom: string + @param pathFrom: An existing library path. + @type pathTo: string + @param pathTo: A new library path. + """ class Libraries: """ diff --git a/source/blender/python/api2_2x/doc/Particle.py b/source/blender/python/api2_2x/doc/Particle.py index 192ecd5355b..511ad81b45f 100644 --- a/source/blender/python/api2_2x/doc/Particle.py +++ b/source/blender/python/api2_2x/doc/Particle.py @@ -56,17 +56,17 @@ class Particle: @type type: int @ivar resolutionGrid: The resolution of the particle grid. @type resolutionGrid: int - @ivar startFrame: Frame # to start emitting particles. + @ivar startFrame: Frame number to start emitting particles. @type startFrame: float - @ivar endFrame: Frame # to stop emitting particles. + @ivar endFrame: Frame number to stop emitting particles. @type endFrame: float @ivar editable: Finalize hair to enable editing in particle mode. @type editable: int @ivar amount: The total number of particles. @type amount: int - @ivar multireact: React multiple times ( Paricle.REACTON[ 'NEAR' | 'COLLISION' | 'DEATH' ] ). + @ivar multireact: React multiple times ( Particle.REACTON[ 'NEAR' | 'COLLISION' | 'DEATH' ] ). @type multireact: int - @ivar reactshape: Power of reaction strength dependence on distance to target. + @ivar reactshape: Power of reaction strength, dependent on distance to target. @type reactshape: float @ivar hairSegments: Amount of hair segments. @type hairSegments: int @@ -74,13 +74,13 @@ class Particle: @type lifetime: float @ivar randlife: Give the particle life a random variation. @type randlife: float - @ivar randemission: Give the particle life a random variation + @ivar randemission: Emit particles in random order. @type randemission: int - @ivar particleDistribution: Where to emit particles from Paricle.EMITFROM[ 'PARTICLE' | 'VOLUME' | 'FACES' | 'VERTS' ] ) + @ivar particleDistribution: Where to emit particles from ( Particle.EMITFROM[ 'PARTICLE' | 'VOLUME' | 'FACES' | 'VERTS' ] ) @type particleDistribution: int @ivar evenDistribution: Use even distribution from faces based on face areas or edge lengths. @type evenDistribution: int - @ivar distribution: How to distribute particles on selected element Paricle.DISTRIBUTION[ 'GRID' | 'RANDOM' | 'JITTERED' ] ). + @ivar distribution: How to distribute particles on selected element ( Particle.DISTRIBUTION[ 'GRID' | 'RANDOM' | 'JITTERED' ] ). @type distribution: int @ivar jitterAmount: Amount of jitter applied to the sampling. @type jitterAmount: float @@ -131,237 +131,56 @@ class Particle: Get the particles locations. A list of tuple is returned in particle mode. A list of list of tuple is returned in hair mode. - The tuple is a vector list of 3 or 4 floats in world space (x,y,z, optionnaly the particle's id). + The tuple is a vector of 3 or 4 floats in world space (x,y,z, +optionally the particle's id). @type all: int @param all: if not 0 export all particles (uninitialized (unborn or died)particles exported as None). @type id: int @param id: add the particle id in the end of the vector tuple - @rtype: list of vectors (tuple of 3 floats and optionnaly the id) or list of list of vectors - @return: list of vectors or list of list of vectors (hair mode) + @rtype: list of vectors (tuple of 3 floats and optionally the id) or list of list of vectors + @return: list of vectors or list of list of vectors (hair mode) or None if system is disabled """ def getRot(all=0,id=0): """ - Get the particles rotations as quaternion. + Get the particles' rotations as quaternion. A list of tuple is returned in particle mode. - The tuple is a vector list of 4 or 5 floats (x,y,z,w, optionnaly the id of the particle). + The tuple is vector of 4 or 5 floats (x,y,z,w, optionally the id of the particle). @type all: int - @param all: if not 0 export all particles (uninitialized (unborn or died) particles exported as None). + @param all: if not 0, export all particles (uninitialized (unborn or died) particles exported as None). @type id: int @param id: add the particle id in the return tuple @rtype: list of tuple of 4 or 5 elements (if id is not zero) - @return: list of 4-tuples + @return: list of 4-tuples or None if system is disabled """ def getMat(): """ - Get the particles material. + Get the particles' material. @rtype: Blender Material - @return: The marterial assigned to particles + @return: The material assigned to particles """ def getSize(all=0,id=0): """ - Get the particles size. + Get the particles' size. A list of float or list of tuple (particle's size,particle's id). @type all: int - @param all: if not 0 export all particles (uninitialized (unborn or died) particles exported as None). + @param all: if not 0, export all particles (uninitialized (unborn or died) particles exported as None). @type id: int @param id: add the particle id in the return tuple @rtype: list of floats - @return: list of floats or list of tuples if id is not zero (size,id). + @return: list of floats or list of tuples if id is not zero (size,id) or None if system is disabled. """ def getAge(all=0,id=0): """ - Get the particles age. - A list of float or list of tuple (particle's age,particle's id). + Get the particles' age. + A list of float or list of tuple (particle's age, particle's id). @type all: int - @param all: if not 0 export all particles (uninitialized (unborn or died) particles exported as None). + @param all: if not 0, export all particles (uninitialized (unborn or died) particles exported as None). @type id: int @param id: add the particle id in the return tuple @rtype: list of floats - @return: list of floats or list of tuples if id is not zero (size,id). - """ -# Blender.Object module and the Object PyType object - -""" -The Blender.Particle submodule - - -Particle -======== - -This module provides access to the B{Particle} in Blender. - -@type TYPE: readonly dictionary -@var TYPE: Constant dict used for with L{Particle.TYPE} - - HAIR: set particle system to hair mode. - - REACTOR: set particle system to reactor mode. - - EMITTER: set particle system to emitter mode. -@type DISTRIBUTION: readonly dictionary -@var DISTRIBUTION: Constant dict used for with L{Particle.DISTRIBUTION} - - GRID: set grid distribution. - - RANDOM: set random distribution. - - JITTERED: set jittered distribution. -@type EMITFROM: readonly dictionary -@var EMITFROM: Constant dict used for with L{Particle.EMITFROM} - - VERTS: set particles emit from vertices - - FACES: set particles emit from faces - - VOLUME: set particles emit from volume - - PARTICLE: set particles emit from particles -@type REACTON: readonly dictionary -@var REACTON: Constant dict used for with L{Particle.REACTON} - - NEAR: react on near - - COLLISION: react on collision - - DEATH: react on death -@type DRAWAS: readonly dictionary -@var DRAWAS: Constant dict used for with L{Particle.DRAWAS} - - NONE: Don't draw - - POINT: Draw as point - - CIRCLE: Draw as circles - - CROSS: Draw as crosses - - AXIS: Draw as axis - - LINE: Draw as lines - - PATH: Draw pathes - - OBJECT: Draw object - - GROUP: Draw goup - - BILLBOARD: Draw as billboard -""" - -def Get(name): - """ - Get the particle system of the object "name". - @type name: string - @return: The particle system of the object. - """ -def New(name): - """ - Assign a new particle system to the object "name". - @type name: string - @return: The newly created particle system. - """ - -class Particle: - """ - The Particle object - =================== - This object gives access to paticles data. - - @ivar seed: Set an offset in the random table. - @type seed: int - @ivar type: Type of particle system ( Particle.TYPE[ 'HAIR' | 'REACTOR' | 'EMITTER' ] ). - @type type: int - @ivar resolutionGrid: The resolution of the particle grid. - @type resolutionGrid: int - @ivar startFrame: Frame # to start emitting particles. - @type startFrame: float - @ivar endFrame: Frame # to stop emitting particles. - @type endFrame: float - @ivar editable: Finalize hair to enable editing in particle mode. - @type editable: int - @ivar amount: The total number of particles. - @type amount: int - @ivar multireact: React multiple times ( Paricle.REACTON[ 'NEAR' | 'COLLISION' | 'DEATH' ] ). - @type multireact: int - @ivar reactshape: Power of reaction strength dependence on distance to target. - @type reactshape: float - @ivar hairSegments: Amount of hair segments. - @type hairSegments: int - @ivar lifetime: Specify the life span of the particles. - @type lifetime: float - @ivar randlife: Give the particle life a random variation. - @type randlife: float - @ivar randemission: Give the particle life a random variation - @type randemission: int - @ivar particleDistribution: Where to emit particles from Paricle.EMITFROM[ 'PARTICLE' | 'VOLUME' | 'FACES' | 'VERTS' ] ) - @type particleDistribution: int - @ivar evenDistribution: Use even distribution from faces based on face areas or edge lengths. - @type evenDistribution: int - @ivar distribution: How to distribute particles on selected element Paricle.DISTRIBUTION[ 'GRID' | 'RANDOM' | 'JITTERED' ] ). - @type distribution: int - @ivar jitterAmount: Amount of jitter applied to the sampling. - @type jitterAmount: float - @ivar pf: Emission locations / face (0 = automatic). - @type pf:int - @ivar invert: Invert what is considered object and what is not. - @type invert: int - @ivar targetObject: The object that has the target particle system (empty if same object). - @type targetObject: Blender object - @ivar targetpsys: The target particle system number in the object. - @type targetpsys: int - @ivar 2d: Constrain boids to a surface. - @type 2d: float - @ivar maxvel: Maximum velocity. - @type maxvel: float - @ivar avvel: The usual speed % of max velocity. - @type avvel: float - @ivar latacc: Lateral acceleration % of max velocity - @type latacc: float - @ivar tanacc: Tangential acceleration % of max velocity - @type tanacc: float - @ivar groundz: Default Z value. - @type groundz: float - @ivar object: Constrain boids to object's surface. - @type object: Blender Object - @ivar renderEmitter: Render emitter object. - @type renderEmitter: int - @ivar displayPercentage: Particle display percentage. - @type displayPercentage: int - @ivar hairDisplayStep: How many steps paths are drawn with (power of 2) in visu mode. - @type hairDisplayStep: int - @ivar hairRenderStep: How many steps paths are rendered with (power of 2) in render mode." - @type hairRenderStep: int - @ivar duplicateObject: Get the duplicate object. - @type duplicateObject: Blender Object - @ivar drawAs: Get draw type Particle.DRAWAS([ 'NONE' | 'OBJECT' | 'POINT' | ... ]). - @type drawAs: int - """ - def freeEdit(): - """ - Free edit mode. - @return: None - """ - - def getLoc(all=0,id=0): - """ - Get the particles locations. - A list of tuple is returned in particle mode. - A list of list of tuple is returned in hair mode. - The tuple is a vector list of 3 floats in world space. - @type all: int - @param all: if not 0 export all particles (uninitialized (unborn or died)particles exported as None). - @type id: int - @param id: add the particle id in the end of the vector tuple - @rtype: list of vectors (tuple of 3 floats and optionnaly the id) or list of list of vectors - @return: list of vectors or list of list of vectors (hair mode) - """ - def getRot(all=0,id=0): - """ - Get the particles rotations as quaternion. - A list of tuple is returned in particle mode. - The tuple is a vector list of 4 floats (quaternion). - @type all: int - @param all: if not 0 export all particles (uninitialized (unborn or died) particles exported as None). - @type id: int - @param id: add the particle id in the return tuple - @rtype: list of tuple of 4 or 5 elements (if id is not zero) - @return: list of 4-tuples - """ - def getMat(): - """ - Get the particles material. - @rtype: Blender Material - @return: The marterial assigned to particles - """ - def getSize(all=0,id=0): - """ - Get the particles size. - A list of float. - @type all: int - @param all: if not 0 export all particles (uninitialized (unborn or died) particles exported as None). - @type id: int - @param id: add the particle id in the return tuple - @rtype: list of floats - @return: list of floats or list of tuples if id is not zero (size,id). + @return: list of floats or list of tuples if id is not zero (size,id) or None if system is disabled. """ diff --git a/source/blender/python/api2_2x/sceneRender.c b/source/blender/python/api2_2x/sceneRender.c index d382d450970..8f251fc8452 100644 --- a/source/blender/python/api2_2x/sceneRender.c +++ b/source/blender/python/api2_2x/sceneRender.c @@ -565,6 +565,8 @@ PyObject *RenderData_SaveRenderedImage ( BPy_RenderData * self, PyObject *args ) PyObject *RenderData_RenderAnim( BPy_RenderData * self ) { Scene *oldsce; + /* this prevents a deadlock when there are pynodes: */ + PyThreadState *tstate = PyEval_SaveThread(); if (!G.background) { oldsce = G.scene; @@ -582,9 +584,9 @@ PyObject *RenderData_RenderAnim( BPy_RenderData * self ) if (G.scene->r.sfra > G.scene->r.efra) return EXPP_ReturnPyObjError (PyExc_RuntimeError, "start frame must be less or equal to end frame"); - RE_BlenderAnim(re, G.scene, G.scene->r.sfra, G.scene->r.efra); } + PyEval_RestoreThread(tstate); Py_RETURN_NONE; } |