1387 lines
43 KiB
C
1387 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)");
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* Function: Armature_compare */
|
|
/* Description: This is a callback function for the BPy_Armature type. It */
|
|
/* compares two Armature_Type objects. Only the "==" and "!=" */
|
|
/* comparisons are meaninful. Returns 0 for equality and -1 if */
|
|
/* they don't point to the same Blender Object struct. */
|
|
/* In Python it becomes 1 if they are equal, 0 otherwise. */
|
|
/*****************************************************************************/
|
|
static int Armature_compare( BPy_Armature * a, BPy_Armature * b )
|
|
{
|
|
return ( a->armature == b->armature ) ? 0 : -1;
|
|
}
|
|
|
|
//------------------------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
|
|
(cmpfunc) Armature_compare, //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
|
|
0, //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;
|
|
}
|