 66bd3fbd18
			
		
	
	66bd3fbd18
	
	
	
		
			
			Bugfix #4886: deleting a bone would disconnect bones when it shouldn't have. Thanks to Michael Ward (easybreasy) for locating the problem.
		
			
				
	
	
		
			1379 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1379 lines
		
	
	
		
			43 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;
 | |
| 						 /* remove the connected flag or else the 'root' ball
 | |
| 						  * doesn't get drawn */
 | |
| 						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!");
 | |
| }
 | |
| 
 | |
| //------------------------Armature.__copy__()
 | |
| static PyObject *Armature_copy(BPy_Armature *self)
 | |
| {
 | |
| 	PyObject *py_armature = NULL;
 | |
| 	bArmature *bl_armature;
 | |
| 	bl_armature= copy_armature(self->armature);
 | |
| 	bl_armature->id.us= 0;
 | |
| 	py_armature= PyArmature_FromArmature( bl_armature );
 | |
| 	return py_armature;
 | |
| }
 | |
| 
 | |
| //------------------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"},
 | |
| 	{"__copy__", (PyCFunction) Armature_copy, METH_NOARGS, 
 | |
| 		"() - Return a copy of the armature."},
 | |
| 	{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");
 | |
| }
 | |
| 
 | |
| 
 | |
| //----------------Blender.Armature.New()
 | |
| static PyObject *M_Armature_New(PyObject * self, PyObject * args)
 | |
| {
 | |
| 	char *name = "Armature";
 | |
| 	struct bArmature *armature;
 | |
| 	BPy_Armature *obj;
 | |
| 	char buf[21];
 | |
| 
 | |
| 	if( !PyArg_ParseTuple( args, "|s", &name ) )
 | |
| 		return EXPP_ReturnPyObjError( PyExc_TypeError,
 | |
| 					      "expected nothing or a string as argument" );
 | |
| 
 | |
| 	armature= add_armature();
 | |
| 	armature->id.us = 0;
 | |
| 	obj = (BPy_Armature *)PyArmature_FromArmature(armature); /*new*/
 | |
| 
 | |
| 	if( !obj )
 | |
| 		return EXPP_ReturnPyObjError( PyExc_RuntimeError,
 | |
| 				       "PyObject_New() failed" );	
 | |
| 
 | |
| 	PyOS_snprintf( buf, sizeof( buf ), "%s", name );
 | |
| 	rename_id( &armature->id, buf );
 | |
| 
 | |
| 	obj->armature = armature;
 | |
| 	return (PyObject *)obj;
 | |
| }
 | |
| 
 | |
| 
 | |
| //-------------------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.";
 | |
| 
 | |
| static char M_Armature_New_doc[] = "(name) - return a new armature object.";
 | |
| 
 | |
| struct PyMethodDef M_Armature_methods[] = {
 | |
| 	{"Get", M_Armature_Get, METH_VARARGS, M_Armature_Get_doc},
 | |
| 	{"New", M_Armature_New, METH_VARARGS, M_Armature_New_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;
 | |
| }
 |