-NLA module added
authorJoseph Gilbert <ascotan@gmail.com>
Mon, 19 Apr 2004 06:57:41 +0000 (06:57 +0000)
committerJoseph Gilbert <ascotan@gmail.com>
Mon, 19 Apr 2004 06:57:41 +0000 (06:57 +0000)
-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

source/blender/python/api2_2x/Armature.c
source/blender/python/api2_2x/Bone.c
source/blender/python/api2_2x/Bone.h
source/blender/python/api2_2x/NLA.c [new file with mode: 0644]
source/blender/python/api2_2x/NLA.h [new file with mode: 0644]
source/blender/python/api2_2x/Object.c
source/blender/python/api2_2x/Types.c
source/blender/python/api2_2x/Types.h
source/blender/python/api2_2x/modules.h

index c8ae99fd67b1f4e26413c638aa32841191356248..6a2264fe4b47ced6a8b52df05c47b7cb2f547204 100644 (file)
@@ -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);
 
index 4a86e0c5c5b55b91e933213b953befbadd5cf022..539d2213547c3c13dd841035e29d7a1fddf78247 100644 (file)
 #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     */
index 84c2b5e88e57cf9a2b21d5aad199525a98e37e88..57ebb398104748f962a40f83674c491e564a9eab 100644 (file)
 #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 (file)
index 0000000..9ae6bd6
--- /dev/null
@@ -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 (file)
index 0000000..1f19900
--- /dev/null
@@ -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
index 4d2108180ed0335486c264db3759d74b14f9cb99..25364642c7afd5e687de71f42217c6aede955da1 100644 (file)
@@ -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);
index 0bcf6b5afe0a8522fc1ca20c026b44aa5464d818..3a1b95f8b5949db3431f0c7687d8c81c0850c2a7 100644 (file)
@@ -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;
 }
index 595f04d038352863ebab313be102fcb1eedaae98..ec812ef183c9f65a9830d2f2cfa72b8608810623 100644 (file)
@@ -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 */
index 7905ee738e64bdef51dd450bed0c88346eb23b08..b761fbad2a0408c1471a872ea882cc56c4fba48a 100644 (file)
@@ -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 */