Merged changes from trunk to soc-2008-mxcurioni: svn merge -r 14534:14595 https://svn.blender.org/svnroot/bf-blender/trunk/blender/
This commit is contained in:
@@ -927,7 +927,7 @@ static PyObject *Blender_CountPackedFiles( PyObject * self )
|
||||
static PyObject *Blender_GetPaths( PyObject * self, PyObject *args, PyObject *keywds )
|
||||
{
|
||||
struct BPathIterator bpi;
|
||||
PyObject *list = PyList_New(0), *st;
|
||||
PyObject *list = PyList_New(0), *st; /* stupidly big string to be safe */
|
||||
/* be sure there is low chance of the path being too short */
|
||||
char filepath_expanded[FILE_MAXDIR*2];
|
||||
|
||||
@@ -944,18 +944,18 @@ static PyObject *Blender_GetPaths( PyObject * self, PyObject *args, PyObject *ke
|
||||
|
||||
/* build the list */
|
||||
if (absolute) {
|
||||
BLI_bpathIterator_copyPathExpanded( &bpi, filepath_expanded );
|
||||
st = PyString_FromString(filepath_expanded);
|
||||
BLI_bpathIterator_getPathExpanded( &bpi, filepath_expanded );
|
||||
} else {
|
||||
st = PyString_FromString(BLI_bpathIterator_getPath(&bpi));
|
||||
BLI_bpathIterator_getPathExpanded( &bpi, filepath_expanded );
|
||||
}
|
||||
st = PyString_FromString(filepath_expanded);
|
||||
|
||||
PyList_Append(list, st);
|
||||
Py_DECREF(st);
|
||||
|
||||
BLI_bpathIterator_step(&bpi);
|
||||
}
|
||||
|
||||
BLI_bpathIterator_free(&bpi);
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
@@ -561,34 +561,9 @@ struct PyMethodDef M_Effect_methods[] = {
|
||||
/*****************************************************************************/
|
||||
PyObject *M_Effect_New( PyObject * self, PyObject * args )
|
||||
{
|
||||
Effect *bleffect = 0;
|
||||
Object *ob;
|
||||
char *name = NULL;
|
||||
|
||||
if( !PyArg_ParseTuple( args, "s", &name ) )
|
||||
return EXPP_ReturnPyObjError( PyExc_TypeError,
|
||||
"expected string argument" );
|
||||
|
||||
for( ob = G.main->object.first; ob; ob = ob->id.next )
|
||||
if( !strcmp( name, ob->id.name + 2 ) )
|
||||
break;
|
||||
|
||||
if( !ob )
|
||||
return EXPP_ReturnPyObjError( PyExc_AttributeError,
|
||||
"object does not exist" );
|
||||
|
||||
if( ob->type != OB_MESH )
|
||||
return EXPP_ReturnPyObjError( PyExc_AttributeError,
|
||||
"object is not a mesh" );
|
||||
|
||||
bleffect = add_effect( EFF_PARTICLE );
|
||||
if( !bleffect )
|
||||
return EXPP_ReturnPyObjError( PyExc_RuntimeError,
|
||||
"couldn't create Effect Data in Blender" );
|
||||
|
||||
BLI_addtail( &ob->effect, bleffect );
|
||||
|
||||
return EffectCreatePyObject( bleffect, ob );
|
||||
printf("warning, static particles api removed\n");
|
||||
Py_INCREF( Py_None );
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -597,86 +572,7 @@ PyObject *M_Effect_New( PyObject * self, PyObject * args )
|
||||
/*****************************************************************************/
|
||||
PyObject *M_Effect_Get( PyObject * self, PyObject * args )
|
||||
{
|
||||
/*arguments : string object name
|
||||
int : position of effect in the obj's effect list */
|
||||
char *name = NULL;
|
||||
Object *object_iter;
|
||||
Effect *eff;
|
||||
int num = -1, i;
|
||||
|
||||
if( !PyArg_ParseTuple( args, "|si", &name, &num ) )
|
||||
return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
|
||||
"expected string int argument" ) );
|
||||
|
||||
object_iter = G.main->object.first;
|
||||
|
||||
if( !object_iter )
|
||||
return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
|
||||
"Scene contains no object" ) );
|
||||
|
||||
if( name ) { /* (name, num = -1) - try to find the given object */
|
||||
|
||||
while( object_iter ) {
|
||||
|
||||
if( !strcmp( name, object_iter->id.name + 2 ) ) {
|
||||
|
||||
eff = object_iter->effect.first; /*can be NULL: None will be returned*/
|
||||
|
||||
if (num >= 0) { /* return effect in given num position if available */
|
||||
|
||||
for( i = 0; i < num; i++ ) {
|
||||
if (!eff) break;
|
||||
eff = eff->next;
|
||||
}
|
||||
|
||||
if (eff) {
|
||||
return EffectCreatePyObject( eff, object_iter );
|
||||
} else { /* didn't find any effect in the given position */
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
else {/*return a list with all effects linked to the given object*/
|
||||
/* this was pointed by Stephen Swaney */
|
||||
PyObject *effectlist = PyList_New( 0 );
|
||||
|
||||
while (eff) {
|
||||
PyObject *found_eff = EffectCreatePyObject( eff,
|
||||
object_iter );
|
||||
PyList_Append( effectlist, found_eff );
|
||||
Py_DECREF( found_eff ); /* PyList_Append incref'ed it */
|
||||
eff = eff->next;
|
||||
}
|
||||
return effectlist;
|
||||
}
|
||||
}
|
||||
|
||||
object_iter = object_iter->id.next;
|
||||
}
|
||||
|
||||
if (!object_iter)
|
||||
return EXPP_ReturnPyObjError (PyExc_AttributeError,
|
||||
"no such object");
|
||||
}
|
||||
|
||||
else { /* () - return a list with all effects currently in Blender */
|
||||
PyObject *effectlist = PyList_New( 0 );
|
||||
|
||||
while( object_iter ) {
|
||||
if( object_iter->effect.first != NULL ) {
|
||||
eff = object_iter->effect.first;
|
||||
while( eff ) {
|
||||
PyObject *found_eff = EffectCreatePyObject( eff,
|
||||
object_iter );
|
||||
PyList_Append( effectlist, found_eff );
|
||||
Py_DECREF( found_eff );
|
||||
eff = eff->next;
|
||||
}
|
||||
}
|
||||
object_iter = object_iter->id.next;
|
||||
}
|
||||
return effectlist;
|
||||
}
|
||||
printf("warning, static particles api removed\n");
|
||||
Py_INCREF( Py_None );
|
||||
return Py_None;
|
||||
}
|
||||
@@ -688,30 +584,8 @@ static PyObject *Effect_FlagsDict( void )
|
||||
PyObject *Flags = PyConstant_New( );
|
||||
|
||||
if( Flags ) {
|
||||
BPy_constant *c = ( BPy_constant * ) Flags;
|
||||
|
||||
PyConstant_Insert( c, "SELECTED",
|
||||
PyInt_FromLong( EFF_SELECT ) );
|
||||
PyConstant_Insert( c, "BSPLINE",
|
||||
PyInt_FromLong( PAF_BSPLINE ) );
|
||||
PyConstant_Insert( c, "STATIC",
|
||||
PyInt_FromLong( PAF_STATIC ) );
|
||||
PyConstant_Insert( c, "FACES",
|
||||
PyInt_FromLong( PAF_FACE ) );
|
||||
PyConstant_Insert( c, "ANIMATED",
|
||||
PyInt_FromLong( PAF_ANIMATED ) );
|
||||
PyConstant_Insert( c, "UNBORN",
|
||||
PyInt_FromLong( PAF_UNBORN ) );
|
||||
PyConstant_Insert( c, "VERTS",
|
||||
PyInt_FromLong( PAF_OFACE ) );
|
||||
PyConstant_Insert( c, "EMESH",
|
||||
PyInt_FromLong( PAF_SHOWE ) );
|
||||
PyConstant_Insert( c, "TRUERAND",
|
||||
PyInt_FromLong( PAF_TRAND ) );
|
||||
PyConstant_Insert( c, "EVENDIST",
|
||||
PyInt_FromLong( PAF_EDISTR ) );
|
||||
PyConstant_Insert( c, "DIED",
|
||||
PyInt_FromLong( PAF_DIED ) );
|
||||
//BPy_constant *c = ( BPy_constant * ) Flags;
|
||||
/* removed */
|
||||
}
|
||||
return Flags;
|
||||
}
|
||||
@@ -1290,134 +1164,7 @@ static int Effect_setStaticStep( BPy_Effect * self , PyObject * args )
|
||||
/*****************************************************************************/
|
||||
static PyObject *Effect_getParticlesLoc( BPy_Effect * self )
|
||||
{
|
||||
Object *ob;
|
||||
Effect *eff;
|
||||
PartEff *paf;
|
||||
Particle *pa=0;
|
||||
PyObject *list, *strand_list, *pyvec, *pyvec2;
|
||||
float p_time, c_time, vec[3], vec1[3], cfra, m_time, s_time;
|
||||
int a;
|
||||
short disp=100 ;
|
||||
|
||||
cfra=frame_to_float( G.scene->r.cfra );
|
||||
|
||||
/* as we need to update the particles system we try to retrieve
|
||||
the object to which the effect is connected */
|
||||
eff =(Effect *) self->effect;
|
||||
|
||||
ob= self->object;
|
||||
if(!ob)
|
||||
return ( EXPP_ReturnPyObjError (PyExc_AttributeError,
|
||||
"Effect has no object" ) );
|
||||
/*get the particles data */
|
||||
paf= (PartEff *)eff;
|
||||
|
||||
/* particles->disp reduce the display number of particles */
|
||||
/* as we want the complete list ... we backup the disp value and restore later */
|
||||
if (paf->disp<100)
|
||||
disp= paf->disp; paf->disp=100;
|
||||
|
||||
|
||||
build_particle_system(ob);
|
||||
pa= paf->keys;
|
||||
|
||||
if(!pa)
|
||||
return ( EXPP_ReturnPyObjError (PyExc_AttributeError,
|
||||
"Particles Location : no Keys" ) );
|
||||
|
||||
/* if object is in motion */
|
||||
if( ob->ipoflag & OB_OFFS_PARTICLE )
|
||||
p_time= give_timeoffset(ob);
|
||||
else
|
||||
p_time= 0.0;
|
||||
|
||||
list = PyList_New( 0 );
|
||||
if( !list )
|
||||
return EXPP_ReturnPyObjError( PyExc_MemoryError, "PyList() failed" );
|
||||
|
||||
c_time= bsystem_time( ob, cfra, p_time );
|
||||
|
||||
for( a=0; a < paf->totpart; a++, pa += paf->totkey ) {
|
||||
|
||||
if(paf->flag & PAF_STATIC ) {
|
||||
strand_list = PyList_New( 0 );
|
||||
m_time= pa->time+pa->lifetime+paf->staticstep-1;
|
||||
for(c_time= pa->time; c_time<m_time; c_time+=paf->staticstep) {
|
||||
where_is_particle(paf, pa, c_time, vec);
|
||||
MTC_Mat4MulVecfl(ob->obmat, vec); /* make worldspace like the others */
|
||||
pyvec = newVectorObject(vec, 3, Py_NEW);
|
||||
if( PyList_Append( strand_list, pyvec) < 0 ) {
|
||||
Py_DECREF( list );
|
||||
Py_DECREF( strand_list );
|
||||
Py_XDECREF( pyvec );
|
||||
|
||||
return EXPP_ReturnPyObjError( PyExc_RuntimeError,
|
||||
"Couldn't append item to PyList" );
|
||||
}
|
||||
Py_DECREF( pyvec );
|
||||
|
||||
}
|
||||
|
||||
if( PyList_Append( list, strand_list) < 0 ) {
|
||||
Py_DECREF( list );
|
||||
Py_DECREF( strand_list );
|
||||
return EXPP_ReturnPyObjError( PyExc_RuntimeError,
|
||||
"Couldn't append item to PyList" );
|
||||
}
|
||||
Py_DECREF( strand_list );
|
||||
} else {
|
||||
if(c_time > pa->time && c_time < pa->time+pa->lifetime ) {
|
||||
/* vector particles are a tuple of 2 vectors */
|
||||
if( paf->stype==PAF_VECT ) {
|
||||
s_time= c_time;
|
||||
p_time= c_time+1.0f;
|
||||
if(c_time < pa->time) {
|
||||
if(paf->flag & PAF_UNBORN)
|
||||
p_time= pa->time+1.0f;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
if(c_time > pa->time+pa->lifetime) {
|
||||
if(paf->flag & PAF_DIED)
|
||||
s_time= pa->time+pa->lifetime-1.0f;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
where_is_particle(paf, pa, s_time, vec);
|
||||
where_is_particle(paf, pa, p_time, vec1);
|
||||
pyvec = newVectorObject(vec, 3, Py_NEW);
|
||||
pyvec2 = newVectorObject(vec1, 3, Py_NEW);
|
||||
if( PyList_Append( list, Py_BuildValue("[OO]", pyvec, pyvec2)) < 0 ) {
|
||||
Py_DECREF( list );
|
||||
Py_XDECREF( pyvec );
|
||||
Py_XDECREF( pyvec2 );
|
||||
return EXPP_ReturnPyObjError( PyExc_RuntimeError,
|
||||
"Couldn't append item to PyList" );
|
||||
}
|
||||
Py_DECREF( pyvec );
|
||||
Py_DECREF( pyvec2 );
|
||||
} else { /* not a vector */
|
||||
where_is_particle(paf, pa, c_time, vec);
|
||||
pyvec = newVectorObject(vec, 3, Py_NEW);
|
||||
if( PyList_Append( list, pyvec) < 0 ) {
|
||||
Py_DECREF( list );
|
||||
Py_XDECREF( pyvec );
|
||||
return EXPP_ReturnPyObjError( PyExc_RuntimeError,
|
||||
"Couldn't append item to PyList" );
|
||||
}
|
||||
Py_DECREF( pyvec );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* restore the real disp value */
|
||||
if (disp<100){
|
||||
paf->disp=disp;
|
||||
build_particle_system(ob);
|
||||
}
|
||||
|
||||
return list;
|
||||
return PyList_New( 0 );
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -1341,7 +1341,7 @@ PyTypeObject Node_Type = {
|
||||
PyObject_HEAD_INIT( NULL ) /* required py macro */
|
||||
0, /* ob_size */
|
||||
/* For printing, in format "<module>.<name>" */
|
||||
"Blender.Node.node", /* char *tp_name; */
|
||||
"Blender.Node.Scripted", /* char *tp_name; */
|
||||
sizeof( BPy_Node ), /* int tp_basicsize; */
|
||||
0, /* tp_itemsize; For allocation */
|
||||
|
||||
|
||||
@@ -466,7 +466,7 @@ static PyObject *Object_upAxis(BPy_Object * self);
|
||||
static PyMethodDef BPy_Object_methods[] = {
|
||||
/* name, method, flags, doc */
|
||||
{"buildParts", ( PyCFunction ) Object_buildParts, METH_NOARGS,
|
||||
"Recalcs particle system (if any) "},
|
||||
"Recalcs particle system (if any), (depricated, will always return an empty list in version 2.46)"},
|
||||
{"getIpo", ( PyCFunction ) Object_getIpo, METH_NOARGS,
|
||||
"Returns the ipo of this object (if any) "},
|
||||
{"clrParent", ( PyCFunction ) Object_clrParent, METH_VARARGS,
|
||||
@@ -1028,7 +1028,7 @@ static PyObject *M_Object_Duplicate( PyObject * self_unused,
|
||||
|
||||
static PyObject *Object_buildParts( BPy_Object * self )
|
||||
{
|
||||
build_particle_system( self->object );
|
||||
/* This is now handles by modifiers */
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
@@ -2986,12 +2986,7 @@ static PyObject *Object_getDupliObjects( BPy_Object * self )
|
||||
|
||||
if(ob->transflag & OB_DUPLI) {
|
||||
/* before make duplis, update particle for current frame */
|
||||
if(ob->transflag & OB_DUPLIVERTS) {
|
||||
PartEff *paf= give_parteff(ob);
|
||||
if(paf) {
|
||||
if(paf->flag & PAF_ANIMATED) build_particle_system(ob);
|
||||
}
|
||||
}
|
||||
/* TODO, build particles for particle dupli's */
|
||||
if(ob->type!=OB_MBALL) {
|
||||
PyObject *list;
|
||||
DupliObject *dupob;
|
||||
@@ -3035,23 +3030,7 @@ static int Object_setDupliGroup( BPy_Object * self, PyObject * value )
|
||||
|
||||
static PyObject *Object_getEffects( BPy_Object * self )
|
||||
{
|
||||
PyObject *effect_list, *pyval;
|
||||
Effect *eff;
|
||||
|
||||
effect_list = PyList_New( 0 );
|
||||
if( !effect_list )
|
||||
return EXPP_ReturnPyObjError( PyExc_RuntimeError,
|
||||
"PyList_New() failed" );
|
||||
|
||||
eff = self->object->effect.first;
|
||||
|
||||
while( eff ) {
|
||||
pyval = EffectCreatePyObject( eff, self->object );
|
||||
PyList_Append( effect_list, pyval );
|
||||
Py_DECREF(pyval);
|
||||
eff = eff->next;
|
||||
}
|
||||
return effect_list;
|
||||
return PyList_New( 0 );
|
||||
}
|
||||
|
||||
static PyObject *Object_getActionStrips( BPy_Object * self )
|
||||
@@ -5028,7 +5007,7 @@ static PyGetSetDef BPy_Object_getseters[] = {
|
||||
|
||||
{"effects",
|
||||
(getter)Object_getEffects, (setter)NULL,
|
||||
"The list of particle effects associated with the object",
|
||||
"The list of particle effects associated with the object, (depricated, will always return an empty list in version 2.46)",
|
||||
NULL},
|
||||
{"actionStrips",
|
||||
(getter)Object_getActionStrips, (setter)NULL,
|
||||
|
||||
@@ -262,43 +262,9 @@ struct PyMethodDef M_Particle_methods[] = {
|
||||
/*****************************************************************************/
|
||||
PyObject *M_Particle_New( PyObject * self, PyObject * args )
|
||||
{
|
||||
BPy_Effect *pyeffect;
|
||||
Effect *bleffect = 0;
|
||||
Object *ob;
|
||||
char *name = NULL;
|
||||
|
||||
if( !PyArg_ParseTuple( args, "s", &name ) )
|
||||
return EXPP_ReturnPyObjError( PyExc_TypeError,
|
||||
"expected string argument" );
|
||||
|
||||
for( ob = G.main->object.first; ob; ob = ob->id.next )
|
||||
if( !strcmp( name, ob->id.name + 2 ) )
|
||||
break;
|
||||
|
||||
if( !ob )
|
||||
return EXPP_ReturnPyObjError( PyExc_AttributeError,
|
||||
"object does not exist" );
|
||||
|
||||
if( ob->type != OB_MESH )
|
||||
return EXPP_ReturnPyObjError( PyExc_AttributeError,
|
||||
"object is not a mesh" );
|
||||
|
||||
pyeffect = ( BPy_Effect * ) PyObject_NEW( BPy_Effect, &Effect_Type );
|
||||
if( !pyeffect )
|
||||
return EXPP_ReturnPyObjError( PyExc_MemoryError,
|
||||
"couldn't create Effect Data object" );
|
||||
|
||||
bleffect = add_effect( EFF_PARTICLE );
|
||||
if( !bleffect ) {
|
||||
Py_DECREF( pyeffect );
|
||||
return EXPP_ReturnPyObjError( PyExc_RuntimeError,
|
||||
"couldn't create Effect Data in Blender" );
|
||||
}
|
||||
|
||||
pyeffect->effect = (PartEff *)bleffect;
|
||||
BLI_addtail( &ob->effect, bleffect );
|
||||
|
||||
return ( PyObject * ) pyeffect;
|
||||
printf("warning, static particles api removed\n");
|
||||
Py_INCREF( Py_None );
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -307,48 +273,7 @@ PyObject *M_Particle_New( PyObject * self, PyObject * args )
|
||||
/*****************************************************************************/
|
||||
PyObject *M_Particle_Get( PyObject * self, PyObject * args )
|
||||
{
|
||||
/*arguments : string object name
|
||||
int : position of effect in the obj's effect list */
|
||||
char *name = 0;
|
||||
Object *object_iter;
|
||||
Effect *eff;
|
||||
BPy_Particle *wanted_eff;
|
||||
int num, i;
|
||||
|
||||
if( !PyArg_ParseTuple( args, "si", &name, &num ) )
|
||||
return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
|
||||
"expected string int argument" ) );
|
||||
|
||||
object_iter = G.main->object.first;
|
||||
if( !object_iter )
|
||||
return EXPP_ReturnPyObjError( PyExc_AttributeError,
|
||||
"Scene contains no object" );
|
||||
|
||||
while( object_iter ) {
|
||||
if( strcmp( name, object_iter->id.name + 2 ) ) {
|
||||
object_iter = object_iter->id.next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( object_iter->effect.first != NULL ) {
|
||||
eff = object_iter->effect.first;
|
||||
for( i = 0; i < num; i++ ) {
|
||||
if( eff->type != EFF_PARTICLE )
|
||||
continue;
|
||||
eff = eff->next;
|
||||
if( !eff )
|
||||
return ( EXPP_ReturnPyObjError
|
||||
( PyExc_AttributeError,
|
||||
"Object" ) );
|
||||
}
|
||||
wanted_eff =
|
||||
( BPy_Particle * ) PyObject_NEW( BPy_Particle,
|
||||
&Particle_Type );
|
||||
wanted_eff->particle = eff;
|
||||
return ( PyObject * ) wanted_eff;
|
||||
}
|
||||
object_iter = object_iter->id.next;
|
||||
}
|
||||
printf("warning, static particles api removed\n");
|
||||
Py_INCREF( Py_None );
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
"""
|
||||
The Blender.Effect submodule
|
||||
|
||||
B{new}: now L{Get}('objname') (without specifying second parameter: 'position') returns a list of all effects linked to object "objname".
|
||||
B{Deprecated}:
|
||||
This module is now maintained but not actively developed.
|
||||
|
||||
Effect
|
||||
======
|
||||
|
||||
@@ -383,7 +383,7 @@ class Object:
|
||||
@ivar sel: The selection state of the object in the current scene.
|
||||
True is selected, False is unselected. Setting makes the object active.
|
||||
@type sel: boolean
|
||||
@ivar effects: The list of particle effects associated with the object.
|
||||
@ivar effects: The list of particle effects associated with the object. (depricated, will always return an empty list)
|
||||
Read-only.
|
||||
@type effects: list of Effect objects
|
||||
@ivar parentbonename: The string name of the parent bone (if defined).
|
||||
@@ -645,7 +645,7 @@ class Object:
|
||||
def buildParts():
|
||||
"""
|
||||
Recomputes the particle system. This method only applies to an Object of
|
||||
the type Effect.
|
||||
the type Effect. (depricated, does nothing now, use makeDisplayList instead to update the modifier stack)
|
||||
"""
|
||||
|
||||
def insertShapeKey():
|
||||
@@ -1195,12 +1195,9 @@ class Object:
|
||||
|
||||
def makeDisplayList():
|
||||
"""
|
||||
Updates this object's display list. Blender uses display lists to store
|
||||
already transformed data (like a mesh with its vertices already modified
|
||||
by coordinate transformations and armature deformation). If the object
|
||||
isn't modified, there's no need to recalculate this data. This method is
|
||||
here for the *few cases* where a script may need it, like when toggling
|
||||
the "SubSurf" mode for a mesh:
|
||||
Forces an update to the objects display data. If the object isn't modified,
|
||||
there's no need to recalculate this data.
|
||||
This method is here for the *few cases* where it is needed.
|
||||
|
||||
Example::
|
||||
import Blender
|
||||
|
||||
Reference in New Issue
Block a user