diff options
author | Joseph Gilbert <ascotan@gmail.com> | 2004-04-19 10:57:41 +0400 |
---|---|---|
committer | Joseph Gilbert <ascotan@gmail.com> | 2004-04-19 10:57:41 +0400 |
commit | a6a32cf50414b5660c802dcd9067d422aaf5537f (patch) | |
tree | caf1a009946eef9ec9c74fdb90bc43b70a29f806 /source/blender | |
parent | 713a0ceefea27ea3d0b3a18a5d21cbe65803b93c (diff) |
-NLA module added
-ability to set poses for the armatures - allows for keyframing armatures
-adds support for actions/actionchannels
-additional checking for addBone and clear parenting
-moved getActionIpos from object module to NLA module
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/python/api2_2x/Armature.c | 39 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Bone.c | 206 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Bone.h | 12 | ||||
-rw-r--r-- | source/blender/python/api2_2x/NLA.c | 468 | ||||
-rw-r--r-- | source/blender/python/api2_2x/NLA.h | 53 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Object.c | 72 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Types.c | 2 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Types.h | 1 | ||||
-rw-r--r-- | source/blender/python/api2_2x/modules.h | 3 |
9 files changed, 755 insertions, 101 deletions
diff --git a/source/blender/python/api2_2x/Armature.c b/source/blender/python/api2_2x/Armature.c index c8ae99fd67b..6a2264fe4b4 100644 --- a/source/blender/python/api2_2x/Armature.c +++ b/source/blender/python/api2_2x/Armature.c @@ -31,6 +31,7 @@ #include "Armature.h" #include "Bone.h" +#include "NLA.h" #include <stdio.h> @@ -60,18 +61,18 @@ PyObject *Armature_Init (void); /* In Python these will be written to the console when doing a */ /* Blender.Armature.__doc__ */ /*****************************************************************************/ -char M_Armature_doc[] = "The Blender Armature module\n\n\ +static char M_Armature_doc[] = "The Blender Armature module\n\n\ This module provides control over **Armature Data** objects in Blender.\n"; -char M_Armature_New_doc[] = "(name) - return a new Armature datablock of \n\ +static char M_Armature_New_doc[] = "(name) - return a new Armature datablock of \n\ optional name 'name'."; -char M_Armature_Get_doc[] = +static char M_Armature_Get_doc[] = "(name) - return the armature with the name 'name', \ returns None if not found.\n If 'name' is not specified, \ it returns a list of all armatures in the\ncurrent scene."; -char M_Armature_get_doc[] = "(name) - DEPRECATED. Use 'Get' instead. \ +static char M_Armature_get_doc[] = "(name) - DEPRECATED. Use 'Get' instead. \ return the armature with the name 'name', \ returns None if not found.\n If 'name' is not specified, \ it returns a list of all armatures in the\ncurrent scene."; @@ -179,9 +180,10 @@ M_Armature_New (PyObject * self, PyObject * args, PyObject * keywords) /* now create the wrapper obj in Python */ py_armature = (BPy_Armature *)PyObject_NEW(BPy_Armature, &Armature_Type); } - else + else{ return (EXPP_ReturnPyObjError (PyExc_RuntimeError, "couldn't create Armature Data in Blender")); + } if (py_armature == NULL) return (EXPP_ReturnPyObjError (PyExc_MemoryError, @@ -296,6 +298,7 @@ Armature_Init (void) /* Add the Bone submodule to this module */ dict = PyModule_GetDict (submodule); PyDict_SetItemString (dict, "Bone", Bone_Init ()); + PyDict_SetItemString (dict, "NLA", NLA_Init ()); return (submodule); } @@ -391,6 +394,24 @@ doesBoneName_exist(char *name, bArmature* arm) return 0; } +static int +testChildInChildbase(Bone *bone, Bone *test) +{ + Bone *child; + for(child = bone->childbase.first; child; child = child->next){ + if(child == test){ + return 1; + }else{ + if(child->childbase.first != NULL){ + if(testChildInChildbase(child, test)){ + return 1; + } + } + } + } + return 0; +} + static int testBoneInArmature(bArmature *arm, Bone *test) { @@ -399,6 +420,12 @@ testBoneInArmature(bArmature *arm, Bone *test) for(root = arm->bonebase.first; root; root = root->next){ if(root == test){ return 1; + }else{ + if(root->childbase.first != NULL){ + if(testChildInChildbase(root, test)){ + return 1; + } + } } } @@ -432,7 +459,7 @@ static PyObject *Armature_addBone(BPy_Armature *self, PyObject *args) //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, 0,0); diff --git a/source/blender/python/api2_2x/Bone.c b/source/blender/python/api2_2x/Bone.c index 4a86e0c5c5b..539d2213547 100644 --- a/source/blender/python/api2_2x/Bone.c +++ b/source/blender/python/api2_2x/Bone.c @@ -38,12 +38,17 @@ #include <BKE_library.h> #include <MEM_guardedalloc.h> #include <BLI_blenlib.h> +#include <DNA_action_types.h> +#include <BIF_poseobject.h> +#include <BKE_action.h> +#include <BSE_editaction.h> +#include <BKE_constraint.h> #include "constant.h" #include "gen_utils.h" #include "modules.h" #include "quat.h" - +#include "NLA.h" /*****************************************************************************/ /* Python API function prototypes for the Bone module. */ @@ -102,6 +107,7 @@ 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_setWeight(BPy_Bone *self, PyObject *args); +static PyObject *Bone_setPose (BPy_Bone *self, PyObject *args); /*****************************************************************************/ /* Python BPy_Bone methods table: */ @@ -157,6 +163,8 @@ static PyMethodDef BPy_Bone_methods[] = { "() - set the Bone parent of this one."}, {"setWeight", (PyCFunction)Bone_setWeight, METH_VARARGS, "() - set the Bone weight."}, + {"setPose", (PyCFunction)Bone_setPose, METH_VARARGS, + "() - set a pose for this bone at a frame."}, {NULL, NULL, 0, NULL} }; @@ -254,6 +262,10 @@ Bone_Init (void) submodule = Py_InitModule3 ("Blender.Armature.Bone", M_Bone_methods, M_Bone_doc); + PyModule_AddIntConstant(submodule, "ROT", POSE_ROT); + PyModule_AddIntConstant(submodule, "LOC", POSE_LOC); + PyModule_AddIntConstant(submodule, "SIZE", POSE_SIZE); + return (submodule); } @@ -728,7 +740,7 @@ Bone_setWeight(BPy_Bone *self, PyObject *args) float weight; if (!self->bone) - (EXPP_ReturnPyObjError (PyExc_RuntimeError, + return (EXPP_ReturnPyObjError (PyExc_RuntimeError, "couldn't get attribute from a NULL bone")); if (!PyArg_ParseTuple (args, "f", &weight)) @@ -753,7 +765,7 @@ Bone_clearParent(BPy_Bone *self) float M_boneObjectspace[4][4]; if (!self->bone) - (EXPP_ReturnPyObjError (PyExc_RuntimeError, "bone contains no data!")); + return (EXPP_ReturnPyObjError (PyExc_RuntimeError, "bone contains no data!")); if(self->bone->parent == NULL) return EXPP_incr_ret(Py_None); @@ -810,46 +822,43 @@ Bone_clearParent(BPy_Bone *self) static PyObject * Bone_clearChildren(BPy_Bone *self) { + Bone *root = NULL; Bone *child = NULL; bArmature *arm = NULL; Bone *bone = NULL; - Bone *parent = NULL; Bone *prev = NULL; Bone *next = NULL; float M_boneObjectspace[4][4]; int first; if (!self->bone) - (EXPP_ReturnPyObjError (PyExc_RuntimeError, "bone contains no data!")); + return (EXPP_ReturnPyObjError (PyExc_RuntimeError, "bone contains no data!")); if(self->bone->childbase.first == NULL) return EXPP_incr_ret(Py_None); - //get the root bone - parent = bone->parent; - - if(parent != NULL){ - while(parent->parent != NULL){ - parent = parent->parent; - } - }else{ - parent = bone; - } - - //get the armature - for (arm = G.main->armature.first; arm; arm = arm->id.next) { - for(bone = arm->bonebase.first; bone; bone = bone->next){ - if(parent == bone){ - //we found the correct armature - goto gotArmature; - } - } - } - -gotArmature: + //is this bone a part of an armature.... + //get root bone for testing + root = self->bone->parent; + if(root != NULL){ + while (root->parent != NULL){ + root = root->parent; + } + }else{ + root = self->bone; + } + //test armatures for root bone + for(arm= G.main->armature.first; arm; arm = arm->id.next){ + for(bone = arm->bonebase.first; bone; bone = bone->next){ + if(bone == root) + break; + } + if(bone == root) + break; + } if(arm == NULL) - (EXPP_ReturnPyObjError (PyExc_RuntimeError, "couldn't find armature that contains this bone")); + return (EXPP_ReturnPyObjError (PyExc_RuntimeError, "couldn't find armature that contains this bone")); //now get rid of the parent transformation get_objectspace_bone_matrix(self->bone, M_boneObjectspace, 0,0); @@ -888,7 +897,7 @@ static PyObject * Bone_hide(BPy_Bone *self) { if (!self->bone) - (EXPP_ReturnPyObjError (PyExc_RuntimeError, "bone contains no data!")); + return (EXPP_ReturnPyObjError (PyExc_RuntimeError, "bone contains no data!")); if(!(self->bone->flag & BONE_HIDDEN)) self->bone->flag |= BONE_HIDDEN; @@ -902,7 +911,7 @@ static PyObject * Bone_unhide(BPy_Bone *self) { if (!self->bone) - (EXPP_ReturnPyObjError (PyExc_RuntimeError, "bone contains no data!")); + return (EXPP_ReturnPyObjError (PyExc_RuntimeError, "bone contains no data!")); if(self->bone->flag & BONE_HIDDEN) self->bone->flag &= ~BONE_HIDDEN; @@ -912,7 +921,144 @@ Bone_unhide(BPy_Bone *self) } +static PyObject * +Bone_setPose (BPy_Bone *self, PyObject *args) +{ + Bone *root = NULL; + bPoseChannel *chan = NULL; + bPoseChannel *setChan = NULL; + bPoseChannel *test = NULL; + Object *object =NULL; + bArmature *arm = NULL; + Bone *bone = NULL; + PyObject *flaglist = NULL; + PyObject *item = NULL; + BPy_Action *py_action = NULL; + int x; + int flagValue = 0; + int makeCurve = 1; + + if (!PyArg_ParseTuple (args, "O!|O!", &PyList_Type, &flaglist, &Action_Type, &py_action)) + return (EXPP_ReturnPyObjError (PyExc_AttributeError, + "expected list of flags and optional action")); + + for(x = 0; x < PyList_Size(flaglist); x++){ + item = PyList_GetItem(flaglist, x); + if(PyInt_Check(item)){ + flagValue |= PyInt_AsLong(item); + }else{ + return (EXPP_ReturnPyObjError (PyExc_AttributeError, + "expected list of flags (ints)")); + } + } + + //is this bone a part of an armature.... + //get root bone for testing + root = self->bone->parent; + if(root != NULL){ + while (root->parent != NULL){ + root = root->parent; + } + }else{ + root = self->bone; + } + //test armatures for root bone + for(arm= G.main->armature.first; arm; arm = arm->id.next){ + for(bone = arm->bonebase.first; bone; bone = bone->next){ + if(bone == root) + break; + } + if(bone == root) + break; + } + if(arm == NULL) + return (EXPP_ReturnPyObjError (PyExc_RuntimeError, + "bone must belong to an armature to set it's pose!")); + + //find if armature is object linked.... + for(object = G.main->object.first; object; object = object->id.next){ + if(object->data == arm){ + break; + } + } + + if(object == NULL) + return (EXPP_ReturnPyObjError (PyExc_RuntimeError, + "armature must be linked to an object to set a pose!")); + + //set the active action as this one + if(py_action !=NULL){ + if(py_action->action != NULL){ + object->action = py_action->action; + } + } + + //if object doesn't have a pose create one + if (!object->pose) + object->pose = MEM_callocN(sizeof(bPose), "Pose"); + + //if bone does have a channel create one + verify_pose_channel(object->pose, self->bone->name); + + //create temp Pose Channel + chan = MEM_callocN(sizeof(bPoseChannel), "PoseChannel"); + //set the variables for this pose + memcpy (chan->loc, self->bone->loc, sizeof (chan->loc)); + memcpy (chan->quat, self->bone->quat, sizeof (chan->quat)); + memcpy (chan->size, self->bone->size, sizeof (chan->size)); + strcpy (chan->name, self->bone->name); + chan->flag |= flagValue; + + //set it to the channel + setChan = set_pose_channel(object->pose, chan); + + //frees unlinked pose/bone channels from object + collect_pose_garbage(object); + + //create an action if one not already assigned to object + if (!py_action && !object->action){ + object->action = (bAction*)add_empty_action(); + object->ipowin= ID_AC; + }else{ + //test if posechannel is already in action + for(test = object->action->chanbase.first; test; test = test->next){ + if(test == setChan) + makeCurve = 0; //already there + } + } + + //set posekey flag + filter_pose_keys (); + + //set action keys + if (setChan->flag & POSE_ROT){ + set_action_key(object->action, setChan, AC_QUAT_X, makeCurve); + set_action_key(object->action, setChan, AC_QUAT_Y, makeCurve); + set_action_key(object->action, setChan, AC_QUAT_Z, makeCurve); + set_action_key(object->action, setChan, AC_QUAT_W, makeCurve); + } + if (setChan->flag & POSE_SIZE){ + set_action_key(object->action, setChan, AC_SIZE_X, makeCurve); + set_action_key(object->action, setChan, AC_SIZE_Y, makeCurve); + set_action_key(object->action, setChan, AC_SIZE_Z, makeCurve); + } + if (setChan->flag & POSE_LOC){ + set_action_key(object->action, setChan, AC_LOC_X, makeCurve); + set_action_key(object->action, setChan, AC_LOC_Y, makeCurve); + set_action_key(object->action, setChan, AC_LOC_Z, makeCurve); + } + + //rebuild ipos + remake_action_ipos(object->action); + + //rebuild displists + rebuild_all_armature_displists(); + + Py_INCREF(Py_None); + return Py_None; +} + /*****************************************************************************/ /* Function: Bone_dealloc */ /* Description: This is a callback function for the BPy_Bone type. It is */ diff --git a/source/blender/python/api2_2x/Bone.h b/source/blender/python/api2_2x/Bone.h index 84c2b5e88e5..57ebb398104 100644 --- a/source/blender/python/api2_2x/Bone.h +++ b/source/blender/python/api2_2x/Bone.h @@ -33,20 +33,16 @@ #define EXPP_BONE_H #include <Python.h> - #include <DNA_armature_types.h> /** Bone module initialization function. */ PyObject *Bone_Init (void); - /** Python BPy_Bone structure definition. */ -typedef struct -{ - PyObject_HEAD Bone *bone; -} -BPy_Bone; - +typedef struct{ + PyObject_HEAD + Bone *bone; +}BPy_Bone; PyObject *Bone_CreatePyObject (struct Bone *obj); int Bone_CheckPyObject (PyObject * py_obj); diff --git a/source/blender/python/api2_2x/NLA.c b/source/blender/python/api2_2x/NLA.c new file mode 100644 index 00000000000..9ae6bd66bbc --- /dev/null +++ b/source/blender/python/api2_2x/NLA.c @@ -0,0 +1,468 @@ +/* + * + * ***** 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. + * + * This is a new part of Blender. + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#include "NLA.h" +#include "Object.h" +#include <BKE_action.h> +#include <BKE_global.h> +#include <BKE_main.h> +#include "Types.h" + +/*****************************************************************************/ +/* Python API function prototypes for the NLA module. */ +/*****************************************************************************/ +static PyObject *M_NLA_NewAction (PyObject * self, PyObject * args); +static PyObject *M_NLA_CopyAction (PyObject * self, PyObject * args); +static PyObject *M_NLA_GetActions(PyObject* self); + +/*****************************************************************************/ +/* The following string definitions are used for documentation strings. */ +/* In Python these will be written to the console when doing a */ +/* Blender.Armature.NLA.__doc__ */ +/*****************************************************************************/ +char M_NLA_doc[] = "The Blender NLA module -This module provides control over Armature keyframing in Blender."; +char M_NLA_NewAction_doc[] = "(name) - Create new action for linking to an object."; +char M_NLA_CopyAction_doc[] = "(name) - Copy action and return copy."; +char M_NLA_GetActions_doc[] = "(name) - Returns a dictionary of actions."; + +/*****************************************************************************/ +/* Python method structure definition for Blender.Armature.NLA module: */ +/*****************************************************************************/ +struct PyMethodDef M_NLA_methods[] = { + {"NewAction", (PyCFunction) M_NLA_NewAction, METH_VARARGS, + M_NLA_NewAction_doc}, + {"CopyAction", (PyCFunction) M_NLA_CopyAction, METH_VARARGS, + M_NLA_CopyAction_doc}, + {"GetActions", (PyCFunction) M_NLA_GetActions, METH_NOARGS, + M_NLA_GetActions_doc}, + {NULL, NULL, 0, NULL} +}; +/*****************************************************************************/ +/* Python BPy_Action methods declarations: */ +/*****************************************************************************/ +static PyObject *Action_getName (BPy_Action * self); +static PyObject *Action_setName (BPy_Action * self, PyObject * args); +static PyObject *Action_setActive (BPy_Action * self, PyObject * args); +static PyObject *Action_getChannelIpo(BPy_Action * self, PyObject * args); +static PyObject *Action_removeChannel(BPy_Action * self, PyObject * args); +static PyObject *Action_getAllChannelIpos(BPy_Action*self); + +/*****************************************************************************/ +/* Python BPy_Action methods table: */ +/*****************************************************************************/ +static PyMethodDef BPy_Action_methods[] = { + /* name, method, flags, doc */ + {"getName", (PyCFunction) Action_getName, METH_NOARGS, + "() - return Action name"}, + {"setName", (PyCFunction) Action_setName, METH_VARARGS, + "(str) - rename Action"}, + {"setActive", (PyCFunction) Action_setActive, METH_VARARGS, + "(str) -set this action as the active action for an object"}, + {"getChannelIpo", (PyCFunction) Action_getChannelIpo, METH_VARARGS, + "(str) -get the Ipo from a named action channel in this action"}, + {"removeChannel", (PyCFunction) Action_removeChannel, METH_VARARGS, + "(str) -remove the channel from the action"}, + {"getAllChannelIpos", (PyCFunction)Action_getAllChannelIpos, METH_NOARGS, + "() - Return a dict of (name:ipo)-keys containing each channel in the object's action"}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python TypeAction callback function prototypes: */ +/*****************************************************************************/ +static void Action_dealloc (BPy_Action * bone); +static PyObject *Action_getAttr (BPy_Action * bone, char *name); +static int Action_setAttr (BPy_Action * bone, char *name, PyObject * v); +static PyObject *Action_repr (BPy_Action * bone); + +/*****************************************************************************/ +/* Python TypeAction structure definition: */ +/*****************************************************************************/ +PyTypeObject Action_Type = { + PyObject_HEAD_INIT (NULL) 0, /* ob_size */ + "Blender Action", /* tp_name */ + sizeof (BPy_Action), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor) Action_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + (getattrfunc) Action_getAttr, /* tp_getattr */ + (setattrfunc) Action_setAttr, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc) Action_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_as_hash */ + 0, 0, 0, 0, 0, 0, + 0, /* tp_doc */ + 0, 0, 0, 0, 0, 0, + BPy_Action_methods, /* tp_methods */ + 0, /* tp_members */ +}; + +//------------------------------------------------------------------------------------------------------------------------------- +static PyObject * +M_NLA_NewAction (PyObject * self, PyObject * args) +{ + char *name_str = "DefaultAction"; + BPy_Action *py_action = NULL; /* for Action Data object wrapper in Python */ + bAction *bl_action = NULL; /* for actual Action Data we create in Blender */ + + if (!PyArg_ParseTuple (args, "|s", &name_str)){ + EXPP_ReturnPyObjError (PyExc_AttributeError, + "expected string or nothing"); + return NULL; + } + + //Create new action globally + bl_action = alloc_libblock(&G.main->action, ID_AC, name_str); + bl_action->id.flag |= LIB_FAKEUSER; + bl_action->id.us++; + + // now create the wrapper obj in Python + if (bl_action) + py_action = (BPy_Action *) PyObject_NEW (BPy_Action, &Action_Type); + else{ + EXPP_ReturnPyObjError (PyExc_RuntimeError, + "couldn't create Action Data in Blender"); + return NULL; + } + + if (py_action == NULL){ + EXPP_ReturnPyObjError (PyExc_MemoryError, + "couldn't create Action Data object"); + return NULL; + } + + py_action->action = bl_action; // link Python action wrapper with Blender Action + + Py_INCREF(py_action); + return (PyObject *) py_action; +} + +static PyObject * +M_NLA_CopyAction(PyObject* self, PyObject * args) +{ + BPy_Action *py_action = NULL; + bAction *copyAction = NULL; + + if (!PyArg_ParseTuple (args, "O!", &Action_Type, &py_action)){ + EXPP_ReturnPyObjError (PyExc_AttributeError, + "expected python action type"); + return NULL; + } + copyAction = copy_action(py_action->action); + return Action_CreatePyObject (copyAction); +} + +static PyObject * +M_NLA_GetActions(PyObject* self) +{ + PyObject *dict=PyDict_New (); + bAction *action = NULL; + + for(action = G.main->action.first; action; action = action->id.next){ + PyObject * py_action = Action_CreatePyObject (action); + if (py_action) { + // Insert dict entry using the bone name as key + if (PyDict_SetItemString (dict, action->id.name + 2, py_action) !=0) { + Py_DECREF (py_action); + Py_DECREF ( dict ); + + return EXPP_ReturnPyObjError (PyExc_RuntimeError, + "NLA_GetActions: couldn't set dict item"); + } + Py_DECREF (py_action); + } else { + Py_DECREF ( dict ); + return (PythonReturnErrorObject (PyExc_RuntimeError, + "NLA_GetActions: could not create Action object")); + } + } + return dict; +} + +/*****************************************************************************/ +/* Function: NLA_Init */ +/*****************************************************************************/ +PyObject * +NLA_Init (void) +{ + PyObject *submodule; + + Action_Type.ob_type = &PyType_Type; + + submodule = Py_InitModule3 ("Blender.Armature.NLA", + M_NLA_methods, M_NLA_doc); + + return (submodule); +} + +//------------------------------------------------------------------------------------------------------------------------------- +static PyObject * +Action_getName (BPy_Action * self) +{ + PyObject *attr = NULL; + + if (!self->action) + (EXPP_ReturnPyObjError (PyExc_RuntimeError, + "couldn't get attribute from a NULL action")); + + attr = PyString_FromString (self->action->id.name+2); + + if (attr) + return attr; + + return (EXPP_ReturnPyObjError (PyExc_RuntimeError, + "couldn't get Action.name attribute")); +} +//------------------------------------------------------------------------------------------------------------------------------- +static PyObject * +Action_setName (BPy_Action * self, PyObject * args) +{ + char *name; + + if (!self->action) + (EXPP_ReturnPyObjError (PyExc_RuntimeError, + "couldn't get attribute from a NULL action")); + + if (!PyArg_ParseTuple (args, "s", &name)) + return (EXPP_ReturnPyObjError (PyExc_AttributeError, + "expected string argument")); + + //change name + strcpy(self->action->id.name+2, name); + + Py_INCREF (Py_None); + return Py_None; +} + +static PyObject * +Action_setActive(BPy_Action * self, PyObject * args) +{ + BPy_Object *object; + + if (!self->action) + (EXPP_ReturnPyObjError (PyExc_RuntimeError, + "couldn't get attribute from a NULL action")); + + if (!PyArg_ParseTuple (args, "O!", &Object_Type, &object)) + return (EXPP_ReturnPyObjError (PyExc_AttributeError, + "expected python object argument")); + + if(object->object->type != OB_ARMATURE) { + return (EXPP_ReturnPyObjError (PyExc_AttributeError, + "object not of type armature")); + } + + //set the active action to object + object->object->action = self->action; + + Py_INCREF (Py_None); + return Py_None; +} + +static PyObject * +Action_getChannelIpo(BPy_Action * self, PyObject * args) +{ + char *chanName; + bActionChannel *chan; + + if(!PyArg_ParseTuple(args, "s", &chanName)){ + EXPP_ReturnPyObjError(PyExc_AttributeError, "string expected"); + return NULL; + } + + chan = get_named_actionchannel(self->action,chanName); + if(chan == NULL){ + EXPP_ReturnPyObjError(PyExc_AttributeError, "no channel with that name..."); + return NULL; + } + + //return IPO + return Ipo_CreatePyObject (chan->ipo); +} + +static PyObject * +Action_removeChannel(BPy_Action * self, PyObject * args) +{ + char *chanName; + bActionChannel *chan; + + if(!PyArg_ParseTuple(args, "s", &chanName)){ + EXPP_ReturnPyObjError(PyExc_AttributeError, "string expected"); + return NULL; + } + + chan = get_named_actionchannel(self->action,chanName); + if(chan == NULL){ + EXPP_ReturnPyObjError(PyExc_AttributeError, "no channel with that name..."); + return NULL; + } + + //release ipo + if(chan->ipo) + chan->ipo->id.us--; + + //remove channel + BLI_freelinkN (&self->action->chanbase, chan); + + Py_INCREF (Py_None); + return (Py_None); +} + +static PyObject *Action_getAllChannelIpos (BPy_Action *self) +{ + PyObject *dict=PyDict_New (); + bActionChannel *chan = NULL; + + for(chan = self->action->chanbase.first; chan; chan = chan->next){ + PyObject * ipo_attr = Ipo_CreatePyObject (chan->ipo); + if (ipo_attr) { + // Insert dict entry using the bone name as key + if (PyDict_SetItemString (dict, chan->name, ipo_attr) !=0) { + Py_DECREF ( ipo_attr ); + Py_DECREF ( dict ); + + return EXPP_ReturnPyObjError (PyExc_RuntimeError, + "Action_getAllChannelIpos: couldn't set dict item"); + } + Py_DECREF (ipo_attr); + } else { + Py_DECREF ( dict ); + return (PythonReturnErrorObject (PyExc_RuntimeError, + "Action_getAllChannelIpos: could not create Ipo object")); + } + } + return dict; +} + +//------------------------------------------------------------------------------------------------------------------------------- +static void +Action_dealloc (BPy_Action * self) +{ + PyObject_DEL (self); +} +//------------------------------------------------------------------------------------------------------------------------------- +static PyObject * +Action_getAttr (BPy_Action * self, char *name) +{ + PyObject *attr = Py_None; + + if (strcmp (name, "name") == 0) + attr = Action_getName (self); + else if (strcmp (name, "__members__") == 0) { + attr = Py_BuildValue ("[s]", + "name"); + } + + if (!attr) + return (EXPP_ReturnPyObjError (PyExc_MemoryError, + "couldn't create PyObject")); + + if (attr != Py_None) + return attr; /* member attribute found, return it */ + + /* not an attribute, search the methods table */ + return Py_FindMethod (BPy_Action_methods, (PyObject *) self, name); +} + +//------------------------------------------------------------------------------------------------------------------------------- +static int +Action_setAttr (BPy_Action * self, char *name, PyObject * value) +{ + PyObject *valtuple; + PyObject *error = NULL; + + valtuple = Py_BuildValue ("(O)", value); /* the set* functions expect a tuple */ + + if (!valtuple) + return EXPP_ReturnIntError (PyExc_MemoryError, + "ActionSetAttr: couldn't create tuple"); + + if (strcmp (name, "name") == 0) + error = Action_setName (self, valtuple); + else + { /* Error */ + Py_DECREF (valtuple); + + /* ... member with the given name was found */ + return (EXPP_ReturnIntError (PyExc_KeyError, "attribute not found")); + } + + Py_DECREF (valtuple); + + if (error != Py_None) + return -1; + + Py_DECREF (Py_None); /* was incref'ed by the called Action_set* function */ + return 0; /* normal exit */ +} +//------------------------------------------------------------------------------------------------------------------------------- +static PyObject * +Action_repr (BPy_Action * self) +{ + if (self->action) + return PyString_FromFormat ("[Action \"%s\"]", self->action->id.name + 2); + else + return PyString_FromString ("NULL"); +} +//------------------------------------------------------------------------------------------------------------------------------- +PyObject * +Action_CreatePyObject (struct bAction * act) +{ + BPy_Action *blen_action; + + blen_action = (BPy_Action *) PyObject_NEW (BPy_Action, &Action_Type); + + if (blen_action == NULL) + { + return (NULL); + } + blen_action->action = act; + return ((PyObject *) blen_action); +} +//------------------------------------------------------------------------------------------------------------------------------- +int +Action_CheckPyObject (PyObject * py_obj) +{ + return (py_obj->ob_type == &Action_Type); +} +//------------------------------------------------------------------------------------------------------------------------------- +struct bAction * +Action_FromPyObject (PyObject * py_obj) +{ + BPy_Action *blen_obj; + + blen_obj = (BPy_Action *) py_obj; + return (blen_obj->action); +} diff --git a/source/blender/python/api2_2x/NLA.h b/source/blender/python/api2_2x/NLA.h new file mode 100644 index 00000000000..1f19900f9a7 --- /dev/null +++ b/source/blender/python/api2_2x/NLA.h @@ -0,0 +1,53 @@ +/* + * + * ***** 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. + * + * This is a new part of Blender. + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef EXPP_NLA_H +#define EXPP_NLA_H + +#include <Python.h> +#include <DNA_action_types.h> + +/** NLA module initialization function. */ +PyObject *NLA_Init (void); + +/** Python BPy_NLA structure definition. */ +typedef struct +{ + PyObject_HEAD + bAction *action; +} +BPy_Action; + +PyObject *Action_CreatePyObject (struct bAction *action); +int Action_CheckPyObject (PyObject * py_obj); +bAction *Action_FromPyObject (PyObject * py_obj); + +#endif diff --git a/source/blender/python/api2_2x/Object.c b/source/blender/python/api2_2x/Object.c index 4d2108180ed..25364642c7a 100644 --- a/source/blender/python/api2_2x/Object.c +++ b/source/blender/python/api2_2x/Object.c @@ -34,6 +34,7 @@ */ #include "Object.h" +#include "NLA.h" /*****************************************************************************/ /* Python API function prototypes for the Blender module. */ @@ -89,7 +90,6 @@ struct PyMethodDef M_Object_methods[] = { static PyObject *Object_buildParts (BPy_Object *self); static PyObject *Object_clearIpo (BPy_Object *self); static PyObject *Object_clrParent (BPy_Object *self, PyObject *args); -static PyObject *Object_getActionIpos (BPy_Object *self); static PyObject *Object_getData (BPy_Object *self); static PyObject *Object_getDeltaLocation (BPy_Object *self); static PyObject *Object_getDrawMode (BPy_Object *self); @@ -107,6 +107,7 @@ static PyObject *Object_getTimeOffset (BPy_Object *self); static PyObject *Object_getTracked (BPy_Object *self); static PyObject *Object_getType (BPy_Object *self); static PyObject *Object_getBoundBox (BPy_Object *self); +static PyObject *Object_getAction (BPy_Object *self); static PyObject *Object_makeDisplayList (BPy_Object *self); static PyObject *Object_link (BPy_Object *self, PyObject *args); static PyObject *Object_makeParent (BPy_Object *self, PyObject *args); @@ -137,8 +138,6 @@ static PyMethodDef BPy_Object_methods[] = { "Clears parent object. Optionally specify:\n\ mode\n\t2: Keep object transform\nfast\n\t>0: Don't update scene \ hierarchy (faster)"}, - {"getActionIpos", (PyCFunction)Object_getActionIpos, METH_NOARGS, - "() - Return a dict of (name:ipo)-keys containing each channel in the object's action"}, {"getData", (PyCFunction)Object_getData, METH_NOARGS, "Returns the datablock object containing the object's data, e.g. Mesh"}, {"getDeltaLocation", (PyCFunction)Object_getDeltaLocation, METH_NOARGS, @@ -147,6 +146,8 @@ hierarchy (faster)"}, "Returns the object draw modes"}, {"getDrawType", (PyCFunction)Object_getDrawType, METH_NOARGS, "Returns the object draw type"}, + {"getAction", (PyCFunction)Object_getAction, METH_NOARGS, + "Returns the active action for this object"}, {"getEuler", (PyCFunction)Object_getEuler, METH_NOARGS, "Returns the object's rotation as Euler rotation vector\n\ (rotX, rotY, rotZ)"}, @@ -645,59 +646,6 @@ int EXPP_add_obdata(struct Object *object) return 0; } -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) { - - action = obj->action; - bone = (bActionChannel*)(action->chanbase.first); - - // Go through the list of bones - while (bone!=0) { - - // Does this bone have an ipo? - if (bone->ipo!=0) { - - PyObject *ipo_attr=Ipo_CreatePyObject (bone->ipo); - - if (ipo_attr) { - - // Insert dict entry using the bone name as key - if (PyDict_SetItemString (dict, bone->name, ipo_attr)!=0) { - Py_DECREF ( ipo_attr ); - Py_DECREF ( dict ); - - return EXPP_ReturnPyObjError (PyExc_RuntimeError, - "Object_getActionIpos: couldn't set dict item"); - } - - Py_DECREF (ipo_attr); - - } else { - - Py_DECREF ( dict ); - - return (PythonReturnErrorObject (PyExc_RuntimeError, - "Object_getActionIpos: could not create Ipo object")); - - } - } - - bone=bone->next; - } - } - } - - return dict; -} - static PyObject *Object_getData (BPy_Object *self) { @@ -791,6 +739,18 @@ static PyObject *Object_getDrawMode (BPy_Object *self) "couldn't get Object.drawMode attribute")); } +static PyObject *Object_getAction (BPy_Object *self) +{ + BPy_Action *py_action = NULL; + + if(!self->object->action){ + Py_INCREF (Py_None); + return (Py_None); + }else{ + return Action_CreatePyObject (self->object->action); + } +} + static PyObject *Object_getDrawType (BPy_Object *self) { PyObject *attr = Py_BuildValue ("b", self->object->dt); diff --git a/source/blender/python/api2_2x/Types.c b/source/blender/python/api2_2x/Types.c index 0bcf6b5afe0..3a1b95f8b59 100644 --- a/source/blender/python/api2_2x/Types.c +++ b/source/blender/python/api2_2x/Types.c @@ -48,6 +48,7 @@ PyObject *Types_Init (void) * do it now, we get an easy way to crash Blender. Maybe we'd better * have an Init function for all these internal types that more than one * module can use. We could call it after setting the Blender dictionary */ + Action_Type.ob_type = &PyType_Type; matrix_Type.ob_type = &PyType_Type; vector_Type.ob_type = &PyType_Type; euler_Type.ob_type = &PyType_Type; @@ -111,6 +112,7 @@ PyObject *Types_Init (void) PyDict_SetItemString(dict, "eulerType", (PyObject *)&euler_Type); PyDict_SetItemString(dict, "quaternionType", (PyObject *)&quaternion_Type); PyDict_SetItemString(dict, "BezTripleType", (PyObject *)&BezTriple_Type); + PyDict_SetItemString(dict, "ActionType", (PyObject *)&Action_Type); return submodule; } diff --git a/source/blender/python/api2_2x/Types.h b/source/blender/python/api2_2x/Types.h index 595f04d0383..ec812ef183c 100644 --- a/source/blender/python/api2_2x/Types.h +++ b/source/blender/python/api2_2x/Types.h @@ -50,5 +50,6 @@ extern PyTypeObject buffer_Type, rgbTuple_Type, constant_Type, BezTriple_Type; extern PyTypeObject vector_Type, matrix_Type, euler_Type, quaternion_Type; +extern PyTypeObject Action_Type; #endif /* EXPP_TYPES_H */ diff --git a/source/blender/python/api2_2x/modules.h b/source/blender/python/api2_2x/modules.h index 7905ee738e6..b761fbad2a0 100644 --- a/source/blender/python/api2_2x/modules.h +++ b/source/blender/python/api2_2x/modules.h @@ -48,6 +48,7 @@ #include <DNA_image_types.h> #include <DNA_text_types.h> #include <DNA_world_types.h> +#include <DNA_action_types.h> /*****************************************************************************/ /* Global variables */ @@ -188,6 +189,6 @@ PyObject * Window_Init (void); PyObject * Draw_Init (void); PyObject * BGL_Init (void); PyObject * Mathutils_Init (void); - +PyObject * NLA_Init (void); #endif /* EXPP_modules_h */ |