[Bf-committers] First data extraction from armatures using python (patch)

Jordi Rovira i Bonet bf-committers@blender.org
Tue, 29 Apr 2003 13:28:02 +0200


This is a multi-part message in MIME format.
--------------070201000005070004020906
Content-Type: text/plain; charset=ISO-8859-15; format=flowed
Content-Transfer-Encoding: 7bit

Hello,

    Finally i've been able to generate a patch on what i've been doing 
about armatures: The current supported python api includes the following 
additions:

Blender.Armature.getRaw(string name) :
    get the armature with the given name

Mesh.getVertexInfluences(int index):
    returns a list of pairs (string bonename, float weight) with the 
vertex influences received by the vertex indicated in the index.

Blender.Armature has two properties:

    * name (string)
    * bones (list of Bone)

Bone has many properties matching the ones in the C structure:

    * head (vector 3d)
    * tail (vector 3d)
    * roll (float)
    * loc (vector 3d)
    * quat (quaternion)
    * size (vector 3d)
    * children (list of Bone)
    * parent (Bone)
    * valid (1 or 0 if wrapping a null bone)


    This is a completely provisional API. And unstable. I'm posting it 
here so i can receive flaming and some good notes on what should it be, 
so i can change it. Python masters: what do you say? I've been focusing 
mainly in QUERYING the information (despite some function can set some 
values), because it seems that the main use of this will be exporting data.
    As i don't have a full exporter yet, i don't know if i've made all 
required data accessible. But it's a beginning.
    One problem i have is that when getting the parent of a mesh, if its 
an armature, the call to "getType()" returns "25" which is the constant 
associated to the armatures, but doesn't return "Armature". And when 
trying to getData() it doen't work. I have to get the armature by 
getting the name, and then:
    Blender.Object.Get(object.parent.name).getData()
    I need to figure out how to export animations now (actions).

Attached to this file you can find a patch appliable to the CVS source 
(at least on 29 April 12:51 C.E.T). The command is

patch -p0 < armature_api.pp

from the root of the blender source. There are also 3 files to add: 
opy_armature* that should go into directory

/source/blender/bpython/intern

and Armature.py, that should go into

/intern/python/modules/Blender

to get a blender with the modifications i've been playing with.

    I did'nt know if it was possible to generate a patch which added the 
files automatically. Any hint?


(bandoler)

--------------070201000005070004020906
Content-Type: text/plain;
 name="armature_api.pp"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="armature_api.pp"

Index: intern/python/py_main.c
===================================================================
RCS file: /cvsroot/bf-blender/blender/intern/python/py_main.c,v
retrieving revision 1.3
diff -B -b -c -r1.3 py_main.c
*** intern/python/py_main.c	25 Nov 2002 09:53:06 -0000	1.3
--- intern/python/py_main.c	29 Apr 2003 10:22:56 -0000
***************
*** 2062,2067 ****
--- 2062,2071 ----
  		}
  	    }
    	  break;
+   	case OB_ARMATURE:
+ 	  object->data = PyString_FromString(((bArmature*) obj->data)->id.name+2);
+ 	  object->type = PyString_FromString("Armature");
+   	  break;
    	case OB_CURVE:
    	  printf("Curve\n");
    	  break;
Index: intern/python/modules/Makefile.am
===================================================================
RCS file: /cvsroot/bf-blender/blender/intern/python/modules/Makefile.am,v
retrieving revision 1.4
diff -B -b -c -r1.4 Makefile.am
*** intern/python/modules/Makefile.am	12 Apr 2003 17:20:55 -0000	1.4
--- intern/python/modules/Makefile.am	29 Apr 2003 10:22:56 -0000
***************
*** 12,17 ****
--- 12,18 ----
  	Blender/Material.py \
  	Blender/Mesh.py \
  	Blender/NMesh.py \
+ 	Blender/Armature.py \
  	Blender/Object.py \
  	Blender/Scene.py \
  	Blender/Text.py \
Index: intern/python/modules/Blender/Object.py
===================================================================
RCS file: /cvsroot/bf-blender/blender/intern/python/modules/Blender/Object.py,v
retrieving revision 1.3
diff -B -b -c -r1.3 Object.py
*** intern/python/modules/Blender/Object.py	6 Feb 2003 03:30:22 -0000	1.3
--- intern/python/modules/Blender/Object.py	29 Apr 2003 10:22:56 -0000
***************
*** 276,293 ****
  
  	_getters = {}	 
  
! 	from Blender import Mesh, Camera, Lamp
  
  	t = _Object.Types
  	Types = {"Camera"   : t.CAMERA,
  			 "Empty"    : t.EMPTY,
  			 "Lamp"     : t.LAMP,
  			 "Mesh"     : t.MESH,
  			} 
  
  	# create lookup table for data wrappers
  	_dataWrappers = range(max(Types.values()) + 1)
  	_dataWrappers[t.MESH] = ("Mesh", Mesh.rawMesh)
  	_dataWrappers[t.CAMERA] = ("Camera", Camera.Camera)
  	_dataWrappers[t.LAMP] = ("Lamp", Lamp.Lamp)
  	_dataWrappers[t.EMPTY] = ("Empty", _Empty_nodata)
--- 276,295 ----
  
  	_getters = {}	 
  
! 	from Blender import Mesh, Camera, Lamp, Armature
  
  	t = _Object.Types
  	Types = {"Camera"   : t.CAMERA,
  			 "Empty"    : t.EMPTY,
  			 "Lamp"     : t.LAMP,
  			 "Mesh"     : t.MESH,
+ 			 "Armature" : t.ARMATURE,
  			} 
  
  	# create lookup table for data wrappers
  	_dataWrappers = range(max(Types.values()) + 1)
  	_dataWrappers[t.MESH] = ("Mesh", Mesh.rawMesh)
+ 	_dataWrappers[t.ARMATURE] = ("Armature", Armature.Armature)
  	_dataWrappers[t.CAMERA] = ("Camera", Camera.Camera)
  	_dataWrappers[t.LAMP] = ("Lamp", Lamp.Lamp)
  	_dataWrappers[t.EMPTY] = ("Empty", _Empty_nodata)
Index: intern/python/modules/Blender/__init__.py
===================================================================
RCS file: /cvsroot/bf-blender/blender/intern/python/modules/Blender/__init__.py,v
retrieving revision 1.4
diff -B -b -c -r1.4 __init__.py
*** intern/python/modules/Blender/__init__.py	6 Feb 2003 03:30:22 -0000	1.4
--- intern/python/modules/Blender/__init__.py	29 Apr 2003 10:22:56 -0000
***************
*** 2,8 ****
  # The Blender main module wrapper
  # (c) 06/2001, NaN // strubi@blender.nl
  
! __all__ = ["Object", "Image", "NMesh", "Window", "Mesh", "sys",
             "Lamp", "Scene", "Draw", "Camera", "Material", "Types", "Ipo",
             "BGL"]
  
--- 2,8 ----
  # The Blender main module wrapper
  # (c) 06/2001, NaN // strubi@blender.nl
  
! __all__ = ["Object", "Image", "NMesh", "Armature", "Window", "Mesh", "sys",
             "Lamp", "Scene", "Draw", "Camera", "Material", "Types", "Ipo",
             "BGL"]
  
***************
*** 14,20 ****
  bylink = _Blender.bylink
  
  import Object, Image, Mesh, Window, sys, Lamp, Scene, Draw, Camera
! import Material, NMesh, BGL, Types, Ipo, Text
  
  deg = lambda x: 0.0174532925199 * x  # conversion from degrees to radians
  
--- 14,20 ----
  bylink = _Blender.bylink
  
  import Object, Image, Mesh, Window, sys, Lamp, Scene, Draw, Camera
! import Material, NMesh, Armature, BGL, Types, Ipo, Text
  
  deg = lambda x: 0.0174532925199 * x  # conversion from degrees to radians
  
Index: source/blender/bpython/Makefile.am
===================================================================
RCS file: /cvsroot/bf-blender/blender/source/blender/bpython/Makefile.am,v
retrieving revision 1.8
diff -B -b -c -r1.8 Makefile.am
*** source/blender/bpython/Makefile.am	12 Apr 2003 17:21:00 -0000	1.8
--- source/blender/bpython/Makefile.am	29 Apr 2003 10:22:58 -0000
***************
*** 38,43 ****
--- 38,45 ----
  	intern/opy_matrix.c \
  	intern/opy_nmesh.c \
  	intern/opy_nmesh.h \
+ 	intern/opy_armature.c \
+ 	intern/opy_armature.h \
  	intern/opy_vector.c \
  	intern/opy_vector.h \
  	intern/opy_window.c
Index: source/blender/bpython/intern/BPY_main.h
===================================================================
RCS file: /cvsroot/bf-blender/blender/source/blender/bpython/intern/BPY_main.h,v
retrieving revision 1.5
diff -B -b -c -r1.5 BPY_main.h
*** source/blender/bpython/intern/BPY_main.h	27 Dec 2002 13:10:15 -0000	1.5
--- source/blender/bpython/intern/BPY_main.h	29 Apr 2003 10:22:58 -0000
***************
*** 51,56 ****
--- 51,57 ----
  #include "BKE_text.h"
  #include "BKE_displist.h"
  #include "BKE_mesh.h"
+ #include "BKE_armature.h"
  #include "BKE_material.h"
  #include "BKE_object.h"
  #include "BKE_screen.h"
Index: source/blender/bpython/intern/BPY_modules.h
===================================================================
RCS file: /cvsroot/bf-blender/blender/source/blender/bpython/intern/BPY_modules.h,v
retrieving revision 1.6
diff -B -b -c -r1.6 BPY_modules.h
*** source/blender/bpython/intern/BPY_modules.h	27 Dec 2002 13:10:15 -0000	1.6
--- source/blender/bpython/intern/BPY_modules.h	29 Apr 2003 10:22:58 -0000
***************
*** 33,38 ****
--- 33,39 ----
  
  extern PyObject *init_blender(void);
  extern PyObject *init_py_nmesh(void);
+ extern PyObject *init_py_armature(void);
  extern PyObject *init_py_draw(void);
  extern PyObject *init_py_bgl(void);
  extern PyObject *initWindow(void);
Index: source/blender/bpython/intern/BPY_object.c
===================================================================
RCS file: /cvsroot/bf-blender/blender/source/blender/bpython/intern/BPY_object.c,v
retrieving revision 1.3
diff -B -b -c -r1.3 BPY_object.c
*** source/blender/bpython/intern/BPY_object.c	25 Nov 2002 12:01:57 -0000	1.3
--- source/blender/bpython/intern/BPY_object.c	29 Apr 2003 10:22:58 -0000
***************
*** 480,485 ****
--- 480,486 ----
  	PyDict_SetItemString(dict, "Types", d);
  	BPY_ADDCONST(d, EMPTY);
  	BPY_ADDCONST(d, MESH);
+ 	BPY_ADDCONST(d, ARMATURE);
  	BPY_ADDCONST(d, LAMP);
  	BPY_ADDCONST(d, CAMERA);
  
Index: source/blender/bpython/intern/b_interface.h
===================================================================
RCS file: /cvsroot/bf-blender/blender/source/blender/bpython/intern/b_interface.h,v
retrieving revision 1.5
diff -B -b -c -r1.5 b_interface.h
*** source/blender/bpython/intern/b_interface.h	27 Dec 2002 13:10:15 -0000	1.5
--- source/blender/bpython/intern/b_interface.h	29 Apr 2003 10:22:58 -0000
***************
*** 101,106 ****
--- 101,107 ----
  #define getSceneList()  _GETMAINLIST(scene)
  #define getObjectList()  _GETMAINLIST(object)
  #define getMeshList()  _GETMAINLIST(mesh)
+ #define getArmatureList()  _GETMAINLIST(armature)
  #define getMaterialList()  _GETMAINLIST(mat)
  #define getCameraList()  _GETMAINLIST(camera)
  #define getLampList()  _GETMAINLIST(lamp)
Index: source/blender/bpython/intern/opy_blender.c
===================================================================
RCS file: /cvsroot/bf-blender/blender/source/blender/bpython/intern/opy_blender.c,v
retrieving revision 1.3
diff -B -b -c -r1.3 opy_blender.c
*** source/blender/bpython/intern/opy_blender.c	25 Nov 2002 12:01:57 -0000	1.3
--- source/blender/bpython/intern/opy_blender.c	29 Apr 2003 10:22:58 -0000
***************
*** 324,329 ****
--- 324,330 ----
  	PyDict_SetItemString(dict, "Image",	INITMODULE(Image)());
  	PyDict_SetItemString(dict, "Window",INITMODULE(Window)());
  	PyDict_SetItemString(dict, "NMesh", init_py_nmesh());
+ 	PyDict_SetItemString(dict, "Armature", init_py_armature());
  	PyDict_SetItemString(dict, "Draw",	init_py_draw());
  	PyDict_SetItemString(dict, "BGL",	init_py_bgl());
  #ifdef EXPERIMENTAL
Index: source/blender/bpython/intern/opy_datablock.c
===================================================================
RCS file: /cvsroot/bf-blender/blender/source/blender/bpython/intern/opy_datablock.c,v
retrieving revision 1.3
diff -B -b -c -r1.3 opy_datablock.c
*** source/blender/bpython/intern/opy_datablock.c	25 Nov 2002 12:01:57 -0000	1.3
--- source/blender/bpython/intern/opy_datablock.c	29 Apr 2003 10:22:58 -0000
***************
*** 88,93 ****
--- 88,94 ----
  
  #include "opy_datablock.h"
  #include "opy_nmesh.h"
+ #include "opy_armature.h"
  
  #include "opy_vector.h" /* matrix datatypes */
  
***************
*** 1100,1105 ****
--- 1101,1115 ----
  		 */
  		 
  //		return newNCurveObject(data);			
+ 
+ 	} else if (idn==ID_AR) {
+ 	  return newArmature(data);
+ 	  /*		newb= PyObject_NEW(DataBlock, &DataBlock_Type);
+ 		newb->type= "Armature";
+ 		newb->type_list= getArmatureList();
+ 		newb->properties= Armature_Properties;
+ 	  */
+ 	  
  
  	} else if (idn==ID_LA) {
  		newb= PyObject_NEW(DataBlock, &DataBlock_Type);
Index: source/blender/bpython/intern/opy_nmesh.c
===================================================================
RCS file: /cvsroot/bf-blender/blender/source/blender/bpython/intern/opy_nmesh.c,v
retrieving revision 1.4
diff -B -b -c -r1.4 opy_nmesh.c
*** source/blender/bpython/intern/opy_nmesh.c	20 Dec 2002 02:18:57 -0000	1.4
--- source/blender/bpython/intern/opy_nmesh.c	29 Apr 2003 10:22:58 -0000
***************
*** 38,43 ****
--- 38,45 ----
  #include "BPY_tools.h"
  #include "BPY_main.h"
  
+ #include "DNA_armature_types.h"
+ 
  #include "opy_datablock.h"
  #include "opy_nmesh.h"
  
***************
*** 746,751 ****
--- 748,808 ----
  }
  
  
+ 
+ /** Python documentation string for the function getVertexInfluence. */
+ static char NMesh_getVertexInfluences_doc[] = "Return a list of the influences of bones in the vertex specified by index. The list contains pairs with the bone name and the weight.";
+ 
+ /** Implementation of the python method getVertexInfluence for an NMesh object.
+  * This method returns a list of pairs (string,float) with bone nemaes and influences that this vertex receives.
+  * @author Jordi Rovira i Bonet
+  */
+ static PyObject *NMesh_getVertexInfluences(PyObject *self, PyObject *args)
+ {
+   // Get a reference to the mesh object wrapped in here.
+   Mesh *me= ((NMesh*)self)->mesh;
+ 
+   // Parse the parameters: only on integer (vertex index)
+   int index;
+   BPY_TRY(PyArg_ParseTuple(args, "i", &index));
+ 
+   // Declare the list to return
+   PyObject* influence_list = NULL;
+ 
+   // Proceed only if we have vertex deformation information and index is valid
+   if (me->dvert)
+     if ((index>=0) && (index<me->totvert))
+       {
+ 	// Number of bones influencig the vertex
+ 	int totinfluences=me->dvert[index].totweight;
+ 	
+ 	// Build the list only with weights and names of the influent bones
+ 	influence_list = PyList_New(totinfluences);
+ 
+ 	//Get the reference of the first wwight structure
+ 	MDeformWeight *sweight = me->dvert[index].dw;      
+ 	int i;
+ 	for (i=0; i<totinfluences; i++) {
+ 
+ 	  // Some check that should always be true
+ 	  assert(sweight->data);
+ 
+ 	  //Add the weight and the name of the bone, which is used to identify it
+ 	  PyList_SetItem(influence_list, i, Py_BuildValue("[sf]", sweight->data->name, sweight->weight));
+ 
+ 	  //Next weight
+ 	  sweight++;
+ 	}
+       }
+     else influence_list = PyList_New(0);
+   else influence_list = PyList_New(0);
+ 
+   // Return the list. !QUESTION! Should i reincrement the number of references like i'm doing?
+   return BPY_incr_ret(influence_list);
+ 
+ }
+ 
+ 
+ 
  static char NMesh_update_doc[] = "updates the Mesh";
  static PyObject *NMesh_update(PyObject *self, PyObject *args)
  {
***************
*** 841,846 ****
--- 898,904 ----
  	MethodDef(getActiveFace),
  	MethodDef(getSelectedFaces),
  	MethodDef(update),
+ 	MethodDef(getVertexInfluences),
  #ifdef EXPERIMENTAL	
  	MethodDef(asMesh),
  #endif	

--------------070201000005070004020906
Content-Type: text/x-csrc;
 name="opy_armature.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="opy_armature.c"

/*  python.c      MIXED MODEL
 * 
 *  june 99
 * $Id: opy_armature.c,v 1.4 2002/12/20 02:18:57 mein Exp $
 *
 * ***** 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.
 *
 *
 * Contributor(s): none yet.
 *
 * ***** END GPL/BL DUAL LICENSE BLOCK *****
 */

#include "Python.h"
#include "BPY_macros.h"
#include "b_interface.h"
#include "BPY_tools.h"
#include "BPY_main.h"

#include "opy_datablock.h"
#include "opy_armature.h"

#include "MEM_guardedalloc.h"

#include "BKE_armature.h"
#include "BKE_mesh.h"
#include "BKE_main.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_displist.h"
#include "BKE_screen.h"
#include "BKE_object.h"
#include "BPY_objtypes.h"
#include "BLI_blenlib.h"
#include "BIF_space.h"

#include "opy_vector.h"

#include "b_interface.h"

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

/* PROTOS */

static int unlink_existingArmaturedata(bArmature *armature);
void initArmature(void);
PyObject *init_py_armature(void);
int BPY_check_sequence_consistency(PyObject *seq, PyTypeObject *against);
static wBone *wbone_from_data(Bone* rawbone);

/* TYPE OBJECTS */

PyTypeObject Armature_Type;
PyTypeObject Bone_Type;

/* DEFINES */


/* GLOBALS */

static PyObject *g_armaturemodule = NULL;


/*****************************/
/* Armature Bone Object      */
/*****************************/

static void Bone_dealloc(PyObject *self) {
	PyMem_DEL(self);
}

static wBone *newbone (Bone* rawbone, wBone* parent) {
  // Create wrapper object
  wBone *mc= (wBone *) PyObject_NEW(wBone, &Bone_Type);

  // Set reference to real blender bone
  mc->bone = rawbone;

  // check that we are really wrapping a bone
  if (rawbone)
    {
      // Set parent, or wrap null in no parent
      if (parent) mc->parent = parent;
      else mc->parent = newbone(NULL,NULL);
      
      // Count child bones
      int totbones = 0;
      Bone* current = rawbone->childbase.first;
      for (;current; current=current->next) totbones++;

      // Build the list of children recursively
      mc->children= PyList_New(totbones);
      Bone *mbone = rawbone->childbase.first;      
      int i;
      for (i=0; i<totbones; i++) {
	assert(mbone);
	PyList_SetItem(mc->children, i, (PyObject *) newbone(mbone,mc));
	mbone = mbone->next;
      }
    }
  else
    {
      // We are null, so parent doesn't matter. Set NULL too.
      mc->parent = NULL;
    }
  
  return mc;	
}

PyObject *Bone_repr(wBone *self) 
{
	static char s[256];
	if (self->bone)
	  sprintf (s, "[Bone - name<%s>, head<%f, %f, %f>, tail<%f,%f,%f>, roll<%f>]", self->bone->name, self->bone->head[0], self->bone->head[1], self->bone->head[2], self->bone->tail[0], self->bone->tail[1], self->bone->tail[2]);
	else sprintf(s,"[Bone - NULL]");
	return Py_BuildValue("s", s);
}

static PyObject *Bone_getattr(PyObject *self, char *name) {
	wBone *mc= (wBone *) self;

	if (mc->bone)
	  {
	    if (strcmp(name, "roll")==0) return Py_BuildValue("f", mc->bone->roll);
	    else if (strcmp(name, "valid")==0) return Py_BuildValue("i", 1);
	    else if (strcmp(name, "name")==0) return Py_BuildValue("s", mc->bone->name);
	    else if (strcmp(name, "head")==0) return Py_BuildValue("[fff]", mc->bone->head[0],mc->bone->head[1],mc->bone->head[2]);
	    else if (strcmp(name, "tail")==0) return Py_BuildValue("[fff]", mc->bone->tail[0],mc->bone->tail[1],mc->bone->tail[2]);
	    else if (strcmp(name, "loc")==0) return Py_BuildValue("[fff]", mc->bone->loc[0], mc->bone->loc[1], mc->bone->loc[2]);
	    else if (strcmp(name, "size")==0) return Py_BuildValue("[fff]", mc->bone->size[0], mc->bone->size[1], mc->bone->size[2]);
	    else if (strcmp(name, "quat")==0) return Py_BuildValue("[ffff]", mc->bone->quat[0], mc->bone->quat[1], mc->bone->quat[2], mc->bone->quat[3]);
	    else if (strcmp(name, "parent")==0) return BPY_incr_ret(mc->parent);
	    else if (strcmp(name, "children")==0) return BPY_incr_ret(mc->children);
	  }
	else if (strcmp(name, "valid")==0) return Py_BuildValue("i", 0);
	
	PyErr_SetString(PyExc_AttributeError, name);
	return NULL;
}

PyTypeObject Bone_Type = {
	PyObject_HEAD_INIT(NULL)
	0,								/*ob_size*/
	"Bone",						/*tp_name*/
	sizeof(wBone),					/*tp_basicsize*/
	0,								/*tp_itemsize*/
	/* methods */
	(destructor) Bone_dealloc,	/*tp_dealloc*/
	(printfunc) 0,		        /*tp_print*/
	(getattrfunc) Bone_getattr,	/*tp_getattr*/
	0,	/*tp_setattr*/
	0,								/*tp_compare*/
	(reprfunc) Bone_repr,								/*tp_repr*/
	0,								/*tp_as_number*/
	0,								/*tp_as_sequence*/
	0,								/*tp_as_mapping*/
	0,								/*tp_hash*/
	0,								/*tp_as_number*/
	0,								/*tp_as_sequence*/
	0,								/*tp_as_mapping*/
	0,								/*tp_hash*/
};

/*****************************/
/*    Armature Python Object    */
/*****************************/


static void Armature_dealloc(PyObject *self) {
	Armature *me= (Armature *) self;

	Py_DECREF(me->name);
	
	PyMem_DEL(self);
}


static char Armature_link_doc[] = "(object) - Links Armature data with Object 'object'";

PyObject * Armature_link(PyObject *self, PyObject *args) 
{
	return DataBlock_link(self, args);
}

#undef MethodDef
#define MethodDef(func) {#func, Armature_##func, METH_VARARGS, Armature_##func##_doc}

static struct PyMethodDef Armature_methods[] = {
	{NULL, NULL}
};


static PyObject *Armature_getattr(PyObject *self, char *name)
{
  Armature *me= (Armature *) self;
  
  if (STREQ(name, "name")) 
    return BPY_incr_ret(me->name);
  
	else if (STREQ(name, "bones")) 
	  return BPY_incr_ret(me->bones);
  
  else if (STREQ(name, "users")) {
    if (me->armature)
      {
	return PyInt_FromLong(me->armature->id.us); 
      } else { // it's a free mesh:
	return Py_BuildValue("i", 0); 
      }
  }
  
  return Py_FindMethod(Armature_methods, (PyObject*)self, name);	
}

static int Armature_setattr(PyObject *self, char *name, PyObject *v) {
	Armature *me= (Armature *) self;

	if (STREQ2(name, "name", "bones")) {
		if(PySequence_Check(v)) {
			if(STREQ(name, "name")) {
				Py_DECREF(me->name);
				me->name= BPY_incr_ret(v);
			} else if (STREQ(name, "bones")) {
				Py_DECREF(me->bones);
				me->bones= BPY_incr_ret(v);
			}
		} else {
			PyErr_SetString(PyExc_AttributeError, "expected a sequence");
			return -1;
		}
	} else {
		PyErr_SetString(PyExc_AttributeError, name);
		return -1;
	}

	return 0;
}

#undef BPY_ADDCONST
#define BPY_ADDCONST(dict, name) insertConst(dict, #name, PyInt_FromLong(TF_##name))

/* set constants for face drawing mode -- see drawmesh.c */

static void init_ArmatureConst(PyObject *d)
{
/* transparent modes 
	BPY_ADDCONST(d, SOLID);
	BPY_ADDCONST(d, ADD);
	BPY_ADDCONST(d, ALPHA);
	BPY_ADDCONST(d, SUB);
*/
}

PyTypeObject Armature_Type = {
	PyObject_HEAD_INIT(NULL)
	0,								/*ob_size*/
	"Armature",						/*tp_name*/
	sizeof(bArmature),					/*tp_basicsize*/
	0,								/*tp_itemsize*/
	/* methods */
	(destructor)	Armature_dealloc,	/*tp_dealloc*/
	(printfunc)	0,	/*tp_print*/
	(getattrfunc)	Armature_getattr,	/*tp_getattr*/
	(setattrfunc)	Armature_setattr,	/*tp_setattr*/
};


PyObject *newArmature(bArmature *oldarmature) 
{
	Armature *me= PyObject_NEW(Armature, &Armature_Type);

	if (!oldarmature) {
		me->name= BPY_incr_ret(Py_None);
		me->bones= PyList_New(0);
		me->armature= 0;
	} else {
		int totbones = 0;

		Bone* current = oldarmature->bonebase.first;
		for (;current; current=current->next) totbones++;

		Bone *mbone = oldarmature->bonebase.first;

		me->name= PyString_FromString(oldarmature->id.name+2);
		me->armature= oldarmature;
			
		me->bones= PyList_New(totbones);
		int i;
		for (i=0; i<totbones; i++) {
		  assert(mbone);
		  // Create bone with null parent
		  PyList_SetItem(me->bones, i, (PyObject *) newbone(mbone,NULL));
		  mbone = mbone->next;
		}
	}
	
	return (PyObject *) me;	
}


static char Armaturemodule_New_doc[]=
"() - returns a new, empty Armature object\n";

static PyObject *Armaturemodule_New(PyObject *self, PyObject *args) 
{
	return newArmature(NULL);
}

static char Armaturemodule_GetRaw_doc[]=
"([name]) - Get a raw armature from Blender\n \
\n \
[name] Name of the armature to be returned\n \
\n \
If name is not specified a new empty armature is\n \
returned, otherwise Blender returns an existing\n \
armature.";

static PyObject *Armaturemodule_GetRaw(PyObject *self, PyObject *args) 
{
	char *name=NULL;
	bArmature *oldarmature=NULL;
	
	BPY_TRY(PyArg_ParseTuple(args, "|s", &name));	

	if(name) {
		oldarmature = (bArmature *) getFromList(getArmatureList(), name);

		if (!oldarmature) return BPY_incr_ret(Py_None);
	}
	return newArmature(oldarmature);
}


static int unlink_existingArmaturedata(bArmature *armature)
{
  // not implemented?
  //	unlink_armature(armature);
	return 1;
}


#undef MethodDef
#define MethodDef(func) {#func, Armaturemodule_##func, METH_VARARGS, Armaturemodule_##func##_doc}

static struct PyMethodDef Armaturemodule_methods[] = {
	MethodDef(GetRaw),
	MethodDef(New),
	{NULL, NULL}
};


#undef BPY_ADDCONST
#define BPY_ADDCONST(dict, name) insertConst(dict, #name, PyInt_FromLong(TF_##name))


PyObject *init_py_armature(void) 
{
	PyObject *d;
	PyObject *mod= Py_InitModule(SUBMODULE(Armature), Armaturemodule_methods);
	PyObject *dict= PyModule_GetDict(mod);

	Armature_Type.ob_type= &PyType_Type;	
	
	d = ConstObject_New();
	PyDict_SetItemString(dict, "Const" , d);
	init_ArmatureConst(d);

	g_armaturemodule = mod;
	return mod;
}

#ifdef SHAREDMODULE
void initArmature(void) 
{
	init_py_armature();
}
#endif

--------------070201000005070004020906
Content-Type: text/x-chdr;
 name="opy_armature.h"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="opy_armature.h"

/**
 * $Id: opy_nmesh.h,v 1.5 2002/12/27 13:10:16 mein Exp $
 *
 * ***** 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.
 *
 * The Original Code is: all of this file.
 *
 * Contributor(s): none yet.
 *
 * ***** END GPL/BL DUAL LICENSE BLOCK *****
 */
/* opy_armature.h */

#include "DNA_armature_types.h"

#define Armature_Check(v)       ((v)->ob_type == &Armature_Type)
#define Bone_Check(v)      ((v)->ob_type == &Bone_Type)


struct PyBlock;

typedef struct _Armature
{
  PyObject_HEAD
  bArmature *armature;
  PyObject *name;
  PyObject *bones;
  char flags;
} Armature;


typedef struct _Bone {
  PyObject_HEAD
  Bone *bone;
  PyObject *parent;
  PyObject *children;
	
} wBone;



/* PROTOS */

PyObject *newArmature(bArmature *oldarmature);


--------------070201000005070004020906
Content-Type: text/plain;
 name="Armature.py"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="Armature.py"

"""The Blender Armature module

  This module provides access to the raw **Armature** data block.

  This module is worse than experimental.
"""  

import _Blender.Armature as _Armature
import shadow

class Armature:
	"""The Armature object

    This contains a copy of the armature object data. 

  Attributes
  
"""
	def __init__(self, object):
		if object:
			self._object = object
		else:	
			self._object = _Armature.GetRaw()

	def __repr__(self):
		return "[Armature \"%s\"]" % self.name

	def __getattr__(self, name):
		if name == 'bones':
			return self._object.bones
		elif name == 'name':
			return self._object.name
		else:
			return getattr(self._object, name)

def New(name = None):
	"""Creates a new Armature mesh object and returns it"""
	pass

def GetRaw(name = None):
	"""If 'name' specified, the Armature object with 'name' is returned, 'None'
if not existant. Otherwise, a new empty Armature is initialized and returned."""
	pass

	
# override all these functions again, because we only used them for
# documentation 

New              = _Armature.New
GetRaw           = _Armature.GetRaw

def Armature(data):
	return data

# Bone wrapper class
class Bone:
	"""Bone wrapper class
This class emulates a bone allowing to read its data
"""
	def __init__(self, vlist):
		self.name = "unnamed"
		self.head = [0.0,0.0,0.0]
		self.tail = [1.0,0.0,0.0]
		self.roll = 0.0

# override:

#Bone = _Armature.Bone

--------------070201000005070004020906--