From 32b0677d96a2cd533e585a4b59e40ae1189d40e2 Mon Sep 17 00:00:00 2001 From: Joseph Gilbert Date: Sun, 4 Apr 2004 08:34:43 +0000 Subject: [PATCH] - added support for adding/parenting bones to armatures - fixed getArmatureIpo compiling error --- source/blender/python/api2_2x/Armature.c | 172 +++++++++++++++++------ source/blender/python/api2_2x/Armature.h | 9 +- source/blender/python/api2_2x/Bone.c | 61 +++++--- source/blender/python/api2_2x/Object.c | 15 +- source/blender/python/api2_2x/Object.h | 1 + 5 files changed, 188 insertions(+), 70 deletions(-) diff --git a/source/blender/python/api2_2x/Armature.c b/source/blender/python/api2_2x/Armature.c index 6bc5bd34c54..a5b24bcada5 100644 --- a/source/blender/python/api2_2x/Armature.c +++ b/source/blender/python/api2_2x/Armature.c @@ -40,10 +40,12 @@ #include #include #include +#include #include "constant.h" #include "gen_utils.h" #include "modules.h" +#include "Types.h" /*****************************************************************************/ /* Python API function prototypes for the Armature module. */ @@ -90,6 +92,7 @@ struct PyMethodDef M_Armature_methods[] = { /*****************************************************************************/ static PyObject *Armature_getName (BPy_Armature * self); static PyObject *Armature_getBones (BPy_Armature * self); +static PyObject *Armature_addBone(BPy_Armature *self, PyObject *args); static PyObject *Armature_setName (BPy_Armature * self, PyObject * args); /* static PyObject *Armature_setBones(BPy_Armature *self, PyObject *args); */ @@ -104,6 +107,8 @@ static PyMethodDef BPy_Armature_methods[] = { "() - return Armature root bones"}, {"setName", (PyCFunction) Armature_setName, METH_VARARGS, "(str) - rename Armature"}, + {"addBone", (PyCFunction)Armature_addBone, METH_VARARGS, + "(bone)-add bone"}, /* {"setBones", (PyCFunction)Armature_setBones, METH_VARARGS, "(list of bones) - replace the whole bone list of the armature"}, */ @@ -120,6 +125,7 @@ static int Armature_setAttr (BPy_Armature * armature, char *name, static int Armature_compare (BPy_Armature * a1, BPy_Armature * a2); static PyObject *Armature_repr (BPy_Armature * armature); +static int doesBoneName_exist(char *name, bArmature* arm); /*****************************************************************************/ /* Python TypeArmature structure definition: */ /*****************************************************************************/ @@ -154,47 +160,42 @@ PyTypeObject Armature_Type = { static PyObject * M_Armature_New (PyObject * self, PyObject * args, PyObject * keywords) { - char *type_str = "Armature"; - char *name_str = "ArmatureData"; - static char *kwlist[] = { "type_str", "name_str", NULL }; - BPy_Armature *py_armature; /* for Armature Data object wrapper in Python */ - bArmature *bl_armature; /* for actual Armature Data we create in Blender */ - char buf[21]; + char *name_str = "ArmatureData"; + BPy_Armature *py_armature; /* for Armature Data object wrapper in Python */ + bArmature *bl_armature; /* for actual Armature Data we create in Blender */ + char buf[21]; - if (!PyArg_ParseTupleAndKeywords (args, keywords, "|ss", kwlist, - &type_str, &name_str)) + if (!PyArg_ParseTuple(args, "|s", &name_str)) return (EXPP_ReturnPyObjError (PyExc_AttributeError, - "expected string(s) or empty argument")); + "expected string or empty argument")); - bl_armature = add_armature (); /* first create in Blender */ - if (bl_armature) - { - /* return user count to zero because add_armature() inc'd it */ - bl_armature->id.us = 0; - /* now create the wrapper obj in Python */ - py_armature = - (BPy_Armature *) PyObject_NEW (BPy_Armature, &Armature_Type); - } + bl_armature = add_armature(); /* first create in Blender */ + + if (bl_armature){ + /* return user count to zero because add_armature() inc'd it */ + bl_armature->id.us = 0; + /* now create the wrapper obj in Python */ + py_armature = (BPy_Armature *)PyObject_NEW(BPy_Armature, &Armature_Type); + } else return (EXPP_ReturnPyObjError (PyExc_RuntimeError, - "couldn't create Armature Data in Blender")); + "couldn't create Armature Data in Blender")); if (py_armature == NULL) return (EXPP_ReturnPyObjError (PyExc_MemoryError, - "couldn't create Armature Data object")); + "couldn't create ArmaturePyObject")); /* link Python armature wrapper with Blender Armature: */ py_armature->armature = bl_armature; - if (strcmp (name_str, "ArmatureData") == 0) - return (PyObject *) py_armature; - else - { /* user gave us a name for the armature, use it */ - PyOS_snprintf (buf, sizeof (buf), "%s", name_str); - rename_id (&bl_armature->id, buf); - } + if (strcmp(name_str, "ArmatureData") == 0) + return (PyObject *)py_armature; + else { /* user gave us a name for the armature, use it */ + PyOS_snprintf(buf, sizeof(buf), "%s", name_str); + rename_id(&bl_armature->id, buf); + } - return (PyObject *) py_armature; + return (PyObject *)py_armature; } /*****************************************************************************/ @@ -340,6 +341,107 @@ Armature_getBones (BPy_Armature * self) return listbones; } +static void +unique_BoneName(char *name, bArmature* arm) +{ + char tempname[64]; + int number; + char *dot; + + if (doesBoneName_exist(name, arm)){ + /* Strip off the suffix */ + dot=strchr(name, '.'); + if (dot) + *dot=0; + + for (number = 1; number <=999; number++){ + sprintf (tempname, "%s.%03d", name, number); + if (!doesBoneName_exist(tempname, arm)){ + strcpy (name, tempname); + return; + } + } + } +} + +static int +doesBoneName_exist(char *name, bArmature* arm) +{ + Bone *parent = NULL; + Bone *child = NULL; + + for (parent = arm->bonebase.first; parent; parent = parent->next){ + if (!strcmp (name, parent->name)) + return 1; + for (child = parent->childbase.first; child; child = child->next){ + if (!strcmp (name, child->name)) + return 1; + } + } + return 0; +} + +static PyObject *Armature_addBone(BPy_Armature *self, PyObject *args) +{ + BPy_Bone* py_bone = NULL; + float M_boneObjectspace[4][4]; + float M_parentRest[4][4]; + float iM_parentRest[4][4]; + float delta[3]; + float rootHead[3]; + float rootTail[3]; + + + if (!PyArg_ParseTuple(args, "O!", &Bone_Type, &py_bone)) + return (EXPP_ReturnPyObjError (PyExc_TypeError, + "expected bone object argument (or nothing)")); + + if(py_bone != NULL) + if(!py_bone->bone) + return (EXPP_ReturnPyObjError (PyExc_TypeError, "bone contains no data!")); + + //make sure the name is unique for this armature + unique_BoneName(py_bone->bone->name, self->armature); + + //if bone has a parent.... + if(py_bone->bone->parent){ + + //add to parent's childbase + BLI_addtail (&py_bone->bone->parent->childbase, py_bone->bone); + + //get the worldspace coords for the parent + get_objectspace_bone_matrix(py_bone->bone->parent, M_boneObjectspace, 1,0); + rootHead[0] = M_boneObjectspace[3][0]; + rootHead[1] = M_boneObjectspace[3][1]; + rootHead[2] = M_boneObjectspace[3][2]; + get_objectspace_bone_matrix(py_bone->bone->parent, M_boneObjectspace, 0,0); + rootTail[0] = M_boneObjectspace[3][0]; + rootTail[1] = M_boneObjectspace[3][1]; + rootTail[2] = M_boneObjectspace[3][2]; + + //rest matrix of parent + VecSubf (delta, rootTail, rootHead); + make_boneMatrixvr(M_parentRest, delta, py_bone->bone->parent->roll); + + // Invert the parent rest matrix + Mat4Invert (iM_parentRest, M_parentRest); + + // Get the new head and tail + VecSubf (py_bone->bone->head, py_bone->bone->head, rootTail); + VecSubf (py_bone->bone->tail, py_bone->bone->tail, rootTail); + + //transformation of local bone + Mat4MulVecfl(iM_parentRest, py_bone->bone->head); + Mat4MulVecfl(iM_parentRest, py_bone->bone->tail); + + }else //no parent.... + BLI_addtail (&self->armature->bonebase,py_bone->bone); + + precalc_bonelist_irestmats(&self->armature->bonebase); + + Py_INCREF(Py_None); + return Py_None; +} static PyObject * Armature_setName (BPy_Armature * self, PyObject * args) @@ -359,19 +461,6 @@ Armature_setName (BPy_Armature * self, PyObject * args) return Py_None; } - -#if 0 -static PyObject * -Armature_setBones (BPy_Armature * self, PyObject * args) -{ - /* TODO: Implement me! */ - printf ("ERROR: Armature_setBones NOT implemented yet!\n"); - Py_INCREF (Py_None); - return Py_None; - -} -#endif - /*****************************************************************************/ /* Function: Armature_dealloc */ /* Description: This is a callback function for the BPy_Armature type. It is */ @@ -498,6 +587,7 @@ Armature_CreatePyObject (struct bArmature * obj) return (NULL); } blen_armature->armature = obj; + return ((PyObject *) blen_armature); } diff --git a/source/blender/python/api2_2x/Armature.h b/source/blender/python/api2_2x/Armature.h index f74f9ee6661..7f74f69c9d1 100644 --- a/source/blender/python/api2_2x/Armature.h +++ b/source/blender/python/api2_2x/Armature.h @@ -39,10 +39,9 @@ /* Python BPy_Armature structure definition: */ /*****************************************************************************/ -typedef struct -{ - PyObject_HEAD bArmature * armature; -} -BPy_Armature; +typedef struct { + PyObject_HEAD + bArmature *armature; +} BPy_Armature; #endif /* EXPP_ARMATURE_H */ diff --git a/source/blender/python/api2_2x/Bone.c b/source/blender/python/api2_2x/Bone.c index b1d1ddc6446..e5484b738ed 100644 --- a/source/blender/python/api2_2x/Bone.c +++ b/source/blender/python/api2_2x/Bone.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "constant.h" #include "gen_utils.h" @@ -92,8 +93,7 @@ static PyObject *Bone_setTail (BPy_Bone * self, PyObject * args); static PyObject *Bone_setLoc (BPy_Bone * self, PyObject * args); static PyObject *Bone_setSize (BPy_Bone * self, PyObject * args); static PyObject *Bone_setQuat (BPy_Bone * self, PyObject * args); -/* static PyObject *Bone_setParent(BPy_Bone *self, PyObject *args); */ -/* static PyObject *Bone_setChildren(BPy_Bone *self, PyObject *args); */ +static PyObject *Bone_setParent(BPy_Bone *self, PyObject *args); /*****************************************************************************/ /* Python BPy_Bone methods table: */ @@ -135,12 +135,8 @@ static PyMethodDef BPy_Bone_methods[] = { "(float,float,float) - set Bone size"}, {"setQuat", (PyCFunction) Bone_setQuat, METH_VARARGS, "(float,float,float,float) - set Bone quat"}, -#if 0 - {"setParent", (PyCFunction) Bone_setParent, METH_NOARGS, + {"setParent", (PyCFunction)Bone_setParent, METH_VARARGS, "() - set the Bone parent of this one."}, - {"setChildren", (PyCFunction) Bone_setChildren, METH_NOARGS, - "() - replace the children list of the bone."}, -#endif {NULL, NULL, 0, NULL} }; @@ -184,6 +180,7 @@ PyTypeObject Bone_Type = { /* Function: M_Bone_New */ /* Python equivalent: Blender.Armature.Bone.New */ /*****************************************************************************/ + static PyObject * M_Bone_New (PyObject * self, PyObject * args, PyObject * keywords) { @@ -196,10 +193,17 @@ M_Bone_New (PyObject * self, PyObject * args, PyObject * keywords) "expected string or empty argument")); /* Create the C structure for the newq bone */ - bl_bone = (Bone *) malloc (sizeof (Bone)); + bl_bone = (Bone *) MEM_callocN(sizeof (Bone), "bone"); strncpy (bl_bone->name, name_str, sizeof (bl_bone->name)); - if (bl_bone) /* now create the wrapper obj in Python */ + bl_bone->dist=1.0; + bl_bone->weight=1.0; + bl_bone->flag=32; + bl_bone->parent = NULL; + bl_bone->roll = 0.0; + + // now create the wrapper obj in Python + if (bl_bone) py_bone = (BPy_Bone *) PyObject_NEW (BPy_Bone, &Bone_Type); else return (EXPP_ReturnPyObjError (PyExc_RuntimeError, @@ -209,16 +213,9 @@ M_Bone_New (PyObject * self, PyObject * args, PyObject * keywords) return (EXPP_ReturnPyObjError (PyExc_MemoryError, "couldn't create Bone Data object")); - py_bone->bone = bl_bone; /* link Python bone wrapper with Blender Bone */ - - if (strcmp (name_str, "BoneData") == 0) - return (PyObject *) py_bone; - else - { /* user gave us a name for the bone, use it */ - /* TODO: check that name is not already in use? */ - PyOS_snprintf (bl_bone->name, sizeof (bl_bone->name), "%s", name_str); - } - + py_bone->bone = bl_bone; // link Python bone wrapper with Blender Bone + + Py_INCREF(py_bone); return (PyObject *) py_bone; } @@ -379,7 +376,6 @@ Bone_getQuat (BPy_Bone * self) "couldn't get Bone.tail attribute")); } - static PyObject * Bone_hasParent (BPy_Bone * self) { @@ -495,7 +491,6 @@ Bone_setRoll (BPy_Bone * self, PyObject * args) return Py_None; } - static PyObject * Bone_setHead (BPy_Bone * self, PyObject * args) { @@ -636,6 +631,27 @@ Bone_setQuat (BPy_Bone * self, PyObject * args) return Py_None; } +static PyObject * +Bone_setParent(BPy_Bone *self, PyObject *args) +{ + BPy_Bone* py_bone; + + if (!self->bone) + (EXPP_ReturnPyObjError (PyExc_RuntimeError, "bone contains no data!")); + + if (!PyArg_ParseTuple(args, "O", &py_bone)) + return (EXPP_ReturnPyObjError (PyExc_TypeError, "expected bone object argument")); + + if(!py_bone->bone) + return (EXPP_ReturnPyObjError (PyExc_TypeError, "bone contains no data!")); + + //set the parent of self + self->bone->parent = py_bone->bone; + + Py_INCREF(Py_None); + return Py_None; +} + /*****************************************************************************/ /* Function: Bone_dealloc */ /* Description: This is a callback function for the BPy_Bone type. It is */ @@ -644,7 +660,8 @@ Bone_setQuat (BPy_Bone * self, PyObject * args) static void Bone_dealloc (BPy_Bone * self) { - PyObject_DEL (self); + MEM_freeN(self->bone); + PyObject_DEL (self); } /*****************************************************************************/ diff --git a/source/blender/python/api2_2x/Object.c b/source/blender/python/api2_2x/Object.c index f5514cf3350..4d2108180ed 100644 --- a/source/blender/python/api2_2x/Object.c +++ b/source/blender/python/api2_2x/Object.c @@ -649,13 +649,15 @@ static PyObject *Object_getActionIpos (BPy_Object *self) { Object *obj=self->object; PyObject *dict=PyDict_New (); + bAction *action = NULL; + bActionChannel *bone = NULL; if (obj->type==OB_ARMATURE) { if (obj->action!=0) { - bAction *action=obj->action; - bActionChannel *bone=(bActionChannel*)(action->chanbase.first); + action = obj->action; + bone = (bActionChannel*)(action->chanbase.first); // Go through the list of bones while (bone!=0) { @@ -1030,6 +1032,8 @@ static PyObject *Object_link (BPy_Object *self, PyObject *args) return (PythonReturnErrorObject (PyExc_AttributeError, "expected an object as argument")); } + if (Armature_CheckPyObject (py_data)) + data = (void *)Armature_FromPyObject (py_data); if (Camera_CheckPyObject (py_data)) data = (void *)Camera_FromPyObject (py_data); if (Lamp_CheckPyObject (py_data)) @@ -1054,6 +1058,13 @@ static PyObject *Object_link (BPy_Object *self, PyObject *args) switch (obj_id) { + case ID_AR: + if (self->object->type != OB_ARMATURE) + { + return (PythonReturnErrorObject (PyExc_AttributeError, + "The 'link' object is incompatible with the base object")); + } + break; case ID_CA: if (self->object->type != OB_CAMERA) { diff --git a/source/blender/python/api2_2x/Object.h b/source/blender/python/api2_2x/Object.h index a0127d503ec..aad0af8ba77 100644 --- a/source/blender/python/api2_2x/Object.h +++ b/source/blender/python/api2_2x/Object.h @@ -56,6 +56,7 @@ #include #include #include +#include #include "bpy_types.h" #include "gen_utils.h"