This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/python/api2_2x/Bone.c

1426 lines
44 KiB
C
Raw Normal View History

/*
* $Id: Bone.c 12399 2007-10-26 08:19:40Z campbellbarton $
*
* ***** 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 "vector.h"
#include "matrix.h"
#include "BLI_blenlib.h"
#include "BLI_arithb.h"
Mathutils update - also included is some fixes for preprocessor inclues and some clean up of the previous commit -rewrite and bugfixes ---------------------------------- Here's my changelog: -fixed Rand() so that it doesn't seed everytime and should generate better random numbers - changed a few error return types to something more appropriate - clean up of uninitialized variables & removal of unneccessary objects - NMesh returns wrapped vectors now - World returns wrapped matrices now - Object.getEuler() and Object.getBoundingBox() return Wrapped data when data is present - Object.getMatrix() returns wrapped data if it's worldspace, 'localspace' returns a new matrix - Vector, Euler, Mat, Quat, call all now internally wrap object without destroying internal datablocks - Removed memory allocation (unneeded) from all methods - Vector's resize methods are only applicable to new vectors not wrapped data. - Matrix(), Quat(), Euler(), Vector() now accepts ANY sequence list, including tuples, list, or a self object to copy - matrices accept multiple sequences - Fixed Slerp() so that it now works correctly values are clamped between 0 and 1 - Euler.rotate does internal rotation now - Slice assignment now works better for all types - Vector * Vector and Quat * Quat are defined and return the DOT product - Mat * Vec and Vec * Mat are defined now - Moved #includes to .c file from headers. Also fixed prototypes in mathutils - Added new helper functions for incref'ing to genutils - Major cleanup of header files includes - include Mathutils.h for access to math types - matrix.toQuat() and .toEuler() now fixed take appropriate matrix sizes - Matrix() with no parameters now returns an identity matrix by default not a zero matrix - printf() now prints with 6 digits instead of 4 - printf() now prints output with object descriptor - Matrices now support [x][y] assignment (e.g. matrix[x][y] = 5.4) - Matrix[index] = value now expectes a sequence not an integer. This will now set a ROW of the matrix through a sequence. index cannot go above the row size of the matrix. - slice operations on matrices work with sequences now (rows of the matrix) example: mymatrix[0:2] returns a list of 2 wrapped vectors with access to the matrix data. - slice assignment will no longer modify the data if the assignment operation fails - fixed error in matrix * scalar multiplication - euler.toMatrix(), toQuat() no longer causes "creep" from repeated use - Wrapped data will generate wrapped objects when toEuler(), toQuat(), toMatrix() is used - Quats can be created with angle/axis, axis/angle - 4x4 matrices can be multiplied by 3D vectors (by popular demand :)) - vec *quat / quat * vec is now defined - vec.magnitude alias for vec.length - all self, internal methods return a pointer to self now so you can do print vector.internalmethod() or vector.internalmethod().nextmethod() (no more print matrix.inverse() returning 'none') - these methods have been deprecated (still functioning but suggested to use the corrected functionality): * CopyVec() - replaced by Vector() functionality * CopyMat() - replaced by Matrix() functionality * CopyQuat() - replace by Quaternion() functionality * CopyEuler() - replaced by Euler() functionality * RotateEuler() - replaced by Euler.rotate() funtionality * MatMultVec() - replaced by matrix * vector * VecMultMat() - replaced by vector * matrix - New struct containers references to python object data or internally allocated blender data for wrapping * Explaination here: math structs now function as a 'simple wrapper' or a 'py_object' - data that is created on the fly will now be a 'py_object' with its memory managed by python * otherwise if the data is returned by blender's G.main then the math object is a 'simple wrapper' and data can be accessed directly from the struct just like other python objects.
2005-07-14 03:34:56 +00:00
#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
//------------------------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)
static 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 = atan2(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()
static PyObject *EditBone_hasParent(BPy_EditBone *self)
{
if (self->editbone){
if (self->editbone->parent)
Py_RETURN_TRUE;
else
Py_RETURN_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()
static PyObject *EditBone_clearParent(BPy_EditBone *self)
{
if (self->editbone){
if (self->editbone->parent)
self->editbone->parent = NULL;
Py_RETURN_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 PyFloat_FromDouble((self->editbone->roll * (180/Py_PI)));
}else{
return 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 list;
RuntimeError:
Py_XDECREF( list );
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
Py_RETURN_NONE;
}else{
Py_RETURN_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;
}
//------------------------Bone.headRadius (get)
static PyObject *EditBone_getHeadRadius(BPy_EditBone *self, void *closure)
{
if (self->editbone)
if (self->editbone->parent && self->editbone->flag & BONE_CONNECTED)
return PyFloat_FromDouble(self->editbone->parent->rad_tail);
else
return PyFloat_FromDouble(self->editbone->rad_head);
else
if (self->parent && self->flag & BONE_CONNECTED)
return PyFloat_FromDouble(self->parent->rad_tail);
else
return PyFloat_FromDouble(self->rad_head);
}
//------------------------Bone.headRadius (set)
static int EditBone_setHeadRadius(BPy_EditBone *self, PyObject *value, void *closure)
{
float radius;
if (!PyArg_Parse(value, "f", &radius))
goto AttributeError;
CLAMP(radius, 0.0f, 10000.0f);
if (self->editbone)
if (self->editbone->parent && self->editbone->flag & BONE_CONNECTED)
self->editbone->parent->rad_tail= radius;
else
self->editbone->rad_head= radius;
else
if (self->parent && self->flag & BONE_CONNECTED)
self->parent->rad_tail= radius;
else
self->rad_head= radius;
return 0;
AttributeError:
return EXPP_intError(PyExc_AttributeError, "%s%s%s",
sEditBoneError, ".headRadius: ", "expects a float");
}
//------------------------Bone.tailRadius (get)
static PyObject *EditBone_getTailRadius(BPy_EditBone *self, void *closure)
{
if (self->editbone)
return PyFloat_FromDouble(self->editbone->rad_tail);
else
return PyFloat_FromDouble(self->rad_tail);
}
//------------------------Bone.tailRadius (set)
static int EditBone_setTailRadius(BPy_EditBone *self, PyObject *value, void *closure)
{
float radius;
if (!PyArg_Parse(value, "f", &radius))
goto AttributeError;
CLAMP(radius, 0.0f, 10000.0f);
if (self->editbone)
self->editbone->rad_tail = radius;
else
self->rad_tail = radius;
return 0;
AttributeError:
return EXPP_intError(PyExc_AttributeError, "%s%s%s",
sEditBoneError, ".tailRadius: ", "expects a float");
}
//------------------------Bone.layerMask (get)
static PyObject *EditBone_getLayerMask(BPy_EditBone *self)
{
/* do this extra stuff because the short's bits can be negative values */
unsigned short laymask = 0;
if (self->editbone) laymask |= self->editbone->layer;
else laymask |= self->layer;
return PyInt_FromLong((int)laymask);
}
//------------------------Bone.layerMask (set)
static int EditBone_setLayerMask(BPy_EditBone *self, PyObject *value)
{
int laymask;
if (!PyInt_Check(value)) {
return EXPP_ReturnIntError( PyExc_AttributeError,
"expected an integer (bitmask) as argument" );
}
laymask = PyInt_AsLong(value);
if (laymask <= 0 || laymask > (1<<16) - 1)
return EXPP_ReturnIntError( PyExc_AttributeError,
"bitmask must have from 1 up to 16 bits set");
if (self->editbone) {
self->editbone->layer = 0;
self->editbone->layer |= laymask;
} else {
self->layer = 0;
self->layer |= laymask;
}
return 0;
}
//------------------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"},
2006-01-16 17:55:03 +00:00
{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},
{"tailRadius", (getter)EditBone_getTailRadius, (setter)EditBone_setTailRadius,
"Set the radius of this bones tip", NULL},
{"headRadius", (getter)EditBone_getHeadRadius, (setter)EditBone_setHeadRadius,
"Set the radius of this bones head", NULL},
{"layerMask", (getter)EditBone_getLayerMask, (setter)EditBone_setLayerMask,
"Layer bitmask", NULL },
2006-01-16 17:55:03 +00:00
{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 );
}
static int EditBone_compare( BPy_EditBone * a, BPy_EditBone * b )
{
/* if they are not wrapped, then they cant be the same */
if (a->editbone==NULL && b->editbone==NULL) return -1;
return ( a->editbone == b->editbone ) ? 0 : -1;
}
//------------------------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(NULL, 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->layer= 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
(cmpfunc)EditBone_compare, //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){
return 0;
}
Py_DECREF(py_bone);
if (bone->childbase.first)
if (!PyBone_ChildrenAsList(list, &bone->childbase))
return 0;
}
return 1;
}
//-------------------------Bone.hasParent()
static PyObject *Bone_hasParent(BPy_Bone *self)
{
if (self->bone->parent)
Py_RETURN_TRUE;
else
Py_RETURN_FALSE;
}
//-------------------------Bone.hasChildren()
static PyObject *Bone_hasChildren(BPy_Bone *self)
{
if (self->bone->childbase.first)
Py_RETURN_TRUE;
else
Py_RETURN_FALSE;
}
//-------------------------Bone.getAllChildren()
static PyObject *Bone_getAllChildren(BPy_Bone *self)
{
PyObject *list = PyList_New(0);
if (!self->bone->childbase.first) {
/* do nothing */
} else if (!PyBone_ChildrenAsList(list, &self->bone->childbase)) {
Py_XDECREF(list);
EXPP_objError(PyExc_RuntimeError, "%s%s",
sBoneError, "Internal error trying to wrap blender bones!");
}
return list;
}
//------------------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:f, s:f}",
"BONESPACE", self->bone->roll * (180/Py_PI),
"ARMATURESPACE", 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)
{
PyObject *val1 = newVectorObject(self->bone->head, 3, Py_WRAP);
PyObject *val2 = newVectorObject(self->bone->arm_head, 3, Py_WRAP);
PyObject *ret = Py_BuildValue(
"{s:O, s:O}", "BONESPACE", val1, "ARMATURESPACE", val2);
Py_DECREF(val1);
Py_DECREF(val2);
return ret;
}
//------------------------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)
{
PyObject *val1 = newVectorObject(self->bone->tail, 3, Py_WRAP);
PyObject *val2 = newVectorObject(self->bone->arm_tail, 3, Py_WRAP);
PyObject *ret = Py_BuildValue("{s:O, s:O}",
"BONESPACE", val1, "ARMATURESPACE", val2);
Py_DECREF(val1);
Py_DECREF(val2);
return ret;
}
//------------------------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 list;
RuntimeError:
Py_XDECREF(list);
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
Py_RETURN_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 = PyList_New(0);
Bone *bone = NULL;
PyObject *py_bone = NULL;
if (self->bone->childbase.first){
for (bone = self->bone->childbase.first; bone; bone = bone->next){
py_bone = PyBone_FromBone(bone);
if (py_bone == NULL)
goto RuntimeError;
if (PyList_Append(list, py_bone) == -1)
goto RuntimeError;
Py_DECREF(py_bone);
}
}
return list;
RuntimeError:
Py_XDECREF(list);
Py_XDECREF(py_bone);
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)
{
PyObject *val1 = newMatrixObject((float*)self->bone->bone_mat, 3,3, Py_WRAP);
PyObject *val2 = newMatrixObject((float*)self->bone->arm_mat, 4,4, Py_WRAP);
PyObject *ret = Py_BuildValue("{s:O, s:O}",
"BONESPACE", val1, "ARMATURESPACE", val2);
Py_DECREF(val1);
Py_DECREF(val2);
return ret;
}
//------------------------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 PyFloat_FromDouble(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");
}
//------------------------Bone.headRadius (get)
static PyObject *Bone_getHeadRadius(BPy_Bone *self, void *closure)
{
if (self->bone->parent && self->bone->flag & BONE_CONNECTED)
return PyFloat_FromDouble(self->bone->parent->rad_tail);
else
return PyFloat_FromDouble(self->bone->rad_head);
}
//------------------------Bone.headRadius (set)
static int Bone_setHeadRadius(BPy_Bone *self, PyObject *value, void *closure)
{
float radius;
if (!PyArg_Parse(value, "f", &radius))
goto AttributeError;
CLAMP(radius, 0.0f, 10000.0f);
if (self->bone->parent && self->bone->flag & BONE_CONNECTED)
self->bone->parent->rad_tail= radius;
else
self->bone->rad_head= radius;
return 0;
AttributeError:
return EXPP_intError(PyExc_AttributeError, "%s%s%s",
sEditBoneError, ".headRadius: ", "expects a float");
}
//------------------------Bone.tailRadius (get)
static PyObject *Bone_getTailRadius(BPy_Bone *self, void *closure)
{
return PyFloat_FromDouble(self->bone->rad_tail);
}
//------------------------Bone.headRadius (set)
static int Bone_setTailRadius(BPy_Bone *self, PyObject *value, void *closure)
{
float radius;
if (!PyArg_Parse(value, "f", &radius))
goto AttributeError;
CLAMP(radius, 0.0f, 10000.0f);
self->bone->rad_tail= radius;
return 0;
AttributeError:
return EXPP_intError(PyExc_AttributeError, "%s%s%s",
sEditBoneError, ".headRadius: ", "expects a float");
}
//------------------------Bone.layerMask (get)
static PyObject *Bone_getLayerMask(BPy_Bone *self)
{
/* do this extra stuff because the short's bits can be negative values */
unsigned short laymask = 0;
laymask |= self->bone->layer;
return PyInt_FromLong((int)laymask);
}
//------------------------Bone.layerMask (set)
static int Bone_setLayerMask(BPy_Bone *self, PyObject *value)
{
int laymask;
if (!PyInt_Check(value)) {
return EXPP_ReturnIntError( PyExc_AttributeError,
"expected an integer (bitmask) as argument" );
}
laymask = PyInt_AsLong(value);
if (laymask <= 0 || laymask > (1<<16) - 1)
return EXPP_ReturnIntError( PyExc_AttributeError,
"bitmask must have from 1 up to 16 bits set");
self->bone->layer = 0;
self->bone->layer |= laymask;
return 0;
}
//------------------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"},
2006-01-16 17:55:03 +00:00
{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},
{"tailRadius", (getter)Bone_getTailRadius, (setter)Bone_setTailRadius,
"Set the radius of this bones tip", NULL},
{"headRadius", (getter)Bone_getHeadRadius, (setter)Bone_setHeadRadius,
"Set the radius of this bones head", NULL},
{"layerMask", (getter)Bone_getLayerMask, (setter)Bone_setLayerMask,
"Layer bitmask", NULL },
2006-01-16 17:55:03 +00:00
{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 );
}
static int Bone_compare( BPy_Bone * a, BPy_Bone * b )
{
return ( a->bone == b->bone ) ? 0 : -1;
}
//------------------------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
(cmpfunc) Bone_compare, //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 = ( BPy_Bone * ) PyObject_NEW( BPy_Bone, &Bone_Type );
py_Bone->bone = bone;
Result of 2 weeks of quiet coding work in Greece :) Aim was to get a total refresh of the animation system. This is needed because; - we need to upgrade it with 21st century features - current code is spaghetti/hack combo, and hides good design - it should become lag-free with using dependency graphs A full log, with complete code API/structure/design explanation will follow, that's a load of work... so here below the list with hot changes; - The entire object update system (matrices, geometry) is now centralized. Calls to where_is_object and makeDispList are forbidden, instead we tag objects 'changed' and let the depgraph code sort it out - Removed all old "Ika" code - Depgraph is aware of all relationships, including meta balls, constraints, bevelcurve, and so on. - Made depgraph aware of relation types and layers, to do smart flushing of 'changed' events. Nothing gets calculated too often! - Transform uses depgraph to detect changes - On frame-advance, depgraph flushes animated changes Armatures; Almost all armature related code has been fully built from scratch. It now reveils the original design much better, with a very clean implementation, lag free without even calculating each Bone more than once. Result is quite a speedup yes! Important to note is; 1) Armature is data containing the 'rest position' 2) Pose is the changes of rest position, and always on object level. That way more Objects can use same Pose. Also constraints are in Pose 3) Actions only contain the Ipos to change values in Poses. - Bones draw unrotated now - Drawing bones speedup enormously (10-20 times) - Bone selecting in EditMode, selection state is saved for PoseMode, and vice-versa - Undo in editmode - Bone renaming does vertexgroups, constraints, posechannels, actions, for all users of Armature in entire file - Added Bone renaming in NKey panel - Nkey PoseMode shows eulers now - EditMode and PoseMode now have 'active' bone too (last clicked) - Parenting in EditMode' CTRL+P, ALT+P, with nice options! - Pose is added in Outliner now, with showing that constraints are in the Pose, not Armature - Disconnected IK solving from constraints. It's a separate phase now, on top of the full Pose calculations - Pose itself has a dependency graph too, so evaluation order is lag free. TODO NOW; - Rotating in Posemode has incorrect inverse transform (Martin will fix) - Python Bone/Armature/Pose API disabled... needs full recode too (wait for my doc!) - Game engine will need upgrade too - Depgraph code needs revision, cleanup, can be much faster! (But, compliments for Jean-Luc, it works like a charm!) - IK changed, it now doesnt use previous position to advance to next position anymore. That system looks nice (no flips) but is not well suited for NLA and background render. TODO LATER; We now can do loadsa new nifty features as well; like: - Kill PoseMode (can be option for armatures itself) - Make B-Bones (Bezier, Bspline, like for spines) - Move all silly button level edit to 3d window (like CTRL+I = add IK) - Much better & informative drawing - Fix action/nla editors - Put all ipos in Actions (object, mesh key, lamp color) - Add hooks - Null bones - Much more advanced constraints... Bugfixes; - OGL render (view3d header) had wrong first frame on anim render - Ipo 'recording' mode had wrong playback speed - Vertex-key mode now sticks to show 'active key', until frame change -Ton-
2005-07-03 17:35:38 +00:00
return (PyObject *) py_Bone;
}
//-----------------(internal)
//Converts a PyBone to a bBone
struct Bone *PyBone_AsBone(BPy_Bone *py_Bone)
{
return (py_Bone->bone);
}