Bugfix #4690: BonesDict_repr() had a string overflow for really complicated armatures. Added a string length check and terminate before overflowing.
		
			
				
	
	
		
			1332 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1332 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * $Id$
 | 
						|
 *
 | 
						|
 * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
 | 
						|
 *
 | 
						|
 * This program is free software; you can redistribute it and/or
 | 
						|
 * modify it under the terms of the GNU General Public License
 | 
						|
 * as published by the Free Software Foundation; either version 2
 | 
						|
 * of the License, or (at your option) any later version. The Blender
 | 
						|
 * Foundation also sells licenses for use in proprietary software under
 | 
						|
 * the Blender License.  See http://www.blender.org/BL/ for information
 | 
						|
 * about this.
 | 
						|
 *
 | 
						|
 * This program is distributed in the hope that it will be useful,
 | 
						|
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
 * GNU General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU General Public License
 | 
						|
 * along with this program; if not, write to the Free Software Foundation,
 | 
						|
 * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 | 
						|
 *
 | 
						|
 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
 | 
						|
 * All rights reserved.
 | 
						|
 *
 | 
						|
 * ***** END GPL/BL DUAL LICENSE BLOCK *****
 | 
						|
*/
 | 
						|
 | 
						|
#include "Armature.h" //This must come first
 | 
						|
 | 
						|
#include "BKE_main.h"
 | 
						|
#include "BKE_global.h"
 | 
						|
#include "BKE_armature.h"
 | 
						|
#include "BKE_library.h"
 | 
						|
#include "BKE_depsgraph.h"
 | 
						|
#include "BKE_utildefines.h"
 | 
						|
#include "BLI_blenlib.h"
 | 
						|
#include "BLI_arithb.h"
 | 
						|
#include "MEM_guardedalloc.h"
 | 
						|
#include "Bone.h"
 | 
						|
#include "NLA.h"
 | 
						|
#include "gen_utils.h"
 | 
						|
 | 
						|
#include "DNA_object_types.h" //This must come before BIF_editarmature.h...
 | 
						|
#include "BIF_editarmature.h"
 | 
						|
 | 
						|
//------------------EXTERNAL PROTOTYPES--------------------
 | 
						|
extern void make_boneList(ListBase* list, ListBase *bones, EditBone *parent);
 | 
						|
extern void editbones_to_armature (ListBase *list, Object *ob);
 | 
						|
 | 
						|
//------------------------ERROR CODES---------------------------------
 | 
						|
//This is here just to make me happy and to have more consistant error strings :)
 | 
						|
static const char sBoneDictError[] = "ArmatureType.bones - Error: ";
 | 
						|
static const char sBoneDictBadArgs[] = "ArmatureType.bones - Bad Arguments: ";
 | 
						|
static const char sArmatureError[] = "ArmatureType - Error: ";
 | 
						|
static const char sArmatureBadArgs[] = "ArmatureType - Bad Arguments: ";
 | 
						|
static const char sModuleError[] = "Blender.Armature - Error: ";
 | 
						|
static const char sModuleBadArgs[] = "Blender.Armature - Bad Arguments: ";
 | 
						|
 | 
						|
//################## BonesDict_Type (internal) ########################
 | 
						|
/*This is an internal psuedo-dictionary type that allows for manipulation
 | 
						|
* of bones inside of an armature. It is a subobject of armature.
 | 
						|
* i.e. Armature.bones['key']*/
 | 
						|
//#####################################################################
 | 
						|
 | 
						|
//------------------METHOD IMPLEMENTATIONS-----------------------------
 | 
						|
//------------------------Armature.bones.items()
 | 
						|
//Returns a list of key:value pairs like dict.items()
 | 
						|
static PyObject* BonesDict_items(BPy_BonesDict *self)
 | 
						|
{
 | 
						|
	if (self->editmode_flag){
 | 
						|
		return PyDict_Items(self->editbonesMap); 
 | 
						|
	}else{
 | 
						|
		return PyDict_Items(self->bonesMap); 
 | 
						|
	}
 | 
						|
}
 | 
						|
//------------------------Armature.bones.keys()
 | 
						|
//Returns a list of keys like dict.keys()
 | 
						|
static PyObject* BonesDict_keys(BPy_BonesDict *self)
 | 
						|
{
 | 
						|
	if (self->editmode_flag){
 | 
						|
		return PyDict_Keys(self->editbonesMap);
 | 
						|
	}else{
 | 
						|
		return PyDict_Keys(self->bonesMap);
 | 
						|
	}
 | 
						|
}
 | 
						|
//------------------------Armature.bones.values()
 | 
						|
//Returns a list of values like dict.values()
 | 
						|
static PyObject* BonesDict_values(BPy_BonesDict *self)
 | 
						|
{
 | 
						|
	if (self->editmode_flag){
 | 
						|
		return PyDict_Values(self->editbonesMap);
 | 
						|
	}else{
 | 
						|
		return PyDict_Values(self->bonesMap);
 | 
						|
	}
 | 
						|
}
 | 
						|
//------------------ATTRIBUTE IMPLEMENTATION---------------------------
 | 
						|
//------------------TYPE_OBECT IMPLEMENTATION-----------------------
 | 
						|
//------------------------tp_doc
 | 
						|
//The __doc__ string for this object
 | 
						|
static char BPy_BonesDict_doc[] = "This is an internal subobject of armature\
 | 
						|
designed to act as a Py_Bone dictionary.";
 | 
						|
 | 
						|
//------------------------tp_methods
 | 
						|
//This contains a list of all methods the object contains
 | 
						|
static PyMethodDef BPy_BonesDict_methods[] = {
 | 
						|
	{"items", (PyCFunction) BonesDict_items, METH_NOARGS, 
 | 
						|
		"() - Returns the key:value pairs from the dictionary"},
 | 
						|
	{"keys", (PyCFunction) BonesDict_keys, METH_NOARGS, 
 | 
						|
		"() - Returns the keys the dictionary"},
 | 
						|
	{"values", (PyCFunction) BonesDict_values, METH_NOARGS, 
 | 
						|
		"() - Returns the values from the dictionary"},
 | 
						|
	{NULL, NULL, 0, NULL}
 | 
						|
};
 | 
						|
//-----------------(internal)
 | 
						|
static int BoneMapping_Init(PyObject *dictionary, ListBase *bones){
 | 
						|
	Bone *bone = NULL;
 | 
						|
	PyObject *py_bone = NULL;
 | 
						|
 | 
						|
	for (bone = bones->first; bone; bone = bone->next){
 | 
						|
		py_bone = PyBone_FromBone(bone);
 | 
						|
		if (!py_bone)
 | 
						|
			return -1;
 | 
						|
 | 
						|
		if(PyDict_SetItem(dictionary, 
 | 
						|
			PyString_FromString(bone->name), py_bone) == -1){
 | 
						|
			return -1;
 | 
						|
		}
 | 
						|
		Py_DECREF(py_bone);
 | 
						|
		if (bone->childbase.first) 
 | 
						|
			BoneMapping_Init(dictionary, &bone->childbase);
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
//-----------------(internal)
 | 
						|
static int EditBoneMapping_Init(PyObject *dictionary, ListBase *editbones){
 | 
						|
	EditBone *editbone = NULL;
 | 
						|
	PyObject *py_editbone = NULL;
 | 
						|
 | 
						|
	for (editbone = editbones->first; editbone; editbone = editbone->next){
 | 
						|
		py_editbone = PyEditBone_FromEditBone(editbone);
 | 
						|
		if (!py_editbone)
 | 
						|
			return -1;
 | 
						|
 | 
						|
		if(PyDict_SetItem(dictionary, 
 | 
						|
			PyString_FromString(editbone->name), py_editbone) == -1){
 | 
						|
			return -1;
 | 
						|
		}
 | 
						|
		Py_DECREF(py_editbone);
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
//----------------- BonesDict_InitBones
 | 
						|
static int BonesDict_InitBones(BPy_BonesDict *self)
 | 
						|
{
 | 
						|
	PyDict_Clear(self->bonesMap);
 | 
						|
	if (BoneMapping_Init(self->bonesMap, self->bones) == -1)
 | 
						|
		return 0;
 | 
						|
	return 1;
 | 
						|
} 
 | 
						|
//----------------- BonesDict_InitEditBones
 | 
						|
static int BonesDict_InitEditBones(BPy_BonesDict *self)
 | 
						|
{
 | 
						|
	PyDict_Clear(self->editbonesMap);
 | 
						|
	if (EditBoneMapping_Init(self->editbonesMap, &self->editbones) == -1)
 | 
						|
		return 0;
 | 
						|
	return 1;
 | 
						|
}
 | 
						|
//------------------------tp_repr
 | 
						|
//This is the string representation of the object
 | 
						|
static PyObject *BonesDict_repr(BPy_BonesDict *self)
 | 
						|
{
 | 
						|
	char str[2048];
 | 
						|
	PyObject *key, *value;
 | 
						|
	int pos = 0;
 | 
						|
	char *p = str;
 | 
						|
	char *keys, *vals;
 | 
						|
 | 
						|
	p += sprintf(str, "[Bone Dict: {");
 | 
						|
 | 
						|
	if (self->editmode_flag){
 | 
						|
		while (PyDict_Next(self->editbonesMap, &pos, &key, &value)) {
 | 
						|
			keys = PyString_AsString(key);
 | 
						|
			vals = PyString_AsString(value->ob_type->tp_repr(value));
 | 
						|
			if( strlen(str) + strlen(keys) + strlen(vals) < sizeof(str)-20 )
 | 
						|
				p += sprintf(p, "%s : %s, ", keys, vals );
 | 
						|
			else {
 | 
						|
				p += sprintf(p, "...." );
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}else{
 | 
						|
		while (PyDict_Next(self->bonesMap, &pos, &key, &value)) {
 | 
						|
			keys = PyString_AsString(key);
 | 
						|
			vals = PyString_AsString(value->ob_type->tp_repr(value));
 | 
						|
			if( strlen(str) + strlen(keys) + strlen(vals) < sizeof(str)-20 )
 | 
						|
				p += sprintf(p, "%s : %s, ", keys, vals );
 | 
						|
			else {
 | 
						|
				p += sprintf(p, "...." );
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	sprintf(p, "}]");
 | 
						|
	return PyString_FromString(str);
 | 
						|
}
 | 
						|
 | 
						|
//------------------------tp_dealloc
 | 
						|
//This tells how to 'tear-down' our object when ref count hits 0
 | 
						|
static void BonesDict_dealloc(BPy_BonesDict * self)
 | 
						|
{
 | 
						|
	Py_DECREF(self->bonesMap);
 | 
						|
	Py_DECREF(self->editbonesMap);
 | 
						|
	BLI_freelistN(&self->editbones); 
 | 
						|
	BonesDict_Type.tp_free(self);
 | 
						|
	return;
 | 
						|
}
 | 
						|
//------------------------mp_length
 | 
						|
//This gets the size of the dictionary
 | 
						|
static int BonesDict_len(BPy_BonesDict *self)
 | 
						|
{
 | 
						|
	if (self->editmode_flag){
 | 
						|
		return BLI_countlist(&self->editbones);
 | 
						|
	}else{
 | 
						|
		return BLI_countlist(self->bones);
 | 
						|
	}
 | 
						|
}
 | 
						|
//-----------------------mp_subscript
 | 
						|
//This defines getting a bone from the dictionary - x = Bones['key']
 | 
						|
static PyObject *BonesDict_GetItem(BPy_BonesDict *self, PyObject* key)
 | 
						|
{ 
 | 
						|
	PyObject *value = NULL;
 | 
						|
 | 
						|
	if (self->editmode_flag){
 | 
						|
		value = PyDict_GetItem(self->editbonesMap, key);
 | 
						|
	}else{
 | 
						|
		value = PyDict_GetItem(self->bonesMap, key);
 | 
						|
	}
 | 
						|
	if(value == NULL){  /* item not found in dict. throw exception */
 | 
						|
		char buffer[128];
 | 
						|
		char* key_str;
 | 
						|
		key_str = PyString_AsString( key );
 | 
						|
		if( !key_str ){  /* key not a py string */
 | 
						|
			key_str = "";  /* use empty string for printing */
 | 
						|
		}
 | 
						|
  
 | 
						|
		PyOS_snprintf( buffer, sizeof(buffer),
 | 
						|
					   "bone %s not found", key_str);
 | 
						|
			
 | 
						|
        return EXPP_ReturnPyObjError(PyExc_KeyError, buffer );
 | 
						|
	}
 | 
						|
	return EXPP_incr_ret(value);
 | 
						|
}
 | 
						|
//-----------------------mp_ass_subscript
 | 
						|
//This does dict assignment - Bones['key'] = value
 | 
						|
static int BonesDict_SetItem(BPy_BonesDict *self, PyObject *key, PyObject *value)
 | 
						|
{
 | 
						|
	BPy_EditBone *editbone_for_deletion;
 | 
						|
	struct EditBone *editbone = NULL;
 | 
						|
	char *key_str = "";
 | 
						|
 | 
						|
	if (self->editmode_flag){
 | 
						|
		//Get the key name
 | 
						|
		if(key && PyString_Check(key)){
 | 
						|
			key_str = PyString_AsString(key);
 | 
						|
		}else{
 | 
						|
			goto AttributeError;
 | 
						|
		}
 | 
						|
		//parse value for assignment
 | 
						|
		if (value && EditBoneObject_Check(value)){
 | 
						|
			//create a new editbone
 | 
						|
			editbone = MEM_callocN(sizeof(EditBone), "eBone");
 | 
						|
			BLI_strncpy(editbone->name, key_str, 32);
 | 
						|
			unique_editbone_name(editbone->name);
 | 
						|
			editbone->dist = ((BPy_EditBone*)value)->dist;
 | 
						|
			editbone->ease1 = ((BPy_EditBone*)value)->ease1;
 | 
						|
			editbone->ease2 = ((BPy_EditBone*)value)->ease2;
 | 
						|
			editbone->flag = ((BPy_EditBone*)value)->flag;
 | 
						|
			editbone->parent = ((BPy_EditBone*)value)->parent;
 | 
						|
			editbone->rad_head = ((BPy_EditBone*)value)->rad_head;
 | 
						|
			editbone->rad_tail = ((BPy_EditBone*)value)->rad_tail;
 | 
						|
			editbone->roll = ((BPy_EditBone*)value)->roll;
 | 
						|
			editbone->segments = ((BPy_EditBone*)value)->segments;
 | 
						|
			editbone->weight = ((BPy_EditBone*)value)->weight;
 | 
						|
			editbone->xwidth = ((BPy_EditBone*)value)->xwidth;
 | 
						|
			editbone->zwidth = ((BPy_EditBone*)value)->zwidth;
 | 
						|
			VECCOPY(editbone->head, ((BPy_EditBone*)value)->head);
 | 
						|
			VECCOPY(editbone->tail, ((BPy_EditBone*)value)->tail);
 | 
						|
			
 | 
						|
			// FIXME, should be exposed via python. this avoids creating bones with no layers.
 | 
						|
			editbone->layer= 1;
 | 
						|
			
 | 
						|
			//set object pointer
 | 
						|
			((BPy_EditBone*)value)->editbone = editbone;
 | 
						|
 | 
						|
			//fix the bone's head position if flags indicate that it is 'connected'
 | 
						|
			if (editbone->flag & BONE_CONNECTED){
 | 
						|
				if(!editbone->parent){
 | 
						|
					((BPy_EditBone*)value)->editbone = NULL;
 | 
						|
					MEM_freeN(editbone);
 | 
						|
					goto AttributeError3;
 | 
						|
				}else{
 | 
						|
					VECCOPY(editbone->head, editbone->parent->tail);
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			//set in editbonelist
 | 
						|
			BLI_addtail(&self->editbones, editbone);
 | 
						|
 | 
						|
			//set the new editbone in the mapping
 | 
						|
			if(PyDict_SetItemString(self->editbonesMap, key_str, value) == -1){
 | 
						|
				((BPy_EditBone*)value)->editbone = NULL;
 | 
						|
				BLI_freelinkN(&self->editbones, editbone);
 | 
						|
				goto RuntimeError;
 | 
						|
			}
 | 
						|
		}else if(!value){
 | 
						|
			//they are trying to delete the bone using 'del'
 | 
						|
			if(PyDict_GetItem(self->editbonesMap, key) != NULL){
 | 
						|
				/*first kill the datastruct then remove the item from the dict
 | 
						|
				and wait for GC to pick it up.
 | 
						|
				We have to delete the datastruct here because the tp_dealloc
 | 
						|
				doesn't handle it*/
 | 
						|
				editbone_for_deletion = (BPy_EditBone*)PyDict_GetItem(self->editbonesMap, key);
 | 
						|
				/*this is ugly but you have to set the parent to NULL for else 
 | 
						|
				editbones_to_armature will crash looking for this bone*/
 | 
						|
				for (editbone = self->editbones.first; editbone; editbone = editbone->next){
 | 
						|
					if (editbone->parent == editbone_for_deletion->editbone)
 | 
						|
						editbone->parent = NULL;
 | 
						|
					    /*any parent's were connected to this we must remove the flag
 | 
						|
					    or else the 'root' ball doesn't get draw*/
 | 
						|
					    if (editbone->flag & BONE_CONNECTED)
 | 
						|
							editbone->flag &= ~BONE_CONNECTED;
 | 
						|
				}
 | 
						|
				BLI_freelinkN(&self->editbones, editbone_for_deletion->editbone);
 | 
						|
				if(PyDict_DelItem(self->editbonesMap, key) == -1)
 | 
						|
					goto RuntimeError;
 | 
						|
			}else{
 | 
						|
				goto KeyError;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return 0;
 | 
						|
	}else{
 | 
						|
		goto AttributeError2;
 | 
						|
	}
 | 
						|
 | 
						|
KeyError:
 | 
						|
return EXPP_intError(PyExc_KeyError, "%s%s%s%s", 
 | 
						|
	    sBoneDictError,  "The key: ", key_str, " is not present in this dictionary!");
 | 
						|
RuntimeError:
 | 
						|
	return EXPP_intError(PyExc_RuntimeError, "%s%s", 
 | 
						|
		sBoneDictError,  "Unable to access dictionary!");
 | 
						|
AttributeError:
 | 
						|
	return EXPP_intError(PyExc_AttributeError, "%s%s", 
 | 
						|
		sBoneDictBadArgs,  "Expects EditboneType Object");
 | 
						|
AttributeError2:
 | 
						|
	return EXPP_intError(PyExc_AttributeError, "%s%s", 
 | 
						|
		sBoneDictBadArgs,  "You must call makeEditable() first");
 | 
						|
AttributeError3:
 | 
						|
	return EXPP_intError(PyExc_AttributeError, "%s%s", 
 | 
						|
		sBoneDictBadArgs,  "The 'connected' flag is set but the bone has no parent!");
 | 
						|
}
 | 
						|
//------------------TYPE_OBJECT DEFINITION--------------------------
 | 
						|
//Mapping Protocol
 | 
						|
static PyMappingMethods BonesDict_MapMethods = {
 | 
						|
	(inquiry) BonesDict_len,					//mp_length
 | 
						|
	(binaryfunc)BonesDict_GetItem,		//mp_subscript
 | 
						|
	(objobjargproc)BonesDict_SetItem,	//mp_ass_subscript
 | 
						|
};
 | 
						|
//BonesDict TypeObject
 | 
						|
PyTypeObject BonesDict_Type = {
 | 
						|
	PyObject_HEAD_INIT(NULL)			//tp_head
 | 
						|
	0,												//tp_internal
 | 
						|
	"BonesDict",								//tp_name
 | 
						|
	sizeof(BPy_BonesDict),					//tp_basicsize
 | 
						|
	0,												//tp_itemsize
 | 
						|
	(destructor)BonesDict_dealloc,		//tp_dealloc
 | 
						|
	0,												//tp_print
 | 
						|
	0,												//tp_getattr
 | 
						|
	0,												//tp_setattr
 | 
						|
	0,												//tp_compare
 | 
						|
	(reprfunc) BonesDict_repr,				//tp_repr
 | 
						|
	0,												//tp_as_number
 | 
						|
	0,												//tp_as_sequence
 | 
						|
	&BonesDict_MapMethods,				//tp_as_mapping
 | 
						|
	0,												//tp_hash
 | 
						|
	0,												//tp_call
 | 
						|
	0,												//tp_str
 | 
						|
	0,												//tp_getattro
 | 
						|
	0,												//tp_setattro
 | 
						|
	0,												//tp_as_buffer
 | 
						|
	Py_TPFLAGS_DEFAULT,					//tp_flags
 | 
						|
	BPy_BonesDict_doc,						//tp_doc
 | 
						|
	0,												//tp_traverse
 | 
						|
	0,												//tp_clear
 | 
						|
	0,												//tp_richcompare
 | 
						|
	0,												//tp_weaklistoffset
 | 
						|
	0,												//tp_iter
 | 
						|
	0,												//tp_iternext
 | 
						|
	BPy_BonesDict_methods,				//tp_methods
 | 
						|
	0,												//tp_members
 | 
						|
	0,												//tp_getset
 | 
						|
	0,												//tp_base
 | 
						|
	0,												//tp_dict
 | 
						|
	0,												//tp_descr_get
 | 
						|
	0,												//tp_descr_set
 | 
						|
	0,												//tp_dictoffset
 | 
						|
	0, 				                                //tp_init
 | 
						|
	0,												//tp_alloc
 | 
						|
	0,												//tp_new
 | 
						|
	0,												//tp_free
 | 
						|
	0,												//tp_is_gc
 | 
						|
	0,												//tp_bases
 | 
						|
	0,												//tp_mro
 | 
						|
	0,												//tp_cache
 | 
						|
	0,												//tp_subclasses
 | 
						|
	0,												//tp_weaklist
 | 
						|
	0												//tp_del
 | 
						|
};
 | 
						|
//-----------------------PyBonesDict_FromPyArmature
 | 
						|
static PyObject *PyBonesDict_FromPyArmature(BPy_Armature *py_armature)
 | 
						|
{
 | 
						|
	BPy_BonesDict *py_BonesDict = NULL;
 | 
						|
 | 
						|
	//create py object
 | 
						|
	py_BonesDict = (BPy_BonesDict *)BonesDict_Type.tp_alloc(&BonesDict_Type, 0); 
 | 
						|
	if (!py_BonesDict)
 | 
						|
		goto RuntimeError;
 | 
						|
 | 
						|
	//create internal dictionaries
 | 
						|
	py_BonesDict->bonesMap = PyDict_New();
 | 
						|
	py_BonesDict->editbonesMap = PyDict_New();
 | 
						|
	if (!py_BonesDict->bonesMap || !py_BonesDict->editbonesMap)
 | 
						|
		goto RuntimeError;
 | 
						|
 | 
						|
	//set listbase pointer
 | 
						|
	py_BonesDict->bones = &py_armature->armature->bonebase;
 | 
						|
 | 
						|
	//now that everything is setup - init the mappings
 | 
						|
	if (!BonesDict_InitBones(py_BonesDict))
 | 
						|
		goto RuntimeError;
 | 
						|
	if (!BonesDict_InitEditBones(py_BonesDict))
 | 
						|
		goto RuntimeError;
 | 
						|
 | 
						|
	//set editmode flag
 | 
						|
	py_BonesDict->editmode_flag = 0; 
 | 
						|
 | 
						|
	return (PyObject*)py_BonesDict;
 | 
						|
 | 
						|
RuntimeError:
 | 
						|
	return EXPP_objError(PyExc_RuntimeError, "%s%s", 
 | 
						|
		sBoneDictError, "Failed to create class");
 | 
						|
}
 | 
						|
 | 
						|
//######################### Armature_Type #############################
 | 
						|
/*This type represents a thin wrapper around bArmature data types
 | 
						|
* internal to blender. It contains the psuedo-dictionary BonesDict
 | 
						|
* as an assistant in manipulating it's own bone collection*/
 | 
						|
//#################################################################
 | 
						|
 | 
						|
//------------------METHOD IMPLEMENTATION------------------------------
 | 
						|
//------------------------Armature.makeEditable()
 | 
						|
static PyObject *Armature_makeEditable(BPy_Armature *self)
 | 
						|
{
 | 
						|
	if (self->armature->flag & ARM_EDITMODE)
 | 
						|
		goto AttributeError;
 | 
						|
 | 
						|
	make_boneList(&self->Bones->editbones, self->Bones->bones, NULL);
 | 
						|
	if (!BonesDict_InitEditBones(self->Bones))
 | 
						|
		return NULL;
 | 
						|
	self->Bones->editmode_flag = 1;
 | 
						|
	return EXPP_incr_ret(Py_None);
 | 
						|
 | 
						|
AttributeError:
 | 
						|
	return EXPP_objError(PyExc_AttributeError, "%s%s", 
 | 
						|
		sArmatureBadArgs, "The armature cannot be placed manually in editmode before you call makeEditable()!");
 | 
						|
}
 | 
						|
//------------------------Armature.update()
 | 
						|
//This is a bit ugly because you need an object link to do this
 | 
						|
static PyObject *Armature_update(BPy_Armature *self)
 | 
						|
{
 | 
						|
	Object *obj = NULL;
 | 
						|
 | 
						|
	for (obj = G.main->object.first; obj; obj = obj->id.next){
 | 
						|
		if (obj->data == self->armature)
 | 
						|
			break;
 | 
						|
	}
 | 
						|
	if (obj){
 | 
						|
		editbones_to_armature (&self->Bones->editbones, obj);
 | 
						|
		if (!BonesDict_InitBones(self->Bones))
 | 
						|
			return NULL;
 | 
						|
		self->Bones->editmode_flag = 0;
 | 
						|
		BLI_freelistN(&self->Bones->editbones);
 | 
						|
	}else{
 | 
						|
		goto AttributeError;
 | 
						|
 | 
						|
	}
 | 
						|
	return EXPP_incr_ret(Py_None);
 | 
						|
 | 
						|
AttributeError:
 | 
						|
	return EXPP_objError(PyExc_AttributeError, "%s%s", 
 | 
						|
		sArmatureBadArgs, "The armature must be linked to an object before you can save changes!");
 | 
						|
}
 | 
						|
//------------------ATTRIBUTE IMPLEMENTATION---------------------------
 | 
						|
//------------------------Armature.autoIK (getter)
 | 
						|
static PyObject *Armature_getAutoIK(BPy_Armature *self, void *closure)
 | 
						|
{
 | 
						|
	if (self->armature->flag & ARM_AUTO_IK)
 | 
						|
		return EXPP_incr_ret(Py_True);
 | 
						|
	else
 | 
						|
		return EXPP_incr_ret(Py_False);
 | 
						|
}
 | 
						|
//------------------------Armature.autoIK (setter)
 | 
						|
static int Armature_setAutoIK(BPy_Armature *self, PyObject *value, void *closure)
 | 
						|
{
 | 
						|
	if(value){
 | 
						|
		if(PyBool_Check(value)){
 | 
						|
			if (value == Py_True){
 | 
						|
				self->armature->flag |= ARM_AUTO_IK;
 | 
						|
				return 0;
 | 
						|
			}else if (value == Py_False){
 | 
						|
				self->armature->flag &= ~ARM_AUTO_IK;
 | 
						|
				return 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	goto AttributeError;
 | 
						|
 | 
						|
AttributeError:
 | 
						|
	return EXPP_intError(PyExc_AttributeError, "%s%s", 
 | 
						|
		sArmatureBadArgs, "Expects True or False");
 | 
						|
}
 | 
						|
//------------------------Armature.layers (getter)
 | 
						|
static PyObject *Armature_getLayers(BPy_Armature *self, void *closure)
 | 
						|
{
 | 
						|
	int layers, bit = 0, val = 0;
 | 
						|
	PyObject *item = NULL, *laylist = PyList_New( 0 );
 | 
						|
 | 
						|
	if( !laylist )
 | 
						|
		return EXPP_ReturnPyObjError( PyExc_MemoryError,
 | 
						|
			"couldn't create pylist!" );
 | 
						|
 | 
						|
	layers = self->armature->layer;
 | 
						|
 | 
						|
	while( bit < 20 ) {
 | 
						|
		val = 1 << bit;
 | 
						|
		if( layers & val ) {
 | 
						|
			item = Py_BuildValue( "i", bit + 1 );
 | 
						|
			PyList_Append( laylist, item );
 | 
						|
			Py_DECREF( item );
 | 
						|
		}
 | 
						|
		bit++;
 | 
						|
	}
 | 
						|
	return laylist;
 | 
						|
}
 | 
						|
//------------------------Armature.layer (setter)
 | 
						|
static int Armature_setLayers(BPy_Armature *self, PyObject *value, void *closure)
 | 
						|
{
 | 
						|
	if(value){
 | 
						|
		if(PyList_Check(value)){
 | 
						|
			int layers = 0, len_list = 0;
 | 
						|
			int val;
 | 
						|
			PyObject *item = NULL;
 | 
						|
 | 
						|
			len_list = PyList_Size(value);
 | 
						|
 | 
						|
			if( len_list == 0 )
 | 
						|
				return EXPP_ReturnIntError( PyExc_AttributeError,
 | 
						|
				  "list can't be empty, at least one layer must be set" );
 | 
						|
 | 
						|
			while( len_list ) {
 | 
						|
				--len_list;
 | 
						|
				item = PyList_GetItem( value, len_list );
 | 
						|
				if( !PyInt_Check( item ) )
 | 
						|
					return EXPP_ReturnIntError( PyExc_AttributeError,
 | 
						|
							"list must contain only integer numbers" );
 | 
						|
 | 
						|
				val = ( int ) PyInt_AsLong( item );
 | 
						|
				if( val < 1 || val > 20 )
 | 
						|
					return EXPP_ReturnIntError( PyExc_AttributeError,
 | 
						|
						  "layer values must be in the range [1, 20]" );
 | 
						|
 | 
						|
				layers |= 1 << ( val - 1 );
 | 
						|
			}
 | 
						|
 | 
						|
			/* update any bases pointing to our object */
 | 
						|
			self->armature->layer = (short)layers;
 | 
						|
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	goto AttributeError;
 | 
						|
 | 
						|
AttributeError:
 | 
						|
	return EXPP_ReturnIntError( PyExc_TypeError,
 | 
						|
			"expected a list of integers" );
 | 
						|
}
 | 
						|
//------------------------Armature.mirrorEdit (getter)
 | 
						|
static PyObject *Armature_getMirrorEdit(BPy_Armature *self, void *closure)
 | 
						|
{
 | 
						|
	if (self->armature->flag & ARM_MIRROR_EDIT)
 | 
						|
		return EXPP_incr_ret(Py_True);
 | 
						|
	else
 | 
						|
		return EXPP_incr_ret(Py_False);
 | 
						|
}
 | 
						|
//------------------------Armature.mirrorEdit (setter)
 | 
						|
static int Armature_setMirrorEdit(BPy_Armature *self, PyObject *value, void *closure)
 | 
						|
{
 | 
						|
	if(value){
 | 
						|
		if(PyBool_Check(value)){
 | 
						|
			if (value == Py_True){
 | 
						|
				self->armature->flag |= ARM_MIRROR_EDIT;
 | 
						|
				return 0;
 | 
						|
			}else if (value == Py_False){
 | 
						|
				self->armature->flag &= ~ARM_MIRROR_EDIT;
 | 
						|
				return 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	goto AttributeError;
 | 
						|
 | 
						|
AttributeError:
 | 
						|
	return EXPP_intError(PyExc_AttributeError, "%s%s", 
 | 
						|
		sArmatureBadArgs, "Expects True or False");
 | 
						|
}
 | 
						|
//------------------------Armature.drawType (getter)
 | 
						|
static PyObject *Armature_getDrawType(BPy_Armature *self, void *closure)
 | 
						|
{
 | 
						|
	if (self->armature->drawtype == ARM_OCTA){
 | 
						|
		return EXPP_GetModuleConstant("Blender.Armature", "OCTAHEDRON") ;
 | 
						|
	}else if (self->armature->drawtype == ARM_LINE){
 | 
						|
		return EXPP_GetModuleConstant("Blender.Armature", "STICK") ;
 | 
						|
	}else if (self->armature->drawtype == ARM_B_BONE){
 | 
						|
		return EXPP_GetModuleConstant("Blender.Armature", "BBONE") ;
 | 
						|
	}else if (self->armature->drawtype == ARM_ENVELOPE){
 | 
						|
		return EXPP_GetModuleConstant("Blender.Armature", "ENVELOPE") ;
 | 
						|
	}else{
 | 
						|
		goto RuntimeError;
 | 
						|
	}
 | 
						|
 | 
						|
RuntimeError:
 | 
						|
	return EXPP_objError(PyExc_RuntimeError, "%s%s%s", 
 | 
						|
		sArmatureError, "drawType: ", "Internal failure!");
 | 
						|
}
 | 
						|
//------------------------Armature.drawType (setter)
 | 
						|
static int Armature_setDrawType(BPy_Armature *self, PyObject *value, void *closure)
 | 
						|
{
 | 
						|
	PyObject *val = NULL, *name = NULL;
 | 
						|
	long numeric_value;
 | 
						|
 | 
						|
	if(value){
 | 
						|
		if(BPy_Constant_Check(value)){
 | 
						|
			name = PyDict_GetItemString(((BPy_constant*)value)->dict, "name");
 | 
						|
			if (!STREQ2(PyString_AsString(name), "OCTAHEDRON", "STICK") &&
 | 
						|
				!STREQ2(PyString_AsString(name), "BBONE", "ENVELOPE"))
 | 
						|
				goto ValueError;
 | 
						|
			val = PyDict_GetItemString(((BPy_constant*)value)->dict, "value");
 | 
						|
			if (PyInt_Check(val)){
 | 
						|
				numeric_value = PyInt_AS_LONG(val);
 | 
						|
				self->armature->drawtype = (int)numeric_value;
 | 
						|
				return 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	goto AttributeError;
 | 
						|
 | 
						|
AttributeError:
 | 
						|
	return EXPP_intError(PyExc_AttributeError, "%s%s", 
 | 
						|
		sArmatureBadArgs, "Expects module constant");
 | 
						|
 | 
						|
ValueError:
 | 
						|
	return EXPP_intError(PyExc_AttributeError, "%s%s", 
 | 
						|
		sArmatureBadArgs, "Argument must be the constant OCTAHEDRON, STICK, BBONE, or ENVELOPE");
 | 
						|
}
 | 
						|
//------------------------Armature.ghostStep (getter)
 | 
						|
static PyObject *Armature_getStep(BPy_Armature *self, void *closure)
 | 
						|
{
 | 
						|
	return PyInt_FromLong((long)self->armature->ghostsize);
 | 
						|
}
 | 
						|
//------------------------Armature.ghostStep (setter)
 | 
						|
static int Armature_setStep(BPy_Armature *self, PyObject *value, void *closure)
 | 
						|
{
 | 
						|
	long numerical_value;
 | 
						|
 | 
						|
	if(value){
 | 
						|
		if(PyInt_Check(value)){
 | 
						|
			numerical_value = PyInt_AS_LONG(value);
 | 
						|
			if (numerical_value > 20.0f || numerical_value < 1.0f)
 | 
						|
				goto ValueError;
 | 
						|
			self->armature->ghostsize = (short)numerical_value;
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	goto AttributeError;
 | 
						|
 | 
						|
AttributeError:
 | 
						|
	return EXPP_intError(PyExc_AttributeError, "%s%s", 
 | 
						|
		sArmatureBadArgs, "Expects Integer");
 | 
						|
 | 
						|
ValueError:
 | 
						|
	return EXPP_intError(PyExc_AttributeError, "%s%s", 
 | 
						|
		sArmatureBadArgs, "Argument must fall within 1-20");
 | 
						|
}
 | 
						|
//------------------------Armature.ghost (getter)
 | 
						|
static PyObject *Armature_getGhost(BPy_Armature *self, void *closure)
 | 
						|
{
 | 
						|
	return PyInt_FromLong((long)self->armature->ghostep);
 | 
						|
}
 | 
						|
//------------------------Armature.ghost (setter)
 | 
						|
static int Armature_setGhost(BPy_Armature *self, PyObject *value, void *closure)
 | 
						|
{
 | 
						|
	long numerical_value;
 | 
						|
 | 
						|
	if(value){
 | 
						|
		if(PyInt_Check(value)){
 | 
						|
			numerical_value = PyInt_AS_LONG(value);
 | 
						|
			if (numerical_value > 30.0f || numerical_value < 0.0f)
 | 
						|
				goto ValueError;
 | 
						|
			self->armature->ghostep = (short)numerical_value;
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	goto AttributeError;
 | 
						|
 | 
						|
AttributeError:
 | 
						|
	return EXPP_intError(PyExc_AttributeError, "%s%s", 
 | 
						|
		sArmatureBadArgs, "Expects Integer");
 | 
						|
 | 
						|
ValueError:
 | 
						|
	return EXPP_intError(PyExc_AttributeError, "%s%s", 
 | 
						|
		sArmatureBadArgs, "Argument must fall within 0-30");
 | 
						|
}
 | 
						|
//------------------------Armature.drawNames (getter)
 | 
						|
static PyObject *Armature_getDrawNames(BPy_Armature *self, void *closure)
 | 
						|
{
 | 
						|
	if (self->armature->flag & ARM_DRAWNAMES)
 | 
						|
		return EXPP_incr_ret(Py_True);
 | 
						|
	else
 | 
						|
		return EXPP_incr_ret(Py_False);
 | 
						|
}
 | 
						|
//------------------------Armature.drawNames (setter)
 | 
						|
static int Armature_setDrawNames(BPy_Armature *self, PyObject *value, void *closure)
 | 
						|
{
 | 
						|
	if(value){
 | 
						|
		if(PyBool_Check(value)){
 | 
						|
			if (value == Py_True){
 | 
						|
				self->armature->flag |= ARM_DRAWNAMES;
 | 
						|
				return 0;
 | 
						|
			}else if (value == Py_False){
 | 
						|
				self->armature->flag &= ~ARM_DRAWNAMES;
 | 
						|
				return 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	goto AttributeError;
 | 
						|
 | 
						|
AttributeError:
 | 
						|
	return EXPP_intError(PyExc_AttributeError, "%s%s", 
 | 
						|
		sArmatureBadArgs, "Expects True or False");
 | 
						|
}
 | 
						|
//------------------------Armature.drawAxes (getter)
 | 
						|
static PyObject *Armature_getDrawAxes(BPy_Armature *self, void *closure)
 | 
						|
{
 | 
						|
	if (self->armature->flag & ARM_DRAWAXES)
 | 
						|
		return EXPP_incr_ret(Py_True);
 | 
						|
	else
 | 
						|
		return EXPP_incr_ret(Py_False);
 | 
						|
}
 | 
						|
//------------------------Armature.drawAxes (setter)
 | 
						|
static int Armature_setDrawAxes(BPy_Armature *self, PyObject *value, void *closure)
 | 
						|
{
 | 
						|
	if(value){
 | 
						|
		if(PyBool_Check(value)){
 | 
						|
			if (value == Py_True){
 | 
						|
				self->armature->flag |= ARM_DRAWAXES;
 | 
						|
				return 0;
 | 
						|
			}else if (value == Py_False){
 | 
						|
				self->armature->flag &= ~ARM_DRAWAXES;
 | 
						|
				return 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	goto AttributeError;
 | 
						|
 | 
						|
AttributeError:
 | 
						|
	return EXPP_intError(PyExc_AttributeError, "%s%s", 
 | 
						|
		sArmatureBadArgs, "Expects True or False");
 | 
						|
}
 | 
						|
//------------------------Armature.delayDeform (getter)
 | 
						|
static PyObject *Armature_getDelayDeform(BPy_Armature *self, void *closure)
 | 
						|
{
 | 
						|
	if (self->armature->flag & ARM_DELAYDEFORM)
 | 
						|
		return EXPP_incr_ret(Py_True);
 | 
						|
	else
 | 
						|
		return EXPP_incr_ret(Py_False);
 | 
						|
}
 | 
						|
//------------------------Armature.delayDeform (setter)
 | 
						|
static int Armature_setDelayDeform(BPy_Armature *self, PyObject *value, void *closure)
 | 
						|
{
 | 
						|
	if(value){
 | 
						|
		if(PyBool_Check(value)){
 | 
						|
			if (value == Py_True){
 | 
						|
				self->armature->flag |= ARM_DELAYDEFORM;
 | 
						|
				return 0;
 | 
						|
			}else if (value == Py_False){
 | 
						|
				self->armature->flag &= ~ARM_DELAYDEFORM;
 | 
						|
				return 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	goto AttributeError;
 | 
						|
 | 
						|
AttributeError:
 | 
						|
	return EXPP_intError(PyExc_AttributeError, "%s%s", 
 | 
						|
		sArmatureBadArgs, "Expects True or False");
 | 
						|
}
 | 
						|
//------------------------Armature.restPosition (getter)
 | 
						|
static PyObject *Armature_getRestPosition(BPy_Armature *self, void *closure)
 | 
						|
{
 | 
						|
	if (self->armature->flag & ARM_RESTPOS)
 | 
						|
		return EXPP_incr_ret(Py_True);
 | 
						|
	else
 | 
						|
		return EXPP_incr_ret(Py_False);
 | 
						|
}
 | 
						|
//------------------------Armature.restPosition (setter)
 | 
						|
static int Armature_setRestPosition(BPy_Armature *self, PyObject *value, void *closure)
 | 
						|
{
 | 
						|
	if(value){
 | 
						|
		if(PyBool_Check(value)){
 | 
						|
			if (value == Py_True){
 | 
						|
				self->armature->flag |= ARM_RESTPOS;
 | 
						|
				return 0;
 | 
						|
			}else if (value == Py_False){
 | 
						|
				self->armature->flag &= ~ARM_RESTPOS;
 | 
						|
				return 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	goto AttributeError;
 | 
						|
 | 
						|
AttributeError:
 | 
						|
	return EXPP_intError(PyExc_AttributeError, "%s%s", 
 | 
						|
		sArmatureBadArgs, "Expects True or False");
 | 
						|
}
 | 
						|
//------------------------Armature.envelopes (getter)
 | 
						|
static PyObject *Armature_getEnvelopes(BPy_Armature *self, void *closure)
 | 
						|
{
 | 
						|
	if (self->armature->deformflag & ARM_DEF_ENVELOPE)
 | 
						|
		return EXPP_incr_ret(Py_True);
 | 
						|
	else
 | 
						|
		return EXPP_incr_ret(Py_False);
 | 
						|
}
 | 
						|
//------------------------Armature.envelopes (setter)
 | 
						|
static int Armature_setEnvelopes(BPy_Armature *self, PyObject *value, void *closure)
 | 
						|
{
 | 
						|
	if(value){
 | 
						|
		if(PyBool_Check(value)){
 | 
						|
			if (value == Py_True){
 | 
						|
				self->armature->deformflag |= ARM_DEF_ENVELOPE;
 | 
						|
				return 0;
 | 
						|
			}else if (value == Py_False){
 | 
						|
				self->armature->deformflag &= ~ARM_DEF_ENVELOPE;
 | 
						|
				return 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	goto AttributeError;
 | 
						|
 | 
						|
AttributeError:
 | 
						|
	return EXPP_intError(PyExc_AttributeError, "%s%s", 
 | 
						|
		sArmatureBadArgs, "Expects True or False");
 | 
						|
}
 | 
						|
//------------------------Armature.vertexGroups (getter)
 | 
						|
static PyObject *Armature_getVertexGroups(BPy_Armature *self, void *closure)
 | 
						|
{
 | 
						|
	if (self->armature->deformflag & ARM_DEF_VGROUP)
 | 
						|
		return EXPP_incr_ret(Py_True);
 | 
						|
	else
 | 
						|
		return EXPP_incr_ret(Py_False);
 | 
						|
}
 | 
						|
//------------------------Armature.vertexGroups (setter)
 | 
						|
static int Armature_setVertexGroups(BPy_Armature *self, PyObject *value, void *closure)
 | 
						|
{
 | 
						|
	if(value){
 | 
						|
		if(PyBool_Check(value)){
 | 
						|
			if (value == Py_True){
 | 
						|
				self->armature->deformflag |= ARM_DEF_VGROUP;
 | 
						|
				return 0;
 | 
						|
			}else if (value == Py_False){
 | 
						|
				self->armature->deformflag &= ~ARM_DEF_VGROUP;
 | 
						|
				return 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	goto AttributeError;
 | 
						|
 | 
						|
AttributeError:
 | 
						|
	return EXPP_intError(PyExc_AttributeError, "%s%s", 
 | 
						|
		sArmatureBadArgs, "Expects True or False");
 | 
						|
}
 | 
						|
//------------------------Armature.name (getter)
 | 
						|
//Gets the name of the armature
 | 
						|
static PyObject *Armature_getName(BPy_Armature *self, void *closure)
 | 
						|
{
 | 
						|
    return PyString_FromString(self->armature->id.name +2); //*new*
 | 
						|
}
 | 
						|
//------------------------Armature.name (setter)
 | 
						|
//Sets the name of the armature
 | 
						|
static int Armature_setName(BPy_Armature *self, PyObject *value, void *closure)
 | 
						|
{
 | 
						|
	char buffer[24];
 | 
						|
	char *name = "";
 | 
						|
 | 
						|
	if(value){
 | 
						|
		if(PyString_Check(value)){
 | 
						|
			name = PyString_AsString(value);
 | 
						|
			PyOS_snprintf(buffer, sizeof(buffer), "%s", name);
 | 
						|
			rename_id(&self->armature->id, buffer);
 | 
						|
			return 0; 
 | 
						|
		}
 | 
						|
	}
 | 
						|
	goto AttributeError;
 | 
						|
 | 
						|
AttributeError:
 | 
						|
	return EXPP_intError(PyExc_AttributeError, "%s%s", 
 | 
						|
		sArmatureBadArgs, "Expects string");
 | 
						|
}
 | 
						|
//------------------------Armature.bones (getter)
 | 
						|
//Gets the name of the armature
 | 
						|
static PyObject *Armature_getBoneDict(BPy_Armature *self, void *closure)
 | 
						|
{
 | 
						|
    return EXPP_incr_ret((PyObject*)self->Bones);
 | 
						|
}
 | 
						|
//------------------------Armature.bones (setter)
 | 
						|
//Sets the name of the armature
 | 
						|
/*TODO*/
 | 
						|
/*Copy Bones through x = y*/
 | 
						|
static int Armature_setBoneDict(BPy_Armature *self, PyObject *value, void *closure)
 | 
						|
{
 | 
						|
	goto AttributeError;
 | 
						|
 | 
						|
AttributeError:
 | 
						|
	return EXPP_intError(PyExc_AttributeError, "%s%s", 
 | 
						|
		sArmatureError, "You are not allowed to change the .Bones attribute");
 | 
						|
}
 | 
						|
//------------------TYPE_OBECT IMPLEMENTATION--------------------------
 | 
						|
//------------------------tp_doc
 | 
						|
//The __doc__ string for this object
 | 
						|
static char BPy_Armature_doc[] = "This object wraps a Blender Armature object.";
 | 
						|
//------------------------tp_methods
 | 
						|
//This contains a list of all methods the object contains
 | 
						|
static PyMethodDef BPy_Armature_methods[] = {
 | 
						|
	{"makeEditable", (PyCFunction) Armature_makeEditable, METH_NOARGS, 
 | 
						|
		"() - Unlocks the ability to modify armature bones"},
 | 
						|
	{"update", (PyCFunction) Armature_update, METH_NOARGS, 
 | 
						|
		"() - Rebuilds the armature based on changes to bones since the last call to makeEditable"},
 | 
						|
	{NULL, NULL, 0, NULL}
 | 
						|
};
 | 
						|
//------------------------tp_getset
 | 
						|
//This contains methods for attributes that require checking
 | 
						|
static PyGetSetDef BPy_Armature_getset[] = {
 | 
						|
	{"name", (getter)Armature_getName, (setter)Armature_setName, 
 | 
						|
		"The armature's name", NULL},
 | 
						|
	{"bones", (getter)Armature_getBoneDict, (setter)Armature_setBoneDict, 
 | 
						|
		"The armature's Bone dictionary", NULL},
 | 
						|
	{"vertexGroups", (getter)Armature_getVertexGroups, (setter)Armature_setVertexGroups, 
 | 
						|
		"Enable/Disable vertex group defined deformation", NULL},
 | 
						|
	{"envelopes", (getter)Armature_getEnvelopes, (setter)Armature_setEnvelopes, 
 | 
						|
		"Enable/Disable bone envelope defined deformation", NULL},
 | 
						|
	{"restPosition", (getter)Armature_getRestPosition, (setter)Armature_setRestPosition, 
 | 
						|
		"Show armature rest position - disables posing", NULL},
 | 
						|
	{"delayDeform", (getter)Armature_getDelayDeform, (setter)Armature_setDelayDeform, 
 | 
						|
		"Don't deform children when manipulating bones in pose mode", NULL},
 | 
						|
	{"drawAxes", (getter)Armature_getDrawAxes, (setter)Armature_setDrawAxes, 
 | 
						|
		"Enable/Disable  drawing  the bone axes", NULL},
 | 
						|
	{"drawNames", (getter)Armature_getDrawNames, (setter)Armature_setDrawNames, 
 | 
						|
		"Enable/Disable  drawing the bone names", NULL},
 | 
						|
	{"ghost", (getter)Armature_getGhost, (setter)Armature_setGhost, 
 | 
						|
		"Draw a number of ghosts around the current frame for current Action", NULL},
 | 
						|
	{"ghostStep", (getter)Armature_getStep, (setter)Armature_setStep, 
 | 
						|
		"The number of frames between ghost instances", NULL},
 | 
						|
	{"drawType", (getter)Armature_getDrawType, (setter)Armature_setDrawType, 
 | 
						|
		"The type of drawing currently applied to the armature", NULL},
 | 
						|
	{"mirrorEdit", (getter)Armature_getMirrorEdit, (setter)Armature_setMirrorEdit, 
 | 
						|
		"Enable/Disable X-axis mirrored editing", NULL},
 | 
						|
	{"autoIK", (getter)Armature_getAutoIK, (setter)Armature_setAutoIK, 
 | 
						|
		"Adds temporal IK chains while grabbing bones", NULL},
 | 
						|
	{"layers", (getter)Armature_getLayers, (setter)Armature_setLayers, 
 | 
						|
		"List of layers for the armature", NULL},
 | 
						|
	{NULL, NULL, NULL, NULL, NULL}
 | 
						|
};
 | 
						|
//------------------------tp_new
 | 
						|
//This methods creates a new object (note it does not initialize it - only the building)
 | 
						|
//This can be called through python by myObject.__new__() however, tp_init is not called
 | 
						|
static PyObject *Armature_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 | 
						|
{
 | 
						|
	BPy_Armature *py_armature = NULL;
 | 
						|
	bArmature *bl_armature;
 | 
						|
 | 
						|
	bl_armature = add_armature();
 | 
						|
	if(bl_armature) {
 | 
						|
		bl_armature->id.us = 0; // return count to 0 - add_armature() inc'd it 
 | 
						|
 | 
						|
		py_armature = (BPy_Armature*)type->tp_alloc(type, 0); //*new*
 | 
						|
		if (py_armature == NULL)
 | 
						|
			goto RuntimeError;
 | 
						|
 | 
						|
		py_armature->armature = bl_armature;
 | 
						|
 | 
						|
		//create armature.bones
 | 
						|
		py_armature->Bones = (BPy_BonesDict*)PyBonesDict_FromPyArmature(py_armature);
 | 
						|
		if (!py_armature->Bones)
 | 
						|
			goto RuntimeError;
 | 
						|
 | 
						|
	} else {
 | 
						|
		goto RuntimeError;
 | 
						|
	}
 | 
						|
	return (PyObject*)py_armature; 
 | 
						|
 | 
						|
RuntimeError:
 | 
						|
	return EXPP_objError(PyExc_RuntimeError, "%s%s%s", 
 | 
						|
		sArmatureError, " __new__: ", "couldn't create Armature Data in Blender");
 | 
						|
}
 | 
						|
//------------------------tp_init
 | 
						|
//This methods does initialization of the new object
 | 
						|
//This method will get called in python by 'myObject(argument, keyword=value)'
 | 
						|
//tp_new will be automatically called before this
 | 
						|
static int Armature_init(BPy_Armature *self, PyObject *args, PyObject *kwds)
 | 
						|
{
 | 
						|
	char buf[21];
 | 
						|
	char *name = "myArmature";
 | 
						|
	static char *kwlist[] = {"name", NULL};
 | 
						|
 | 
						|
	if(!PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist, &name)){
 | 
						|
		goto AttributeError;
 | 
						|
	}
 | 
						|
 | 
						|
	//rename the armature if a name is supplied
 | 
						|
	if(!BLI_streq(name, "myArmature")){
 | 
						|
		PyOS_snprintf(buf, sizeof(buf), "%s", name);
 | 
						|
		rename_id(&self->armature->id, buf);
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
 | 
						|
AttributeError:
 | 
						|
	return EXPP_intError(PyExc_AttributeError, "%s%s%s", 
 | 
						|
		sArmatureBadArgs, " __init__: ", "Expects string(name)");
 | 
						|
}
 | 
						|
//------------------------tp_richcompare
 | 
						|
//This method allows the object to use comparison operators
 | 
						|
//TODO: We need some armature comparisons
 | 
						|
static PyObject *Armature_richcmpr(BPy_Armature *self, PyObject *v, int op)
 | 
						|
{
 | 
						|
	return EXPP_incr_ret(Py_None);
 | 
						|
}
 | 
						|
//------------------------tp_repr
 | 
						|
//This is the string representation of the object
 | 
						|
static PyObject *Armature_repr(BPy_Armature *self)
 | 
						|
{
 | 
						|
	return PyString_FromFormat( "[Armature: \"%s\"]", self->armature->id.name + 2 ); //*new*
 | 
						|
}
 | 
						|
//------------------------tp_dealloc
 | 
						|
//This tells how to 'tear-down' our object when ref count hits 0
 | 
						|
///tp_dealloc
 | 
						|
static void Armature_dealloc(BPy_Armature * self)
 | 
						|
{
 | 
						|
	Py_DECREF(self->Bones);
 | 
						|
	Armature_Type.tp_free(self);
 | 
						|
	return;
 | 
						|
}
 | 
						|
//------------------TYPE_OBECT DEFINITION--------------------------
 | 
						|
PyTypeObject Armature_Type = {
 | 
						|
	PyObject_HEAD_INIT(NULL)		//tp_head
 | 
						|
	0,								//tp_internal
 | 
						|
	"Armature",						//tp_name
 | 
						|
	sizeof(BPy_Armature),			//tp_basicsize
 | 
						|
	0,								//tp_itemsize
 | 
						|
	(destructor)Armature_dealloc,	//tp_dealloc
 | 
						|
	0,								//tp_print
 | 
						|
	0,								//tp_getattr
 | 
						|
	0,								//tp_setattr
 | 
						|
	0,								//tp_compare
 | 
						|
	(reprfunc) Armature_repr,		//tp_repr
 | 
						|
	0,								//tp_as_number
 | 
						|
	0,								//tp_as_sequence
 | 
						|
	0,								//tp_as_mapping
 | 
						|
	0,								//tp_hash
 | 
						|
	0,								//tp_call
 | 
						|
	0,								//tp_str
 | 
						|
	0,								//tp_getattro
 | 
						|
	0,								//tp_setattro
 | 
						|
	0,								//tp_as_buffer
 | 
						|
	Py_TPFLAGS_DEFAULT,				//tp_flags
 | 
						|
	BPy_Armature_doc,				//tp_doc
 | 
						|
	0,								//tp_traverse
 | 
						|
	0,								//tp_clear
 | 
						|
	(richcmpfunc)Armature_richcmpr,	//tp_richcompare
 | 
						|
	0,								//tp_weaklistoffset
 | 
						|
	0,								//tp_iter
 | 
						|
	0,								//tp_iternext
 | 
						|
	BPy_Armature_methods,			//tp_methods
 | 
						|
	0,								//tp_members
 | 
						|
	BPy_Armature_getset,			//tp_getset
 | 
						|
	0,								//tp_base
 | 
						|
	0,								//tp_dict
 | 
						|
	0,								//tp_descr_get
 | 
						|
	0,								//tp_descr_set
 | 
						|
	0,								//tp_dictoffset
 | 
						|
	(initproc)Armature_init,		//tp_init
 | 
						|
	0,								//tp_alloc
 | 
						|
	(newfunc)Armature_new,			//tp_new
 | 
						|
	0,								//tp_free
 | 
						|
	0,								//tp_is_gc
 | 
						|
	0,								//tp_bases
 | 
						|
	0,								//tp_mro
 | 
						|
	0,								//tp_cache
 | 
						|
	0,								//tp_subclasses
 | 
						|
	0,								//tp_weaklist
 | 
						|
	0								//tp_del
 | 
						|
};
 | 
						|
 | 
						|
//-------------------MODULE METHODS IMPLEMENTATION------------------------
 | 
						|
//----------------Blender.Armature.Get()
 | 
						|
/* This function will return a Py_Armature when a single string is passed
 | 
						|
* or else it will return a {key:value} dictionary when mutliple strings are passed
 | 
						|
* or it will return a {key:value} dictionary of all armatures when nothing is passed*/
 | 
						|
static PyObject *M_Armature_Get(PyObject * self, PyObject * args)
 | 
						|
{
 | 
						|
	PyObject *seq = NULL, *item = NULL, *dict = NULL, *py_armature = NULL;
 | 
						|
	char *name = "", buffer[24];
 | 
						|
	int size = 0, i;
 | 
						|
	void *data;
 | 
						|
 | 
						|
	//GET ARGUMENTS - () ('s') ('s',..) (['s',..]) are exceptable
 | 
						|
	size = PySequence_Length(args);
 | 
						|
	if (size == 1) {
 | 
						|
		seq = PySequence_GetItem(args, 0); //*new*
 | 
						|
		if (!seq)
 | 
						|
			goto RuntimeError;
 | 
						|
		if(!PyString_Check(seq)){
 | 
						|
			if (PySequence_Check(seq)) {
 | 
						|
				size = PySequence_Length(seq);
 | 
						|
			} else {
 | 
						|
				Py_DECREF(seq);
 | 
						|
				goto AttributeError;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		seq = EXPP_incr_ret(args); //*take ownership*
 | 
						|
	}
 | 
						|
	//'seq' should be a list, empty tuple or string - check list for strings
 | 
						|
	if(!PyString_Check(seq)){
 | 
						|
		for(i = 0; i < size; i++){
 | 
						|
			item = PySequence_GetItem(seq, i); //*new*
 | 
						|
			if (!item) {
 | 
						|
				Py_DECREF(seq);
 | 
						|
				goto RuntimeError;
 | 
						|
			}
 | 
						|
			if(!PyString_Check(item)){
 | 
						|
				EXPP_decr2(item, seq);
 | 
						|
				goto AttributeError;
 | 
						|
			}
 | 
						|
			Py_DECREF(item);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	//GET ARMATURES
 | 
						|
	if(size != 1){
 | 
						|
		dict = PyDict_New(); //*new*
 | 
						|
		if(!dict){
 | 
						|
			Py_DECREF(seq);
 | 
						|
			goto RuntimeError;
 | 
						|
		}
 | 
						|
		if(size == 0){	//GET ALL ARMATURES
 | 
						|
			data = G.main->armature.first; //get the first data ID from the armature library
 | 
						|
			while (data){
 | 
						|
				py_armature = PyArmature_FromArmature(data); //*new*
 | 
						|
				sprintf(buffer, "%s", ((bArmature*)data)->id.name +2);
 | 
						|
				if(PyDict_SetItemString(dict, buffer, py_armature) == -1){ //add to dictionary
 | 
						|
					EXPP_decr3(seq, dict, py_armature);
 | 
						|
					goto RuntimeError;
 | 
						|
				}
 | 
						|
				Py_DECREF(py_armature);
 | 
						|
				data = ((ID*)data)->next;
 | 
						|
			}
 | 
						|
			Py_DECREF(seq);
 | 
						|
		}else{	//GET ARMATURE LIST
 | 
						|
			for (i = 0; i < size; i++) {
 | 
						|
				item = PySequence_GetItem(seq, i); //*new*
 | 
						|
				name = PyString_AsString(item);
 | 
						|
				Py_DECREF(item);
 | 
						|
				data = find_id("AR", name); //get data from library
 | 
						|
				if (data != NULL){
 | 
						|
					py_armature = PyArmature_FromArmature(data); //*new*
 | 
						|
					if(PyDict_SetItemString(dict, name, py_armature) == -1){ //add to dictionary
 | 
						|
						EXPP_decr3(seq, dict, py_armature);
 | 
						|
						goto RuntimeError;
 | 
						|
					}
 | 
						|
					Py_DECREF(py_armature);
 | 
						|
				}else{
 | 
						|
					if(PyDict_SetItemString(dict, name, Py_None) == -1){ //add to dictionary
 | 
						|
						EXPP_decr2(seq, dict);
 | 
						|
						goto RuntimeError;
 | 
						|
					}
 | 
						|
					Py_DECREF(Py_None);
 | 
						|
				}
 | 
						|
			}
 | 
						|
			Py_DECREF(seq);
 | 
						|
		}
 | 
						|
		return dict;
 | 
						|
	}else{	//GET SINGLE ARMATURE
 | 
						|
		if(!PyString_Check(seq)){ //This handles the bizarre case where (['s']) is passed
 | 
						|
			item = PySequence_GetItem(seq, 0); //*new*
 | 
						|
			name = PyString_AsString(item);
 | 
						|
			Py_DECREF(item);
 | 
						|
		}else{
 | 
						|
			name = PyString_AsString(seq);
 | 
						|
		}
 | 
						|
		Py_DECREF(seq);
 | 
						|
		data = find_id("AR", name); //get data from library
 | 
						|
		if (data != NULL){
 | 
						|
			return PyArmature_FromArmature(data); //*new*
 | 
						|
		}else{
 | 
						|
			return EXPP_incr_ret(Py_None);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
RuntimeError:
 | 
						|
	return EXPP_objError(PyExc_RuntimeError, "%s%s%s", 
 | 
						|
		sModuleError, "Get(): ", "Internal Error Ocurred");
 | 
						|
 | 
						|
AttributeError:
 | 
						|
	return EXPP_objError(PyExc_AttributeError, "%s%s%s", 
 | 
						|
		sModuleBadArgs, "Get(): ", "- Expects (optional) string sequence");
 | 
						|
}
 | 
						|
 | 
						|
//-------------------MODULE METHODS DEFINITION-----------------------------
 | 
						|
 | 
						|
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.";
 | 
						|
 | 
						|
struct PyMethodDef M_Armature_methods[] = {
 | 
						|
	{"Get", M_Armature_Get, METH_VARARGS, M_Armature_Get_doc},
 | 
						|
	{NULL, NULL, 0, NULL}
 | 
						|
};
 | 
						|
//------------------VISIBLE PROTOTYPE IMPLEMENTATION-----------------------
 | 
						|
//-----------------(internal)
 | 
						|
//Converts a bArmature to a PyArmature
 | 
						|
PyObject *PyArmature_FromArmature(struct bArmature *armature)
 | 
						|
{
 | 
						|
	BPy_Armature *py_armature = NULL;
 | 
						|
 | 
						|
	//create armature type
 | 
						|
	py_armature = (BPy_Armature*)Armature_Type.tp_alloc(&Armature_Type, 0); //*new*
 | 
						|
	if (!py_armature)
 | 
						|
		goto RuntimeError;
 | 
						|
	py_armature->armature = armature;
 | 
						|
 | 
						|
	//create armature.bones
 | 
						|
	py_armature->Bones = (BPy_BonesDict*)PyBonesDict_FromPyArmature(py_armature);
 | 
						|
	if (!py_armature->Bones)
 | 
						|
		goto RuntimeError;
 | 
						|
 | 
						|
	return (PyObject *) py_armature; 
 | 
						|
 | 
						|
RuntimeError:
 | 
						|
	return EXPP_objError(PyExc_RuntimeError, "%s%s%s", 
 | 
						|
		sModuleError, "PyArmature_FromArmature: ", "Internal Error Ocurred");
 | 
						|
}
 | 
						|
//-----------------(internal)
 | 
						|
//Converts a PyArmature to a bArmature
 | 
						|
struct bArmature *PyArmature_AsArmature(BPy_Armature *py_armature)
 | 
						|
{
 | 
						|
	return (py_armature->armature);
 | 
						|
}
 | 
						|
//-------------------MODULE INITIALIZATION--------------------------------
 | 
						|
PyObject *Armature_Init(void)
 | 
						|
{
 | 
						|
	PyObject *module, *dict;
 | 
						|
 | 
						|
	//Initializes TypeObject.ob_type
 | 
						|
	if (PyType_Ready(&Armature_Type) < 0 ||	PyType_Ready(&BonesDict_Type) < 0 || 
 | 
						|
		PyType_Ready(&EditBone_Type) < 0 ||	PyType_Ready(&Bone_Type) < 0) {
 | 
						|
		return EXPP_incr_ret(Py_None);
 | 
						|
	}
 | 
						|
 | 
						|
	//Register the module
 | 
						|
	module = Py_InitModule3("Blender.Armature", M_Armature_methods, 
 | 
						|
		"The Blender Armature module"); 
 | 
						|
 | 
						|
	//Add TYPEOBJECTS to the module
 | 
						|
	PyModule_AddObject(module, "Armature", 
 | 
						|
		EXPP_incr_ret((PyObject *)&Armature_Type)); //*steals*
 | 
						|
	PyModule_AddObject(module, "Bone", 
 | 
						|
		EXPP_incr_ret((PyObject *)&Bone_Type)); //*steals*
 | 
						|
	PyModule_AddObject(module, "Editbone", 
 | 
						|
		EXPP_incr_ret((PyObject *)&EditBone_Type)); //*steals*
 | 
						|
 | 
						|
	//Add CONSTANTS to the module
 | 
						|
	PyModule_AddObject(module, "CONNECTED", 
 | 
						|
		EXPP_incr_ret(PyConstant_NewInt("CONNECTED", BONE_CONNECTED)));
 | 
						|
	PyModule_AddObject(module, "HINGE", 
 | 
						|
		EXPP_incr_ret(PyConstant_NewInt("HINGE", BONE_HINGE)));
 | 
						|
	PyModule_AddObject(module, "NO_DEFORM", 
 | 
						|
		EXPP_incr_ret(PyConstant_NewInt("NO_DEFORM", BONE_NO_DEFORM)));
 | 
						|
	PyModule_AddObject(module, "MULTIPLY", 
 | 
						|
		EXPP_incr_ret(PyConstant_NewInt("MULTIPLY", BONE_MULT_VG_ENV)));
 | 
						|
	PyModule_AddObject(module, "HIDDEN_EDIT", 
 | 
						|
		EXPP_incr_ret(PyConstant_NewInt("HIDDEN_EDIT", BONE_HIDDEN_A)));
 | 
						|
	PyModule_AddObject(module, "ROOT_SELECTED", 
 | 
						|
		EXPP_incr_ret(PyConstant_NewInt("ROOT_SELECTED", BONE_ROOTSEL)));
 | 
						|
	PyModule_AddObject(module, "BONE_SELECTED", 
 | 
						|
		EXPP_incr_ret(PyConstant_NewInt("BONE_SELECTED", BONE_SELECTED)));
 | 
						|
	PyModule_AddObject(module, "TIP_SELECTED", 
 | 
						|
		EXPP_incr_ret(PyConstant_NewInt("TIP_SELECTED", BONE_TIPSEL)));
 | 
						|
 | 
						|
	PyModule_AddObject(module, "OCTAHEDRON", 
 | 
						|
		EXPP_incr_ret(PyConstant_NewInt("OCTAHEDRON", ARM_OCTA)));
 | 
						|
	PyModule_AddObject(module, "STICK", 
 | 
						|
		EXPP_incr_ret(PyConstant_NewInt("STICK", ARM_LINE)));
 | 
						|
	PyModule_AddObject(module, "BBONE", 
 | 
						|
		EXPP_incr_ret(PyConstant_NewInt("BBONE", ARM_B_BONE)));
 | 
						|
	PyModule_AddObject(module, "ENVELOPE", 
 | 
						|
		EXPP_incr_ret(PyConstant_NewInt("ENVELOPE", ARM_ENVELOPE)));
 | 
						|
 | 
						|
	//Add SUBMODULES to the module
 | 
						|
	dict = PyModule_GetDict( module ); //borrowed
 | 
						|
	PyDict_SetItemString(dict, "NLA", NLA_Init()); //creates a *new* module
 | 
						|
 | 
						|
	return module;
 | 
						|
}
 |