/* * $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. * * Contributor(s): Joseph Gilbert * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ #include "Bone.h" #include "BLI_blenlib.h" #include "BLI_arithb.h" #include "BKE_utildefines.h" #include "gen_utils.h" #include "BKE_armature.h" #include "Mathutils.h" #include "BKE_library.h" //these must come in this order #include "DNA_object_types.h" //1 #include "BIF_editarmature.h" //2 //------------------UNDECLARED EXTERNAL PROTOTYPES-------------------- extern void mat3_to_vec_roll(float mat[][3], float *vec, float *roll); //------------------------ERROR CODES--------------------------------- //This is here just to make me happy and to have more consistant error strings :) static const char sEditBoneError[] = "EditBone - Error: "; static const char sEditBoneBadArgs[] = "EditBone - Bad Arguments: "; static const char sBoneError[] = "Bone - Error: "; static const char sBoneBadArgs[] = "Bone - Bad Arguments: "; //----------------------(internal) //gets the bone->roll (which is a localspace roll) and puts it in parentspace //(which is the 'roll' value the user sees) double boneRoll_ToArmatureSpace(struct Bone *bone) { float head[3], tail[3], delta[3]; float premat[3][3], postmat[3][3]; float imat[3][3], difmat[3][3]; double roll = 0.0f; VECCOPY(head, bone->arm_head); VECCOPY(tail, bone->arm_tail); VECSUB (delta, tail, head); vec_roll_to_mat3(delta, 0.0f, postmat); Mat3CpyMat4(premat, bone->arm_mat); Mat3Inv(imat, postmat); Mat3MulMat3(difmat, imat, premat); roll = atan(difmat[2][0] / difmat[2][2]); if (difmat[0][0] < 0.0){ roll += M_PI; } return roll; //result is in radians } //################## EditBone_Type ######################## /*This type is a wrapper for a tempory bone. This is an 'unparented' bone *object. The armature->bonebase will be calculated from these temporary *python tracked objects.*/ //#################################################### //------------------METHOD IMPLEMENTATIONS----------------------------- //-------------------------EditBone.hasParent() PyObject *EditBone_hasParent(BPy_EditBone *self) { if (self->editbone){ if (self->editbone->parent) return EXPP_incr_ret(Py_True); else return EXPP_incr_ret(Py_False); }else{ goto AttributeError; } AttributeError: return EXPP_objError(PyExc_AttributeError, "%s%s%s", sEditBoneError, ".hasParent: ", "EditBone must be added to the armature first"); } //-------------------------EditBone.clearParent() PyObject *EditBone_clearParent(BPy_EditBone *self) { if (self->editbone){ if (self->editbone->parent) self->editbone->parent = NULL; return EXPP_incr_ret(Py_None); }else{ goto AttributeError; } AttributeError: return EXPP_objError(PyExc_AttributeError, "%s%s%s", sEditBoneError, ".clearParent: ", "EditBone must be added to the armature first"); } //------------------ATTRIBUTE IMPLEMENTATION--------------------------- //------------------------EditBone.name (get) static PyObject *EditBone_getName(BPy_EditBone *self, void *closure) { if (self->editbone) return PyString_FromString(self->editbone->name); else return PyString_FromString(self->name); } //------------------------EditBone.name (set) //check for char[] overflow here... static int EditBone_setName(BPy_EditBone *self, PyObject *value, void *closure) { char *name = ""; if (!PyArg_Parse(value, "s", &name)) goto AttributeError; if (self->editbone) BLI_strncpy(self->editbone->name, name, 32); else BLI_strncpy(self->name, name, 32); return 0; AttributeError: return EXPP_intError(PyExc_AttributeError, "%s%s%s", sEditBoneError, ".name: ", "expects a string"); } //------------------------EditBone.roll (get) static PyObject *EditBone_getRoll(BPy_EditBone *self, void *closure) { if (self->editbone){ return Py_BuildValue("f", PyFloat_FromDouble((self->editbone->roll * (180/Py_PI)))); }else{ return Py_BuildValue("f", PyFloat_FromDouble((self->roll * (180/Py_PI)))); } } //------------------------EditBone.roll (set) static int EditBone_setRoll(BPy_EditBone *self, PyObject *value, void *closure) { float roll = 0.0f; if (!PyArg_Parse(value, "f", &roll)) goto AttributeError; if (self->editbone){ self->editbone->roll = (float)(roll * (Py_PI/180)); }else{ self->roll = (float)(roll * (Py_PI/180)); } return 0; AttributeError: return EXPP_intError(PyExc_AttributeError, "%s%s%s", sEditBoneError, ".roll: ", "expects a float"); } //------------------------EditBone.head (get) static PyObject *EditBone_getHead(BPy_EditBone *self, void *closure) { if (self->editbone){ return newVectorObject(self->editbone->head, 3, Py_WRAP); }else{ return newVectorObject(self->head, 3, Py_NEW); } } //------------------------EditBone.head (set) static int EditBone_setHead(BPy_EditBone *self, PyObject *value, void *closure) { VectorObject *vec = NULL; int x; if (!PyArg_Parse(value, "O!", &vector_Type, &vec)) goto AttributeError; if (vec->size != 3) goto AttributeError2; if (self->editbone){ for (x = 0; x < 3; x++){ self->editbone->head[x] = vec->vec[x]; } }else{ for (x = 0; x < 3; x++){ self->head[x] = vec->vec[x]; } } return 0; AttributeError: return EXPP_intError(PyExc_AttributeError, "%s%s%s", sEditBoneError, ".head: ", "expects a Vector Object"); AttributeError2: return EXPP_intError(PyExc_AttributeError, "%s%s%s", sEditBoneError, ".head: ", "Vector Object needs to be (x,y,z)"); } //------------------------EditBone.tail (get) static PyObject *EditBone_getTail(BPy_EditBone *self, void *closure) { if (self->editbone){ return newVectorObject(self->editbone->tail, 3, Py_WRAP); }else{ return newVectorObject(self->tail, 3, Py_NEW); } } //------------------------EditBone.tail (set) static int EditBone_setTail(BPy_EditBone *self, PyObject *value, void *closure) { VectorObject *vec = NULL; int x; if (!PyArg_Parse(value, "O!", &vector_Type, &vec)) goto AttributeError; if (vec->size != 3) goto AttributeError2; if (self->editbone){ for (x = 0; x < 3; x++){ self->editbone->tail[x] = vec->vec[x]; } }else{ for (x = 0; x < 3; x++){ self->tail[x] = vec->vec[x]; } } return 0; AttributeError: return EXPP_intError(PyExc_AttributeError, "%s%s%s", sEditBoneError, ".tail: ", "expects a Vector Object"); AttributeError2: return EXPP_intError(PyExc_AttributeError, "%s%s%s", sEditBoneError, ".tail: ", "Vector Object needs to be (x,y,z)"); } //------------------------EditBone.weight (get) static PyObject *EditBone_getWeight(BPy_EditBone *self, void *closure) { if (self->editbone) return PyFloat_FromDouble(self->editbone->weight); else return PyFloat_FromDouble(self->weight); } //------------------------EditBone.weight (set) static int EditBone_setWeight(BPy_EditBone *self, PyObject *value, void *closure) { float weight; if (!PyArg_Parse(value, "f", &weight)) goto AttributeError; CLAMP(weight, 0.0f, 1000.0f); if (self->editbone) self->editbone->weight = weight; else self->weight = weight; return 0; AttributeError: return EXPP_intError(PyExc_AttributeError, "%s%s%s", sEditBoneError, ".weight: ", "expects a float"); } //------------------------EditBone.deform_dist (get) static PyObject *EditBone_getDeform_dist(BPy_EditBone *self, void *closure) { if (self->editbone) return PyFloat_FromDouble(self->editbone->dist); else return PyFloat_FromDouble(self->dist); } //------------------------EditBone.deform_dist (set) static int EditBone_setDeform_dist(BPy_EditBone *self, PyObject *value, void *closure) { float deform; if (!PyArg_Parse(value, "f", &deform)) goto AttributeError; CLAMP(deform, 0.0f, 1000.0f); if (self->editbone) self->editbone->dist = deform; else self->dist = deform; return 0; AttributeError: return EXPP_intError(PyExc_AttributeError, "%s%s%s", sEditBoneError, ".deform_dist: ", "expects a float"); } //------------------------EditBone.subdivisions (get) static PyObject *EditBone_getSubdivisions(BPy_EditBone *self, void *closure) { if (self->editbone) return PyInt_FromLong(self->editbone->segments); else return PyInt_FromLong(self->segments); } //------------------------EditBone.subdivisions (set) static int EditBone_setSubdivisions(BPy_EditBone *self, PyObject *value, void *closure) { int segs; if (!PyArg_Parse(value, "i", &segs)) goto AttributeError; CLAMP(segs, 1, 32); if (self->editbone) self->editbone->segments = (short)segs; else self->segments = (short)segs; return 0; AttributeError: return EXPP_intError(PyExc_AttributeError, "%s%s%s", sEditBoneError, ".subdivisions: ", "expects a integer"); } //------------------------EditBone.options (get) static PyObject *EditBone_getOptions(BPy_EditBone *self, void *closure) { PyObject *list = NULL; list = PyList_New(0); if (!list) goto RuntimeError; if(self->editbone){ if(self->editbone->flag & BONE_CONNECTED) if (PyList_Append(list, EXPP_GetModuleConstant("Blender.Armature", "CONNECTED")) == -1) goto RuntimeError; if(self->editbone->flag & BONE_HINGE) if (PyList_Append(list, EXPP_GetModuleConstant("Blender.Armature", "HINGE")) == -1) goto RuntimeError; if(self->editbone->flag & BONE_NO_DEFORM) if (PyList_Append(list, EXPP_GetModuleConstant("Blender.Armature", "NO_DEFORM")) == -1) goto RuntimeError; if(self->editbone->flag & BONE_MULT_VG_ENV) if (PyList_Append(list, EXPP_GetModuleConstant("Blender.Armature", "MULTIPLY")) == -1) goto RuntimeError; if(self->editbone->flag & BONE_HIDDEN_A) if (PyList_Append(list, EXPP_GetModuleConstant("Blender.Armature", "HIDDEN_EDIT")) == -1) goto RuntimeError; if(self->editbone->flag & BONE_ROOTSEL) if (PyList_Append(list, EXPP_GetModuleConstant("Blender.Armature", "ROOT_SELECTED")) == -1) goto RuntimeError; if(self->editbone->flag & BONE_SELECTED) if (PyList_Append(list, EXPP_GetModuleConstant("Blender.Armature", "BONE_SELECTED")) == -1) goto RuntimeError; if(self->editbone->flag & BONE_TIPSEL) if (PyList_Append(list, EXPP_GetModuleConstant("Blender.Armature", "TIP_SELECTED")) == -1) goto RuntimeError; }else{ if(self->flag & BONE_CONNECTED) if (PyList_Append(list, EXPP_GetModuleConstant("Blender.Armature", "CONNECTED")) == -1) goto RuntimeError; if(self->flag & BONE_HINGE) if (PyList_Append(list, EXPP_GetModuleConstant("Blender.Armature", "HINGE")) == -1) goto RuntimeError; if(self->flag & BONE_NO_DEFORM) if (PyList_Append(list, EXPP_GetModuleConstant("Blender.Armature", "NO_DEFORM")) == -1) goto RuntimeError; if(self->flag & BONE_MULT_VG_ENV) if (PyList_Append(list, EXPP_GetModuleConstant("Blender.Armature", "MULTIPLY")) == -1) goto RuntimeError; if(self->flag & BONE_HIDDEN_A) if (PyList_Append(list, EXPP_GetModuleConstant("Blender.Armature", "HIDDEN_EDIT")) == -1) goto RuntimeError; if(self->flag & BONE_ROOTSEL) if (PyList_Append(list, EXPP_GetModuleConstant("Blender.Armature", "ROOT_SELECTED")) == -1) goto RuntimeError; if(self->flag & BONE_SELECTED) if (PyList_Append(list, EXPP_GetModuleConstant("Blender.Armature", "BONE_SELECTED")) == -1) goto RuntimeError; if(self->flag & BONE_TIPSEL) if (PyList_Append(list, EXPP_GetModuleConstant("Blender.Armature", "TIP_SELECTED")) == -1) goto RuntimeError; } return EXPP_incr_ret(list); RuntimeError: return EXPP_objError(PyExc_RuntimeError, "%s%s%s", sEditBoneError, ".options: ", "Internal failure!"); } //----------------------(internal) EditBone_CheckValidConstant static int EditBone_CheckValidConstant(PyObject *constant) { PyObject *name = NULL; if (constant){ if (BPy_Constant_Check(constant)){ name = PyDict_GetItemString(((BPy_constant*)constant)->dict, "name"); if (!name) return 0; if (!STREQ3(PyString_AsString(name), "CONNECTED", "HINGE", "NO_DEFORM") && !STREQ3(PyString_AsString(name), "ROOT_SELECTED", "BONE_SELECTED", "TIP_SELECTED") && !STREQ2(PyString_AsString(name), "MULTIPLY", "HIDDEN_EDIT")) return 0; else return 1; }else{ return 0; } }else{ return 0; } } //------------------------EditBone.options (set) static int EditBone_setOptions(BPy_EditBone *self, PyObject *value, void *closure) { int length, numeric_value, new_flag = 0, x; PyObject *val = NULL, *index = NULL; if (PyList_Check(value)){ length = PyList_Size(value); for (x = 0; x < length; x++){ index = PyList_GetItem(value, x); if (!EditBone_CheckValidConstant(index)) goto AttributeError2; val = PyDict_GetItemString(((BPy_constant*)index)->dict, "value"); if (PyInt_Check(val)){ numeric_value = (int)PyInt_AS_LONG(val); new_flag |= numeric_value; }else{ goto AttributeError2; } } //set the options if(self->editbone){ //make sure the 'connected' property is set up correctly if (new_flag & BONE_CONNECTED) { if(!self->editbone->parent) goto AttributeError3; else VECCOPY(self->editbone->head, self->editbone->parent->tail); } self->editbone->flag = new_flag; }else{ self->flag = new_flag; } return 0; }else if (BPy_Constant_Check(value)){ if (!EditBone_CheckValidConstant(value)) goto AttributeError2; val = PyDict_GetItemString(((BPy_constant*)value)->dict, "value"); if (PyInt_Check(val)){ numeric_value = (int)PyInt_AS_LONG(val); if(self->editbone){ //make sure the 'connected' property is set up correctly if (numeric_value & BONE_CONNECTED) { if(!self->editbone->parent) goto AttributeError3; else VECCOPY(self->editbone->head, self->editbone->parent->tail); } self->editbone->flag = numeric_value; }else{ self->flag = numeric_value; } return 0; }else{ goto AttributeError2; } }else{ goto AttributeError1; } AttributeError1: return EXPP_intError(PyExc_AttributeError, "%s%s%s", sEditBoneError, ".options: ", "Expects a constant or list of constants"); AttributeError2: return EXPP_intError(PyExc_AttributeError, "%s%s%s", sEditBoneError, ".options: ", "Please use a constant defined in the Armature module"); AttributeError3: return EXPP_intError(PyExc_AttributeError, "%s%s%s", sEditBoneError, ".options: ", "You can't connect to parent because no parent is set"); } //------------------------EditBone.parent (get) static PyObject *EditBone_getParent(BPy_EditBone *self, void *closure) { if (self->editbone){ if (self->editbone->parent) return PyEditBone_FromEditBone(self->editbone->parent); else return EXPP_incr_ret(Py_None); }else{ return EXPP_incr_ret(Py_None); //not in the list yet can't have a parent } } //------------------------EditBone.parent (set) static int EditBone_setParent(BPy_EditBone *self, PyObject *value, void *closure) { BPy_EditBone *parent = NULL; if (!PyArg_Parse(value, "O!", &EditBone_Type, &parent)) goto AttributeError; if (!parent->editbone) goto AttributeError2; if (self->editbone){ self->editbone->parent = parent->editbone; }else{ self->parent = parent->editbone; } return 0; AttributeError: return EXPP_intError(PyExc_AttributeError, "%s%s%s", sEditBoneError, ".parent: ", "expects a EditBone Object"); AttributeError2: return EXPP_intError(PyExc_AttributeError, "%s%s%s", sEditBoneError, ".parent: ", "This object is not in the armature's bone list!"); } //------------------------EditBone.matrix (get) static PyObject *EditBone_getMatrix(BPy_EditBone *self, void *closure) { float boneMatrix[3][3]; float axis[3]; if (self->editbone){ VECSUB(axis, self->editbone->tail, self->editbone->head); vec_roll_to_mat3(axis, self->editbone->roll, boneMatrix); }else{ VECSUB(axis, self->tail, self->head); vec_roll_to_mat3(axis, self->roll, boneMatrix); } return newMatrixObject((float*)boneMatrix, 3, 3, Py_NEW); } //------------------------EditBone.matrix (set) static int EditBone_setMatrix(BPy_EditBone *self, PyObject *value, void *closure) { PyObject *matrix; float roll, length, vec[3], axis[3], mat3[3][3]; if (!PyArg_Parse(value, "O!", &matrix_Type, &matrix)) goto AttributeError; //make sure we have the right sizes if (((MatrixObject*)matrix)->rowSize != 3 && ((MatrixObject*)matrix)->colSize != 3){ if(((MatrixObject*)matrix)->rowSize != 4 && ((MatrixObject*)matrix)->colSize != 4){ goto AttributeError; } } /*vec will be a normalized directional vector * together with the length of the old bone vec*length = the new vector*/ /*The default rotation is 0,1,0 on the Y axis (see mat3_to_vec_roll)*/ if (((MatrixObject*)matrix)->rowSize == 4){ Mat3CpyMat4(mat3, ((float (*)[4])*((MatrixObject*)matrix)->matrix)); }else{ Mat3CpyMat3(mat3, ((float (*)[3])*((MatrixObject*)matrix)->matrix)); } mat3_to_vec_roll(mat3, vec, &roll); //if a 4x4 matrix was passed we'll translate the vector otherwise not if (self->editbone){ self->editbone->roll = roll; VecSubf(axis, self->editbone->tail, self->editbone->head); length = VecLength(axis); VecMulf(vec, length); if (((MatrixObject*)matrix)->rowSize == 4) VecCopyf(self->editbone->head, ((MatrixObject*)matrix)->matrix[3]); VecAddf(self->editbone->tail, self->editbone->head, vec); return 0; }else{ self->roll = roll; VecSubf(axis, self->tail, self->head); length = VecLength(axis); VecMulf(vec, length); if (((MatrixObject*)matrix)->rowSize == 4) VecCopyf(self->head, ((MatrixObject*)matrix)->matrix[3]); VecAddf(self->tail, self->head, vec); return 0; } AttributeError: return EXPP_intError(PyExc_AttributeError, "%s%s%s", sEditBoneError, ".matrix: ", "expects a 3x3 or 4x4 Matrix Object"); } //------------------------Bone.length (get) static PyObject *EditBone_getLength(BPy_EditBone *self, void *closure) { float delta[3]; double dot = 0.0f; int x; if (self->editbone){ VECSUB(delta, self->editbone->tail, self->editbone->head); for(x = 0; x < 3; x++){ dot += (delta[x] * delta[x]); } return PyFloat_FromDouble(sqrt(dot)); }else{ VECSUB(delta, self->tail, self->head); for(x = 0; x < 3; x++){ dot += (delta[x] * delta[x]); } return PyFloat_FromDouble(sqrt(dot)); } } //------------------------Bone.length (set) static int EditBone_setLength(BPy_EditBone *self, PyObject *value, void *closure) { printf("Sorry this isn't implemented yet.... :/"); return 1; } //------------------TYPE_OBECT IMPLEMENTATION-------------------------- //------------------------tp_methods //This contains a list of all methods the object contains static PyMethodDef BPy_EditBone_methods[] = { {"hasParent", (PyCFunction) EditBone_hasParent, METH_NOARGS, "() - True/False - Bone has a parent"}, {"clearParent", (PyCFunction) EditBone_clearParent, METH_NOARGS, "() - sets the parent to None"}, {NULL, NULL, 0, NULL} }; ///------------------------tp_getset //This contains methods for attributes that require checking static PyGetSetDef BPy_EditBone_getset[] = { {"name", (getter)EditBone_getName, (setter)EditBone_setName, "The name of the bone", NULL}, {"roll", (getter)EditBone_getRoll, (setter)EditBone_setRoll, "The roll (or rotation around the axis) of the bone", NULL}, {"head", (getter)EditBone_getHead, (setter)EditBone_setHead, "The start point of the bone", NULL}, {"tail", (getter)EditBone_getTail, (setter)EditBone_setTail, "The end point of the bone", NULL}, {"matrix", (getter)EditBone_getMatrix, (setter)EditBone_setMatrix, "The matrix of the bone", NULL}, {"weight", (getter)EditBone_getWeight, (setter)EditBone_setWeight, "The weight of the bone in relation to a parented mesh", NULL}, {"deformDist", (getter)EditBone_getDeform_dist, (setter)EditBone_setDeform_dist, "The distance at which deformation has effect", NULL}, {"subdivisions", (getter)EditBone_getSubdivisions, (setter)EditBone_setSubdivisions, "The number of subdivisions (for B-Bones)", NULL}, {"options", (getter)EditBone_getOptions, (setter)EditBone_setOptions, "The options effective on this bone", NULL}, {"parent", (getter)EditBone_getParent, (setter)EditBone_setParent, "The parent bone of this bone", NULL}, {"length", (getter)EditBone_getLength, (setter)EditBone_setLength, "The length of this bone", NULL}, {NULL, NULL, NULL, NULL,NULL} }; //------------------------tp_repr //This is the string representation of the object static PyObject *EditBone_repr(BPy_EditBone *self) { if (self->editbone) return PyString_FromFormat( "[EditBone \"%s\"]", self->editbone->name ); else return PyString_FromFormat( "[EditBone \"%s\"]", self->name ); } //------------------------tp_doc //The __doc__ string for this object static char BPy_EditBone_doc[] = "This is an internal subobject of armature\ designed to act as a wrapper for an 'edit bone'."; //------------------------tp_new //This methods creates a new object (note it does not initialize it - only the building) static PyObject *EditBone_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { char *name = "myEditBone"; BPy_EditBone *py_editBone = NULL; float head[3], tail[3]; py_editBone = (BPy_EditBone*)type->tp_alloc(type, 0); //new if (py_editBone == NULL) goto RuntimeError; //this pointer will be set when this bone is placed in ListBase //otherwise this will act as a py_object py_editBone->editbone = NULL; unique_editbone_name(name); BLI_strncpy(py_editBone->name, name, 32); py_editBone->parent = NULL; py_editBone->weight= 1.0f; py_editBone->dist= 0.25f; py_editBone->xwidth= 0.1f; py_editBone->zwidth= 0.1f; py_editBone->ease1= 1.0f; py_editBone->ease2= 1.0f; py_editBone->rad_head= 0.10f; py_editBone->rad_tail= 0.05f; py_editBone->segments= 1; py_editBone->flag = 0; py_editBone->roll = 0.0f; head[0] = head[1] = head[2] = 0.0f; tail[1] = tail[2] = 0.0f; tail[0] = 1.0f; VECCOPY(py_editBone->head, head); VECCOPY(py_editBone->tail, tail); return (PyObject*)py_editBone; RuntimeError: return EXPP_objError(PyExc_RuntimeError, "%s%s%s", sEditBoneError, " __new__: ", "Internal Error"); } //------------------------tp_dealloc //This tells how to 'tear-down' our object when ref count hits 0 //the struct EditBone pointer will be handled by the BPy_BonesDict class static void EditBone_dealloc(BPy_EditBone * self) { EditBone_Type.tp_free(self); return; } //------------------TYPE_OBECT DEFINITION-------------------------- PyTypeObject EditBone_Type = { PyObject_HEAD_INIT(NULL) //tp_head 0, //tp_internal "EditBone", //tp_name sizeof(BPy_EditBone), //tp_basicsize 0, //tp_itemsize (destructor)EditBone_dealloc, //tp_dealloc 0, //tp_print 0, //tp_getattr 0, //tp_setattr 0, //tp_compare (reprfunc)EditBone_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_EditBone_doc, //tp_doc 0, //tp_traverse 0, //tp_clear 0, //tp_richcompare 0, //tp_weaklistoffset 0, //tp_iter 0, //tp_iternext BPy_EditBone_methods, //tp_methods 0, //tp_members BPy_EditBone_getset, //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 (newfunc)EditBone_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 }; //------------------METHOD IMPLEMENTATIONS-------------------------------- //------------------------(internal) PyBone_ChildrenAsList static int PyBone_ChildrenAsList(PyObject *list, 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 == NULL) return 0; if(PyList_Append(list, py_bone) == -1){ goto RuntimeError; } if (bone->childbase.first) PyBone_ChildrenAsList(list, &bone->childbase); } return 1; RuntimeError: return EXPP_intError(PyExc_RuntimeError, "%s%s", sBoneError, "Internal error trying to wrap blender bones!"); } //-------------------------Bone.hasParent() PyObject *Bone_hasParent(BPy_Bone *self) { if (self->bone->parent) return EXPP_incr_ret(Py_True); else return EXPP_incr_ret(Py_False); } //-------------------------Bone.hasChildren() PyObject *Bone_hasChildren(BPy_Bone *self) { if (self->bone->childbase.first) return EXPP_incr_ret(Py_True); else return EXPP_incr_ret(Py_False); } //-------------------------Bone.getAllChildren() PyObject *Bone_getAllChildren(BPy_Bone *self) { PyObject *list = NULL; if (self->bone->childbase.first){ list = PyList_New(0); if (!PyBone_ChildrenAsList(list, &self->bone->childbase)) return NULL; return EXPP_incr_ret(list); }else{ return EXPP_incr_ret(Py_None); } } //------------------ATTRIBUTE IMPLEMENTATIONS----------------------------- //------------------------Bone.name (get) static PyObject *Bone_getName(BPy_Bone *self, void *closure) { return PyString_FromString(self->bone->name); } //------------------------Bone.name (set) //check for char[] overflow here... static int Bone_setName(BPy_Bone *self, PyObject *value, void *closure) { return EXPP_intError(PyExc_ValueError, "%s%s", sBoneError, "You must first call .makeEditable() to edit the armature"); } //------------------------Bone.roll (get) static PyObject *Bone_getRoll(BPy_Bone *self, void *closure) { return Py_BuildValue("{s:O, s:O}", "BONESPACE", PyFloat_FromDouble((self->bone->roll * (180/Py_PI))), "ARMATURESPACE", PyFloat_FromDouble((boneRoll_ToArmatureSpace(self->bone) * (180/Py_PI)))); } //------------------------Bone.roll (set) static int Bone_setRoll(BPy_Bone *self, PyObject *value, void *closure) { return EXPP_intError(PyExc_ValueError, "%s%s", sBoneError, "You must first call .makeEditable() to edit the armature"); } //------------------------Bone.head (get) static PyObject *Bone_getHead(BPy_Bone *self, void *closure) { return Py_BuildValue("{s:O, s:O}", "BONESPACE", newVectorObject(self->bone->head, 3, Py_WRAP), "ARMATURESPACE", newVectorObject(self->bone->arm_head, 3, Py_WRAP)); } //------------------------Bone.head (set) static int Bone_setHead(BPy_Bone *self, PyObject *value, void *closure) { return EXPP_intError(PyExc_ValueError, "%s%s", sBoneError, "You must first call .makeEditable() to edit the armature"); } //------------------------Bone.tail (get) static PyObject *Bone_getTail(BPy_Bone *self, void *closure) { return Py_BuildValue("{s:O, s:O}", "BONESPACE", newVectorObject(self->bone->tail, 3, Py_WRAP), "ARMATURESPACE", newVectorObject(self->bone->arm_tail, 3, Py_WRAP)); } //------------------------Bone.tail (set) static int Bone_setTail(BPy_Bone *self, PyObject *value, void *closure) { return EXPP_intError(PyExc_ValueError, "%s%s", sBoneError, "You must first call .makeEditable() to edit the armature"); } //------------------------Bone.weight (get) static PyObject *Bone_getWeight(BPy_Bone *self, void *closure) { return PyFloat_FromDouble(self->bone->weight); } //------------------------Bone.weight (set) static int Bone_setWeight(BPy_Bone *self, PyObject *value, void *closure) { return EXPP_intError(PyExc_ValueError, "%s%s", sBoneError, "You must first call .makeEditable() to edit the armature"); } //------------------------Bone.deform_dist (get) static PyObject *Bone_getDeform_dist(BPy_Bone *self, void *closure) { return PyFloat_FromDouble(self->bone->dist); } //------------------------Bone.deform_dist (set) static int Bone_setDeform_dist(BPy_Bone *self, PyObject *value, void *closure) { return EXPP_intError(PyExc_ValueError, "%s%s", sBoneError, "You must first call .makeEditable() to edit the armature"); } //------------------------Bone.subdivisions (get) static PyObject *Bone_getSubdivisions(BPy_Bone *self, void *closure) { return PyInt_FromLong(self->bone->segments); } //------------------------Bone.subdivisions (set) static int Bone_setSubdivisions(BPy_Bone *self, PyObject *value, void *closure) { return EXPP_intError(PyExc_ValueError, "%s%s", sBoneError, "You must first call .makeEditable() to edit the armature"); } //------------------------Bone.connected (get) static PyObject *Bone_getOptions(BPy_Bone *self, void *closure) { PyObject *list = NULL; list = PyList_New(0); if (list == NULL) goto RuntimeError; if(self->bone->flag & BONE_CONNECTED) if (PyList_Append(list, EXPP_GetModuleConstant("Blender.Armature", "CONNECTED")) == -1) goto RuntimeError; if(self->bone->flag & BONE_HINGE) if (PyList_Append(list, EXPP_GetModuleConstant("Blender.Armature", "HINGE")) == -1) goto RuntimeError; if(self->bone->flag & BONE_NO_DEFORM) if (PyList_Append(list, EXPP_GetModuleConstant("Blender.Armature", "NO_DEFORM")) == -1) goto RuntimeError; if(self->bone->flag & BONE_MULT_VG_ENV) if (PyList_Append(list, EXPP_GetModuleConstant("Blender.Armature", "MULTIPLY")) == -1) goto RuntimeError; if(self->bone->flag & BONE_HIDDEN_A) if (PyList_Append(list, EXPP_GetModuleConstant("Blender.Armature", "HIDDEN_EDIT")) == -1) goto RuntimeError; if(self->bone->flag & BONE_ROOTSEL) if (PyList_Append(list, EXPP_GetModuleConstant("Blender.Armature", "ROOT_SELECTED")) == -1) goto RuntimeError; if(self->bone->flag & BONE_SELECTED) if (PyList_Append(list, EXPP_GetModuleConstant("Blender.Armature", "BONE_SELECTED")) == -1) goto RuntimeError; if(self->bone->flag & BONE_TIPSEL) if (PyList_Append(list, EXPP_GetModuleConstant("Blender.Armature", "TIP_SELECTED")) == -1) goto RuntimeError; return EXPP_incr_ret(list); RuntimeError: return EXPP_objError(PyExc_RuntimeError, "%s%s%s", sBoneError, "getOptions(): ", "Internal failure!"); } //------------------------Bone.connected (set) static int Bone_setOptions(BPy_Bone *self, PyObject *value, void *closure) { return EXPP_intError(PyExc_ValueError, "%s%s", sBoneError, "You must first call .makeEditable() to edit the armature"); } //------------------------Bone.parent (get) static PyObject *Bone_getParent(BPy_Bone *self, void *closure) { if (self->bone->parent) return PyBone_FromBone(self->bone->parent); else return EXPP_incr_ret(Py_None); } //------------------------Bone.parent (set) static int Bone_setParent(BPy_Bone *self, PyObject *value, void *closure) { return EXPP_intError(PyExc_ValueError, "%s%s", sBoneError, "You must first call .makeEditable() to edit the armature"); } //------------------------Bone.children (get) static PyObject *Bone_getChildren(BPy_Bone *self, void *closure) { PyObject *list = NULL; Bone *bone = NULL; PyObject *py_bone = NULL; if (self->bone->childbase.first){ list = PyList_New(0); for (bone = self->bone->childbase.first; bone; bone = bone->next){ py_bone = PyBone_FromBone(bone); if (py_bone == NULL) return 0; if(PyList_Append(list, py_bone) == -1){ goto RuntimeError; } } return EXPP_incr_ret(list); }else{ return EXPP_incr_ret(Py_None); } RuntimeError: return EXPP_objError(PyExc_RuntimeError, "%s%s", sBoneError, "Internal error trying to wrap blender bones!"); } //------------------------Bone.children (set) static int Bone_setChildren(BPy_Bone *self, PyObject *value, void *closure) { return EXPP_intError(PyExc_ValueError, "%s%s", sBoneError, "You must first call .makeEditable() to edit the armature"); } //------------------------Bone.matrix (get) static PyObject *Bone_getMatrix(BPy_Bone *self, void *closure) { return Py_BuildValue("{s:O, s:O}", "BONESPACE", newMatrixObject((float*)self->bone->bone_mat, 3,3, Py_WRAP), "ARMATURESPACE", newMatrixObject((float*)self->bone->arm_mat, 4,4, Py_WRAP)); } //------------------------Bone.matrix (set) static int Bone_setMatrix(BPy_Bone *self, PyObject *value, void *closure) { return EXPP_intError(PyExc_ValueError, "%s%s", sBoneError, "You must first call .makeEditable() to edit the armature"); } //------------------------Bone.length (get) static PyObject *Bone_getLength(BPy_Bone *self, void *closure) { return Py_BuildValue("f", self->bone->length); } //------------------------Bone.length (set) static int Bone_setLength(BPy_Bone *self, PyObject *value, void *closure) { return EXPP_intError(PyExc_ValueError, "%s%s", sBoneError, "You must first call .makeEditable() to edit the armature"); } //------------------TYPE_OBECT IMPLEMENTATION-------------------------- //------------------------tp_methods //This contains a list of all methods the object contains static PyMethodDef BPy_Bone_methods[] = { {"hasParent", (PyCFunction) Bone_hasParent, METH_NOARGS, "() - True/False - Bone has a parent"}, {"hasChildren", (PyCFunction) Bone_hasChildren, METH_NOARGS, "() - True/False - Bone has 1 or more children"}, {"getAllChildren", (PyCFunction) Bone_getAllChildren, METH_NOARGS, "() - All the children for this bone - including children's children"}, {NULL, NULL, 0, NULL} }; //------------------------tp_getset //This contains methods for attributes that require checking static PyGetSetDef BPy_Bone_getset[] = { {"name", (getter)Bone_getName, (setter)Bone_setName, "The name of the bone", NULL}, {"roll", (getter)Bone_getRoll, (setter)Bone_setRoll, "The roll (or rotation around the axis) of the bone", NULL}, {"head", (getter)Bone_getHead, (setter)Bone_setHead, "The start point of the bone", NULL}, {"tail", (getter)Bone_getTail, (setter)Bone_setTail, "The end point of the bone", NULL}, {"matrix", (getter)Bone_getMatrix, (setter)Bone_setMatrix, "The matrix of the bone", NULL}, {"weight", (getter)Bone_getWeight, (setter)Bone_setWeight, "The weight of the bone in relation to a parented mesh", NULL}, {"deform_dist", (getter)Bone_getDeform_dist, (setter)Bone_setDeform_dist, "The distance at which deformation has effect", NULL}, {"subdivisions", (getter)Bone_getSubdivisions, (setter)Bone_setSubdivisions, "The number of subdivisions (for B-Bones)", NULL}, {"options", (getter)Bone_getOptions, (setter)Bone_setOptions, "The options effective on this bone", NULL}, {"parent", (getter)Bone_getParent, (setter)Bone_setParent, "The parent bone of this bone", NULL}, {"children", (getter)Bone_getChildren, (setter)Bone_setChildren, "The child bones of this bone", NULL}, {"length", (getter)Bone_getLength, (setter)Bone_setLength, "The length of this bone", NULL}, {NULL, NULL, NULL, NULL,NULL} }; //------------------------tp_repr //This is the string representation of the object static PyObject *Bone_repr(BPy_Bone *self) { return PyString_FromFormat( "[Bone \"%s\"]", self->bone->name ); } //------------------------tp_dealloc //This tells how to 'tear-down' our object when ref count hits 0 static void Bone_dealloc(BPy_Bone * self) { Bone_Type.tp_free(self); return; } //------------------------tp_doc //The __doc__ string for this object static char BPy_Bone_doc[] = "This object wraps a Blender Boneobject.\n\ This object is a subobject of the Armature object."; //------------------TYPE_OBECT DEFINITION-------------------------- PyTypeObject Bone_Type = { PyObject_HEAD_INIT(NULL) //tp_head 0, //tp_internal "Bone", //tp_name sizeof(BPy_Bone), //tp_basicsize 0, //tp_itemsize (destructor)Bone_dealloc, //tp_dealloc 0, //tp_print 0, //tp_getattr 0, //tp_setattr 0, //tp_compare (reprfunc) Bone_repr, //tp_repr 0, //tp_as_number 0, //tp_as_sequence 0, //tp_as_mapping 0, //tp_hash 0, //tp_call 0, //tp_str 0, //tp_getattro 0, //tp_setattro 0, //tp_as_buffer Py_TPFLAGS_DEFAULT, //tp_flags BPy_Bone_doc, //tp_doc 0, //tp_traverse 0, //tp_clear 0, //tp_richcompare 0, //tp_weaklistoffset 0, //tp_iter 0, //tp_iternext BPy_Bone_methods, //tp_methods 0, //tp_members BPy_Bone_getset, //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 }; //------------------VISIBLE PROTOTYPE IMPLEMENTATION----------------------- //-----------------(internal) //Converts a struct EditBone to a BPy_EditBone PyObject *PyEditBone_FromEditBone(struct EditBone *editbone) { BPy_EditBone *py_editbone = NULL; py_editbone = (BPy_EditBone*)EditBone_Type.tp_alloc(&EditBone_Type, 0); //*new* if (!py_editbone) goto RuntimeError; py_editbone->editbone = editbone; return (PyObject *) py_editbone; RuntimeError: return EXPP_objError(PyExc_RuntimeError, "%s%s%s", sEditBoneError, "PyEditBone_FromEditBone: ", "Internal Error Ocurred"); } //-----------------(internal) //Converts a struct Bone to a BPy_Bone PyObject *PyBone_FromBone(struct Bone *bone) { BPy_Bone *py_Bone = NULL; py_Bone = (BPy_Bone*)Bone_Type.tp_alloc(&Bone_Type, 0); //*new* if (py_Bone == NULL) goto RuntimeError; py_Bone->bone = bone; return (PyObject *) py_Bone; RuntimeError: return EXPP_objError(PyExc_RuntimeError, "%s%s%s", sBoneError, "PyBone_FromBone: ", "Internal Error Ocurred"); } //-----------------(internal) //Converts a PyBone to a bBone struct Bone *PyBone_AsBone(BPy_Bone *py_Bone) { return (py_Bone->bone); }