diff options
Diffstat (limited to 'source/blender/python')
29 files changed, 1735 insertions, 485 deletions
diff --git a/source/blender/python/BPY_interface.c b/source/blender/python/BPY_interface.c index 3cdc0de4f52..529d428692b 100644 --- a/source/blender/python/BPY_interface.c +++ b/source/blender/python/BPY_interface.c @@ -1706,8 +1706,9 @@ static PyObject *reimportText( PyObject *module ) /* if previously compiled, free the object */ /* (can't see how could be NULL, but check just in case) */ - if( text->compiled ) + if( text->compiled ){ Py_DECREF( (PyObject *)text->compiled ); + } /* compile the buffer */ buf = txt_to_buf( text ); diff --git a/source/blender/python/SConscript b/source/blender/python/SConscript index c7a597c62c9..aedafd84e96 100644 --- a/source/blender/python/SConscript +++ b/source/blender/python/SConscript @@ -43,6 +43,7 @@ source_files = ['BPY_interface.c', 'api2_2x/Types.c', 'api2_2x/Window.c', 'api2_2x/World.c', + 'api2_2x/Pose.c', 'api2_2x/Image.c', 'api2_2x/Text.c', 'api2_2x/Text3d.c', diff --git a/source/blender/python/api2_2x/Armature.c b/source/blender/python/api2_2x/Armature.c index 743956a1f61..28ae3eadcc7 100644 --- a/source/blender/python/api2_2x/Armature.c +++ b/source/blender/python/api2_2x/Armature.c @@ -44,8 +44,7 @@ #include "DNA_object_types.h" //This must come before BIF_editarmature.h... #include "BIF_editarmature.h" -//------------------UNDECLARED EXTERNAL PROTOTYPES-------------------- -//These are evil 'extern' declarations for functions with no anywhere +//------------------EXTERNAL PROTOTYPES-------------------- extern void free_editArmature(void); extern void make_boneList(ListBase* list, ListBase *bones, EditBone *parent); extern void editbones_to_armature (ListBase *list, Object *ob); @@ -112,7 +111,7 @@ static PyMethodDef BPy_BonesDict_methods[] = { "() - Returns the keys the dictionary"}, {"values", (PyCFunction) BonesDict_values, METH_NOARGS, "() - Returns the values from the dictionary"}, - {NULL} + {NULL, NULL, 0, NULL} }; //-----------------(internal) static int BoneMapping_Init(PyObject *dictionary, ListBase *bones){ @@ -225,8 +224,18 @@ PyObject *BonesDict_GetItem(BPy_BonesDict *self, PyObject* key) }else{ value = PyDict_GetItem(self->bonesMap, key); } - if(value == NULL){ - return EXPP_incr_ret(Py_None); + if(value == NULL){ /* item not found in dict. throw exception */ + char buffer[128]; + char* key_str; + key_str = PyString_AsString( key ); + if( !key_str ){ /* key not a py string */ + key_str = ""; /* use empty string for printing */ + } + + PyOS_snprintf( buffer, sizeof(buffer), + "bone %s not found", key_str); + + return EXPP_ReturnPyObjError(PyExc_KeyError, buffer ); } return EXPP_incr_ret(value); } @@ -335,7 +344,7 @@ AttributeError3: return EXPP_intError(PyExc_AttributeError, "%s%s", sBoneDictBadArgs, "The 'connected' flag is set but the bone has no parent!"); } -//------------------TYPE_OBECT DEFINITION-------------------------- +//------------------TYPE_OBJECT DEFINITION-------------------------- //Mapping Protocol static PyMappingMethods BonesDict_MapMethods = { (inquiry) BonesDict_len, //mp_length @@ -929,7 +938,7 @@ static PyMethodDef BPy_Armature_methods[] = { "() - Unlocks the ability to modify armature bones"}, {"update", (PyCFunction) Armature_update, METH_NOARGS, "() - Rebuilds the armature based on changes to bones since the last call to makeEditable"}, - {NULL} + {NULL, NULL, 0, NULL} }; //------------------------tp_getset //This contains methods for attributes that require checking @@ -1218,7 +1227,7 @@ static char M_Armature_Get_doc[] = "(name) - return the armature with the name ' struct PyMethodDef M_Armature_methods[] = { {"Get", M_Armature_Get, METH_VARARGS, M_Armature_Get_doc}, - {NULL} + {NULL, NULL, 0, NULL} }; //------------------VISIBLE PROTOTYPE IMPLEMENTATION----------------------- //-----------------(internal) diff --git a/source/blender/python/api2_2x/Armature.h b/source/blender/python/api2_2x/Armature.h index 4d14b41fdc8..dbf21d1e5a5 100644 --- a/source/blender/python/api2_2x/Armature.h +++ b/source/blender/python/api2_2x/Armature.h @@ -40,8 +40,8 @@ //-------------------MODULE INIT--------------------------------- PyObject *Armature_Init( void ); //-------------------TYPEOBJECT---------------------------------- -PyTypeObject Armature_Type; -PyTypeObject BonesDict_Type; +extern PyTypeObject Armature_Type; +extern PyTypeObject BonesDict_Type; //-------------------STRUCT DEFINITION--------------------------- typedef struct { PyObject_HEAD diff --git a/source/blender/python/api2_2x/BezTriple.c b/source/blender/python/api2_2x/BezTriple.c index 3d610e38fd6..c8b82d16a88 100644 --- a/source/blender/python/api2_2x/BezTriple.c +++ b/source/blender/python/api2_2x/BezTriple.c @@ -256,39 +256,20 @@ static PyObject *BezTriple_getTriple( BPy_BezTriple * self ) static PyObject *BezTriple_setPoints( BPy_BezTriple * self, PyObject * args ) { - int i; struct BezTriple *bezt = self->beztriple; PyObject *popo = 0; - if( !PyArg_ParseTuple( args, "O", &popo ) ) - return ( EXPP_ReturnPyObjError - ( PyExc_TypeError, "expected sequence argument" ) ); - - if( PySequence_Check( popo ) == 0 ) { - puts( "error in BezTriple_setPoints - expected sequence" ); - Py_INCREF( Py_None ); - return Py_None; - } - - { - /* - some debug stuff - this will become an overloaded args check - */ - int size = PySequence_Size( popo ); - printf( "\n dbg: sequence size is %d\n", size ); - } + if( !PyArg_ParseTuple( args, "O", &popo ) || !PySequence_Check( popo ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected sequence argument" ); for( i = 0; i < 2; i++ ) { - PyObject *o = PySequence_GetItem( popo, i ); - if( !o ) - printf( "\n bad o. o no!\n" ); - - /* bezt->vec[1][i] = PyFloat_AsDouble (PyTuple_GetItem (popo, i)); */ + PyObject *o = PySequence_ITEM( popo, i ); bezt->vec[1][i] = (float)PyFloat_AsDouble( o ); bezt->vec[0][i] = bezt->vec[1][i] - 1; bezt->vec[2][i] = bezt->vec[1][i] + 1; + Py_DECREF( o ); } /* experimental fussing with handles - ipo.c: calchandles_ipocurve */ @@ -298,8 +279,7 @@ static PyObject *BezTriple_setPoints( BPy_BezTriple * self, PyObject * args ) if( bezt->vec[2][0] < bezt->vec[1][0] ) bezt->vec[2][0] = bezt->vec[1][0]; - Py_INCREF( Py_None ); - return Py_None; + Py_RETURN_NONE; } diff --git a/source/blender/python/api2_2x/Bone.c b/source/blender/python/api2_2x/Bone.c index b4f8af4fe12..7e233e5f647 100644 --- a/source/blender/python/api2_2x/Bone.c +++ b/source/blender/python/api2_2x/Bone.c @@ -42,14 +42,15 @@ #include "DNA_object_types.h" //1 #include "BIF_editarmature.h" //2 +//------------------UNDECLARED EXTERNAL PROTOTYPES-------------------- +extern void mat3_to_vec_roll(float mat[][3], float *vec, float *roll); + //------------------------ERROR CODES--------------------------------- //This is here just to make me happy and to have more consistant error strings :) -static const char sEditBoneError[] = "EditBone (internal) - Error: "; -static const char sEditBoneBadArgs[] = "EditBone (internal) - Bad Arguments: "; +static const char sEditBoneError[] = "EditBone - Error: "; +static const char sEditBoneBadArgs[] = "EditBone - Bad Arguments: "; static const char sBoneError[] = "Bone - Error: "; static const char sBoneBadArgs[] = "Bone - Bad Arguments: "; -static const char sConstListError[] = "ConstantList - Error: "; -static const char sConstListBadArgs[] = "ConstantList - Bad Arguments: "; //----------------------(internal) //gets the bone->roll (which is a localspace roll) and puts it in parentspace @@ -541,7 +542,6 @@ static int EditBone_setParent(BPy_EditBone *self, PyObject *value, void *closure AttributeError: return EXPP_intError(PyExc_AttributeError, "%s%s%s", sEditBoneError, ".parent: ", "expects a EditBone Object"); - AttributeError2: return EXPP_intError(PyExc_AttributeError, "%s%s%s", sEditBoneError, ".parent: ", "This object is not in the armature's bone list!"); @@ -565,8 +565,53 @@ static PyObject *EditBone_getMatrix(BPy_EditBone *self, void *closure) //------------------------EditBone.matrix (set) static int EditBone_setMatrix(BPy_EditBone *self, PyObject *value, void *closure) { - printf("Sorry this isn't implemented yet.... :/"); - return 1; + PyObject *matrix; + float roll, length, vec[3], axis[3], mat3[3][3]; + + if (!PyArg_Parse(value, "O!", &matrix_Type, &matrix)) + goto AttributeError; + + //make sure we have the right sizes + if (((MatrixObject*)matrix)->rowSize != 3 && ((MatrixObject*)matrix)->colSize != 3){ + if(((MatrixObject*)matrix)->rowSize != 4 && ((MatrixObject*)matrix)->colSize != 4){ + goto AttributeError; + } + } + + /*vec will be a normalized directional vector + * together with the length of the old bone vec*length = the new vector*/ + /*The default rotation is 0,1,0 on the Y axis (see mat3_to_vec_roll)*/ + if (((MatrixObject*)matrix)->rowSize == 4){ + Mat3CpyMat4(mat3, ((float (*)[4])*((MatrixObject*)matrix)->matrix)); + }else{ + Mat3CpyMat3(mat3, ((float (*)[3])*((MatrixObject*)matrix)->matrix)); + } + mat3_to_vec_roll(mat3, vec, &roll); + + //if a 4x4 matrix was passed we'll translate the vector otherwise not + if (self->editbone){ + self->editbone->roll = roll; + VecSubf(axis, self->editbone->tail, self->editbone->head); + length = VecLength(axis); + VecMulf(vec, length); + if (((MatrixObject*)matrix)->rowSize == 4) + VecCopyf(self->editbone->head, ((MatrixObject*)matrix)->matrix[3]); + VecAddf(self->editbone->tail, self->editbone->head, vec); + return 0; + }else{ + self->roll = roll; + VecSubf(axis, self->tail, self->head); + length = VecLength(axis); + VecMulf(vec, length); + if (((MatrixObject*)matrix)->rowSize == 4) + VecCopyf(self->head, ((MatrixObject*)matrix)->matrix[3]); + VecAddf(self->tail, self->head, vec); + return 0; + } + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sEditBoneError, ".matrix: ", "expects a 3x3 or 4x4 Matrix Object"); } //------------------------Bone.length (get) static PyObject *EditBone_getLength(BPy_EditBone *self, void *closure) @@ -603,7 +648,7 @@ static PyMethodDef BPy_EditBone_methods[] = { "() - True/False - Bone has a parent"}, {"clearParent", (PyCFunction) EditBone_clearParent, METH_NOARGS, "() - sets the parent to None"}, - {NULL} + {NULL, NULL, 0, NULL} }; ///------------------------tp_getset //This contains methods for attributes that require checking @@ -630,7 +675,7 @@ static PyGetSetDef BPy_EditBone_getset[] = { "The parent bone of this bone", NULL}, {"length", (getter)EditBone_getLength, (setter)EditBone_setLength, "The length of this bone", NULL}, - {NULL} + {NULL, NULL, NULL, NULL,NULL} }; //------------------------tp_repr @@ -751,6 +796,28 @@ PyTypeObject EditBone_Type = { }; //------------------METHOD IMPLEMENTATIONS-------------------------------- +//------------------------(internal) PyBone_ChildrenAsList +static int PyBone_ChildrenAsList(PyObject *list, ListBase *bones){ + Bone *bone = NULL; + PyObject *py_bone = NULL; + + for (bone = bones->first; bone; bone = bone->next){ + py_bone = PyBone_FromBone(bone); + if (py_bone == NULL) + return 0; + + if(PyList_Append(list, py_bone) == -1){ + goto RuntimeError; + } + if (bone->childbase.first) + PyBone_ChildrenAsList(list, &bone->childbase); + } + return 1; + +RuntimeError: + return EXPP_intError(PyExc_RuntimeError, "%s%s", + sBoneError, "Internal error trying to wrap blender bones!"); +} //-------------------------Bone.hasParent() PyObject *Bone_hasParent(BPy_Bone *self) { @@ -767,6 +834,20 @@ PyObject *Bone_hasChildren(BPy_Bone *self) else return EXPP_incr_ret(Py_False); } +//-------------------------Bone.getAllChildren() +PyObject *Bone_getAllChildren(BPy_Bone *self) +{ + PyObject *list = NULL; + + if (self->bone->childbase.first){ + list = PyList_New(0); + if (!PyBone_ChildrenAsList(list, &self->bone->childbase)) + return NULL; + return EXPP_incr_ret(list); + }else{ + return EXPP_incr_ret(Py_None); + } +} //------------------ATTRIBUTE IMPLEMENTATIONS----------------------------- //------------------------Bone.name (get) static PyObject *Bone_getName(BPy_Bone *self, void *closure) @@ -920,42 +1001,31 @@ static int Bone_setParent(BPy_Bone *self, PyObject *value, void *closure) return EXPP_intError(PyExc_ValueError, "%s%s", sBoneError, "You must first call .makeEditable() to edit the armature"); } -//------------------------(internal) PyBone_ChildrenAsList -static int PyBone_ChildrenAsList(PyObject *list, ListBase *bones){ - Bone *bone = NULL; - PyObject *py_bone = NULL; - - for (bone = bones->first; bone; bone = bone->next){ - py_bone = PyBone_FromBone(bone); - if (py_bone == NULL) - return 0; - - if(PyList_Append(list, py_bone) == -1){ - goto RuntimeError; - } - if (bone->childbase.first) - PyBone_ChildrenAsList(list, &bone->childbase); - } - return 1; - -RuntimeError: - return EXPP_intError(PyExc_RuntimeError, "%s%s", - sBoneError, "Internal error trying to wrap blender bones!"); -} - //------------------------Bone.children (get) static PyObject *Bone_getChildren(BPy_Bone *self, void *closure) { PyObject *list = NULL; + Bone *bone = NULL; + PyObject *py_bone = NULL; if (self->bone->childbase.first){ list = PyList_New(0); - if (!PyBone_ChildrenAsList(list, &self->bone->childbase)) - return NULL; + for (bone = self->bone->childbase.first; bone; bone = bone->next){ + py_bone = PyBone_FromBone(bone); + if (py_bone == NULL) + return 0; + if(PyList_Append(list, py_bone) == -1){ + goto RuntimeError; + } + } return EXPP_incr_ret(list); }else{ return EXPP_incr_ret(Py_None); } + +RuntimeError: + return EXPP_objError(PyExc_RuntimeError, "%s%s", + sBoneError, "Internal error trying to wrap blender bones!"); } //------------------------Bone.children (set) static int Bone_setChildren(BPy_Bone *self, PyObject *value, void *closure) @@ -995,7 +1065,9 @@ static PyMethodDef BPy_Bone_methods[] = { "() - True/False - Bone has a parent"}, {"hasChildren", (PyCFunction) Bone_hasChildren, METH_NOARGS, "() - True/False - Bone has 1 or more children"}, - {NULL} + {"getAllChildren", (PyCFunction) Bone_getAllChildren, METH_NOARGS, + "() - All the children for this bone - including children's children"}, + {NULL, NULL, 0, NULL} }; //------------------------tp_getset //This contains methods for attributes that require checking @@ -1024,7 +1096,7 @@ static PyGetSetDef BPy_Bone_getset[] = { "The child bones of this bone", NULL}, {"length", (getter)Bone_getLength, (setter)Bone_setLength, "The length of this bone", NULL}, - {NULL} + {NULL, NULL, NULL, NULL,NULL} }; //------------------------tp_repr //This is the string representation of the object diff --git a/source/blender/python/api2_2x/Bone.h b/source/blender/python/api2_2x/Bone.h index aa095733d05..8c10aeb3075 100644 --- a/source/blender/python/api2_2x/Bone.h +++ b/source/blender/python/api2_2x/Bone.h @@ -38,8 +38,8 @@ #define BoneObject_Check(v) ((v)->ob_type == &Bone_Type) #define EditBoneObject_Check(v) ((v)->ob_type == &EditBone_Type) //-------------------TYPEOBJECT---------------------------------- -PyTypeObject EditBone_Type; -PyTypeObject Bone_Type; +extern PyTypeObject EditBone_Type; +extern PyTypeObject Bone_Type; //-------------------STRUCT DEFINITION---------------------------- typedef struct { diff --git a/source/blender/python/api2_2x/Key.c b/source/blender/python/api2_2x/Key.c index e71602ad6b4..32d7bc26191 100644 --- a/source/blender/python/api2_2x/Key.c +++ b/source/blender/python/api2_2x/Key.c @@ -25,7 +25,8 @@ * * This is a new part of Blender. * - * Contributor(s): Pontus Lidman, Johnny Matthews, Ken Hughes + * Contributor(s): Pontus Lidman, Johnny Matthews, Ken Hughes, + * Michael Reimpell * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ @@ -36,6 +37,7 @@ #include <BKE_global.h> #include <BKE_main.h> #include <BKE_curve.h> +#include "BIF_space.h" #include "Ipocurve.h" #include "Key.h" @@ -62,10 +64,12 @@ static void KeyBlock_dealloc( PyObject * self ); static PyObject *Key_repr( BPy_Key * self ); static PyObject *Key_getBlocks( PyObject * self ); -static PyObject *Key_getType( PyObject * self ); +static PyObject *Key_getType( BPy_Key * self ); +static PyObject *Key_getRelative( BPy_Key * self ); static PyObject *Key_getIpo( PyObject * self ); static int Key_setIpo( PyObject * self, PyObject * args ); static PyObject *Key_getValue( PyObject * self ); +static int Key_setRelative( BPy_Key * self, PyObject * value ); static struct PyMethodDef Key_methods[] = { { "getBlocks", (PyCFunction) Key_getBlocks, METH_NOARGS, "Get key blocks" }, @@ -74,21 +78,21 @@ static struct PyMethodDef Key_methods[] = { }; static PyGetSetDef BPy_Key_getsetters[] = { - {"type",(getter)Key_getType, (setter)NULL, - "Key Type",NULL}, - {"value",(getter)Key_getValue, (setter)NULL, - "Key value",NULL}, - {"ipo",(getter)Key_getIpo, (setter)Key_setIpo, - "ipo linked to key",NULL}, - {"blocks",(getter)Key_getBlocks, (setter)NULL, - "blocks linked to the key",NULL}, - {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ - }; - - + {"type",(getter)Key_getType, (setter)NULL, + "Key Type",NULL}, + {"value",(getter)Key_getValue, (setter)NULL, + "Key value",NULL}, + {"ipo",(getter)Key_getIpo, (setter)Key_setIpo, + "Ipo linked to key",NULL}, + {"blocks",(getter)Key_getBlocks, (setter)NULL, + "Blocks linked to the key",NULL}, + {"relative",(getter)Key_getRelative, (setter)Key_setRelative, + "Non-zero is key is relative",NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; static PyObject *KeyBlock_getData( PyObject * self ); - +static PyObject *KeyBlock_getCurval( BPy_KeyBlock * self ); static PyObject *KeyBlock_getName( BPy_KeyBlock * self ); static PyObject *KeyBlock_getPos( BPy_KeyBlock * self ); static PyObject *KeyBlock_getSlidermin( BPy_KeyBlock * self ); @@ -107,6 +111,8 @@ static struct PyMethodDef KeyBlock_methods[] = { }; static PyGetSetDef BPy_KeyBlock_getsetters[] = { + {"curval",(getter)KeyBlock_getCurval, (setter)NULL, + "Current value of the corresponding IpoCurve",NULL}, {"name",(getter)KeyBlock_getName, (setter)KeyBlock_setName, "Keyblock Name",NULL}, {"pos",(getter)KeyBlock_getPos, (setter)NULL, @@ -362,13 +368,32 @@ static int Key_setIpo( PyObject * self, PyObject * value ) return 0; } -static PyObject *Key_getType( PyObject * self ) +static PyObject *Key_getRelative( BPy_Key * self ) +{ + if( self->key->type == KEY_RELATIVE ) + return EXPP_incr_ret(Py_True); + else + return EXPP_incr_ret(Py_False); +} + +static int Key_setRelative( BPy_Key * self, PyObject * value ) +{ + if( PyObject_IsTrue( value ) ) + self->key->type = KEY_RELATIVE; + else + self->key->type = KEY_NORMAL; + allqueue(REDRAWIPO, 0); + allspace(REMAKEIPO, 0); + + return 0; +} + +static PyObject *Key_getType( BPy_Key * self ) { - BPy_Key *k = ( BPy_Key * ) self; int idcode; int type = -1; - idcode = GS( k->key->from->name ); + idcode = GS( self->key->from->name ); switch( idcode ) { case ID_ME: @@ -437,55 +462,51 @@ PyObject *KeyBlock_CreatePyObject( KeyBlock * kb, Key *parentKey ) return ( PyObject * ) keyBlock; } +static PyObject *KeyBlock_getCurval( BPy_KeyBlock * self ) { + return PyFloat_FromDouble( self->keyblock->curval ); +} + static PyObject *KeyBlock_getName( BPy_KeyBlock * self ) { - BPy_KeyBlock *kb = ( BPy_KeyBlock * ) self; - PyObject *name = Py_BuildValue( "s", kb->keyblock->name); + PyObject *name = Py_BuildValue( "s", self->keyblock->name); return name; } static PyObject *KeyBlock_getPos( BPy_KeyBlock * self ){ - BPy_KeyBlock *kb = ( BPy_KeyBlock * ) self; - return PyFloat_FromDouble( kb->keyblock->pos ); + return PyFloat_FromDouble( self->keyblock->pos ); } static PyObject *KeyBlock_getSlidermin( BPy_KeyBlock * self ){ - BPy_KeyBlock *kb = ( BPy_KeyBlock * ) self; - return PyFloat_FromDouble( kb->keyblock->slidermin ); + return PyFloat_FromDouble( self->keyblock->slidermin ); } static PyObject *KeyBlock_getSlidermax( BPy_KeyBlock * self ){ - BPy_KeyBlock *kb = ( BPy_KeyBlock * ) self; - return PyFloat_FromDouble( kb->keyblock->slidermax ); + return PyFloat_FromDouble( self->keyblock->slidermax ); } static PyObject *KeyBlock_getVgroup( BPy_KeyBlock * self ){ - BPy_KeyBlock *kb = ( BPy_KeyBlock * ) self; - PyObject *name = Py_BuildValue( "s", kb->keyblock->vgroup); - return name; + return Py_BuildValue( "s", self->keyblock->vgroup); } static int KeyBlock_setName( BPy_KeyBlock * self, PyObject * args ){ char* text = NULL; - BPy_KeyBlock *kb = ( BPy_KeyBlock * ) self; - + text = PyString_AsString ( args ); if( !text ) return EXPP_ReturnIntError( PyExc_TypeError, "expected string argument" ); - strncpy( kb->keyblock->name, text , 32); + strncpy( self->keyblock->name, text , 32); return 0; } static int KeyBlock_setVgroup( BPy_KeyBlock * self, PyObject * args ){ char* text = NULL; - BPy_KeyBlock *kb = ( BPy_KeyBlock * ) self; - + text = PyString_AsString ( args ); if( !text ) return EXPP_ReturnIntError( PyExc_TypeError, "expected string argument" ); - strncpy( kb->keyblock->vgroup, text , 32); + strncpy( self->keyblock->vgroup, text , 32); return 0; } @@ -635,7 +656,8 @@ static PyObject *M_Key_Get( PyObject * self, PyObject * args ) "expected string argument (or nothing)" ) ); if ( name ) { - for (key_iter = G.main->key.first; key_iter; key_iter=key_iter->id.next) { + for (key_iter = G.main->key.first; key_iter; + key_iter=key_iter->id.next) { if (strcmp ( key_iter->id.name + 2, name ) == 0 ) { return Key_CreatePyObject( key_iter ); } @@ -643,17 +665,16 @@ static PyObject *M_Key_Get( PyObject * self, PyObject * args ) PyOS_snprintf( error_msg, sizeof( error_msg ), "Key \"%s\" not found", name ); - return ( EXPP_ReturnPyObjError ( PyExc_NameError, error_msg ) ); + return EXPP_ReturnPyObjError ( PyExc_NameError, error_msg ); - } - - else { + } else { PyObject *keylist; keylist = PyList_New( BLI_countlist( &( G.main->key ) ) ); - for ( i=0, key_iter = G.main->key.first; key_iter; key_iter=key_iter->id.next, i++ ) { + for ( i=0, key_iter = G.main->key.first; key_iter; + key_iter=key_iter->id.next, i++ ) { PyList_SetItem(keylist, i, Key_CreatePyObject(key_iter)); } return keylist; @@ -665,32 +686,36 @@ struct PyMethodDef M_Key_methods[] = { {NULL, NULL, 0, NULL} }; +static PyObject *M_Key_TypesDict( void ) +{ + PyObject *T = PyConstant_New( ); + + if( T ) { + BPy_constant *d = ( BPy_constant * ) T; + + PyConstant_Insert( d, "MESH", PyInt_FromLong( KEY_TYPE_MESH ) ); + PyConstant_Insert( d, "CURVE", PyInt_FromLong( KEY_TYPE_CURVE ) ); + PyConstant_Insert( d, "LATTICE", PyInt_FromLong( KEY_TYPE_LATTICE ) ); + } + + return T; +} + PyObject *Key_Init( void ) { - PyObject *submodule, *KeyTypes; + PyObject *submodule; + PyObject *Types = NULL; - if( PyType_Ready( &Key_Type ) < 0) + if( PyType_Ready( &Key_Type ) < 0 || PyType_Ready( &KeyBlock_Type ) < 0 ) return NULL; - Key_Type.ob_type = &PyType_Type; - PyType_Ready( &KeyBlock_Type ); - submodule = Py_InitModule3( "Blender.Key", M_Key_methods, "Key module" ); - KeyTypes = PyConstant_New( ); - - PyConstant_Insert(( BPy_constant * ) KeyTypes, "MESH", PyInt_FromLong(KEY_TYPE_MESH)); - PyConstant_Insert(( BPy_constant * ) KeyTypes, "CURVE", PyInt_FromLong(KEY_TYPE_CURVE)); - PyConstant_Insert(( BPy_constant * ) KeyTypes, "LATTICE", PyInt_FromLong(KEY_TYPE_LATTICE)); - - PyModule_AddObject( submodule, "Types", KeyTypes); + Types = M_Key_TypesDict( ); + if( Types ) + PyModule_AddObject( submodule, "Types", Types ); - /* - PyModule_AddIntConstant( submodule, "TYPE_MESH", KEY_TYPE_MESH ); - PyModule_AddIntConstant( submodule, "TYPE_CURVE", KEY_TYPE_CURVE ); - PyModule_AddIntConstant( submodule, "TYPE_LATTICE", KEY_TYPE_LATTICE ); - */ return submodule; } diff --git a/source/blender/python/api2_2x/Mesh.c b/source/blender/python/api2_2x/Mesh.c index 0bb882a046c..91b86947a83 100644 --- a/source/blender/python/api2_2x/Mesh.c +++ b/source/blender/python/api2_2x/Mesh.c @@ -82,8 +82,6 @@ #include "constant.h" #include "gen_utils.h" -#define MESH_TOOLS /* add access to mesh tools */ - /* EXPP Mesh defines */ #define MESH_SMOOTHRESH 30 @@ -126,6 +124,7 @@ typedef struct SrchEdges { typedef struct SrchFaces { unsigned int v[4]; /* indices for verts */ + unsigned int index; /* index in original param list of this edge */ unsigned char order; /* order of original verts, bitpacked */ } SrchFaces; @@ -156,6 +155,22 @@ int medge_comp( const void *va, const void *vb ) } /* + * compare edges by insert list indices + */ + +int medge_index_comp( const void *va, const void *vb ) +{ + const SrchEdges *a = (SrchEdges *)va; + const SrchEdges *b = (SrchEdges *)vb; + + /* compare list indices for differences */ + + if (a->index < b->index) return -1; + else return (a->index > b->index); +} + + +/* * compare faces by vertex indices */ @@ -191,6 +206,23 @@ int mface_comp( const void *va, const void *vb ) } /* + * compare faces by insert list indices + */ + +int mface_index_comp( const void *va, const void *vb ) +{ + const SrchFaces *a = va; + const SrchFaces *b = vb; + + /* compare indices, first to last, for differences */ + if( a->index < b->index ) + return -1; + if( a->index > b->index ) + return 1; + return 0; +} + +/* * compare edges by vertex indices */ @@ -1386,7 +1418,7 @@ static PyObject *MVertSeq_item( BPy_MVertSeq * self, int i ) "array index out of range" ); return MVert_CreatePyObject( self->mesh, i ); -}; +} /* * retrieve a slice of the vertex list (as a Python list) @@ -1453,7 +1485,7 @@ static int MVertSeq_assign_item( BPy_MVertSeq * self, int i, memcpy( dst, src, sizeof(MVert) ); // mesh_update( self->mesh ); return 0; -}; +} static int MVertSeq_assign_slice( BPy_MVertSeq *self, int low, int high, PyObject *args ) @@ -1566,39 +1598,42 @@ static PyObject *MVertSeq_extend( BPy_MVertSeq * self, PyObject *args ) Mesh *mesh = self->mesh; /* make sure we get a sequence of tuples of something */ - switch( PySequence_Size ( args ) ) { + switch( PySequence_Size( args ) ) { case 1: /* better be a list or a tuple */ tmp = PyTuple_GET_ITEM( args, 0 ); if( !VectorObject_Check ( tmp ) ) { if( !PySequence_Check ( tmp ) ) return EXPP_ReturnPyObjError( PyExc_TypeError, - "expected a sequence of tuple triplets" ); + "expected a sequence of sequence triplets" ); args = tmp; } Py_INCREF( args ); /* so we can safely DECREF later */ break; - case 3: /* take any three args and put into a tuple */ + case 3: tmp = PyTuple_GET_ITEM( args, 0 ); - if( PyTuple_Check( tmp ) ) { - Py_INCREF( args ); - break; - } + /* if first item is not a number, it's wrong */ + if( !PyNumber_Check( tmp ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected a sequence of sequence triplets" ); + + /* otherwise, put into a new tuple */ args = Py_BuildValue( "((OOO))", tmp, PyTuple_GET_ITEM( args, 1 ), PyTuple_GET_ITEM( args, 2 ) ); if( !args ) return EXPP_ReturnPyObjError( PyExc_RuntimeError, "Py_BuildValue() failed" ); break; + default: /* anything else is definitely wrong */ return EXPP_ReturnPyObjError( PyExc_TypeError, - "expected a sequence of tuple triplets" ); + "expected a sequence of sequence triplets" ); } + /* if no verts given, return quietly */ len = PySequence_Size( args ); if( len == 0 ) { Py_DECREF ( args ); - return EXPP_ReturnPyObjError( PyExc_ValueError, - "expected at least one tuple" ); + Py_RETURN_NONE; } newlen = mesh->totvert + len; @@ -1620,18 +1655,19 @@ static PyObject *MVertSeq_extend( BPy_MVertSeq * self, PyObject *args ) } for( j = 0; j < 3; ++j ) co[j] = ((VectorObject *)tmp)->vec[j]; - } else if( PyTuple_Check( tmp ) ) { + } else if( PySequence_Check( tmp ) ) { int ok=1; PyObject *flt; - if( PyTuple_Size( tmp ) != 3 ) + if( PySequence_Size( tmp ) != 3 ) ok = 0; else for( j = 0; ok && j < 3; ++j ) { - flt = PyTuple_GET_ITEM( tmp, j ); + flt = PySequence_ITEM( tmp, j ); if( !PyNumber_Check ( flt ) ) ok = 0; else co[j] = (float)PyFloat_AsDouble( flt ); + Py_DECREF( flt ); } if( !ok ) { @@ -1639,9 +1675,16 @@ static PyObject *MVertSeq_extend( BPy_MVertSeq * self, PyObject *args ) Py_DECREF ( args ); Py_DECREF ( tmp ); return EXPP_ReturnPyObjError( PyExc_ValueError, - "expected tuple triplet of floats" ); + "expected sequence triplet of floats" ); } + } else { + MEM_freeN( newvert ); + Py_DECREF ( args ); + Py_DECREF ( tmp ); + return EXPP_ReturnPyObjError( PyExc_ValueError, + "expected sequence triplet of floats" ); } + Py_DECREF ( tmp ); /* add the coordinate to the new list */ @@ -1714,7 +1757,7 @@ static PyObject *MVertSeq_extend( BPy_MVertSeq * self, PyObject *args ) mesh_update( mesh ); Py_DECREF ( args ); - return EXPP_incr_ret( Py_None ); + Py_RETURN_NONE; } static PyObject *MVertSeq_delete( BPy_MVertSeq * self, PyObject *args ) @@ -1725,15 +1768,20 @@ static PyObject *MVertSeq_delete( BPy_MVertSeq * self, PyObject *args ) Mesh *mesh = self->mesh; MFace *tmpface; - Py_INCREF( args ); /* so we can safely DECREF later */ - - /* accept a sequence (lists or tuples) also */ + /* + * if input tuple contains a single sequence, use it as input instead; + * otherwise use the sequence as-is and check later that it contains + * one or more integers or MVerts + */ if( PySequence_Size( args ) == 1 ) { PyObject *tmp = PyTuple_GET_ITEM( args, 0 ); - if( PySequence_Check ( tmp ) ) { - Py_DECREF( args ); /* release previous reference */ - args = tmp; /* PyTuple_GET_ITEM returns new ref */ - } + if( PySequence_Check( tmp ) ) + args = tmp; + } + + /* if sequence is empty, do nothing */ + if( PySequence_Size( args ) == 0 ) { + Py_RETURN_NONE; } /* allocate vertex lookup table */ @@ -1747,18 +1795,15 @@ static PyObject *MVertSeq_delete( BPy_MVertSeq * self, PyObject *args ) if( BPy_MVert_Check( tmp ) ) { if( (void *)self->mesh != ((BPy_MVert*)tmp)->data ) { MEM_freeN( vert_table ); - Py_DECREF( args ); Py_DECREF( tmp ); return EXPP_ReturnPyObjError( PyExc_ValueError, "MVert belongs to a different mesh" ); } index = ((BPy_MVert*)tmp)->index; - } - else if( PyInt_CheckExact( tmp ) ) + } else if( PyInt_CheckExact( tmp ) ) { index = PyInt_AsLong ( tmp ); - else { + } else { MEM_freeN( vert_table ); - Py_DECREF( args ); Py_DECREF( tmp ); return EXPP_ReturnPyObjError( PyExc_TypeError, "expected a sequence of ints or MVerts" ); @@ -1766,8 +1811,7 @@ static PyObject *MVertSeq_delete( BPy_MVertSeq * self, PyObject *args ) Py_DECREF( tmp ); if( index < 0 || index >= mesh->totvert ) { MEM_freeN( vert_table ); - Py_DECREF( args ); - return EXPP_ReturnPyObjError( PyExc_ValueError, + return EXPP_ReturnPyObjError( PyExc_IndexError, "array index out of range" ); } vert_table[index] = UINT_MAX; @@ -1802,8 +1846,7 @@ static PyObject *MVertSeq_delete( BPy_MVertSeq * self, PyObject *args ) /* clean up and exit */ MEM_freeN( vert_table ); mesh_update ( mesh ); - Py_DECREF( args ); - return EXPP_incr_ret( Py_None ); + Py_RETURN_NONE; } static PyObject *MVertSeq_selected( BPy_MVertSeq * self ) @@ -2413,40 +2456,52 @@ static PyObject *MEdgeSeq_extend( BPy_MEdgeSeq * self, PyObject *args ) MEdge *tmpedge; Mesh *mesh = self->mesh; - /* make sure we get a sequence of tuples of something */ - - switch( PySequence_Size ( args ) ) { - case 1: /* better be a list or a tuple */ - args = PyTuple_GET_ITEM( args, 0 ); - if( !PySequence_Check ( args ) ) + /* make sure we get a tuple of sequences of something */ + switch( PySequence_Size( args ) ) { + case 1: + /* if a sequence... */ + tmp = PyTuple_GET_ITEM( args, 0 ); + if( PySequence_Check( tmp ) ) { + /* if another sequence, use it */ + PyObject *tmp2 = PySequence_ITEM( tmp, 0 ); + if( PySequence_Check( tmp2 ) ) + args = tmp; + Py_INCREF( args ); + Py_DECREF( tmp2 ); + } else return EXPP_ReturnPyObjError( PyExc_TypeError, - "expected a sequence of tuple pairs" ); - Py_INCREF( args ); /* so we can safely DECREF later */ + "expected a sequence of sequence pairs" ); break; case 2: case 3: case 4: /* two to four args may be individual verts */ tmp = PyTuple_GET_ITEM( args, 0 ); - if( PyTuple_Check( tmp ) ) {/* maybe just tuples, so use args as-is */ + /* + * if first item isn't a sequence, then assume it's a bunch of MVerts + * and wrap inside a tuple + */ + if( !PySequence_Check( tmp ) ) { + args = Py_BuildValue( "(O)", args ); + if( !args ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Py_BuildValue() failed" ); + /* + * otherwise, assume it already a bunch of sequences so use as-is + */ + } else { Py_INCREF( args ); /* so we can safely DECREF later */ - break; } - args = Py_BuildValue( "(O)", args ); - if( !args ) - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Py_BuildValue() failed" ); break; default: /* anything else is definitely wrong */ return EXPP_ReturnPyObjError( PyExc_TypeError, - "expected a sequence of tuple pairs" ); + "expected a sequence of sequence pairs" ); } /* make sure there is something to add */ len = PySequence_Size( args ); if( len == 0 ) { - Py_DECREF( args ); - return EXPP_ReturnPyObjError( PyExc_ValueError, - "expected at least one tuple" ); + Py_DECREF ( args ); + Py_RETURN_NONE; } /* verify the param list and get a total count of number of edges */ @@ -2455,21 +2510,21 @@ static PyObject *MEdgeSeq_extend( BPy_MEdgeSeq * self, PyObject *args ) tmp = PySequence_GetItem( args, i ); /* not a tuple of MVerts... error */ - if( !PyTuple_Check( tmp ) || + if( !PySequence_Check( tmp ) || EXPP_check_sequence_consistency( tmp, &MVert_Type ) != 1 ) { Py_DECREF( tmp ); Py_DECREF( args ); return EXPP_ReturnPyObjError( PyExc_ValueError, - "expected sequence of MVert tuples" ); + "expected sequence of MVert sequences" ); } /* not the right number of MVerts... error */ - nverts = PyTuple_Size( tmp ); + nverts = PySequence_Size( tmp ); if( nverts < 2 || nverts > 4 ) { Py_DECREF( tmp ); Py_DECREF( args ); return EXPP_ReturnPyObjError( PyExc_ValueError, - "expected 2 to 4 MVerts per tuple" ); + "expected 2 to 4 MVerts per sequence" ); } Py_DECREF( tmp ); @@ -2486,14 +2541,15 @@ static PyObject *MEdgeSeq_extend( BPy_MEdgeSeq * self, PyObject *args ) /* scan the input list and build the new edge pair list */ len = PySequence_Size( args ); tmppair = newpair; + new_edge_count = 0; for( i = 0; i < len; ++i ) { int edge_count; tmp = PySequence_GetItem( args, i ); - nverts = PyTuple_Size( tmp ); + nverts = PySequence_Size( tmp ); - /* get copies of vertices */ + /* get new references for the vertices */ for(j = 0; j < nverts; ++j ) - e[j] = (BPy_MVert *)PyTuple_GET_ITEM( tmp, j ); + e[j] = (BPy_MVert *)PySequence_GetItem( tmp, j ); Py_DECREF( tmp ); if( nverts == 2 ) @@ -2518,12 +2574,20 @@ static PyObject *MEdgeSeq_extend( BPy_MEdgeSeq * self, PyObject *args ) tmppair->swap = 1; } else { MEM_freeN( newpair ); + for(j = 0; j < nverts; ++j ) + Py_DECREF( e[j] ); Py_DECREF( args ); return EXPP_ReturnPyObjError( PyExc_ValueError, "tuple contains duplicate vertices" ); } + tmppair->index = new_edge_count; + ++new_edge_count; tmppair++; } + + /* free the new references */ + for( j = 0; j < nverts; ++j ) + Py_DECREF( e[j] ); } /* sort the new edge pairs */ @@ -2605,6 +2669,9 @@ static PyObject *MEdgeSeq_extend( BPy_MEdgeSeq * self, PyObject *args ) } mesh->medge = tmpedge; /* point to the new edge list */ + /* resort edges into original order */ + qsort( newpair, new_edge_count, sizeof(SrchEdges), medge_index_comp ); + /* point to the first edge we're going to add */ tmpedge = &mesh->medge[mesh->totedge]; tmppair = newpair; @@ -2632,7 +2699,7 @@ static PyObject *MEdgeSeq_extend( BPy_MEdgeSeq * self, PyObject *args ) mesh_update( mesh ); MEM_freeN( newpair ); Py_DECREF ( args ); - return EXPP_incr_ret( Py_None ); + Py_RETURN_NONE; } static PyObject *MEdgeSeq_delete( BPy_MEdgeSeq * self, PyObject *args ) @@ -2644,19 +2711,23 @@ static PyObject *MEdgeSeq_delete( BPy_MEdgeSeq * self, PyObject *args ) int i, len; int face_count, edge_count, vert_count; - Py_INCREF( args ); /* so we can safely DECREF later */ - - /* accept a sequence (lists or tuples) also */ + /* + * if input tuple contains a single sequence, use it as input instead; + * otherwise use the sequence as-is and check later that it contains + * one or more integers or MVerts + */ if( PySequence_Size( args ) == 1 ) { PyObject *tmp = PyTuple_GET_ITEM( args, 0 ); - if( PySequence_Check ( tmp ) ) { - Py_DECREF( args ); /* release previous reference */ - args = tmp; /* PyTuple_GET_ITEM returns new ref */ - } + if( PySequence_Check( tmp ) ) + args = tmp; } - /* see how many args we need to parse */ + /* if sequence is empty, do nothing */ len = PySequence_Size( args ); + if( len == 0 ) { + Py_RETURN_NONE; + } + edge_table = (unsigned int *)MEM_callocN( len*sizeof( unsigned int ), "edge_table" ); @@ -2670,7 +2741,6 @@ static PyObject *MEdgeSeq_delete( BPy_MEdgeSeq * self, PyObject *args ) else { MEM_freeN( edge_table ); Py_DECREF( tmp ); - Py_DECREF( args ); return EXPP_ReturnPyObjError( PyExc_TypeError, "expected a sequence of ints or MEdges" ); } @@ -2679,7 +2749,6 @@ static PyObject *MEdgeSeq_delete( BPy_MEdgeSeq * self, PyObject *args ) /* if index out-of-range, throw exception */ if( edge_table[i] >= (unsigned int)mesh->totedge ) { MEM_freeN( edge_table ); - Py_DECREF( args ); return EXPP_ReturnPyObjError( PyExc_ValueError, "array index out of range" ); } @@ -2773,9 +2842,8 @@ static PyObject *MEdgeSeq_delete( BPy_MEdgeSeq * self, PyObject *args ) MEM_freeN( del_table ); MEM_freeN( vert_table ); MEM_freeN( edge_table ); - Py_DECREF( args ); mesh_update ( mesh ); - return EXPP_incr_ret( Py_None ); + Py_RETURN_NONE; } static PyObject *MEdgeSeq_selected( BPy_MEdgeSeq * self ) @@ -3388,21 +3456,22 @@ static int MFace_setUV( BPy_MFace * self, PyObject * value ) if( !MFace_get_pointer( self ) ) return -1; - if( !PyTuple_Check( value ) || + if( !PySequence_Check( value ) || EXPP_check_sequence_consistency( value, &vector_Type ) != 1 ) return EXPP_ReturnIntError( PyExc_TypeError, - "expected tuple of vectors" ); + "expected sequence of vectors" ); length = self->mesh->mface[self->index].v4 ? 4 : 3; - if( length != PyTuple_Size( value ) ) + if( length != PySequence_Size( value ) ) return EXPP_ReturnIntError( PyExc_TypeError, - "size of vertex and UV lists differ" ); + "size of vertex and UV sequences differ" ); face = &self->mesh->tface[self->index]; for( i=0; i<length; ++i ) { - VectorObject *vector = (VectorObject *)PyTuple_GET_ITEM( value, i ); + VectorObject *vector = (VectorObject *)PySequence_ITEM( value, i ); face->uv[i][0] = vector->vec[0]; face->uv[i][1] = vector->vec[1]; + Py_DECREF( vector ); } return 0; } @@ -3531,6 +3600,54 @@ static PyObject *MFace_getCol( BPy_MFace * self ) return attr; } +/* + * set a face's vertex colors + */ + +static int MFace_setCol( BPy_MFace * self, PyObject *value ) +{ + int length, i; + MCol * mcol; + + /* if there's no mesh color vectors or texture faces, nothing to do */ + + if( !self->mesh->mcol && !self->mesh->tface ) + return EXPP_ReturnIntError( PyExc_ValueError, + "face has no vertex colors" ); + + if( !MFace_get_pointer( self ) ) + return -1; + + if( self->mesh->tface ) + mcol = (MCol *) self->mesh->tface[self->index].col; + else + mcol = &self->mesh->mcol[self->index*4]; + + length = self->mesh->mface[self->index].v4 ? 4 : 3; + + if( !PyList_Check( value ) && !PyTuple_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a sequence of MCols" ); + + if( EXPP_check_sequence_consistency( value, &MCol_Type ) != 1 ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected a sequence of MCols" ); + + if( PySequence_Size( value ) != length ) + return EXPP_ReturnIntError( PyExc_ValueError, + "incorrect number of colors for this face" ); + + for( i=0; i<length; ++i ) { + BPy_MCol *obj = (BPy_MCol *)PySequence_ITEM( value, i ); + mcol[i].r = obj->color->r; + mcol[i].g = obj->color->g; + mcol[i].b = obj->color->b; + mcol[i].a = obj->color->a; + Py_DECREF( obj ); + } + return 0; +} + /************************************************************************ * * Python MFace_Type attributes get/set structure @@ -3575,7 +3692,7 @@ static PyGetSetDef BPy_MFace_getseters[] = { /* attributes for texture faces (mostly, I think) */ {"col", - (getter)MFace_getCol, (setter)NULL, + (getter)MFace_getCol, (setter)MFace_setCol, "face's vertex colors", NULL}, {"flag", @@ -3888,43 +4005,56 @@ static PyObject *MFaceSeq_extend( BPy_MEdgeSeq * self, PyObject *args ) tmp = MEdgeSeq_extend( self, args ); if( !tmp ) return NULL; - + Py_DECREF( tmp ); - /* make sure we get a sequence of tuples of something */ + /* make sure we get a tuple of sequences of something */ - switch( PySequence_Size ( args ) ) { - case 1: /* better be a list or a tuple */ - args = PyTuple_GET_ITEM( args, 0 ); - if( !PySequence_Check ( args ) ) + switch( PySequence_Size( args ) ) { + case 1: /* better be a sequence or a tuple */ + /* if a sequence... */ + tmp = PyTuple_GET_ITEM( args, 0 ); + if( PySequence_Check( tmp ) ) { + /* if another sequence, use it */ + PyObject *tmp2 = PySequence_ITEM( tmp, 0 ); + if( PySequence_Check( tmp2 ) ) + args = tmp; + Py_INCREF( args ); + Py_DECREF( tmp2 ); + } else return EXPP_ReturnPyObjError( PyExc_TypeError, - "expected a sequence of tuple pairs" ); - Py_INCREF( args ); /* so we can safely DECREF later */ + "expected a sequence of sequence pairs" ); break; case 2: case 3: case 4: /* two to four args may be individual verts */ tmp = PyTuple_GET_ITEM( args, 0 ); - if( PyTuple_Check( tmp ) ) {/* maybe just tuples, so use args as-is */ + /* + * if first item isn't a sequence, then assume it's a bunch of MVerts + * and wrap inside a tuple + */ + if( !PySequence_Check( tmp ) ) { + args = Py_BuildValue( "(O)", args ); + if( !args ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "Py_BuildValue() failed" ); + /* + * otherwise, assume it already a bunch of sequences so use as-is + */ + } else { Py_INCREF( args ); /* so we can safely DECREF later */ - break; } - args = Py_BuildValue( "(O)", args ); - if( !args ) - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Py_BuildValue() failed" ); break; default: /* anything else is definitely wrong */ return EXPP_ReturnPyObjError( PyExc_TypeError, - "expected a sequence of tuple pairs" ); + "expected a sequence of sequence pairs" ); } - /* make sure there is something to add */ + /* if nothing to add, just exit */ len = PySequence_Size( args ); if( len == 0 ) { Py_DECREF( args ); - return EXPP_ReturnPyObjError( PyExc_ValueError, - "expected at least one tuple" ); + Py_RETURN_NONE; } /* verify the param list and get a total count of number of edges */ @@ -3933,19 +4063,19 @@ static PyObject *MFaceSeq_extend( BPy_MEdgeSeq * self, PyObject *args ) tmp = PySequence_GetItem( args, i ); /* not a tuple of MVerts... error */ - if( !PyTuple_Check( tmp ) || + if( !PySequence_Check( tmp ) || EXPP_check_sequence_consistency( tmp, &MVert_Type ) != 1 ) { Py_DECREF( args ); return EXPP_ReturnPyObjError( PyExc_ValueError, - "expected sequence of MVert tuples" ); + "expected sequence of MVert sequences" ); } /* not the right number of MVerts... error */ - nverts = PyTuple_Size( tmp ); + nverts = PySequence_Size( tmp ); if( nverts < 2 || nverts > 4 ) { Py_DECREF( args ); return EXPP_ReturnPyObjError( PyExc_ValueError, - "expected 2 to 4 MVerts per tuple" ); + "expected 2 to 4 MVerts per sequence" ); } if( nverts != 2 ) /* new faces cannot have only 2 verts */ @@ -3965,7 +4095,7 @@ static PyObject *MFaceSeq_extend( BPy_MEdgeSeq * self, PyObject *args ) unsigned int vert[4]={0,0,0,0}; unsigned char order[4]={0,1,2,3}; tmp = PySequence_GetItem( args, i ); - nverts = PyTuple_Size( tmp ); + nverts = PySequence_Size( tmp ); if( nverts == 2 ) /* again, ignore 2-vert tuples */ break; @@ -3975,15 +4105,19 @@ static PyObject *MFaceSeq_extend( BPy_MEdgeSeq * self, PyObject *args ) * vertices are not index 0 */ - e = (BPy_MVert *)PyTuple_GET_ITEM( tmp, 0 ); + e = (BPy_MVert *)PySequence_ITEM( tmp, 0 ); tmpface.v1 = e->index; - e = (BPy_MVert *)PyTuple_GET_ITEM( tmp, 1 ); + Py_DECREF( e ); + e = (BPy_MVert *)PySequence_ITEM( tmp, 1 ); tmpface.v2 = e->index; - e = (BPy_MVert *)PyTuple_GET_ITEM( tmp, 2 ); + Py_DECREF( e ); + e = (BPy_MVert *)PySequence_ITEM( tmp, 2 ); tmpface.v3 = e->index; + Py_DECREF( e ); if( nverts == 4 ) { - e = (BPy_MVert *)PyTuple_GET_ITEM( tmp, 3 ); + e = (BPy_MVert *)PySequence_ITEM( tmp, 3 ); tmpface.v4 = e->index; + Py_DECREF( e ); } Py_DECREF( tmp ); @@ -4016,6 +4150,7 @@ static PyObject *MFaceSeq_extend( BPy_MEdgeSeq * self, PyObject *args ) } tmppair->v[j] = vert[j]; } + tmppair->index = i; /* pack order into a byte */ tmppair->order = order[0]|(order[1]<<2)|(order[2]<<4)|(order[3]<<6); @@ -4111,6 +4246,9 @@ static PyObject *MFaceSeq_extend( BPy_MEdgeSeq * self, PyObject *args ) mesh->tface = tmptface; } + /* sort the faces back into their original input list order */ + qsort( newpair, new_face_count, sizeof(SrchFaces), mface_index_comp ); + /* allocate new face list */ tmpface = MEM_callocN(totface*sizeof(MFace), "Mesh_addFaces"); @@ -4157,7 +4295,7 @@ static PyObject *MFaceSeq_extend( BPy_MEdgeSeq * self, PyObject *args ) mesh_update( mesh ); Py_DECREF ( args ); MEM_freeN( newpair ); - return EXPP_incr_ret( Py_None ); + Py_RETURN_NONE; } struct fourEdges @@ -4196,7 +4334,7 @@ static PyObject *MFaceSeq_delete( BPy_MFaceSeq * self, PyObject *args ) if( BPy_MFace_Check( tmp ) ) face_table[i] = ((BPy_MFace *)tmp)->index; else if( PyInt_CheckExact( tmp ) ) - face_table[i] = PyInt_AsLong ( tmp ); + face_table[i] = PyInt_AsLong( tmp ); else { MEM_freeN( face_table ); Py_DECREF( tmp ); @@ -4276,7 +4414,7 @@ static PyObject *MFaceSeq_delete( BPy_MFaceSeq * self, PyObject *args ) verts[0] = tmpface->v1; verts[1] = tmpface->v2; verts[2] = tmpface->v3; - if(len == 4) + if( len == 4 ) verts[3] = tmpface->v4; for( j = 0; j < len; ++j ) { k = (j+1) % len; @@ -5373,7 +5511,53 @@ static PyObject *Mesh_getVertGroupNames( BPy_Mesh * self ) return list; } -#ifdef MESH_TOOLS +static PyObject *Mesh_getVertexInfluences( BPy_Mesh * self, PyObject * args ) +{ + int index; + PyObject *influence_list = NULL; + Object *object = self->object; + Mesh *me = self->mesh; + + /* Get a reference to the mesh object wrapped in here. */ + if( !object ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This mesh must be linked to an object" ); + + /* Parse the parameters: only on integer (vertex index) */ + if( !PyArg_ParseTuple( args, "i", &index ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected int argument (index of the vertex)" ); + + /* check for valid index */ + if( index < 0 || index >= me->totvert ) + return EXPP_ReturnPyObjError( PyExc_IndexError, + "vertex index out of range" ); + + influence_list = PyList_New( 0 ); + + /* Proceed only if we have vertex deformation information */ + if( me->dvert ) { + int i; + MDeformWeight *sweight = NULL; + + /* Number of bones influencing the vertex */ + int totinfluences = me->dvert[index].totweight; + + /* Get the reference of the first weight structure */ + sweight = me->dvert[index].dw; + + /* Build the list only with weights and names of the influent bones */ + for( i = 0; i < totinfluences; i++, sweight++ ) { + bDeformGroup *defgroup = BLI_findlink( &object->defbase, + sweight->def_nr ); + if( defgroup ) + PyList_Append( influence_list, Py_BuildValue( "[sf]", + defgroup->name, sweight->weight ) ); + } + } + + return influence_list; +} static PyObject *Mesh_Tools( BPy_Mesh * self, int type, void **args ) { @@ -5575,8 +5759,6 @@ static PyObject *Mesh_fill( BPy_Mesh * self ) return Mesh_Tools( self, MESH_TOOL_FILL, NULL ); } -#endif - static struct PyMethodDef BPy_Mesh_methods[] = { {"calcNormals", (PyCFunction)Mesh_calcNormals, METH_NOARGS, "all recalculate vertex normals"}, @@ -5604,10 +5786,10 @@ static struct PyMethodDef BPy_Mesh_methods[] = { "Rename an existing vertex group"}, {"getVertGroupNames", (PyCFunction)Mesh_getVertGroupNames, METH_NOARGS, "Get names of vertex groups"}, + {"getVertexInfluences", (PyCFunction)Mesh_getVertexInfluences, METH_VARARGS, + "Get list of the influences of bones for a given mesh vertex"}, - - -#ifdef MESH_TOOLS + /* Mesh tools */ {"smooth", (PyCFunction)Mesh_smooth, METH_NOARGS, "Flattens angle of selected faces (experimental)"}, {"flipNormals", (PyCFunction)Mesh_flipNormals, METH_NOARGS, @@ -5626,7 +5808,6 @@ static struct PyMethodDef BPy_Mesh_methods[] = { "Removes duplicates from selected vertices (experimental)"}, {"recalcNormals", (PyCFunction)Mesh_recalcNormals, METH_VARARGS, "Recalculates inside or outside normals (experimental)"}, -#endif {NULL, NULL, 0, NULL} }; @@ -5906,8 +6087,12 @@ static int Mesh_setFlag( BPy_Mesh * self, PyObject *value, void *type ) MEM_freeN( mesh->tface ); mesh->tface = NULL; } - } else if( !mesh->tface ) + } else if( !mesh->tface ) { + if( !mesh->totface ) + return EXPP_ReturnIntError( PyExc_RuntimeError, + "mesh has no faces" ); make_tfaces( mesh ); + } return 0; case MESH_HASMCOL: if( !param ) { @@ -6098,8 +6283,6 @@ static PyGetSetDef BPy_Mesh_getseters[] = { (getter)Mesh_getMode, (setter)Mesh_setMode, "The mesh's mode bitfield", NULL}, - - {"faceUV", (getter)Mesh_getFlag, (setter)Mesh_setFlag, "UV-mapped textured faces enabled", @@ -6125,11 +6308,6 @@ static PyGetSetDef BPy_Mesh_getseters[] = { }; /*****************************************************************************/ -/* Python Mesh_Type callback function prototypes: */ -/*****************************************************************************/ -static void Mesh_dealloc( BPy_Mesh * object ); - -/*****************************************************************************/ /* Python Mesh_Type structure definition: */ /*****************************************************************************/ PyTypeObject Mesh_Type = { @@ -6329,6 +6507,28 @@ static PyObject *M_Mesh_MVert( PyObject * self, PyObject * args ) return PVert_CreatePyObject( &vert ); } +static PyObject *M_Mesh_Modes( PyObject * self, PyObject * args ) +{ + int modes = 0; + + if( !G.scene ) { + Py_RETURN_NONE; + } + + if( !PyArg_ParseTuple( args, "|i", &modes ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "expected optional int as argument" ); + + if( modes > ( SCE_SELECT_VERTEX | SCE_SELECT_EDGE | SCE_SELECT_FACE ) ) + return EXPP_ReturnPyObjError( PyExc_ValueError, + "value out of range" ); + + if( modes > 0 ) + G.scene->selectmode = modes; + + return PyInt_FromLong( G.scene->selectmode ); +} + static struct PyMethodDef M_Mesh_methods[] = { {"New", (PyCFunction)M_Mesh_New, METH_VARARGS, "Create a new mesh"}, @@ -6336,10 +6536,12 @@ static struct PyMethodDef M_Mesh_methods[] = { "Get a mesh by name"}, {"MVert", (PyCFunction)M_Mesh_MVert, METH_VARARGS, "Create a new MVert"}, + {"Mode", (PyCFunction)M_Mesh_Modes, METH_VARARGS, + "Get/set edit selection mode(s)"}, {NULL, NULL, 0, NULL}, }; -static PyObject *M_Mesh_Modes( void ) +static PyObject *M_Mesh_ModesDict( void ) { PyObject *Modes = PyConstant_New( ); @@ -6444,18 +6646,32 @@ static PyObject *M_Mesh_VertAssignDict( void ) return Vert; } + +static PyObject *M_Mesh_SelectModeDict( void ) +{ + PyObject *Mode = PyConstant_New( ); + if( Mode ) { + BPy_constant *d = ( BPy_constant * ) Mode; + PyConstant_Insert(d, "VERTEX", PyInt_FromLong(SCE_SELECT_VERTEX)); + PyConstant_Insert(d, "EDGE", PyInt_FromLong(SCE_SELECT_EDGE)); + PyConstant_Insert(d, "FACE", PyInt_FromLong(SCE_SELECT_FACE)); + } + return Mode; +} + static char M_Mesh_doc[] = "The Blender.Mesh submodule"; PyObject *Mesh_Init( void ) { PyObject *submodule; - PyObject *Modes = M_Mesh_Modes( ); - PyObject *FaceFlags = M_Mesh_FaceFlagsDict( ); - PyObject *FaceModes = M_Mesh_FaceModesDict( ); - PyObject *FaceTranspModes = M_Mesh_FaceTranspModesDict( ); + PyObject *Modes = M_Mesh_ModesDict( ); + PyObject *FaceFlags = M_Mesh_FaceFlagsDict( ); + PyObject *FaceModes = M_Mesh_FaceModesDict( ); + PyObject *FaceTranspModes = M_Mesh_FaceTranspModesDict( ); PyObject *EdgeFlags = M_Mesh_EdgeFlagsDict( ); - PyObject *AssignModes = M_Mesh_VertAssignDict( ); + PyObject *AssignModes = M_Mesh_VertAssignDict( ); + PyObject *SelectModes = M_Mesh_SelectModeDict( ); if( PyType_Ready( &MCol_Type ) < 0 ) return NULL; @@ -6491,6 +6707,8 @@ PyObject *Mesh_Init( void ) PyModule_AddObject( submodule, "EdgeFlags", EdgeFlags ); if( AssignModes ) PyModule_AddObject( submodule, "AssignModes", AssignModes ); + if( SelectModes ) + PyModule_AddObject( submodule, "SelectModes", SelectModes ); return submodule; diff --git a/source/blender/python/api2_2x/NLA.c b/source/blender/python/api2_2x/NLA.c index c1ed37bfe43..dd891472155 100644 --- a/source/blender/python/api2_2x/NLA.c +++ b/source/blender/python/api2_2x/NLA.c @@ -471,11 +471,15 @@ PyObject *Action_CreatePyObject( struct bAction * act ) { BPy_Action *blen_action; + if(!act) + return EXPP_incr_ret(Py_None); + blen_action = ( BPy_Action * ) PyObject_NEW( BPy_Action, &Action_Type ); - if( blen_action == NULL ) { - return ( NULL ); + if( !blen_action) { + return ( EXPP_ReturnPyObjError + ( PyExc_RuntimeError, "failure to create object!" ) ); } blen_action->action = act; return ( ( PyObject * ) blen_action ); diff --git a/source/blender/python/api2_2x/NLA.h b/source/blender/python/api2_2x/NLA.h index 11b44f2401b..07632124bba 100644 --- a/source/blender/python/api2_2x/NLA.h +++ b/source/blender/python/api2_2x/NLA.h @@ -39,6 +39,8 @@ /** NLA module initialization function. */ PyObject *NLA_Init( void ); +extern PyTypeObject Action_Type; + /** Python BPy_NLA structure definition. */ typedef struct { PyObject_HEAD diff --git a/source/blender/python/api2_2x/NMesh.c b/source/blender/python/api2_2x/NMesh.c index f285557d5ee..293b9a2f3f4 100644 --- a/source/blender/python/api2_2x/NMesh.c +++ b/source/blender/python/api2_2x/NMesh.c @@ -1466,71 +1466,55 @@ static PyObject *NMesh_update( PyObject *self, PyObject *a, PyObject *kwd ) * influences that this vertex receives. * @author Jordi Rovira i Bonet */ + static PyObject *NMesh_getVertexInfluences( PyObject * self, PyObject * args ) { int index; PyObject *influence_list = NULL; - - /* Get a reference to the mesh object wrapped in here. */ + Object *object = ( ( BPy_NMesh * ) self )->object; Mesh *me = ( ( BPy_NMesh * ) self )->mesh; + /* Get a reference to the mesh object wrapped in here. */ if( !me ) return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "unlinked nmesh: call its .update() method first" ); + "unlinked nmesh: call its .update() method first" ); + + if( !object ) + return EXPP_ReturnPyObjError( PyExc_RuntimeError, + "This mesh must be linked to an object" ); /* Parse the parameters: only on integer (vertex index) */ if( !PyArg_ParseTuple( args, "i", &index ) ) return EXPP_ReturnPyObjError( PyExc_TypeError, - "expected int argument (index of the vertex)" ); + "expected int argument (index of the vertex)" ); + + /* check for valid index */ + if( index < 0 || index >= me->totvert ) + return EXPP_ReturnPyObjError( PyExc_IndexError, + "vertex index out of range" ); + + influence_list = PyList_New( 0 ); - /* Proceed only if we have vertex deformation information and index is valid */ + /* Proceed only if we have vertex deformation information */ if( me->dvert ) { - if( ( index >= 0 ) && ( index < me->totvert ) ) { - - int i; - MDeformWeight *sweight = NULL; - - /* Number of bones influencing the vertex */ - int totinfluences = me->dvert[index].totweight; - - /* Build the list only with weights and names of the influent bones */ - /*influence_list = PyList_New(totinfluences); */ - influence_list = PyList_New( 0 ); - - /* Get the reference of the first weight structure */ - sweight = me->dvert[index].dw; - - for( i = 0; i < totinfluences; i++ ) { - /*Add the weight and the name of the bone, which is used to identify it */ - - /* Disabled this code, it couldn't be correct! - * sweight->data was being set to a posechannel not a bone - * for one thing, and it is not always set for another. - * The only thing safe here is to return the defgroup number. -zr - */ -// if( sweight->data ) - /* valid bone: return its name */ - /* PyList_SetItem(influence_list, i, - Py_BuildValue("[sf]", sweight->data->name, sweight->weight)); - else // NULL bone: return Py_None instead - PyList_SetItem(influence_list, i, - Py_BuildValue("[Of]", Py_None, sweight->weight)); */ -// PyList_Append( influence_list, -// Py_BuildValue( "[sf]", -// sweight-> -// data-> -// name, -// sweight-> -// weight ) ); - - /* Next weight */ - sweight++; - } - } else //influence_list = PyList_New(0); - return EXPP_ReturnPyObjError( PyExc_IndexError, - "vertex index out of range" ); - } else - influence_list = PyList_New( 0 ); + int i; + MDeformWeight *sweight = NULL; + + /* Number of bones influencing the vertex */ + int totinfluences = me->dvert[index].totweight; + + /* Get the reference of the first weight structure */ + sweight = me->dvert[index].dw; + + /* Build the list only with weights and names of the influent bones */ + for( i = 0; i < totinfluences; i++, sweight++ ) { + bDeformGroup *defgroup = (bDeformGroup *) BLI_findlink( &object->defbase, + sweight->def_nr ); + if( defgroup ) + PyList_Append( influence_list, Py_BuildValue( "[sf]", + defgroup->name, sweight->weight ) ); + } + } return influence_list; } diff --git a/source/blender/python/api2_2x/Object.c b/source/blender/python/api2_2x/Object.c index 77179aad819..89ad6f36576 100644 --- a/source/blender/python/api2_2x/Object.c +++ b/source/blender/python/api2_2x/Object.c @@ -100,7 +100,9 @@ struct rctf; #include "NLA.h" #include "logic.h" #include "Effect.h" +#include "Pose.h" #include "gen_utils.h" +#include "BIF_editkey.h" /* Defines for insertIpoKey */ @@ -291,6 +293,7 @@ static PyObject *Object_getSBUseEdges( BPy_Object * self ); static PyObject *Object_setSBUseEdges( BPy_Object * self, PyObject * args ); static PyObject *Object_getSBStiffQuads( BPy_Object * self ); static PyObject *Object_setSBStiffQuads( BPy_Object * self, PyObject * args ); +static PyObject *Object_insertShapeKey(BPy_Object * self); /*****************************************************************************/ /* Python BPy_Object methods table: */ /*****************************************************************************/ @@ -322,7 +325,7 @@ If 'name_only' is nonzero or True, only the name of the datablock is returned"}, {"getAction", ( PyCFunction ) Object_getAction, METH_NOARGS, "Returns the active action for this object"}, {"getPose", ( PyCFunction ) Object_getPose, METH_NOARGS, - "Returns the pose for this object"}, + "() - returns the pose from an object if it exists, else None"}, {"isSelected", ( PyCFunction ) Object_isSelected, METH_NOARGS, "Return a 1 or 0 depending on whether the object is selected"}, {"getEuler", ( PyCFunction ) Object_getEuler, METH_NOARGS, @@ -585,7 +588,8 @@ works only if self and the object specified are of the same type."}, "([s1<,s2,s3...>]) - Delete specified scriptlinks from this object."}, {"setDupliVerts", ( PyCFunction ) Object_setDupliVerts, METH_VARARGS, "() - set or reset duplicate child objects on all vertices"}, - + {"insertShapeKey", ( PyCFunction ) Object_insertShapeKey, + METH_NOARGS, "() - Insert a Shape Key in the current object"}, {NULL, NULL, 0, NULL} }; @@ -750,9 +754,13 @@ PyObject *M_Object_Get( PyObject * self, PyObject * args ) object = GetObjectByName( name ); /* No object exists with the name specified in the argument name. */ - if( !object ) - return EXPP_ReturnPyObjError( PyExc_AttributeError, - "Unknown object specified." ); + if( !object ){ + char buffer[128]; + PyOS_snprintf( buffer, sizeof(buffer), + "object \"%s\" not found", name); + return EXPP_ReturnPyObjError( PyExc_ValueError, + buffer ); + } return Object_CreatePyObject( object ); } else { @@ -883,7 +891,7 @@ static PyObject *M_Object_Duplicate( PyObject * self, PyObject * args, PyObject /*****************************************************************************/ PyObject *Object_Init( void ) { - PyObject *module; + PyObject *module, *dict; Object_Type.ob_type = &PyType_Type; @@ -908,6 +916,11 @@ PyObject *Object_Init( void ) PyModule_AddIntConstant( module, "MAGNET",PFIELD_MAGNET ); PyModule_AddIntConstant( module, "WIND",PFIELD_WIND ); + //Add SUBMODULES to the module + dict = PyModule_GetDict( module ); //borrowed + PyDict_SetItemString(dict, "Pose", Pose_Init()); //creates a *new* module + //PyDict_SetItemString(dict, "Constraint", Constraint_Init()); //creates a *new* module + return ( module ); } @@ -1178,6 +1191,7 @@ static PyObject *Object_getAction( BPy_Object * self ) } } +#if 0 static PyObject *Object_getPose( BPy_Object * self ) { /*BPy_Action *py_action = NULL; */ @@ -1190,6 +1204,14 @@ static PyObject *Object_getPose( BPy_Object * self ) return Pose_CreatePyObject( self->object->pose ); } +#endif + +static PyObject * Object_getPose(BPy_Object *self) +{ + //if there is no pose will return PyNone + return PyPose_FromPose(self->object->pose, self->object->id.name+2); +} + static PyObject *Object_isSelected( BPy_Object * self ) { Base *base; @@ -3011,6 +3033,12 @@ static PyObject *Object_getEffects( BPy_Object * self ) return effect_list; } +static PyObject *Object_insertShapeKey(BPy_Object * self) +{ + insert_shapekey(self->object); + return Py_None; +} + /*****************************************************************************/ /* Function: Object_CreatePyObject */ /* Description: This function will create a new BlenObject from an existing */ diff --git a/source/blender/python/api2_2x/Pose.c b/source/blender/python/api2_2x/Pose.c index 42fe8c516e7..577eb1029a3 100644 --- a/source/blender/python/api2_2x/Pose.c +++ b/source/blender/python/api2_2x/Pose.c @@ -1,143 +1,940 @@ +/* + * $Id: + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + #include "Pose.h" -#include "NLA.h" -//Action is still there, may move to Action.h -// Action_Type used for typechecking -#include "Types.h" -#include <Python.h> -//#include <DNA_action_types.h> -#include "gen_utils.h" + + +#include "mydevice.h" +#include "BKE_armature.h" +#include "BKE_main.h" +#include "BKE_global.h" #include "BKE_action.h" +#include "BKE_utildefines.h" +#include "BIF_editaction.h" +#include "BIF_space.h" +#include "BKE_depsgraph.h" +#include "DNA_object_types.h" +#include "DNA_ipo_types.h" +#include "DNA_scene_types.h" +#include "DNA_space_types.h" //1 - this order +#include "BSE_editipo.h" //2 +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "Mathutils.h" +#include "Object.h" +#include "NLA.h" +#include "gen_utils.h" -static void Pose_dealloc( PyObject *self ); -static PyObject *Pose_repr( BPy_Pose *self ); -static PyObject *Pose_fromAction( BPy_Pose *self, PyObject *args); +extern void chan_calc_mat(bPoseChannel *chan); + +//------------------------ERROR CODES--------------------------------- +//This is here just to make me happy and to have more consistant error strings :) +static const char sPoseError[] = "Pose - Error: "; +static const char sPoseBadArgs[] = "Pose - Bad Arguments: "; +static const char sPoseBoneError[] = "PoseBone - Error: "; +static const char sPoseBoneBadArgs[] = "PoseBone - Bad Arguments: "; +static const char sPoseBonesDictError[] = "PoseBone - Error: "; +static const char sPoseBonesDictBadArgs[] = "PoseBone - Bad Arguments: "; + +//################## PoseBonesDict_Type (internal) ######################## +/*This is an internal psuedo-dictionary type that allows for manipulation +* of posechannels inside of a pose structure. It is a subobject of pose. +* i.e. Pose.bones['key']*/ +//################################################################ + +//------------------METHOD IMPLEMENTATIONS----------------------------- +//------------------------Pose.bones.items() +//Returns a list of key:value pairs like dict.items() +PyObject* PoseBonesDict_items(BPy_PoseBonesDict *self) +{ + return PyDict_Items(self->bonesMap); +} +//------------------------Pose.bones.keys() +//Returns a list of keys like dict.keys() +PyObject* PoseBonesDict_keys(BPy_PoseBonesDict *self) +{ + return PyDict_Keys(self->bonesMap); +} +//------------------------Armature.bones.values() +//Returns a list of values like dict.values() +PyObject* PoseBonesDict_values(BPy_PoseBonesDict *self) +{ + return PyDict_Values(self->bonesMap); +} +//------------------ATTRIBUTE IMPLEMENTATION--------------------------- +//------------------TYPE_OBECT IMPLEMENTATION----------------------- +//------------------------tp_doc +//The __doc__ string for this object +static char BPy_PoseBonesDict_doc[] = "This is an internal subobject of pose\ +designed to act as a Py_PoseBone dictionary."; -static struct PyMethodDef Pose_methods[] = { - {"fromAction", ( PyCFunction ) Pose_fromAction, - METH_VARARGS, "() - sets the pose based on an action and given time in it."}, - {0, 0, 0, 0} +//------------------------tp_methods +//This contains a list of all methods the object contains +static PyMethodDef BPy_PoseBonesDict_methods[] = { + {"items", (PyCFunction) PoseBonesDict_items, METH_NOARGS, + "() - Returns the key:value pairs from the dictionary"}, + {"keys", (PyCFunction) PoseBonesDict_keys, METH_NOARGS, + "() - Returns the keys the dictionary"}, + {"values", (PyCFunction) PoseBonesDict_values, METH_NOARGS, + "() - Returns the values from the dictionary"}, + {NULL, NULL, 0, NULL} }; +//-----------------(internal) +static int PoseBoneMapping_Init(PyObject *dictionary, ListBase *posechannels){ + bPoseChannel *pchan = NULL; + PyObject *py_posechannel = NULL; -static PyGetSetDef BPy_Pose_getsetters[] = { -// {"type",(getter)Key_getType, (setter)NULL, - {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ - }; + for (pchan = posechannels->first; pchan; pchan = pchan->next){ + py_posechannel = PyPoseBone_FromPosechannel(pchan); + if (!py_posechannel) + return -1; -PyTypeObject Pose_Type = { - PyObject_HEAD_INIT( NULL ) 0, /*ob_size */ - "Blender Pose", /*tp_name */ - sizeof( BPy_Pose ), /*tp_basicsize */ - 0, /*tp_itemsize */ - /* methods */ - ( destructor ) Pose_dealloc, /*tp_dealloc */ - ( printfunc ) 0, /*tp_print */ - ( getattrfunc ) 0, /*tp_getattr */ - ( setattrfunc ) 0, /*tp_setattr */ - 0, /*tp_compare*/ - ( reprfunc ) Pose_repr, /* tp_repr */ - /* Method suites for standard classes */ - - NULL, /* PyNumberMethods *tp_as_number; */ - NULL, /* PySequenceMethods *tp_as_sequence; */ - NULL, /* PyMappingMethods *tp_as_mapping; */ - - /* More standard operations (here for binary compatibility) */ - - NULL, /* hashfunc tp_hash; */ - NULL, /* ternaryfunc tp_call; */ - NULL, /* reprfunc tp_str; */ - NULL, /* getattrofunc tp_getattro; */ - NULL, /* setattrofunc tp_setattro; */ - - /* Functions to access object as input/output buffer */ - NULL, /* PyBufferProcs *tp_as_buffer; */ - - /*** Flags to define presence of optional/expanded features ***/ - Py_TPFLAGS_DEFAULT, /* long tp_flags; */ - - NULL, /* char *tp_doc; Documentation string */ - /*** Assigned meaning in release 2.0 ***/ - /* call function for all accessible objects */ - NULL, /* traverseproc tp_traverse; */ - - /* delete references to contained objects */ - NULL, /* inquiry tp_clear; */ - - /*** Assigned meaning in release 2.1 ***/ - /*** rich comparisons ***/ - NULL, /* richcmpfunc tp_richcompare; */ - - /*** weak reference enabler ***/ - 0, /* long tp_weaklistoffset; */ - - /*** Added in release 2.2 ***/ - /* Iterators */ - NULL, /* getiterfunc tp_iter; */ - NULL, /* iternextfunc tp_iternext; */ - - /*** Attribute descriptor and subclassing stuff ***/ - Pose_methods, /* struct PyMethodDef *tp_methods; */ - NULL, /* struct PyMemberDef *tp_members; */ - BPy_Pose_getsetters, /* struct PyGetSetDef *tp_getset; */ - NULL, /* struct _typeobject *tp_base; */ - NULL, /* PyObject *tp_dict; */ - NULL, /* descrgetfunc tp_descr_get; */ - NULL, /* descrsetfunc tp_descr_set; */ - 0, /* long tp_dictoffset; */ - NULL, /* initproc tp_init; */ - NULL, /* allocfunc tp_alloc; */ - NULL, /* newfunc tp_new; */ - /* Low-level free-memory routine */ - NULL, /* freefunc tp_free; */ - /* For PyObject_IS_GC */ - NULL, /* inquiry tp_is_gc; */ - NULL, /* PyObject *tp_bases; */ - /* method resolution order */ - NULL, /* PyObject *tp_mro; */ - NULL, /* PyObject *tp_cache; */ - NULL, /* PyObject *tp_subclasses; */ - NULL, /* PyObject *tp_weaklist; */ - NULL + if(PyDict_SetItem(dictionary, + PyString_FromString(pchan->name), py_posechannel) == -1){ + return -1; + } + Py_DECREF(py_posechannel); + } + return 0; +} + +//----------------- BonesDict_InitBones +static int PoseBonesDict_InitBones(BPy_PoseBonesDict *self) +{ + PyDict_Clear(self->bonesMap); + if (PoseBoneMapping_Init(self->bonesMap, self->bones) == -1) + return 0; + return 1; +} + +//------------------------tp_repr +//This is the string representation of the object +static PyObject *PoseBonesDict_repr(BPy_PoseBonesDict *self) +{ + char buffer[128], str[4096]; + PyObject *key, *value; + int pos = 0; + + BLI_strncpy(str,"",4096); + sprintf(buffer, "[Pose Bone Dict: {"); + strcat(str,buffer); + while (PyDict_Next(self->bonesMap, &pos, &key, &value)) { + sprintf(buffer, "%s : %s, ", PyString_AsString(key), + PyString_AsString(value->ob_type->tp_repr(value))); + strcat(str,buffer); + } + sprintf(buffer, "}]\n"); + strcat(str,buffer); + return PyString_FromString(str); +} + +//------------------------tp_dealloc +//This tells how to 'tear-down' our object when ref count hits 0 +static void PoseBonesDict_dealloc(BPy_PoseBonesDict * self) +{ + Py_DECREF(self->bonesMap); + PoseBonesDict_Type.tp_free(self); + return; +} +//------------------------mp_length +//This gets the size of the dictionary +int PoseBonesDict_len(BPy_PoseBonesDict *self) +{ + return BLI_countlist(self->bones); +} +//-----------------------mp_subscript +//This defines getting a bone from the dictionary - x = Bones['key'] +PyObject *PoseBonesDict_GetItem(BPy_PoseBonesDict *self, PyObject* key) +{ + PyObject *value = NULL; + + value = PyDict_GetItem(self->bonesMap, key); + if(value == NULL){ + return EXPP_incr_ret(Py_None); + } + return EXPP_incr_ret(value); +} +//------------------TYPE_OBECT DEFINITION-------------------------- +//Mapping Protocol +static PyMappingMethods PoseBonesDict_MapMethods = { + (inquiry) PoseBonesDict_len, //mp_length + (binaryfunc)PoseBonesDict_GetItem, //mp_subscript + 0, //mp_ass_subscript +}; +//PoseBonesDict TypeObject +PyTypeObject PoseBonesDict_Type = { + PyObject_HEAD_INIT(NULL) //tp_head + 0, //tp_internal + "PoseBonesDict", //tp_name + sizeof(BPy_PoseBonesDict), //tp_basicsize + 0, //tp_itemsize + (destructor)PoseBonesDict_dealloc, //tp_dealloc + 0, //tp_print + 0, //tp_getattr + 0, //tp_setattr + 0, //tp_compare + (reprfunc) PoseBonesDict_repr, //tp_repr + 0, //tp_as_number + 0, //tp_as_sequence + &PoseBonesDict_MapMethods, //tp_as_mapping + 0, //tp_hash + 0, //tp_call + 0, //tp_str + 0, //tp_getattro + 0, //tp_setattro + 0, //tp_as_buffer + Py_TPFLAGS_DEFAULT, //tp_flags + BPy_PoseBonesDict_doc, //tp_doc + 0, //tp_traverse + 0, //tp_clear + 0, //tp_richcompare + 0, //tp_weaklistoffset + 0, //tp_iter + 0, //tp_iternext + BPy_PoseBonesDict_methods, //tp_methods + 0, //tp_members + 0, //tp_getset + 0, //tp_base + 0, //tp_dict + 0, //tp_descr_get + 0, //tp_descr_set + 0, //tp_dictoffset + 0, //tp_init + 0, //tp_alloc + 0, //tp_new + 0, //tp_free + 0, //tp_is_gc + 0, //tp_bases + 0, //tp_mro + 0, //tp_cache + 0, //tp_subclasses + 0, //tp_weaklist + 0 //tp_del }; +//-----------------------PyPoseBonesDict_FromPyPose +static PyObject *PyPoseBonesDict_FromPyPose(BPy_Pose *py_pose) +{ + BPy_PoseBonesDict *py_posebonesdict = NULL; + + //create py object + py_posebonesdict = (BPy_PoseBonesDict *)PoseBonesDict_Type.tp_alloc(&PoseBonesDict_Type, 0); + if (!py_posebonesdict) + goto RuntimeError; -static void Pose_dealloc( PyObject * self ) + //create internal dictionaries + py_posebonesdict->bonesMap = PyDict_New(); + if (!py_posebonesdict->bonesMap) + goto RuntimeError; + + //set listbase pointer + py_posebonesdict->bones = &py_pose->pose->chanbase; + + //now that everything is setup - init the mappings + if (!PoseBonesDict_InitBones(py_posebonesdict)) + goto RuntimeError; + + return (PyObject*)py_posebonesdict; + +RuntimeError: + return EXPP_objError(PyExc_RuntimeError, "%s%s", + sPoseBonesDictError, "Failed to create class"); +} + +//################## Pose_Type ########################## +/*This type is a wrapper for a pose*/ +//#################################################### +//------------------METHOD IMPLEMENTATIONS------------------------------ +static PyObject *Pose_update(BPy_Pose *self) +{ + Object *daddy = NULL; + + self->pose->flag |= POSE_RECALC; + + for (daddy = G.main->object.first; daddy; daddy = daddy->id.next){ + if (daddy->pose == self->pose){ + break; + } + } + + if(daddy) + where_is_pose(daddy); + + return EXPP_incr_ret(Py_None); +} +//------------------------tp_methods +//This contains a list of all methods the object contains +static PyMethodDef BPy_Pose_methods[] = { + {"update", (PyCFunction) Pose_update, METH_NOARGS, + "() - Rebuilds the pose with new values"}, + {NULL, NULL, 0, NULL} +}; +//------------------ATTRIBUTE IMPLEMENTATIONS--------------------------- +//------------------------Pose.bones (getter) +//Gets the bones attribute +static PyObject *Pose_getBoneDict(BPy_Pose *self, void *closure) +{ + return EXPP_incr_ret((PyObject*)self->Bones); +} +//------------------------Pose.bones (setter) +//Sets the bones attribute +static int Pose_setBoneDict(BPy_Pose *self, PyObject *value, void *closure) +{ + goto AttributeError; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s", + sPoseError, "You are not allowed to change the .bones attribute"); +} +//------------------TYPE_OBECT IMPLEMENTATION--------------------------- +//------------------------tp_getset +//This contains methods for attributes that require checking +static PyGetSetDef BPy_Pose_getset[] = { + {"bones", (getter)Pose_getBoneDict, (setter)Pose_setBoneDict, + "The pose's Bone dictionary", NULL}, + {NULL, NULL, NULL, NULL, NULL} +}; +//------------------------tp_dealloc +//This tells how to 'tear-down' our object when ref count hits 0 +static void Pose_dealloc(BPy_Pose *self) { - PyObject_DEL( self ); + Py_DECREF(self->Bones); + Pose_Type.tp_free(self); + return; } +//------------------------tp_repr +//This is the string representation of the object +static PyObject *Pose_repr(BPy_Pose *self) +{ + return PyString_FromFormat( "[Pose \"%s\"]", self->name); +} +//------------------------tp_doc +//The __doc__ string for this object +static char BPy_Pose_doc[] = "This object wraps a Blender Pose object."; -PyObject *Pose_CreatePyObject( struct bPose * pose ) - { - BPy_Pose *pypose; - - pypose = - ( BPy_Pose * ) PyObject_NEW( BPy_Pose, &Pose_Type ); +//------------------TYPE_OBECT DEFINITION-------------------------- +PyTypeObject Pose_Type = { + PyObject_HEAD_INIT(NULL) //tp_head + 0, //tp_internal + "Pose", //tp_name + sizeof(BPy_Pose), //tp_basicsize + 0, //tp_itemsize + (destructor)Pose_dealloc, //tp_dealloc + 0, //tp_print + 0, //tp_getattr + 0, //tp_setattr + 0, //tp_compare + (reprfunc)Pose_repr, //tp_repr + 0, //tp_as_number + 0, //tp_as_sequence + 0, //tp_as_mapping + 0, //tp_hash + 0, //tp_call + 0, //tp_str + 0, //tp_getattro + 0, //tp_setattro + 0, //tp_as_buffer + Py_TPFLAGS_DEFAULT, //tp_flags + BPy_Pose_doc, //tp_doc + 0, //tp_traverse + 0, //tp_clear + 0, //tp_richcompare + 0, //tp_weaklistoffset + 0, //tp_iter + 0, //tp_iternext + BPy_Pose_methods, //tp_methods + 0, //tp_members + BPy_Pose_getset, //tp_getset + 0, //tp_base + 0, //tp_dict + 0, //tp_descr_get + 0, //tp_descr_set + 0, //tp_dictoffset + 0, //tp_init + 0, //tp_alloc + 0, //tp_new + 0, //tp_free + 0, //tp_is_gc + 0, //tp_bases + 0, //tp_mro + 0, //tp_cache + 0, //tp_subclasses + 0, //tp_weaklist + 0 //tp_del +}; +//################## PoseBone_Type ##################### +/*This type is a wrapper for a posechannel*/ +//#################################################### +//------------------METHOD IMPLEMENTATIONS------------------------------ +//------------------------------PoseBone.insertKey() +static PyObject *PoseBone_insertKey(BPy_PoseBone *self, PyObject *args) +{ + PyObject *parent_object = NULL; + PyObject *constants = NULL, *item = NULL; + int frame = 1, oldframe, length, x, numeric_value = 0, oldflag; + bPoseChannel *pchan = NULL; - if( !pypose ) - return EXPP_ReturnPyObjError( PyExc_MemoryError, - "couldn't create BPy_Pose object" ); - PyType_Ready(&Pose_Type); + if (!PyArg_ParseTuple(args, "O!i|O", &Object_Type, &parent_object, &frame, &constants )) + goto AttributeError; + + //verify that this pchannel is part of the object->pose + for (pchan = ((BPy_Object*)parent_object)->object->pose->chanbase.first; + pchan; pchan = pchan->next){ + if (pchan == self->posechannel) + break; + } + if (!pchan) + goto AttributeError2; + + //verify that there is an action bound to this object + if (!((BPy_Object*)parent_object)->object->action){ + goto AttributeError5; + } - pypose->pose = pose; - return ( ( PyObject * ) pypose ); + oldflag = self->posechannel->flag; + self->posechannel->flag = 0; + //set the flags for this posechannel + if (constants){ + if(PySequence_Check(constants)){ + length = PySequence_Length(constants); + for (x = 0; x < length; x++){ + item = PySequence_GetItem(constants, x); + if (item == EXPP_GetModuleConstant("Blender.Object.Pose", "ROT")){ + numeric_value |= POSE_ROT; + }else if (item == EXPP_GetModuleConstant("Blender.Object.Pose", "LOC")){ + numeric_value |= POSE_LOC; + }else if (item == EXPP_GetModuleConstant("Blender.Object.Pose", "SIZE")){ + numeric_value |= POSE_SIZE; + }else{ + Py_DECREF(item); + self->posechannel->flag = (short)oldflag; + goto AttributeError4; + } + Py_DECREF(item); + } + self->posechannel->flag = (short)numeric_value; + }else if (BPy_Constant_Check(constants)){ + if (constants == EXPP_GetModuleConstant("Blender.Object.Pose", "ROT")){ + numeric_value |= POSE_ROT; + }else if (constants == EXPP_GetModuleConstant("Blender.Object.Pose", "LOC")){ + numeric_value |= POSE_LOC; + }else if (constants == EXPP_GetModuleConstant("Blender.Object.Pose", "SIZE")){ + numeric_value |= POSE_SIZE; + }else{ + self->posechannel->flag = (short)oldflag; + goto AttributeError4; + } + self->posechannel->flag = (short)numeric_value; + }else{ + goto AttributeError3; + } + }else{ //nothing passed so set them all + self->posechannel->flag |= POSE_ROT; + self->posechannel->flag |= POSE_LOC; + self->posechannel->flag |= POSE_SIZE; } -static PyObject *Pose_fromAction( BPy_Pose *self, PyObject *args) { - BPy_Action *action; - float time; - float factor = 1.0; + //set the frame we want insertion on + oldframe = G.scene->r.cfra; + G.scene->r.cfra = (short)frame; + + //add the action channel if it's not there + verify_action_channel(((BPy_Object*)parent_object)->object->action, + self->posechannel->name); + + //insert the pose keys + if (self->posechannel->flag & POSE_ROT){ + insertkey(&((BPy_Object*)parent_object)->object->id, + ID_PO, self->posechannel->name, NULL, AC_QUAT_X); + insertkey(&((BPy_Object*)parent_object)->object->id, + ID_PO, self->posechannel->name, NULL, AC_QUAT_Y); + insertkey(&((BPy_Object*)parent_object)->object->id, + ID_PO, self->posechannel->name, NULL, AC_QUAT_Z); + insertkey(&((BPy_Object*)parent_object)->object->id, + ID_PO, self->posechannel->name, NULL, AC_QUAT_W); + } + if (self->posechannel->flag & POSE_LOC){ + insertkey(&((BPy_Object*)parent_object)->object->id, + ID_PO, self->posechannel->name, NULL, AC_LOC_X); + insertkey(&((BPy_Object*)parent_object)->object->id, + ID_PO, self->posechannel->name, NULL, AC_LOC_Y); + insertkey(&((BPy_Object*)parent_object)->object->id, + ID_PO, self->posechannel->name, NULL, AC_LOC_Z); + } + if (self->posechannel->flag & POSE_SIZE){ + insertkey(&((BPy_Object*)parent_object)->object->id, + ID_PO, self->posechannel->name, NULL, AC_SIZE_X); + insertkey(&((BPy_Object*)parent_object)->object->id, + ID_PO, self->posechannel->name, NULL, AC_SIZE_Y); + insertkey(&((BPy_Object*)parent_object)->object->id, + ID_PO, self->posechannel->name, NULL, AC_SIZE_Z); + } - if (!PyArg_ParseTuple(args, "O!f|f", &Action_Type, &action, &time, &factor)) - return EXPP_ReturnPyObjError(PyExc_AttributeError, "An action and a time (as number) required as arguments."); + //flip the frame back + G.scene->r.cfra = (short)oldframe; - //todo: range check for time + //update the IPOs + remake_action_ipos (((BPy_Object*)parent_object)->object->action); - extract_pose_from_action(self->pose, action->action, time); + return EXPP_incr_ret(Py_None); - Py_RETURN_NONE; +AttributeError: + return EXPP_objError(PyExc_AttributeError, "%s%s%s", + sPoseBoneError, ".insertKey: ", "expects an Object, int, (optional) constants"); +AttributeError2: + return EXPP_objError(PyExc_AttributeError, "%s%s%s", + sPoseBoneError, ".insertKey: ", "wrong object detected. \ + Use the object this pose came from"); +AttributeError3: + return EXPP_objError(PyExc_AttributeError, "%s%s%s", + sPoseBoneError, ".insertKey: ", "Expects a constant or list of constants"); +AttributeError4: + return EXPP_objError(PyExc_AttributeError, "%s%s%s", + sPoseBoneError, ".insertKey: ", "Please use a constant defined in the Pose module"); +AttributeError5: + return EXPP_objError(PyExc_AttributeError, "%s%s%s", + sPoseBoneError, ".insertKey: ", "You must set up and link an Action to this object first"); } +//------------------------tp_methods +//This contains a list of all methods the object contains +static PyMethodDef BPy_PoseBone_methods[] = { + {"insertKey", (PyCFunction) PoseBone_insertKey, METH_VARARGS, + "() - insert a key for this pose into an action"}, + {NULL, NULL, 0, NULL} +}; +//------------------ATTRIBUTE IMPLEMENTATIONS--------------------------- +//------------------------PoseBone.name (getter) +//Gets the name attribute +static PyObject *PoseBone_getName(BPy_PoseBone *self, void *closure) +{ + return PyString_FromString(self->posechannel->name); +} +//------------------------PoseBone.name (setter) +//Sets the name attribute +static int PoseBone_setName(BPy_PoseBone *self, PyObject *value, void *closure) +{ + char *name = ""; + + if (!PyArg_Parse(value, "s", &name)) + goto AttributeError; -static PyObject *Pose_repr( BPy_Pose * self ) + BLI_strncpy(self->posechannel->name, name, 32); + return 0; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sPoseBoneError, ".name: ", "expects a string"); +} +//------------------------PoseBone.loc (getter) +//Gets the loc attribute +static PyObject *PoseBone_getLoc(BPy_PoseBone *self, void *closure) +{ + return newVectorObject(self->posechannel->loc, 3, Py_WRAP); +} +//------------------------PoseBone.loc (setter) +//Sets the loc attribute +static int PoseBone_setLoc(BPy_PoseBone *self, PyObject *value, void *closure) { - return PyString_FromFormat( "[Pose]"); // \"%s\"]", self->key->id.name + 2 ); + VectorObject *vec = NULL; + int x; + + if (!PyArg_Parse(value, "O!", &vector_Type, &vec)) + goto AttributeError; + if (vec->size != 3) + goto AttributeError; + + for (x = 0; x < 3; x++){ + self->posechannel->loc[x] = vec->vec[x]; + } + return 0; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sPoseBoneError, ".loc: ", "expects a 3d vector object"); +} +//------------------------PoseBone.size (getter) +//Gets the size attribute +static PyObject *PoseBone_getSize(BPy_PoseBone *self, void *closure) +{ + return newVectorObject(self->posechannel->size, 3, Py_WRAP); +} +//------------------------PoseBone.size (setter) +//Sets the size attribute +static int PoseBone_setSize(BPy_PoseBone *self, PyObject *value, void *closure) +{ + VectorObject *vec = NULL; + int x; + + if (!PyArg_Parse(value, "O!", &vector_Type, &vec)) + goto AttributeError; + if (vec->size != 3) + goto AttributeError; + + for (x = 0; x < 3; x++){ + self->posechannel->size[x] = vec->vec[x]; + } + return 0; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sPoseBoneError, ".size: ", "expects a 3d vector object"); +} +//------------------------PoseBone.quat (getter) +//Gets the quat attribute +static PyObject *PoseBone_getQuat(BPy_PoseBone *self, void *closure) +{ + return newQuaternionObject(self->posechannel->quat, Py_WRAP); +} +//------------------------PoseBone.quat (setter) +//Sets the quat attribute +static int PoseBone_setQuat(BPy_PoseBone *self, PyObject *value, void *closure) +{ + QuaternionObject *quat = NULL; + int x; + + if (!PyArg_Parse(value, "O!", &quaternion_Type, &quat)) + goto AttributeError; + + for (x = 0; x < 4; x++){ + self->posechannel->quat[x] = quat->quat[x]; + } + return 0; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sPoseBoneError, ".quat: ", "expects a quaternion object"); +} +//------------------------PoseBone.localMatrix (getter) +//Gets the chan_mat +static PyObject *PoseBone_getLocalMatrix(BPy_PoseBone *self, void *closure) +{ + return newMatrixObject((float*)self->posechannel->chan_mat, 4, 4, Py_WRAP); +} +//------------------------PoseBone.localMatrix (setter) +//Sets the chan_mat +static int PoseBone_setLocalMatrix(BPy_PoseBone *self, PyObject *value, void *closure) +{ + MatrixObject *matrix = NULL; + float size[3], quat[4], loc[3]; + float mat3[3][3], mat4[4][4]; + int matsize = 0; + + if (!PyArg_Parse(value, "O!", &matrix_Type, &matrix)) + goto AttributeError; + + if (matrix->rowSize == 3 && matrix->colSize == 3){ + matsize = 3; + Mat3CpyMat3(mat3, (float(*)[3])*matrix->matrix); + }else if (matrix->rowSize == 4 && matrix->colSize == 4){ + matsize = 4; + Mat4CpyMat4(mat4, (float(*)[4])*matrix->matrix); + } + + if (matsize != 3 && matsize != 4){ + goto AttributeError; + } + + //get size and rotation + if (matsize == 3){ + Mat3ToSize(mat3, size); + Mat3Ortho(mat3); + Mat3ToQuat(mat3, quat); + }else if (matsize == 4){ + Mat4ToSize(mat4, size); + Mat4Ortho(mat4); + Mat4ToQuat(mat4, quat); + } + + //get loc + if (matsize == 4){ + VECCOPY(loc, matrix->matrix[3]); + } + + //copy new attributes + VECCOPY(self->posechannel->size, size); + QUATCOPY(self->posechannel->quat, quat); + if (matsize == 4){ + VECCOPY(self->posechannel->loc, loc); + } + + //rebuild matrix + chan_calc_mat(self->posechannel); + return 0; + +AttributeError: + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sPoseBoneError, ".localMatrix: ", "expects a 3x3 or 4x4 matrix object"); +} +//------------------------PoseBone.poseMatrix (getter) +//Gets the pose_mat +static PyObject *PoseBone_getPoseMatrix(BPy_PoseBone *self, void *closure) +{ + return newMatrixObject((float*)self->posechannel->pose_mat, 4, 4, Py_WRAP); +} +//------------------------PoseBone.poseMatrix (setter) +//Sets the pose_mat +static int PoseBone_setPoseMatrix(BPy_PoseBone *self, PyObject *value, void *closure) +{ + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sPoseBoneError, ".poseMatrix: ", "not able to set this property"); +} +////------------------------PoseBone.constraints (getter) +////Gets the constraints list +//static PyObject *PoseBone_getConstraints(BPy_PoseBone *self, void *closure) +//{ +// PyObject *list = NULL, *py_constraint = NULL; +// bConstraint *constraint = NULL; +// +// list = PyList_New(0); +// for (constraint = self->posechannel->constraints.first; constraint; constraint = constraint->next){ +// py_constraint = PyConstraint_FromConstraint(constraint); +// if (!py_constraint) +// return NULL; +// if (PyList_Append(list, py_constraint) == -1){ +// Py_DECREF(py_constraint); +// goto RuntimeError; +// } +// Py_DECREF(py_constraint); +// } +// return list; +// +//RuntimeError: +// return EXPP_objError(PyExc_RuntimeError, "%s%s%s", +// sPoseBoneError, ".constraints: ", "unable to build constraint list"); +//} +////------------------------PoseBone.constraints (setter) +////Sets the constraints list +//static int PoseBone_setConstraints(BPy_PoseBone *self, PyObject *value, void *closure) +//{ +// printf("This is not implemented yet..."); +// return 1; +//} +//------------------------PoseBone.head (getter) +//Gets the pose head position +static PyObject *PoseBone_getHead(BPy_PoseBone *self, void *closure) +{ + return newVectorObject(self->posechannel->pose_head, 3, Py_NEW); +} +//------------------------PoseBone.head (setter) +//Sets the pose head position +static int PoseBone_setHead(BPy_PoseBone *self, PyObject *value, void *closure) +{ + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sPoseBoneError, ".head: ", "not able to set this property"); +} +//------------------------PoseBone.tail (getter) +//Gets the pose tail position +static PyObject *PoseBone_getTail(BPy_PoseBone *self, void *closure) +{ + return newVectorObject(self->posechannel->pose_tail, 3, Py_NEW); +} +//------------------------PoseBone.tail (setter) +//Sets the pose tail position +static int PoseBone_setTail(BPy_PoseBone *self, PyObject *value, void *closure) +{ + return EXPP_intError(PyExc_AttributeError, "%s%s%s", + sPoseBoneError, ".tail: ", "not able to set this property"); +} +//------------------TYPE_OBECT IMPLEMENTATION--------------------------- +//------------------------tp_getset +//This contains methods for attributes that require checking +static PyGetSetDef BPy_PoseBone_getset[] = { + {"name", (getter)PoseBone_getName, (setter)PoseBone_setName, + "The pose bone's name", NULL}, + {"loc", (getter)PoseBone_getLoc, (setter)PoseBone_setLoc, + "The pose bone's change in location as a vector", NULL}, + {"size", (getter)PoseBone_getSize, (setter)PoseBone_setSize, + "The pose bone's change in size as a vector", NULL}, + {"quat", (getter)PoseBone_getQuat, (setter)PoseBone_setQuat, + "The pose bone's change in rotation as a quat", NULL}, + {"localMatrix", (getter)PoseBone_getLocalMatrix, (setter)PoseBone_setLocalMatrix, + "The pose bone's change matrix built from the quat, loc, and size", NULL}, + {"poseMatrix", (getter)PoseBone_getPoseMatrix, (setter)PoseBone_setPoseMatrix, + "The pose bone's matrix", NULL}, + {"head", (getter)PoseBone_getHead, (setter)PoseBone_setHead, + "The pose bone's head positon", NULL}, + {"tail", (getter)PoseBone_getTail, (setter)PoseBone_setTail, + "The pose bone's tail positon", NULL}, + //{"constraints", (getter)PoseBone_getConstraints, (setter)PoseBone_setConstraints, + // "The list of contraints that pertain to this pose bone", NULL}, + {NULL, NULL, NULL, NULL, NULL} +}; +//------------------------tp_dealloc +//This tells how to 'tear-down' our object when ref count hits 0 +static void PoseBone_dealloc(BPy_PoseBone *self) +{ + PoseBone_Type.tp_free(self); + return; +} +//------------------------tp_repr +//This is the string representation of the object +static PyObject *PoseBone_repr(BPy_PoseBone *self) +{ + return PyString_FromFormat( "[PoseBone \"%s\"]", self->posechannel->name); +} +//------------------------tp_doc +//The __doc__ string for this object +static char BPy_PoseBone_doc[] = "This object wraps a Blender PoseBone object."; + +//------------------TYPE_OBECT DEFINITION-------------------------- +PyTypeObject PoseBone_Type = { + PyObject_HEAD_INIT(NULL) //tp_head + 0, //tp_internal + "PoseBone", //tp_name + sizeof(BPy_PoseBone), //tp_basicsize + 0, //tp_itemsize + (destructor)PoseBone_dealloc, //tp_dealloc + 0, //tp_print + 0, //tp_getattr + 0, //tp_setattr + 0, //tp_compare + (reprfunc)PoseBone_repr, //tp_repr + 0, //tp_as_number + 0, //tp_as_sequence + 0, //tp_as_mapping + 0, //tp_hash + 0, //tp_call + 0, //tp_str + 0, //tp_getattro + 0, //tp_setattro + 0, //tp_as_buffer + Py_TPFLAGS_DEFAULT, //tp_flags + BPy_PoseBone_doc, //tp_doc + 0, //tp_traverse + 0, //tp_clear + 0, //tp_richcompare + 0, //tp_weaklistoffset + 0, //tp_iter + 0, //tp_iternext + BPy_PoseBone_methods, //tp_methods + 0, //tp_members + BPy_PoseBone_getset, //tp_getset + 0, //tp_base + 0, //tp_dict + 0, //tp_descr_get + 0, //tp_descr_set + 0, //tp_dictoffset + 0, //tp_init + 0, //tp_alloc + 0, //tp_new + 0, //tp_free + 0, //tp_is_gc + 0, //tp_bases + 0, //tp_mro + 0, //tp_cache + 0, //tp_subclasses + 0, //tp_weaklist + 0 //tp_del +}; +//-------------------MODULE METHODS IMPLEMENTATION------------------------ +//-------------------MODULE METHODS DEFINITION----------------------------- +struct PyMethodDef M_Pose_methods[] = { + {NULL, NULL, 0, NULL} +}; +//-------------------MODULE INITIALIZATION-------------------------------- +PyObject *Pose_Init(void) +{ + PyObject *module; + + //Initializes TypeObject.ob_type + if (PyType_Ready(&Pose_Type) < 0 || PyType_Ready(&PoseBone_Type) < 0 || + PyType_Ready(&PoseBonesDict_Type) < 0) { + return EXPP_incr_ret(Py_None); + } + + //Register the module + module = Py_InitModule3("Blender.Object.Pose", M_Pose_methods, + "The Blender Pose module"); + + //Add TYPEOBJECTS to the module + PyModule_AddObject(module, "Pose", + EXPP_incr_ret((PyObject *)&Pose_Type)); //*steals* + PyModule_AddObject(module, "PoseBone", + EXPP_incr_ret((PyObject *)&PoseBone_Type)); //*steals* + + //Add CONSTANTS to the module + PyModule_AddObject(module, "ROT", + EXPP_incr_ret(PyConstant_NewInt("ROT", POSE_ROT))); + PyModule_AddObject(module, "LOC", + EXPP_incr_ret(PyConstant_NewInt("LOC", POSE_LOC))); + PyModule_AddObject(module, "SIZE", + EXPP_incr_ret(PyConstant_NewInt("SIZE", POSE_SIZE))); + + return module; +} +//------------------VISIBLE PROTOTYPE IMPLEMENTATION----------------------- +//------------------------------PyPose_FromPose (internal) +//Returns a PyPose from a bPose - return PyNone if bPose is NULL +PyObject *PyPose_FromPose(bPose *pose, char *name) +{ + BPy_Pose *py_pose = NULL; + + if (pose){ + py_pose = (BPy_Pose*)Pose_Type.tp_alloc(&Pose_Type, 0); + if (!py_pose) + goto RuntimeError; + + py_pose->pose = pose; + BLI_strncpy(py_pose->name, name, 24); + + //create armature.bones + py_pose->Bones = (BPy_PoseBonesDict*)PyPoseBonesDict_FromPyPose(py_pose); + if (!py_pose->Bones) + goto RuntimeError; + + return (PyObject*)py_pose; + }else{ + return EXPP_incr_ret(Py_None); + } + +RuntimeError: + return EXPP_objError(PyExc_RuntimeError, "%s%s%s", + sPoseError, "PyPose_FromPose: ", "Internal Error Ocurred"); +} +//------------------------------PyPoseBone_FromPosechannel (internal) +//Returns a PyPoseBone from a bPoseChannel - return PyNone if bPoseChannel is NULL +PyObject *PyPoseBone_FromPosechannel(bPoseChannel *pchan) +{ + BPy_PoseBone *py_posechannel = NULL; + + if (pchan){ + py_posechannel = (BPy_PoseBone*)PoseBone_Type.tp_alloc(&PoseBone_Type, 0); + if (!py_posechannel) + goto RuntimeError; + py_posechannel->posechannel = pchan; + return (PyObject*)py_posechannel; + }else{ + return EXPP_incr_ret(Py_None); + } + +RuntimeError: + return EXPP_objError(PyExc_RuntimeError, "%s%s%s", + sPoseBoneError, "PyPoseBone_FromPosechannel: ", "Internal Error Ocurred"); } diff --git a/source/blender/python/api2_2x/Pose.h b/source/blender/python/api2_2x/Pose.h index c1735d1ebd4..dc90c8820f0 100644 --- a/source/blender/python/api2_2x/Pose.h +++ b/source/blender/python/api2_2x/Pose.h @@ -1,24 +1,68 @@ +/* + * $Id: + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + #ifndef EXPP_POSE_H #define EXPP_POSE_H #include <Python.h> +#include "DNA_action_types.h" -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <DNA_action_types.h> - -/* EXPP PyType Objects */ +//-------------------TYPE CHECKS--------------------------------- +#define PoseObject_Check(v) ((v)->ob_type == &Pose_Type) +#define PoseBoneObject_Check(v) ((v)->ob_type == &PoseBone_Type) +#define PoseBonesDictObject_Check(v) ((v)->ob_type == &PoseBonesDict_Type) +//-------------------TYPEOBJECT---------------------------------- extern PyTypeObject Pose_Type; - -struct BPy_Pose; +extern PyTypeObject PoseBone_Type; +extern PyTypeObject PoseBonesDict_Type; +//-------------------STRUCT DEFINITION---------------------------- +typedef struct { + PyObject_HEAD + PyObject *bonesMap; + ListBase *bones; +} BPy_PoseBonesDict; typedef struct { - PyObject_HEAD /* required python macro */ - bPose * pose; -} BPy_Pose; /* a pose */ + PyObject_HEAD + bPose *pose; + char name[24]; //because poses have not names :( + BPy_PoseBonesDict *Bones; +} BPy_Pose; -PyObject *Pose_CreatePyObject( bPose * p ); +typedef struct { + PyObject_HEAD + bPoseChannel *posechannel; +} BPy_PoseBone; -#endif /* EXPP_KEY_H */ +//-------------------VISIBLE PROTOTYPES------------------------- +PyObject *Pose_Init(void); +PyObject *PyPose_FromPose(bPose *pose, char *name); +PyObject *PyPoseBone_FromPosechannel(bPoseChannel *pchan); +#endif diff --git a/source/blender/python/api2_2x/Window.c b/source/blender/python/api2_2x/Window.c index 8b89296dcde..a7ad2581f45 100644 --- a/source/blender/python/api2_2x/Window.c +++ b/source/blender/python/api2_2x/Window.c @@ -889,20 +889,23 @@ static PyObject *M_Window_EditMode( PyObject * self, PyObject * args ) short status = -1; char *undo_str = "From script"; int undo_str_len = 11; + int do_undo = 1; - if( !PyArg_ParseTuple - ( args, "|hs#", &status, &undo_str, &undo_str_len ) ) + if( !PyArg_ParseTuple( args, + "|hs#i", &status, &undo_str, &undo_str_len, &do_undo ) ) return EXPP_ReturnPyObjError( PyExc_TypeError, - "expected nothing or an int (bool) and a string as arguments" ); + "expected optional int (bool), string and int (bool) as arguments" ); if( status >= 0 ) { if( status ) { if( !G.obedit ) enter_editmode( ); } else if( G.obedit ) { - if( undo_str_len > 63 ) - undo_str[63] = '\0'; /* 64 is max */ - undo_push_mesh( undo_str ); /* use better solution after 2.34 */ + if( do_undo && U.undosteps != 0 ) { + if( undo_str_len > 63 ) + undo_str[63] = '\0'; /* 64 is max */ + undo_push_mesh( undo_str ); /* use better solution after 2.34 */ + } exit_editmode( 1 ); } } diff --git a/source/blender/python/api2_2x/constant.c b/source/blender/python/api2_2x/constant.c index 1ebf50ffa55..f28af8efad6 100644 --- a/source/blender/python/api2_2x/constant.c +++ b/source/blender/python/api2_2x/constant.c @@ -90,7 +90,7 @@ static PyMethodDef BPy_constant_methods[] = { "() - Returns the keys the dictionary"}, {"values", (PyCFunction) constant_values, METH_NOARGS, "() - Returns the values from the dictionary"}, - {NULL} + {NULL, NULL, 0, NULL} }; //------------------------mp_length static int constantLength(BPy_constant *self) diff --git a/source/blender/python/api2_2x/doc/API_intro.py b/source/blender/python/api2_2x/doc/API_intro.py index 9a7c16d5168..a23999f4a0e 100644 --- a/source/blender/python/api2_2x/doc/API_intro.py +++ b/source/blender/python/api2_2x/doc/API_intro.py @@ -33,6 +33,7 @@ The Blender Python API Reference - L{NMesh} (*) - L{Noise} - L{Object} (*) + - L{Pose} - L{Registry} - L{Scene} - L{Radio} diff --git a/source/blender/python/api2_2x/doc/Armature.py b/source/blender/python/api2_2x/doc/Armature.py index 79f9481192d..a8ce2e3c1eb 100644 --- a/source/blender/python/api2_2x/doc/Armature.py +++ b/source/blender/python/api2_2x/doc/Armature.py @@ -212,7 +212,7 @@ class Bone: @type matrix: Matrix Object @ivar parent: The parent Bone. @type parent: Bone Object - @ivar children: The children bones. + @ivar children: The children directly attached to this bone. @type children: List of Bone Objects @ivar weight: The bone's weight. @type weight: Float @@ -246,6 +246,13 @@ class Bone: @rtype: Bool """ + def getAllChildren(): + """ + Gets all the children under this bone including the children's children. + @rtype: List of Bone object + @return: all bones under this one + """ + class Editbone: """ The Editbone Object @@ -260,7 +267,7 @@ class Editbone: @type head: Vector Object @ivar tail: This Bone's "tail" ending position when in rest state (armaturespace). @type tail: Vector Object - @ivar matrix: This Bone's matrix. (armaturespace) This cannot be set. + @ivar matrix: This Bone's matrix. (armaturespace) @type matrix: Matrix Object @ivar parent: The parent Bone. @type parent: Editbone Object diff --git a/source/blender/python/api2_2x/doc/Ipo.py b/source/blender/python/api2_2x/doc/Ipo.py index 8621bd18ca0..01abef7e430 100644 --- a/source/blender/python/api2_2x/doc/Ipo.py +++ b/source/blender/python/api2_2x/doc/Ipo.py @@ -297,6 +297,16 @@ class IpoCurve: Can be Constant, Extrapolation, Cyclic or Cyclic_extrapolation. @rtype: None @return: None + @note: Cyclic Ipo curves never reach the end value. If the first and + last bezier points do not have the same y coordinate, the value of the + curve when it "cycles" is that of the first point. If a user wants to + get the value of the final curve point, read the final point from the + curve's L{bezierPoints} attribute:: + + ipo = Blender.Object.Get('Cube').ipo + icu = ipo.getCurves('LocX') + endtime,endvalue = icu.bezierPoints[-1].pt + """ def getExtrapolation(): diff --git a/source/blender/python/api2_2x/doc/Key.py b/source/blender/python/api2_2x/doc/Key.py index 6d3c8316a0e..795346491a1 100644 --- a/source/blender/python/api2_2x/doc/Key.py +++ b/source/blender/python/api2_2x/doc/Key.py @@ -6,7 +6,7 @@ The Blender.Key submodule. This module provides access to B{Key} objects in Blender. @type Types: readonly dictionary -@var Types: The type of a key, indicating the type of data in the +@var Types: The type of a key owner, indicating the type of data in the data blocks. - MESH - the key is a Mesh key; data blocks contain L{NMVert<NMesh.NMVert>} vertices. @@ -15,7 +15,6 @@ data blocks. 3 floating point numbers). - LATTICE - the key is a Lattice key; data blocks contain BPoints, each point represented by a list of 3 floating point numbers. - """ def Get(name = None): @@ -38,7 +37,7 @@ class Key: keyframe data. @ivar ipo: Key Ipo. Contains the Ipo if one is assigned to the - object, B{None} otherwise. Setting to B{None} clears the current Ipo.. + object, B{None} otherwise. Setting to B{None} clears the current Ipo. @type ipo: Blender Ipo @ivar value: The value of the key. Read-only. @type value: float @@ -47,6 +46,8 @@ class Key: @type type: int @ivar blocks: A list of KeyBlocks for the key. Read-only. @type blocks: Blender KeyBlock. + @ivar relative: Indicates whether the key is relative(=True) or normal. + @type relative: bool """ def getIpo(): @@ -66,6 +67,8 @@ class KeyBlock: Each Key object has a list of KeyBlocks attached, each KeyBlock representing a keyframe. + @ivar curval: Current value of the corresponding IpoCurve. Read-only. + @type curval: float @ivar name: The name of the Keyblock. Truncated to 32 characters. @type name: string @ivar pos: The position of the keyframe. diff --git a/source/blender/python/api2_2x/doc/Mathutils.py b/source/blender/python/api2_2x/doc/Mathutils.py index 2d4e0a0c092..b1a8839110e 100644 --- a/source/blender/python/api2_2x/doc/Mathutils.py +++ b/source/blender/python/api2_2x/doc/Mathutils.py @@ -493,6 +493,7 @@ class Vector: def resize4D(): """ Resize the vector to 4d. New axis will be 0.0. + The last component will be 1.0, to make multiplying 3d vectors by 4x4 matrices easier. @return: a copy of itself """ diff --git a/source/blender/python/api2_2x/doc/Mesh.py b/source/blender/python/api2_2x/doc/Mesh.py index f60d84ff02a..54fd5d59cf0 100644 --- a/source/blender/python/api2_2x/doc/Mesh.py +++ b/source/blender/python/api2_2x/doc/Mesh.py @@ -112,6 +112,11 @@ Example:: already associated with a group, else it does nothing.\n - REPLACE: attempts to replace a weight with the new weight value for an already associated vertex/group, else it does nothing. +@type SelectModes: readonly dictionary. +@var SelectModes: The available edit select modes. + - VERTEX: vertex select mode. + - EDGE: edge select mode. + - FACE: face select mode. """ AssignModes = {'REPLACE':1} @@ -135,6 +140,19 @@ def New(name='Mesh'): @return: a new Blender mesh. """ +def Mode(mode=0): + """ + Get and/or set the selection modes for mesh editing. These are the modes + visible in the 3D window when a mesh is in Edit Mode. + @type mode: int + @param mode: The name of the mesh data object. See L{SelectModes} for values. + Modes can be combined. If omitted, the selection mode is not changed. + @rtype: int + @return: the current selection mode. + @note: The selection mode is an attribute of the current scene. If the + scene is changed, the selection mode may not be the same. + """ + class MCol: """ The MCol object @@ -273,9 +291,9 @@ class MVertSeq: l=[(.1,.1,.1),Vector([2,2,.5])] me.verts.extend(l) # add multiple vertices - @type coords: tuple(s) of floats or vectors + @type coords: sequences(s) of floats or vectors @param coords: coords can be - - a tuple of three floats, + - a sequence of three floats, - a 3D vector, or - a sequence (list or tuple) of either of the above. """ @@ -348,12 +366,12 @@ class MEdgeSeq: v = me.verts # get vertices if len(v) >= 6: # if there are enough vertices... me.edges.extend(v[0],v[1]) # add a single edge - l=[(v[1],v[2],v[3]),(v[0],v[2],v[4],v[5])] + l=[(v[1],v[2],v[3]),[v[0],v[2],v[4],v[5]]] me.edges.extend(l) # add multiple edges - @type vertseq: tuple(s) of MVerts + @type vertseq: sequence(s) of MVerts @param vertseq: either two to four MVerts, or sequence (list or tuple) - of tuples each containing two to four MVerts. + of sequences each containing two to four MVerts. """ def delete(edges): @@ -442,7 +460,7 @@ class MFace: colors; use L{Mesh.faceUV} and L{Mesh.vertexColors} to test. B{Note}: if a mesh has i{both} UV faces and vertex colors, the colors stored in the UV faces will be used here. - @type col: list of MCols + @type col: sequence of MCols @ivar mat: The face's index into the mesh's materials list. It is in the range [0,15]. @type mat: int @@ -520,7 +538,7 @@ class MFaceSeq: def extend(vertseq): """ Add one or more faces to the mesh. Faces which already exist in the - mesh are ignored. Tuples of two vertices are accepted, but no face + mesh are ignored. Sequences of two vertices are accepted, but no face will be created. Example:: @@ -531,12 +549,12 @@ class MFaceSeq: v = me.verts # get vertices if len(v) >= 6: # if there are enough vertices... me.faces.extend(v[1],v[2],v[3]) # add a single edge - l=[(v[0],v[1]),(v[0],v[2],v[4],v[5])] + l=[(v[0],v[1]),[v[0],v[2],v[4],v[5]]] me.faces.extend(l) # add another face - @type vertseq: tuple(s) of MVerts + @type vertseq: sequence(s) of MVerts @param vertseq: either two to four MVerts, or sequence (list or tuple) - of tuples each containing two to four MVerts. + of sequences each containing two to four MVerts. """ def delete(deledges, faces): @@ -608,6 +626,9 @@ class Mesh: be set. Furthermore, if vertexColors is already set when faceUV is set, vertexColors is cleared. This is because the vertex color information is stored with UV faces, so enabling faceUV implies enabling vertexColors. + In addition, faceUV cannot be set when the mesh has no faces defined + (this is the same behavior as the UI). Attempting to do so will throw + a RuntimeError exception. @type faceUV: bool @ivar vertexColors: The mesh contains vertex colors. See L{faceUV} for the use of vertex colors when UV-mapped texture faces are enabled. @@ -706,11 +727,11 @@ class Mesh: def findEdges(edges): """ - Quickly search for the location of an edge. - @type edges: tuple(s) of ints or MVerts + Quickly search for the location of an edges. + @type edges: sequence(s) of ints or MVerts @param edges: can be tuples of MVerts or integer indexes (B{note:} will not work with PVerts) or a sequence (list or tuple) containing two or - more tuples. + more sequences. @rtype: int, None or list @return: if an edge is found, its index is returned; otherwise None is returned. If a sequence of edges is passed, a list is returned. @@ -825,6 +846,16 @@ class Mesh: associated with the mesh's object """ + def getVertexInfluences(index): + """ + Get the bone influences for a specific vertex. + @type index: int + @param index: The index of a vertex. + @rtype: list of lists + @return: List of pairs [name, weight], where name is the bone name (string) + and weight is a float value. + """ + def smooth(): """ Flattens angle of selected faces. Experimental mesh tool. diff --git a/source/blender/python/api2_2x/doc/Object.py b/source/blender/python/api2_2x/doc/Object.py index 45d3fb9c90d..f51a31e85f2 100644 --- a/source/blender/python/api2_2x/doc/Object.py +++ b/source/blender/python/api2_2x/doc/Object.py @@ -269,6 +269,19 @@ class Object: the type Effect. """ + def insertShapeKey(): + """ + Insert a Shape Key in the current object. It applies to Objects of + the type Mesh, Lattice, or Curve. + """ + + def getPose(): + """ + Gets the current Pose of the object. + @rtype: Pose object + @return: the current pose object + """ + def clearIpo(): """ Unlinks the ipo from this object. diff --git a/source/blender/python/api2_2x/doc/Theme.py b/source/blender/python/api2_2x/doc/Theme.py index cd5ea2c3036..16bdf3f4d84 100644 --- a/source/blender/python/api2_2x/doc/Theme.py +++ b/source/blender/python/api2_2x/doc/Theme.py @@ -184,6 +184,10 @@ class ThemeSpace: @ivar face_select: theme rgba var. @ivar face_dot: theme rgba var. @ivar normal: theme rgba var. + @ivar bone_solid: theme rgba var. + @ivar bon_pose: theme rgba var. + @ivar strip: theme rgba var. + @ivar strip_select: theme rgba var. @ivar syntaxl: theme rgba var. @ivar syntaxn: theme rgba var. @ivar syntaxb: theme rgba var. diff --git a/source/blender/python/api2_2x/doc/Window.py b/source/blender/python/api2_2x/doc/Window.py index 64775654054..061ae696f6a 100644 --- a/source/blender/python/api2_2x/doc/Window.py +++ b/source/blender/python/api2_2x/doc/Window.py @@ -232,7 +232,7 @@ def GetPerspMatrix (): @return: the current matrix. """ -def EditMode(enable = -1, undo_msg = 'From script'): +def EditMode(enable = -1, undo_msg = 'From script', undo = 1): """ Get and optionally set the current edit mode status: in or out. @@ -258,6 +258,9 @@ def EditMode(enable = -1, undo_msg = 'From script'): string is used as the undo message in the Mesh->Undo History submenu in the 3d view header. Max length is 63, strings longer than that get clamped. + @param undo: don't save Undo information (only needed when exiting edit + mode). + @type undo: int @rtype: int (bool) @return: 0 if Blender is not in edit mode right now, 1 otherwise. @warn: this is an important function. NMesh operates on normal Blender diff --git a/source/blender/python/api2_2x/matrix.c b/source/blender/python/api2_2x/matrix.c index c66482eab1c..fcf0616b874 100644 --- a/source/blender/python/api2_2x/matrix.c +++ b/source/blender/python/api2_2x/matrix.c @@ -458,7 +458,7 @@ static int Matrix_ass_item(MatrixObject * self, int i, PyObject * ob) float vec[4]; PyObject *m, *f; - if(i > self->rowSize || i < 0){ + if(i >= self->rowSize || i < 0){ return EXPP_ReturnIntError(PyExc_TypeError, "matrix[attribute] = x: bad row\n"); } diff --git a/source/blender/python/api2_2x/vector.c b/source/blender/python/api2_2x/vector.c index bb862fe42f7..d9b656be61f 100644 --- a/source/blender/python/api2_2x/vector.c +++ b/source/blender/python/api2_2x/vector.c @@ -160,9 +160,9 @@ PyObject *Vector_Resize4D(VectorObject * self) self->vec = self->data.py_data; //force if(self->size == 2){ self->data.py_data[2] = 0.0f; - self->data.py_data[3] = 0.0f; + self->data.py_data[3] = 1.0f; }else if(self->size == 3){ - self->data.py_data[3] = 0.0f; + self->data.py_data[3] = 1.0f; } self->size = 4; return EXPP_incr_ret((PyObject*)self); diff --git a/source/blender/python/api2_2x/windowTheme.c b/source/blender/python/api2_2x/windowTheme.c index d07323d0ccd..4043c9e0faf 100644 --- a/source/blender/python/api2_2x/windowTheme.c +++ b/source/blender/python/api2_2x/windowTheme.c @@ -170,6 +170,10 @@ static PyObject *ThemeSpace_getAttr( BPy_ThemeSpace * self, char *name ) ELSEIF_TSP_RGBA( face_select ) ELSEIF_TSP_RGBA( face_dot ) ELSEIF_TSP_RGBA( normal ) + ELSEIF_TSP_RGBA( bone_solid ) + ELSEIF_TSP_RGBA( bone_pose ) + ELSEIF_TSP_RGBA( strip ) + ELSEIF_TSP_RGBA( strip_select ) ELSEIF_TSP_RGBA( syntaxl ) ELSEIF_TSP_RGBA( syntaxn ) ELSEIF_TSP_RGBA( syntaxb ) @@ -180,14 +184,15 @@ static PyObject *ThemeSpace_getAttr( BPy_ThemeSpace * self, char *name ) else if( !strcmp( name, "facedot_size" ) ) attrib = Py_BuildValue( "i", tsp->facedot_size ); else if( !strcmp( name, "__members__" ) ) - attrib = Py_BuildValue( "[sssssssssssssssssssssssssssssss]", "theme", + attrib = Py_BuildValue("[sssssssssssssssssssssssssssssssssss]", "theme", "back", "text", "text_hi", "header", "panel", "shade1", "shade2", "hilite", "grid", "wire", "lamp", "select", "active", "transform", "vertex", "vertex_select", "edge", "edge_select", "edge_seam", "edge_facesel", "face", "face_select", - "face_dot", "normal", + "face_dot", "normal", "bone_solid", "bone_pose", + "strip", "strip_select", "syntaxl", "syntaxn", "syntaxb", "syntaxv", "syntaxc", "vertex_size", "facedot_size" ); @@ -230,6 +235,10 @@ static int ThemeSpace_setAttr( BPy_ThemeSpace * self, char *name, ELSEIF_TSP_RGBA( face_select ) ELSEIF_TSP_RGBA( face_dot ) ELSEIF_TSP_RGBA( normal ) + ELSEIF_TSP_RGBA( bone_solid ) + ELSEIF_TSP_RGBA( bone_pose ) + ELSEIF_TSP_RGBA( strip ) + ELSEIF_TSP_RGBA( strip_select ) ELSEIF_TSP_RGBA( syntaxl ) ELSEIF_TSP_RGBA( syntaxn ) ELSEIF_TSP_RGBA( syntaxb ) |