From ece00ff04a90aa0aaa37f27185c25b0f7b19e77d Mon Sep 17 00:00:00 2001 From: Stephen Swaney Date: Sun, 22 May 2005 17:40:00 +0000 Subject: Roll back changes from Big Mathutils Commit on 2005/05/20. --- source/blender/python/BPY_interface.c | 2 +- source/blender/python/api2_2x/Bone.c | 148 +- source/blender/python/api2_2x/Mathutils.c | 2155 +++++++++++++++++------------ source/blender/python/api2_2x/Mathutils.h | 38 +- source/blender/python/api2_2x/NMesh.c | 10 +- source/blender/python/api2_2x/Object.c | 75 +- source/blender/python/api2_2x/Object.h | 6 +- source/blender/python/api2_2x/Types.c | 1 - source/blender/python/api2_2x/Window.c | 4 +- source/blender/python/api2_2x/euler.c | 546 ++++---- source/blender/python/api2_2x/euler.h | 32 +- source/blender/python/api2_2x/gen_utils.c | 25 - source/blender/python/api2_2x/gen_utils.h | 6 - source/blender/python/api2_2x/matrix.c | 1470 +++++++++++--------- source/blender/python/api2_2x/matrix.h | 43 +- source/blender/python/api2_2x/quat.c | 874 ++++++------ source/blender/python/api2_2x/quat.h | 36 +- source/blender/python/api2_2x/vector.c | 1147 +++++++-------- source/blender/python/api2_2x/vector.h | 38 +- 19 files changed, 3596 insertions(+), 3060 deletions(-) (limited to 'source/blender/python') diff --git a/source/blender/python/BPY_interface.c b/source/blender/python/BPY_interface.c index 0af732936e8..3306f68ccf8 100644 --- a/source/blender/python/BPY_interface.c +++ b/source/blender/python/BPY_interface.c @@ -1523,7 +1523,7 @@ PyObject *CreateGlobalDictionary( void ) PyDict_SetItemString( dict, "__name__", PyString_FromString( "__main__" ) ); - return EXPP_incr_ret(dict); + return dict; } /***************************************************************************** diff --git a/source/blender/python/api2_2x/Bone.c b/source/blender/python/api2_2x/Bone.c index c5175cb2d87..686b791a846 100644 --- a/source/blender/python/api2_2x/Bone.c +++ b/source/blender/python/api2_2x/Bone.c @@ -46,14 +46,12 @@ #include #include #include -#include #include "constant.h" #include "gen_utils.h" #include "NLA.h" #include "quat.h" #include "matrix.h" #include "vector.h" -#include "Types.h" //--------------------Python API function prototypes for the Bone module---- static PyObject *M_Bone_New( PyObject * self, PyObject * args ); @@ -539,19 +537,45 @@ PyObject *Bone_CreatePyObject( struct Bone * bone ) //allocate space for python vars blen_bone->name = PyMem_Malloc( 32 + 1 ); blen_bone->parent = PyMem_Malloc( 32 + 1 ); - blen_bone->head = ( VectorObject *)newVectorObject( NULL, 3, Py_NEW ); - blen_bone->tail = ( VectorObject *)newVectorObject( NULL, 3, Py_NEW ); - blen_bone->loc = ( VectorObject *)newVectorObject( NULL, 3, Py_NEW ); - blen_bone->dloc = ( VectorObject *)newVectorObject( NULL, 3, Py_NEW ); - blen_bone->size = ( VectorObject *)newVectorObject( NULL, 3, Py_NEW ); - blen_bone->dsize = ( VectorObject *)newVectorObject( NULL, 3, Py_NEW ); - blen_bone->quat = ( QuaternionObject *)newQuaternionObject( NULL, Py_NEW ); - blen_bone->dquat = ( QuaternionObject *)newQuaternionObject( NULL, Py_NEW ); - blen_bone->obmat = ( MatrixObject *)newMatrixObject( NULL, 4, 4 , Py_NEW); - blen_bone->parmat = ( MatrixObject *)newMatrixObject( NULL, 4, 4 , Py_NEW); - blen_bone->defmat = ( MatrixObject *)newMatrixObject( NULL, 4, 4 , Py_NEW); - blen_bone->irestmat = ( MatrixObject *)newMatrixObject( NULL, 4, 4 , Py_NEW); - blen_bone->posemat = ( MatrixObject *)newMatrixObject( NULL, 4, 4 , Py_NEW); + blen_bone->head = + ( VectorObject * ) + newVectorObject( PyMem_Malloc( 3 * sizeof( float ) ), 3 ); + blen_bone->tail = + ( VectorObject * ) + newVectorObject( PyMem_Malloc( 3 * sizeof( float ) ), 3 ); + blen_bone->loc = + ( VectorObject * ) + newVectorObject( PyMem_Malloc( 3 * sizeof( float ) ), 3 ); + blen_bone->dloc = + ( VectorObject * ) + newVectorObject( PyMem_Malloc( 3 * sizeof( float ) ), 3 ); + blen_bone->size = + ( VectorObject * ) + newVectorObject( PyMem_Malloc( 3 * sizeof( float ) ), 3 ); + blen_bone->dsize = + ( VectorObject * ) + newVectorObject( PyMem_Malloc( 3 * sizeof( float ) ), 3 ); + blen_bone->quat = + ( QuaternionObject * ) + newQuaternionObject( PyMem_Malloc( 4 * sizeof( float ) ) ); + blen_bone->dquat = + ( QuaternionObject * ) + newQuaternionObject( PyMem_Malloc( 4 * sizeof( float ) ) ); + blen_bone->obmat = + ( MatrixObject * ) + newMatrixObject( PyMem_Malloc( 16 * sizeof( float ) ), 4, 4 ); + blen_bone->parmat = + ( MatrixObject * ) + newMatrixObject( PyMem_Malloc( 16 * sizeof( float ) ), 4, 4 ); + blen_bone->defmat = + ( MatrixObject * ) + newMatrixObject( PyMem_Malloc( 16 * sizeof( float ) ), 4, 4 ); + blen_bone->irestmat = + ( MatrixObject * ) + newMatrixObject( PyMem_Malloc( 16 * sizeof( float ) ), 4, 4 ); + blen_bone->posemat = + ( MatrixObject * ) + newMatrixObject( PyMem_Malloc( 16 * sizeof( float ) ), 4, 4 ); if( !updatePyBone( blen_bone ) ) return EXPP_ReturnPyObjError( PyExc_AttributeError, @@ -600,19 +624,45 @@ static PyObject *M_Bone_New( PyObject * self, PyObject * args ) //allocate space for python vars py_bone->name = PyMem_Malloc( 32 + 1 ); py_bone->parent = PyMem_Malloc( 32 + 1 ); - py_bone->head = ( VectorObject *)newVectorObject( NULL, 3, Py_NEW ); - py_bone->tail = ( VectorObject *)newVectorObject( NULL, 3, Py_NEW ); - py_bone->loc = ( VectorObject *)newVectorObject( NULL, 3, Py_NEW ); - py_bone->dloc = ( VectorObject *)newVectorObject( NULL, 3, Py_NEW ); - py_bone->size = ( VectorObject *)newVectorObject( NULL, 3, Py_NEW ); - py_bone->dsize = ( VectorObject *)newVectorObject( NULL, 3, Py_NEW ); - py_bone->quat = ( QuaternionObject *)newQuaternionObject( NULL, Py_NEW ); - py_bone->dquat = ( QuaternionObject *)newQuaternionObject( NULL, Py_NEW ); - py_bone->obmat = ( MatrixObject *)newMatrixObject( NULL, 4, 4 , Py_NEW); - py_bone->parmat = ( MatrixObject *)newMatrixObject( NULL, 4, 4 , Py_NEW); - py_bone->defmat = ( MatrixObject *)newMatrixObject( NULL, 4, 4 , Py_NEW); - py_bone->irestmat = ( MatrixObject *)newMatrixObject( NULL, 4, 4 , Py_NEW); - py_bone->posemat = ( MatrixObject *)newMatrixObject( NULL, 4, 4 , Py_NEW); + py_bone->head = + ( VectorObject * ) + newVectorObject( PyMem_Malloc( 3 * sizeof( float ) ), 3 ); + py_bone->tail = + ( VectorObject * ) + newVectorObject( PyMem_Malloc( 3 * sizeof( float ) ), 3 ); + py_bone->loc = + ( VectorObject * ) + newVectorObject( PyMem_Malloc( 3 * sizeof( float ) ), 3 ); + py_bone->dloc = + ( VectorObject * ) + newVectorObject( PyMem_Malloc( 3 * sizeof( float ) ), 3 ); + py_bone->size = + ( VectorObject * ) + newVectorObject( PyMem_Malloc( 3 * sizeof( float ) ), 3 ); + py_bone->dsize = + ( VectorObject * ) + newVectorObject( PyMem_Malloc( 3 * sizeof( float ) ), 3 ); + py_bone->quat = + ( QuaternionObject * ) + newQuaternionObject( PyMem_Malloc( 4 * sizeof( float ) ) ); + py_bone->dquat = + ( QuaternionObject * ) + newQuaternionObject( PyMem_Malloc( 4 * sizeof( float ) ) ); + py_bone->obmat = + ( MatrixObject * ) + newMatrixObject( PyMem_Malloc( 16 * sizeof( float ) ), 4, 4 ); + py_bone->parmat = + ( MatrixObject * ) + newMatrixObject( PyMem_Malloc( 16 * sizeof( float ) ), 4, 4 ); + py_bone->defmat = + ( MatrixObject * ) + newMatrixObject( PyMem_Malloc( 16 * sizeof( float ) ), 4, 4 ); + py_bone->irestmat = + ( MatrixObject * ) + newMatrixObject( PyMem_Malloc( 16 * sizeof( float ) ), 4, 4 ); + py_bone->posemat = + ( MatrixObject * ) + newMatrixObject( PyMem_Malloc( 16 * sizeof( float ) ), 4, 4 ); //default py values BLI_strncpy( py_bone->name, name_str, strlen( name_str ) + 1 ); @@ -709,17 +759,19 @@ static PyObject *Bone_getWeight( BPy_Bone * self ) static PyObject *Bone_getHead( BPy_Bone * self ) { PyObject *attr = NULL; - float vec[3]; + float *vec; int x; if( !self->bone ) { //test to see if linked to armature //use python vars + vec = PyMem_Malloc( 3 * sizeof( float ) ); for( x = 0; x < 3; x++ ) vec[x] = self->head->vec[x]; - attr = ( PyObject * ) newVectorObject( vec, 3, Py_NEW ); + attr = ( PyObject * ) newVectorObject( vec, 3 ); } else { //use bone datastruct - attr = newVectorObject( NULL, 3, Py_NEW ); + attr = newVectorObject( PyMem_Malloc( 3 * sizeof( float ) ), + 3 ); ( ( VectorObject * ) attr )->vec[0] = self->bone->head[0]; ( ( VectorObject * ) attr )->vec[1] = self->bone->head[1]; ( ( VectorObject * ) attr )->vec[2] = self->bone->head[2]; @@ -735,17 +787,19 @@ static PyObject *Bone_getHead( BPy_Bone * self ) static PyObject *Bone_getTail( BPy_Bone * self ) { PyObject *attr = NULL; - float vec[3]; + float *vec; int x; if( !self->bone ) { //test to see if linked to armature //use python vars + vec = PyMem_Malloc( 3 * sizeof( float ) ); for( x = 0; x < 3; x++ ) vec[x] = self->tail->vec[x]; - attr = ( PyObject * ) newVectorObject( vec, 3, Py_NEW ); + attr = ( PyObject * ) newVectorObject( vec, 3 ); } else { //use bone datastruct - attr = newVectorObject( NULL, 3, Py_NEW ); + attr = newVectorObject( PyMem_Malloc( 3 * sizeof( float ) ), + 3 ); ( ( VectorObject * ) attr )->vec[0] = self->bone->tail[0]; ( ( VectorObject * ) attr )->vec[1] = self->bone->tail[1]; ( ( VectorObject * ) attr )->vec[2] = self->bone->tail[2]; @@ -761,17 +815,19 @@ static PyObject *Bone_getTail( BPy_Bone * self ) static PyObject *Bone_getLoc( BPy_Bone * self ) { PyObject *attr = NULL; - float vec[3]; + float *vec; int x; if( !self->bone ) { //test to see if linked to armature //use python vars + vec = PyMem_Malloc( 3 * sizeof( float ) ); for( x = 0; x < 3; x++ ) vec[x] = self->loc->vec[x]; - attr = ( PyObject * ) newVectorObject( vec, 3, Py_NEW ); + attr = ( PyObject * ) newVectorObject( vec, 3 ); } else { //use bone datastruct - attr = newVectorObject( vec, 3, Py_NEW ); + attr = newVectorObject( PyMem_Malloc( 3 * sizeof( float ) ), + 3 ); ( ( VectorObject * ) attr )->vec[0] = self->bone->loc[0]; ( ( VectorObject * ) attr )->vec[1] = self->bone->loc[1]; ( ( VectorObject * ) attr )->vec[2] = self->bone->loc[2]; @@ -787,17 +843,19 @@ static PyObject *Bone_getLoc( BPy_Bone * self ) static PyObject *Bone_getSize( BPy_Bone * self ) { PyObject *attr = NULL; - float vec[3]; + float *vec; int x; if( !self->bone ) { //test to see if linked to armature //use python vars + vec = PyMem_Malloc( 3 * sizeof( float ) ); for( x = 0; x < 3; x++ ) vec[x] = self->size->vec[x]; - attr = ( PyObject * ) newVectorObject( vec, 3, Py_NEW ); + attr = ( PyObject * ) newVectorObject( vec, 3 ); } else { //use bone datastruct - attr = newVectorObject( vec, 3, Py_NEW ); + attr = newVectorObject( PyMem_Malloc( 3 * sizeof( float ) ), + 3 ); ( ( VectorObject * ) attr )->vec[0] = self->bone->size[0]; ( ( VectorObject * ) attr )->vec[1] = self->bone->size[1]; ( ( VectorObject * ) attr )->vec[2] = self->bone->size[2]; @@ -813,18 +871,20 @@ static PyObject *Bone_getSize( BPy_Bone * self ) static PyObject *Bone_getQuat( BPy_Bone * self ) { PyObject *attr = NULL; - float quat[4]; + float *quat; int x; if( !self->bone ) { //test to see if linked to armature //use python vars - p.s. - you must return a copy or else //python will trash the internal var + quat = PyMem_Malloc( 4 * sizeof( float ) ); for( x = 0; x < 4; x++ ) quat[x] = self->quat->quat[x]; - attr = ( PyObject * ) newQuaternionObject( quat, Py_NEW ); + attr = ( PyObject * ) newQuaternionObject( quat ); } else { //use bone datastruct - attr = newQuaternionObject( NULL, Py_NEW ); + attr = newQuaternionObject( PyMem_Malloc + ( 4 * sizeof( float ) ) ); ( ( QuaternionObject * ) attr )->quat[0] = self->bone->quat[0]; ( ( QuaternionObject * ) attr )->quat[1] = self->bone->quat[1]; ( ( QuaternionObject * ) attr )->quat[2] = self->bone->quat[2]; @@ -1625,7 +1685,7 @@ static PyObject *Bone_getRestMatrix( BPy_Bone * self, PyObject * args ) return ( EXPP_ReturnPyObjError( PyExc_AttributeError, "expected 'bonespace' or 'worldspace'" ) ); - matrix = newMatrixObject( NULL, 4, 4 , Py_NEW); + matrix = newMatrixObject( PyMem_Malloc( 16 * sizeof( float ) ), 4, 4 ); if( !self->bone ) { //test to see if linked to armature //use python vars diff --git a/source/blender/python/api2_2x/Mathutils.c b/source/blender/python/api2_2x/Mathutils.c index 1ddc572bbd1..910b1587974 100644 --- a/source/blender/python/api2_2x/Mathutils.c +++ b/source/blender/python/api2_2x/Mathutils.c @@ -30,6 +30,7 @@ * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ +#include #include #include #include @@ -39,562 +40,765 @@ #include #include #include +#include "vector.h" +#include "euler.h" +#include "quat.h" +#include "matrix.h" #include "blendef.h" #include "mydevice.h" #include "constant.h" #include "gen_utils.h" #include "Mathutils.h" -//-------------------------DOC STRINGS --------------------------- + + +/*****************************************************************************/ +// Python API function prototypes for the Mathutils module. +/*****************************************************************************/ +static PyObject *M_Mathutils_Rand( PyObject * self, PyObject * args ); +static PyObject *M_Mathutils_Vector( PyObject * self, PyObject * args ); +static PyObject *M_Mathutils_CrossVecs( PyObject * self, PyObject * args ); +static PyObject *M_Mathutils_DotVecs( PyObject * self, PyObject * args ); +static PyObject *M_Mathutils_AngleBetweenVecs( PyObject * self, + PyObject * args ); +static PyObject *M_Mathutils_MidpointVecs( PyObject * self, PyObject * args ); +static PyObject *M_Mathutils_VecMultMat( PyObject * self, PyObject * args ); +static PyObject *M_Mathutils_ProjectVecs( PyObject * self, PyObject * args ); +static PyObject *M_Mathutils_CopyVec( PyObject * self, PyObject * args ); +static PyObject *M_Mathutils_Matrix( PyObject * self, PyObject * args ); +static PyObject *M_Mathutils_RotationMatrix( PyObject * self, + PyObject * args ); +static PyObject *M_Mathutils_ScaleMatrix( PyObject * self, PyObject * args ); +static PyObject *M_Mathutils_OrthoProjectionMatrix( PyObject * self, + PyObject * args ); +static PyObject *M_Mathutils_ShearMatrix( PyObject * self, PyObject * args ); +static PyObject *M_Mathutils_TranslationMatrix( PyObject * self, + PyObject * args ); +static PyObject *M_Mathutils_MatMultVec( PyObject * self, PyObject * args ); +static PyObject *M_Mathutils_CopyMat( PyObject * self, PyObject * args ); +static PyObject *M_Mathutils_Quaternion( PyObject * self, PyObject * args ); +static PyObject *M_Mathutils_CrossQuats( PyObject * self, PyObject * args ); +static PyObject *M_Mathutils_DotQuats( PyObject * self, PyObject * args ); +static PyObject *M_Mathutils_CopyQuat( PyObject * self, PyObject * args ); +static PyObject *M_Mathutils_DifferenceQuats( PyObject * self, + PyObject * args ); +static PyObject *M_Mathutils_Slerp( PyObject * self, PyObject * args ); +static PyObject *M_Mathutils_Euler( PyObject * self, PyObject * args ); +static PyObject *M_Mathutils_CopyEuler( PyObject * self, PyObject * args ); +static PyObject *M_Mathutils_RotateEuler( PyObject * self, PyObject * args ); + +/*****************************************************************************/ +// The following string definitions are used for documentation strings. +// In Python these will be written to the console when doing a +// Blender.Mathutils.__doc__ +/* Mathutils Module strings */ +/****************************************************************************/ static char M_Mathutils_doc[] = "The Blender Mathutils module\n\n"; -static char M_Mathutils_Vector_doc[] = "() - create a new vector object from a list of floats"; -static char M_Mathutils_Matrix_doc[] = "() - create a new matrix object from a list of floats"; -static char M_Mathutils_Quaternion_doc[] = "() - create a quaternion from a list or an axis of rotation and an angle"; -static char M_Mathutils_Euler_doc[] = "() - create and return a new euler object"; +static char M_Mathutils_Vector_doc[] = + "() - create a new vector object from a list of floats"; +static char M_Mathutils_Matrix_doc[] = + "() - create a new matrix object from a list of floats"; +static char M_Mathutils_Quaternion_doc[] = + "() - create a quaternion from a list or an axis of rotation and an angle"; +static char M_Mathutils_Euler_doc[] = + "() - create and return a new euler object"; static char M_Mathutils_Rand_doc[] = "() - return a random number"; -static char M_Mathutils_CrossVecs_doc[] = "() - returns a vector perpedicular to the 2 vectors crossed"; +static char M_Mathutils_CrossVecs_doc[] = + "() - returns a vector perpedicular to the 2 vectors crossed"; static char M_Mathutils_CopyVec_doc[] = "() - create a copy of vector"; -static char M_Mathutils_DotVecs_doc[] = "() - return the dot product of two vectors"; -static char M_Mathutils_AngleBetweenVecs_doc[] = "() - returns the angle between two vectors in degrees"; -static char M_Mathutils_MidpointVecs_doc[] = "() - return the vector to the midpoint between two vectors"; -static char M_Mathutils_MatMultVec_doc[] = "() - multiplies a matrix by a column vector"; -static char M_Mathutils_VecMultMat_doc[] = "() - multiplies a row vector by a matrix"; -static char M_Mathutils_ProjectVecs_doc[] = "() - returns the projection vector from the projection of vecA onto vecB"; -static char M_Mathutils_RotationMatrix_doc[] = "() - construct a rotation matrix from an angle and axis of rotation"; -static char M_Mathutils_ScaleMatrix_doc[] = "() - construct a scaling matrix from a scaling factor"; -static char M_Mathutils_OrthoProjectionMatrix_doc[] = "() - construct a orthographic projection matrix from a selected plane"; -static char M_Mathutils_ShearMatrix_doc[] = "() - construct a shearing matrix from a plane of shear and a shear factor"; +static char M_Mathutils_DotVecs_doc[] = + "() - return the dot product of two vectors"; +static char M_Mathutils_AngleBetweenVecs_doc[] = + "() - returns the angle between two vectors in degrees"; +static char M_Mathutils_MidpointVecs_doc[] = + "() - return the vector to the midpoint between two vectors"; +static char M_Mathutils_MatMultVec_doc[] = + "() - multiplies a matrix by a column vector"; +static char M_Mathutils_VecMultMat_doc[] = + "() - multiplies a row vector by a matrix"; +static char M_Mathutils_ProjectVecs_doc[] = + "() - returns the projection vector from the projection of vecA onto vecB"; +static char M_Mathutils_RotationMatrix_doc[] = + "() - construct a rotation matrix from an angle and axis of rotation"; +static char M_Mathutils_ScaleMatrix_doc[] = + "() - construct a scaling matrix from a scaling factor"; +static char M_Mathutils_OrthoProjectionMatrix_doc[] = + "() - construct a orthographic projection matrix from a selected plane"; +static char M_Mathutils_ShearMatrix_doc[] = + "() - construct a shearing matrix from a plane of shear and a shear factor"; static char M_Mathutils_CopyMat_doc[] = "() - create a copy of a matrix"; -static char M_Mathutils_TranslationMatrix_doc[] = "() - create a translation matrix from a vector"; +static char M_Mathutils_TranslationMatrix_doc[] = + "() - create a translation matrix from a vector"; static char M_Mathutils_CopyQuat_doc[] = "() - copy quatB to quatA"; static char M_Mathutils_CopyEuler_doc[] = "() - copy eulB to eultA"; -static char M_Mathutils_CrossQuats_doc[] = "() - return the mutliplication of two quaternions"; -static char M_Mathutils_DotQuats_doc[] = "() - return the dot product of two quaternions"; -static char M_Mathutils_Slerp_doc[] = "() - returns the interpolation between two quaternions"; -static char M_Mathutils_DifferenceQuats_doc[] = "() - return the angular displacment difference between two quats"; -static char M_Mathutils_RotateEuler_doc[] = "() - rotate euler by an axis and angle"; -//-----------------------METHOD DEFINITIONS ---------------------- +static char M_Mathutils_CrossQuats_doc[] = + "() - return the mutliplication of two quaternions"; +static char M_Mathutils_DotQuats_doc[] = + "() - return the dot product of two quaternions"; +static char M_Mathutils_Slerp_doc[] = + "() - returns the interpolation between two quaternions"; +static char M_Mathutils_DifferenceQuats_doc[] = + "() - return the angular displacment difference between two quats"; +static char M_Mathutils_RotateEuler_doc[] = + "() - rotate euler by an axis and angle"; + + +/****************************************************************************/ +// Python method structure definition for Blender.Mathutils module: +/****************************************************************************/ struct PyMethodDef M_Mathutils_methods[] = { - {"Rand", (PyCFunction) M_Mathutils_Rand, METH_VARARGS, M_Mathutils_Rand_doc}, - {"Vector", (PyCFunction) M_Mathutils_Vector, METH_VARARGS, M_Mathutils_Vector_doc}, - {"CrossVecs", (PyCFunction) M_Mathutils_CrossVecs, METH_VARARGS, M_Mathutils_CrossVecs_doc}, - {"DotVecs", (PyCFunction) M_Mathutils_DotVecs, METH_VARARGS, M_Mathutils_DotVecs_doc}, - {"AngleBetweenVecs", (PyCFunction) M_Mathutils_AngleBetweenVecs, METH_VARARGS, M_Mathutils_AngleBetweenVecs_doc}, - {"MidpointVecs", (PyCFunction) M_Mathutils_MidpointVecs, METH_VARARGS, M_Mathutils_MidpointVecs_doc}, - {"VecMultMat", (PyCFunction) M_Mathutils_VecMultMat, METH_VARARGS, M_Mathutils_VecMultMat_doc}, - {"ProjectVecs", (PyCFunction) M_Mathutils_ProjectVecs, METH_VARARGS, M_Mathutils_ProjectVecs_doc}, - {"CopyVec", (PyCFunction) M_Mathutils_CopyVec, METH_VARARGS, M_Mathutils_CopyVec_doc}, - {"Matrix", (PyCFunction) M_Mathutils_Matrix, METH_VARARGS, M_Mathutils_Matrix_doc}, - {"RotationMatrix", (PyCFunction) M_Mathutils_RotationMatrix, METH_VARARGS, M_Mathutils_RotationMatrix_doc}, - {"ScaleMatrix", (PyCFunction) M_Mathutils_ScaleMatrix, METH_VARARGS, M_Mathutils_ScaleMatrix_doc}, - {"ShearMatrix", (PyCFunction) M_Mathutils_ShearMatrix, METH_VARARGS, M_Mathutils_ShearMatrix_doc}, - {"TranslationMatrix", (PyCFunction) M_Mathutils_TranslationMatrix, METH_VARARGS, M_Mathutils_TranslationMatrix_doc}, - {"CopyMat", (PyCFunction) M_Mathutils_CopyMat, METH_VARARGS, M_Mathutils_CopyMat_doc}, - {"OrthoProjectionMatrix", (PyCFunction) M_Mathutils_OrthoProjectionMatrix, METH_VARARGS, M_Mathutils_OrthoProjectionMatrix_doc}, - {"MatMultVec", (PyCFunction) M_Mathutils_MatMultVec, METH_VARARGS, M_Mathutils_MatMultVec_doc}, - {"Quaternion", (PyCFunction) M_Mathutils_Quaternion, METH_VARARGS, M_Mathutils_Quaternion_doc}, - {"CopyQuat", (PyCFunction) M_Mathutils_CopyQuat, METH_VARARGS, M_Mathutils_CopyQuat_doc}, - {"CrossQuats", (PyCFunction) M_Mathutils_CrossQuats, METH_VARARGS, M_Mathutils_CrossQuats_doc}, - {"DotQuats", (PyCFunction) M_Mathutils_DotQuats, METH_VARARGS, M_Mathutils_DotQuats_doc}, - {"DifferenceQuats", (PyCFunction) M_Mathutils_DifferenceQuats, METH_VARARGS,M_Mathutils_DifferenceQuats_doc}, - {"Slerp", (PyCFunction) M_Mathutils_Slerp, METH_VARARGS, M_Mathutils_Slerp_doc}, - {"Euler", (PyCFunction) M_Mathutils_Euler, METH_VARARGS, M_Mathutils_Euler_doc}, - {"CopyEuler", (PyCFunction) M_Mathutils_CopyEuler, METH_VARARGS, M_Mathutils_CopyEuler_doc}, - {"RotateEuler", (PyCFunction) M_Mathutils_RotateEuler, METH_VARARGS, M_Mathutils_RotateEuler_doc}, + {"Rand", ( PyCFunction ) M_Mathutils_Rand, METH_VARARGS, + M_Mathutils_Rand_doc}, + {"Vector", ( PyCFunction ) M_Mathutils_Vector, METH_VARARGS, + M_Mathutils_Vector_doc}, + {"CrossVecs", ( PyCFunction ) M_Mathutils_CrossVecs, METH_VARARGS, + M_Mathutils_CrossVecs_doc}, + {"DotVecs", ( PyCFunction ) M_Mathutils_DotVecs, METH_VARARGS, + M_Mathutils_DotVecs_doc}, + {"AngleBetweenVecs", ( PyCFunction ) M_Mathutils_AngleBetweenVecs, + METH_VARARGS, + M_Mathutils_AngleBetweenVecs_doc}, + {"MidpointVecs", ( PyCFunction ) M_Mathutils_MidpointVecs, + METH_VARARGS, + M_Mathutils_MidpointVecs_doc}, + {"VecMultMat", ( PyCFunction ) M_Mathutils_VecMultMat, METH_VARARGS, + M_Mathutils_VecMultMat_doc}, + {"ProjectVecs", ( PyCFunction ) M_Mathutils_ProjectVecs, METH_VARARGS, + M_Mathutils_ProjectVecs_doc}, + {"CopyVec", ( PyCFunction ) M_Mathutils_CopyVec, METH_VARARGS, + M_Mathutils_CopyVec_doc}, + {"Matrix", ( PyCFunction ) M_Mathutils_Matrix, METH_VARARGS, + M_Mathutils_Matrix_doc}, + {"RotationMatrix", ( PyCFunction ) M_Mathutils_RotationMatrix, + METH_VARARGS, + M_Mathutils_RotationMatrix_doc}, + {"ScaleMatrix", ( PyCFunction ) M_Mathutils_ScaleMatrix, METH_VARARGS, + M_Mathutils_ScaleMatrix_doc}, + {"ShearMatrix", ( PyCFunction ) M_Mathutils_ShearMatrix, METH_VARARGS, + M_Mathutils_ShearMatrix_doc}, + {"TranslationMatrix", ( PyCFunction ) M_Mathutils_TranslationMatrix, + METH_VARARGS, + M_Mathutils_TranslationMatrix_doc}, + {"CopyMat", ( PyCFunction ) M_Mathutils_CopyMat, METH_VARARGS, + M_Mathutils_CopyMat_doc}, + {"OrthoProjectionMatrix", + ( PyCFunction ) M_Mathutils_OrthoProjectionMatrix, METH_VARARGS, + M_Mathutils_OrthoProjectionMatrix_doc}, + {"MatMultVec", ( PyCFunction ) M_Mathutils_MatMultVec, METH_VARARGS, + M_Mathutils_MatMultVec_doc}, + {"Quaternion", ( PyCFunction ) M_Mathutils_Quaternion, METH_VARARGS, + M_Mathutils_Quaternion_doc}, + {"CopyQuat", ( PyCFunction ) M_Mathutils_CopyQuat, METH_VARARGS, + M_Mathutils_CopyQuat_doc}, + {"CrossQuats", ( PyCFunction ) M_Mathutils_CrossQuats, METH_VARARGS, + M_Mathutils_CrossQuats_doc}, + {"DotQuats", ( PyCFunction ) M_Mathutils_DotQuats, METH_VARARGS, + M_Mathutils_DotQuats_doc}, + {"DifferenceQuats", ( PyCFunction ) M_Mathutils_DifferenceQuats, + METH_VARARGS, + M_Mathutils_DifferenceQuats_doc}, + {"Slerp", ( PyCFunction ) M_Mathutils_Slerp, METH_VARARGS, + M_Mathutils_Slerp_doc}, + {"Euler", ( PyCFunction ) M_Mathutils_Euler, METH_VARARGS, + M_Mathutils_Euler_doc}, + {"CopyEuler", ( PyCFunction ) M_Mathutils_CopyEuler, METH_VARARGS, + M_Mathutils_CopyEuler_doc}, + {"RotateEuler", ( PyCFunction ) M_Mathutils_RotateEuler, METH_VARARGS, + M_Mathutils_RotateEuler_doc}, {NULL, NULL, 0, NULL} }; -//----------------------------MODULE INIT------------------------- -PyObject *Mathutils_Init(void) -{ - PyObject *submodule; - //seed the generator for the rand function - BLI_srand((unsigned int) (PIL_check_seconds_timer() * - 0x7FFFFFFF)); - submodule = Py_InitModule3("Blender.Mathutils", - M_Mathutils_methods, M_Mathutils_doc); - return (submodule); -} -//-----------------------------METHODS---------------------------- -//----------------column_vector_multiplication (internal)--------- -//COLUMN VECTOR Multiplication (Matrix X Vector) -// [1][2][3] [a] -// [4][5][6] * [b] -// [7][8][9] [c] -//vector/matrix multiplication IS NOT COMMUTATIVE!!!! -PyObject *column_vector_multiplication(MatrixObject * mat, VectorObject* vec) +//*************************************************************************** +// Function: M_Mathutils_Rand +//*************************************************************************** +static PyObject *M_Mathutils_Rand( PyObject * self, PyObject * args ) { - float vecNew[4], vecCopy[4]; - double dot = 0.0f; - int x, y, z = 0; - - if(mat->rowSize != vec->size){ - if(mat->rowSize == 4 && vec->size != 3){ - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "matrix * vector: matrix row size and vector size must be the same\n"); - }else{ - vecCopy[3] = 0.0f; - } - } - - for(x = 0; x < vec->size; x++){ - vecCopy[x] = vec->vec[x]; - } - for(x = 0; x < mat->rowSize; x++) { - for(y = 0; y < mat->colSize; y++) { - dot += mat->matrix[x][y] * vecCopy[y]; - } - vecNew[z++] = dot; - dot = 0.0f; - } - return (PyObject *) newVectorObject(vecNew, vec->size, Py_NEW); -} -//-----------------row_vector_multiplication (internal)----------- -//ROW VECTOR Multiplication - Vector X Matrix -//[x][y][z] * [1][2][3] -// [4][5][6] -// [7][8][9] -//vector/matrix multiplication IS NOT COMMUTATIVE!!!! -PyObject *row_vector_multiplication(VectorObject* vec, MatrixObject * mat) -{ - float vecNew[4], vecCopy[4]; - double dot = 0.0f; - int x, y, z = 0, size; - - if(mat->colSize != vec->size){ - if(mat->rowSize == 4 && vec->size != 3){ - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "vector * matrix: matrix column size and the vector size must be the same\n"); - }else{ - vecCopy[3] = 0.0f; - } - } - size = vec->size; - for(x = 0; x < vec->size; x++){ - vecCopy[x] = vec->vec[x]; - } - - //muliplication - for(x = 0; x < mat->colSize; x++) { - for(y = 0; y < mat->rowSize; y++) { - dot += mat->matrix[y][x] * vecCopy[y]; - } - vecNew[z++] = dot; - dot = 0.0f; - } - return (PyObject *) newVectorObject(vecNew, size, Py_NEW); -} -//----------------------------------Mathutils.Rand() -------------------- -//returns a random number between a high and low value -PyObject *M_Mathutils_Rand(PyObject * self, PyObject * args) -{ float high, low, range; double rand; - //initializers high = 1.0; low = 0.0; - if(!PyArg_ParseTuple(args, "|ff", &low, &high)) - return (EXPP_ReturnPyObjError(PyExc_TypeError, - "Mathutils.Rand(): expected nothing or optional (float, float)\n")); + if( !PyArg_ParseTuple( args, "|ff", &low, &high ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected optional float & float\n" ) ); - if((high < low) || (high < 0 && low > 0)) - return (EXPP_ReturnPyObjError(PyExc_ValueError, - "Mathutils.Rand(): high value should be larger than low value\n")); + if( ( high < low ) || ( high < 0 && low > 0 ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "high value should be larger than low value\n" ) ); + + //seed the generator + BLI_srand( ( unsigned int ) ( PIL_check_seconds_timer( ) * + 0x7FFFFFFF ) ); //get the random number 0 - 1 - rand = BLI_drand(); + rand = BLI_drand( ); //set it to range range = high - low; rand = rand * range; rand = rand + low; - return PyFloat_FromDouble(rand); + return PyFloat_FromDouble( ( double ) rand ); } -//----------------------------------VECTOR FUNCTIONS--------------------- -//----------------------------------Mathutils.Vector() ------------------ + +//*************************************************************************** +// Function: M_Mathutils_Vector +// Python equivalent: Blender.Mathutils.Vector // Supports 2D, 3D, and 4D vector objects both int and float values -// accepted. Mixed float and int values accepted. Ints are parsed to float -PyObject *M_Mathutils_Vector(PyObject * self, PyObject * args) +// accepted. Mixed float and int values accepted. Ints are parsed to float +//*************************************************************************** +static PyObject *M_Mathutils_Vector( PyObject * self, PyObject * args ) { PyObject *listObject = NULL; int size, i; float vec[4]; size = PySequence_Length(args); - if (size == 1) { + if ( size == 1 ) { listObject = PySequence_GetItem(args, 0); - if (PySequence_Check(listObject)) { + if ( PySequence_Check(listObject) ) { size = PySequence_Length(listObject); - } else { // Single argument was not a sequence - Py_XDECREF(listObject); - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Mathutils.Vector(): 2-4 floats or ints expected (optionally in a sequence)\n"); + } else { + goto bad_args; // Single argument was not a sequence } - } else if (size == 0) { - //returns a new empty 3d vector - return (PyObject *) newVectorObject(NULL, 3, Py_NEW); + } else if ( size == 0 ) { + return ( PyObject * ) newVectorObject( NULL, 3 ); } else { - listObject = EXPP_incr_ret(args); + Py_INCREF(args); + listObject = args; } - if (size<2 || size>4) { // Invalid vector size - Py_XDECREF(listObject); - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.Vector(): 2-4 floats or ints expected (optionally in a sequence)\n"); + if (size<2 || size>4) { + goto bad_args; // Invalid vector size } for (i=0; isize * sizeof( float ) ); + for( x = 0; x < vector->size; x++ ) { + vec[x] = vector->vec[x]; + } + + retval = ( PyObject * ) newVectorObject( vec, vector->size ); + + PyMem_Free( vec ); + return retval; +} + //finds perpendicular vector - only 3D is supported -PyObject *M_Mathutils_CrossVecs(PyObject * self, PyObject * args) +static PyObject *M_Mathutils_CrossVecs( PyObject * self, PyObject * args ) { - PyObject *vecCross = NULL; - VectorObject *vec1 = NULL, *vec2 = NULL; - - if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2)) - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Mathutils.CrossVecs(): expects (2) 3D vector objects\n"); - if(vec1->size != 3 || vec2->size != 3) - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.CrossVecs(): expects (2) 3D vector objects\n"); - - vecCross = newVectorObject(NULL, 3, Py_NEW); - Crossf(((VectorObject*)vecCross)->vec, vec1->vec, vec2->vec); + PyObject *vecCross; + VectorObject *vec1; + VectorObject *vec2; + + if( !PyArg_ParseTuple + ( args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2 ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "expected 2 vector types\n" ) ); + if( vec1->size != 3 || vec2->size != 3 ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "only 3D vectors are supported\n" ) ); + + vecCross = newVectorObject( NULL, 3 ); + Crossf( ( ( VectorObject * ) vecCross )->vec, vec1->vec, vec2->vec ); + return vecCross; } -//----------------------------------Mathutils.DotVec() ------------------- -//calculates the dot product of two vectors -PyObject *M_Mathutils_DotVecs(PyObject * self, PyObject * args) + +static PyObject *M_Mathutils_DotVecs( PyObject * self, PyObject * args ) { - VectorObject *vec1 = NULL, *vec2 = NULL; - double dot = 0.0f; + VectorObject *vec1; + VectorObject *vec2; + float dot; int x; - if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2)) - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Mathutils.DotVec(): expects (2) vector objects of the same size\n"); - if(vec1->size != vec2->size) - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.DotVec(): expects (2) vector objects of the same size\n"); + dot = 0; + if( !PyArg_ParseTuple + ( args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2 ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "expected vector types\n" ) ); + if( vec1->size != vec2->size ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "vectors must be of the same size\n" ) ); - for(x = 0; x < vec1->size; x++) { + for( x = 0; x < vec1->size; x++ ) { dot += vec1->vec[x] * vec2->vec[x]; } - return PyFloat_FromDouble(dot); + + return PyFloat_FromDouble( ( double ) dot ); } -//----------------------------------Mathutils.AngleBetweenVecs() --------- -//calculates the angle between 2 vectors -PyObject *M_Mathutils_AngleBetweenVecs(PyObject * self, PyObject * args) + +static PyObject *M_Mathutils_AngleBetweenVecs( PyObject * self, + PyObject * args ) { - VectorObject *vec1 = NULL, *vec2 = NULL; - double dot = 0.0f, angleRads; - double norm_a = 0.0f, norm_b = 0.0f; - double vec_a[4], vec_b[4]; - int x, size; - - if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2)) - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Mathutils.AngleBetweenVecs(): expects (2) vector objects of the same size\n"); - if(vec1->size != vec2->size) - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.AngleBetweenVecs(): expects (2) vector objects of the same size\n"); - - //since size is the same.... - size = vec1->size; - - //copy vector info - for (x = 0; x < vec1->size; x++){ - vec_a[x] = vec1->vec[x]; - vec_b[x] = vec2->vec[x]; + VectorObject *vec1; + VectorObject *vec2; + float norm; + double dot, angleRads; + int x; + + dot = 0.0f; + if( !PyArg_ParseTuple + ( args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2 ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "expected 2 vector types\n" ) ); + if( vec1->size != vec2->size ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "vectors must be of the same size\n" ) ); + if( vec1->size > 3 || vec2->size > 3 ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "only 2D,3D vectors are supported\n" ) ); + + //normalize vec1 + norm = 0.0f; + for( x = 0; x < vec1->size; x++ ) { + norm += vec1->vec[x] * vec1->vec[x]; + } + norm = ( float ) sqrt( norm ); + for( x = 0; x < vec1->size; x++ ) { + vec1->vec[x] /= norm; } - //normalize vectors - for(x = 0; x < size; x++) { - norm_a += vec_a[x] * vec_a[x]; - norm_b += vec_b[x] * vec_b[x]; + //normalize vec2 + norm = 0.0f; + for( x = 0; x < vec2->size; x++ ) { + norm += vec2->vec[x] * vec2->vec[x]; } - norm_a = (double)sqrt(norm_a); - norm_b = (double)sqrt(norm_b); - for(x = 0; x < size; x++) { - vec_a[x] /= norm_a; - vec_b[x] /= norm_b; + norm = ( float ) sqrt( norm ); + for( x = 0; x < vec2->size; x++ ) { + vec2->vec[x] /= norm; } + //dot product - for(x = 0; x < size; x++) { - dot += vec_a[x] * vec_b[x]; + for( x = 0; x < vec1->size; x++ ) { + dot += vec1->vec[x] * vec2->vec[x]; } + //I believe saacos checks to see if the vectors are normalized - angleRads = (double)acos(dot); + angleRads = (double)acos( dot ); - return PyFloat_FromDouble(angleRads * (180 / Py_PI)); + return PyFloat_FromDouble( angleRads * ( 180 / Py_PI ) ); } -//----------------------------------Mathutils.MidpointVecs() ------------- -//calculates the midpoint between 2 vectors -PyObject *M_Mathutils_MidpointVecs(PyObject * self, PyObject * args) + +static PyObject *M_Mathutils_MidpointVecs( PyObject * self, PyObject * args ) { - VectorObject *vec1 = NULL, *vec2 = NULL; - float vec[4]; + + VectorObject *vec1; + VectorObject *vec2; + float *vec; int x; + PyObject *retval; + + if( !PyArg_ParseTuple + ( args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2 ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "expected vector types\n" ) ); + if( vec1->size != vec2->size ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "vectors must be of the same size\n" ) ); + + vec = PyMem_Malloc( vec1->size * sizeof( float ) ); + + for( x = 0; x < vec1->size; x++ ) { + vec[x] = 0.5f * ( vec1->vec[x] + vec2->vec[x] ); + } + retval = ( PyObject * ) newVectorObject( vec, vec1->size ); - if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2)) - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Mathutils.MidpointVecs(): expects (2) vector objects of the same size\n"); - if(vec1->size != vec2->size) - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.MidpointVecs(): expects (2) vector objects of the same size\n"); - - for(x = 0; x < vec1->size; x++) { - vec[x] = 0.5f * (vec1->vec[x] + vec2->vec[x]); + PyMem_Free( vec ); + return retval; +} + +//row vector multiplication +static PyObject *M_Mathutils_VecMultMat( PyObject * self, PyObject * args ) +{ + PyObject *ob1 = NULL; + PyObject *ob2 = NULL; + MatrixObject *mat; + VectorObject *vec; + PyObject *retval; + float *vecNew; + int x, y; + int z = 0; + float dot = 0.0f; + + //get pyObjects + if( !PyArg_ParseTuple + ( args, "O!O!", &vector_Type, &ob1, &matrix_Type, &ob2 ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, + "vector and matrix object expected - in that order\n" ) ); + + mat = ( MatrixObject * ) ob2; + vec = ( VectorObject * ) ob1; + if( mat->colSize != vec->size ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "matrix col size and vector size must be the same\n" ) ); + + vecNew = PyMem_Malloc( vec->size * sizeof( float ) ); + + for( x = 0; x < mat->colSize; x++ ) { + for( y = 0; y < mat->rowSize; y++ ) { + dot += mat->matrix[y][x] * vec->vec[y]; + } + vecNew[z] = dot; + z++; + dot = 0; } - return (PyObject *) newVectorObject(vec, vec1->size, Py_NEW); + + retval = ( PyObject * ) newVectorObject( vecNew, vec->size ); + + PyMem_Free( vecNew ); + return retval; } -//----------------------------------Mathutils.ProjectVecs() ------------- -//projects vector 1 onto vector 2 -PyObject *M_Mathutils_ProjectVecs(PyObject * self, PyObject * args) + +static PyObject *M_Mathutils_ProjectVecs( PyObject * self, PyObject * args ) { - VectorObject *vec1 = NULL, *vec2 = NULL; + VectorObject *vec1; + VectorObject *vec2; PyObject *retval; - float vec[4]; - double dot = 0.0f, dot2 = 0.0f; - int x, size; - - if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2)) - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Mathutils.ProjectVecs(): expects (2) vector objects of the same size\n"); - if(vec1->size != vec2->size) - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.ProjectVecs(): expects (2) vector objects of the same size\n"); - - //since they are the same size... - size = vec1->size; - - //get dot products - for(x = 0; x < size; x++) { + float *vec; + float dot = 0.0f; + float dot2 = 0.0f; + int x; + + if( !PyArg_ParseTuple + ( args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2 ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, "expected vector types\n" ) ); + if( vec1->size != vec2->size ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "vectors must be of the same size\n" ) ); + + vec = PyMem_Malloc( vec1->size * sizeof( float ) ); + + //dot of vec1 & vec2 + for( x = 0; x < vec1->size; x++ ) { dot += vec1->vec[x] * vec2->vec[x]; + } + //dot of vec2 & vec2 + for( x = 0; x < vec2->size; x++ ) { dot2 += vec2->vec[x] * vec2->vec[x]; } - //projection dot /= dot2; - for(x = 0; x < size; x++) { - vec[x] = (float)(dot * vec2->vec[x]); + for( x = 0; x < vec1->size; x++ ) { + vec[x] = dot * vec2->vec[x]; } - return (PyObject *) newVectorObject(vec, size, Py_NEW); + + retval = ( PyObject * ) newVectorObject( vec, vec1->size ); + PyMem_Free( vec ); + return retval; } -//----------------------------------MATRIX FUNCTIONS-------------------- -//----------------------------------Mathutils.Matrix() ----------------- + +//End Vector Utils + +//*************************************************************************** +// Function: M_Mathutils_Matrix // Python equivalent: Blender.Mathutils.Matrix +//*************************************************************************** //mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc. -//create a new matrix type -PyObject *M_Mathutils_Matrix(PyObject * self, PyObject * args) +static PyObject *M_Mathutils_Matrix( PyObject * self, PyObject * args ) { - PyObject *listObject = NULL; - int argSize, seqSize = 0, i, j; - float matrix[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - - argSize = PySequence_Length(args); - if(argSize > 4){ //bad arg nums - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n"); - } else if (argSize == 0) { //return empty 4D matrix - return (PyObject *) newMatrixObject(NULL, 4, 4, Py_NEW); - }else if (argSize == 1){ - //copy constructor for matrix objects - PyObject *argObject; - argObject = PySequence_GetItem(args, 0); - Py_INCREF(argObject); - if(MatrixObject_Check(argObject)){ - MatrixObject *mat; - mat = (MatrixObject*)argObject; - argSize = mat->rowSize; //rows - seqSize = mat->colSize; //cols - for(i = 0; i < (seqSize * argSize); i++){ - matrix[i] = mat->contigPtr[i]; - } + + PyObject *rowA = NULL; + PyObject *rowB = NULL; + PyObject *rowC = NULL; + PyObject *rowD = NULL; + PyObject *checkOb = NULL; + PyObject *retval = NULL; + int x, rowSize, colSize; + float *mat; + int OK; + + if( !PyArg_ParseTuple( args, "|O!O!O!O!", &PyList_Type, &rowA, + &PyList_Type, &rowB, + &PyList_Type, &rowC, &PyList_Type, &rowD ) ) { + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected 0, 2,3 or 4 lists\n" ) ); + } + + if( !rowA ) + return newMatrixObject( NULL, 4, 4 ); + + if( !rowB ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected 0, 2,3 or 4 lists\n" ) ); + + //get rowSize + if( rowC ) { + if( rowD ) { + rowSize = 4; + } else { + rowSize = 3; } - Py_DECREF(argObject); - }else{ //2-4 arguments (all seqs? all same size?) - for(i =0; i < argSize; i++){ - PyObject *argObject; - argObject = PySequence_GetItem(args, i); - if (PySequence_Check(argObject)) { //seq? - if(seqSize){ //0 at first - if(PySequence_Length(argObject) != seqSize){ //seq size not same - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n"); + } else { + rowSize = 2; + } + + //check size and get colSize + OK = 0; + if( ( PyList_Size( rowA ) == PyList_Size( rowB ) ) ) { + if( rowC ) { + if( ( PyList_Size( rowA ) == PyList_Size( rowC ) ) ) { + if( rowD ) { + if( ( PyList_Size( rowA ) == + PyList_Size( rowD ) ) ) { + OK = 1; } } - seqSize = PySequence_Length(argObject); - }else{ //arg not a sequence - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n"); + OK = 1; } - Py_XDECREF(argObject); + } else + OK = 1; + } + + if( !OK ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "each row of vector must contain the same number of parameters\n" ); + colSize = PyList_Size( rowA ); + + //check for numeric types + /* PyList_GetItem() returns borrowed ref */ + for( x = 0; x < colSize; x++ ) { + checkOb = PyList_GetItem( rowA, x ); + if( !PyInt_Check( checkOb ) && !PyFloat_Check( checkOb ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "1st list - expected list of numbers\n" ) ); + checkOb = PyList_GetItem( rowB, x ); + if( !PyInt_Check( checkOb ) && !PyFloat_Check( checkOb ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "2nd list - expected list of numbers\n" ) ); + if( rowC ) { + checkOb = PyList_GetItem( rowC, x ); + if( !PyInt_Check( checkOb ) + && !PyFloat_Check( checkOb ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, + "3rd list - expected list of numbers\n" ) ); } - //all is well... let's continue parsing - listObject = EXPP_incr_ret(args); - for (i = 0; i < argSize; i++){ - PyObject *m; - - m = PySequence_GetItem(listObject, i); - if (m == NULL) { // Failed to read sequence - Py_XDECREF(listObject); - return EXPP_ReturnPyObjError(PyExc_RuntimeError, - "Mathutils.Matrix(): failed to parse arguments...\n"); - } - for (j = 0; j < seqSize; j++) { - PyObject *s, *f; - - s = PySequence_GetItem(m, j); - if (s == NULL) { // Failed to read sequence - Py_DECREF(m); - Py_XDECREF(listObject); - return EXPP_ReturnPyObjError(PyExc_RuntimeError, - "Mathutils.Matrix(): failed to parse arguments...\n"); - } - f = PyNumber_Float(s); - if(f == NULL) { // parsed item is not a number - EXPP_decr2(m,s); - Py_XDECREF(listObject); - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n"); - } - matrix[(seqSize*i)+j]=PyFloat_AS_DOUBLE(f); - EXPP_decr2(f,s); - } - Py_DECREF(m); + if( rowD ) { + checkOb = PyList_GetItem( rowD, x ); + if( !PyInt_Check( checkOb ) + && !PyFloat_Check( checkOb ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, + "4th list - expected list of numbers\n" ) ); } - Py_DECREF(listObject); } - return (PyObject *)newMatrixObject(matrix, argSize, seqSize, Py_NEW); + + //allocate space for 1D array + mat = PyMem_Malloc( rowSize * colSize * sizeof( float ) ); + + //parse rows + for( x = 0; x < colSize; x++ ) { + if( !PyArg_Parse( PyList_GetItem( rowA, x ), "f", &mat[x] ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "rowA - python list not parseable\n" ); + } + for( x = 0; x < colSize; x++ ) { + if( !PyArg_Parse + ( PyList_GetItem( rowB, x ), "f", &mat[( colSize + x )] ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "rowB - python list not parseable\n" ); + } + if( rowC ) { + for( x = 0; x < colSize; x++ ) { + if( !PyArg_Parse + ( PyList_GetItem( rowC, x ), "f", + &mat[( ( 2 * colSize ) + x )] ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "rowC - python list not parseable\n" ); + } + } + if( rowD ) { + for( x = 0; x < colSize; x++ ) { + if( !PyArg_Parse + ( PyList_GetItem( rowD, x ), "f", + &mat[( ( 3 * colSize ) + x )] ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "rowD - python list not parseable\n" ); + } + } + //pass to matrix creation + retval = newMatrixObject( mat, rowSize, colSize ); + + PyMem_Free( mat); + return retval; } -//----------------------------------Mathutils.RotationMatrix() ---------- + +//*************************************************************************** +// Function: M_Mathutils_RotationMatrix +// Python equivalent: Blender.Mathutils.RotationMatrix +//*************************************************************************** //mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc. -//creates a rotation matrix -PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args) +static PyObject *M_Mathutils_RotationMatrix( PyObject * self, PyObject * args ) { - VectorObject *vec = NULL; + PyObject *retval; + float *mat; + float angle = 0.0f; char *axis = NULL; + VectorObject *vec = NULL; int matSize; - float angle = 0.0f, norm = 0.0f, cosAngle = 0.0f, sinAngle = 0.0f; - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - - if(!PyArg_ParseTuple - (args, "fi|sO!", &angle, &matSize, &axis, &vector_Type, &vec)) { - return EXPP_ReturnPyObjError (PyExc_TypeError, - "Mathutils.RotationMatrix(): expected float int and optional string and vector\n"); + float norm = 0.0f; + float cosAngle = 0.0f; + float sinAngle = 0.0f; + + if( !PyArg_ParseTuple + ( args, "fi|sO!", &angle, &matSize, &axis, &vector_Type, &vec ) ) { + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, + "expected float int and optional string and vector\n" ) ); } - if(angle < -360.0f || angle > 360.0f) - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.RotationMatrix(): angle size not appropriate\n"); - if(matSize != 2 && matSize != 3 && matSize != 4) - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.RotationMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n"); - if(matSize == 2 && (axis != NULL || vec != NULL)) - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.RotationMatrix(): cannot create a 2x2 rotation matrix around arbitrary axis\n"); - if((matSize == 3 || matSize == 4) && axis == NULL) - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.RotationMatrix(): please choose an axis of rotation for 3d and 4d matrices\n"); - if(axis) { - if(((strcmp(axis, "r") == 0) || - (strcmp(axis, "R") == 0)) && vec == NULL) - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.RotationMatrix(): please define the arbitrary axis of rotation\n"); + if( angle < -360.0f || angle > 360.0f ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "angle size not appropriate\n" ); + if( matSize != 2 && matSize != 3 && matSize != 4 ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "can only return a 2x2 3x3 or 4x4 matrix\n" ); + if( matSize == 2 && ( axis != NULL || vec != NULL ) ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "cannot create a 2x2 rotation matrix around arbitrary axis\n" ); + if( ( matSize == 3 || matSize == 4 ) && axis == NULL ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "please choose an axis of rotation\n" ); + if( axis ) { + if( ( ( strcmp( axis, "r" ) == 0 ) || + ( strcmp( axis, "R" ) == 0 ) ) && vec == NULL ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "please define the arbitrary axis of rotation\n" ); } - if(vec) { - if(vec->size != 3) - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.RotationMatrix(): the arbitrary axis must be a 3D vector\n"); + if( vec ) { + if( vec->size != 3 ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "the arbitrary axis must be a 3D vector\n" ); } + + mat = PyMem_Malloc( matSize * matSize * sizeof( float ) ); + //convert to radians - angle = angle * (float) (Py_PI / 180); - if(axis == NULL && matSize == 2) { + angle = angle * ( float ) ( Py_PI / 180 ); + + if( axis == NULL && matSize == 2 ) { //2D rotation matrix - mat[0] = (float) cosf (angle); - mat[1] = (float) sin (angle); - mat[2] = -((float) sin(angle)); - mat[3] = (float) cos(angle); - } else if((strcmp(axis, "x") == 0) || (strcmp(axis, "X") == 0)) { + mat[0] = ( ( float ) cos( ( double ) ( angle ) ) ); + mat[1] = ( ( float ) sin( ( double ) ( angle ) ) ); + mat[2] = ( -( ( float ) sin( ( double ) ( angle ) ) ) ); + mat[3] = ( ( float ) cos( ( double ) ( angle ) ) ); + } else if( ( strcmp( axis, "x" ) == 0 ) || + ( strcmp( axis, "X" ) == 0 ) ) { //rotation around X mat[0] = 1.0f; - mat[4] = (float) cos(angle); - mat[5] = (float) sin(angle); - mat[7] = -((float) sin(angle)); - mat[8] = (float) cos(angle); - } else if((strcmp(axis, "y") == 0) || (strcmp(axis, "Y") == 0)) { + mat[1] = 0.0f; + mat[2] = 0.0f; + mat[3] = 0.0f; + mat[4] = ( ( float ) cos( ( double ) ( angle ) ) ); + mat[5] = ( ( float ) sin( ( double ) ( angle ) ) ); + mat[6] = 0.0f; + mat[7] = ( -( ( float ) sin( ( double ) ( angle ) ) ) ); + mat[8] = ( ( float ) cos( ( double ) ( angle ) ) ); + } else if( ( strcmp( axis, "y" ) == 0 ) || + ( strcmp( axis, "Y" ) == 0 ) ) { //rotation around Y - mat[0] = (float) cos(angle); - mat[2] = -((float) sin(angle)); + mat[0] = ( ( float ) cos( ( double ) ( angle ) ) ); + mat[1] = 0.0f; + mat[2] = ( -( ( float ) sin( ( double ) ( angle ) ) ) ); + mat[3] = 0.0f; mat[4] = 1.0f; - mat[6] = (float) sin(angle); - mat[8] = (float) cos(angle); - } else if((strcmp(axis, "z") == 0) || (strcmp(axis, "Z") == 0)) { + mat[5] = 0.0f; + mat[6] = ( ( float ) sin( ( double ) ( angle ) ) ); + mat[7] = 0.0f; + mat[8] = ( ( float ) cos( ( double ) ( angle ) ) ); + } else if( ( strcmp( axis, "z" ) == 0 ) || + ( strcmp( axis, "Z" ) == 0 ) ) { //rotation around Z - mat[0] = (float) cos(angle); - mat[1] = (float) sin(angle); - mat[3] = -((float) sin(angle)); - mat[4] = (float) cos(angle); + mat[0] = ( ( float ) cos( ( double ) ( angle ) ) ); + mat[1] = ( ( float ) sin( ( double ) ( angle ) ) ); + mat[2] = 0.0f; + mat[3] = ( -( ( float ) sin( ( double ) ( angle ) ) ) ); + mat[4] = ( ( float ) cos( ( double ) ( angle ) ) ); + mat[5] = 0.0f; + mat[6] = 0.0f; + mat[7] = 0.0f; mat[8] = 1.0f; - } else if((strcmp(axis, "r") == 0) || (strcmp(axis, "R") == 0)) { + } else if( ( strcmp( axis, "r" ) == 0 ) || + ( strcmp( axis, "R" ) == 0 ) ) { //arbitrary rotation //normalize arbitrary axis - norm = (float) sqrt(vec->vec[0] * vec->vec[0] + + norm = ( float ) sqrt( vec->vec[0] * vec->vec[0] + vec->vec[1] * vec->vec[1] + - vec->vec[2] * vec->vec[2]); + vec->vec[2] * vec->vec[2] ); vec->vec[0] /= norm; vec->vec[1] /= norm; vec->vec[2] /= norm; //create matrix - cosAngle = (float) cos(angle); - sinAngle = (float) sin(angle); - mat[0] = ((vec->vec[0] * vec->vec[0]) * (1 - cosAngle)) + + cosAngle = ( ( float ) cos( ( double ) ( angle ) ) ); + sinAngle = ( ( float ) sin( ( double ) ( angle ) ) ); + mat[0] = ( ( vec->vec[0] * vec->vec[0] ) * ( 1 - cosAngle ) ) + cosAngle; - mat[1] = ((vec->vec[0] * vec->vec[1]) * (1 - cosAngle)) + - (vec->vec[2] * sinAngle); - mat[2] = ((vec->vec[0] * vec->vec[2]) * (1 - cosAngle)) - - (vec->vec[1] * sinAngle); - mat[3] = ((vec->vec[0] * vec->vec[1]) * (1 - cosAngle)) - - (vec->vec[2] * sinAngle); - mat[4] = ((vec->vec[1] * vec->vec[1]) * (1 - cosAngle)) + + mat[1] = ( ( vec->vec[0] * vec->vec[1] ) * ( 1 - cosAngle ) ) + + ( vec->vec[2] * sinAngle ); + mat[2] = ( ( vec->vec[0] * vec->vec[2] ) * ( 1 - cosAngle ) ) - + ( vec->vec[1] * sinAngle ); + mat[3] = ( ( vec->vec[0] * vec->vec[1] ) * ( 1 - cosAngle ) ) - + ( vec->vec[2] * sinAngle ); + mat[4] = ( ( vec->vec[1] * vec->vec[1] ) * ( 1 - cosAngle ) ) + cosAngle; - mat[5] = ((vec->vec[1] * vec->vec[2]) * (1 - cosAngle)) + - (vec->vec[0] * sinAngle); - mat[6] = ((vec->vec[0] * vec->vec[2]) * (1 - cosAngle)) + - (vec->vec[1] * sinAngle); - mat[7] = ((vec->vec[1] * vec->vec[2]) * (1 - cosAngle)) - - (vec->vec[0] * sinAngle); - mat[8] = ((vec->vec[2] * vec->vec[2]) * (1 - cosAngle)) + + mat[5] = ( ( vec->vec[1] * vec->vec[2] ) * ( 1 - cosAngle ) ) + + ( vec->vec[0] * sinAngle ); + mat[6] = ( ( vec->vec[0] * vec->vec[2] ) * ( 1 - cosAngle ) ) + + ( vec->vec[1] * sinAngle ); + mat[7] = ( ( vec->vec[1] * vec->vec[2] ) * ( 1 - cosAngle ) ) - + ( vec->vec[0] * sinAngle ); + mat[8] = ( ( vec->vec[2] * vec->vec[2] ) * ( 1 - cosAngle ) ) + cosAngle; } else { - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.RotationMatrix(): unrecognizable axis of rotation type - expected x,y,z or r\n"); + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "unrecognizable axis of rotation type - expected x,y,z or r\n" ); } - if(matSize == 4) { + if( matSize == 4 ) { //resize matrix + mat[15] = 1.0f; + mat[14] = 0.0f; + mat[13] = 0.0f; + mat[12] = 0.0f; + mat[11] = 0.0f; mat[10] = mat[8]; mat[9] = mat[7]; mat[8] = mat[6]; @@ -605,93 +809,146 @@ PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args) mat[3] = 0.0f; } //pass to matrix creation - return newMatrixObject(mat, matSize, matSize, Py_NEW); + retval = newMatrixObject( mat, matSize, matSize ); + + PyMem_Free( mat ); + return retval; } -//----------------------------------Mathutils.TranslationMatrix() ------- -//creates a translation matrix -PyObject *M_Mathutils_TranslationMatrix(PyObject * self, PyObject * args) + +//*************************************************************************** +// Function: M_Mathutils_TranslationMatrix +// Python equivalent: Blender.Mathutils.TranslationMatrix +//*************************************************************************** +static PyObject *M_Mathutils_TranslationMatrix( PyObject * self, + PyObject * args ) { - VectorObject *vec = NULL; - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + VectorObject *vec; + PyObject *retval; + float *mat; - if(!PyArg_ParseTuple(args, "O!", &vector_Type, &vec)) { - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Mathutils.TranslationMatrix(): expected vector\n"); + if( !PyArg_ParseTuple( args, "O!", &vector_Type, &vec ) ) { + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected vector\n" ) ); } - if(vec->size != 3 && vec->size != 4) { - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Mathutils.TranslationMatrix(): vector must be 3D or 4D\n"); + if( vec->size != 3 && vec->size != 4 ) { + return EXPP_ReturnPyObjError( PyExc_TypeError, + "vector must be 3D or 4D\n" ); } - //create a identity matrix and add translation - Mat4One((float(*)[4]) mat); + + mat = PyMem_Malloc( 4 * 4 * sizeof( float ) ); + Mat4One( ( float ( * )[4] ) mat ); + mat[12] = vec->vec[0]; mat[13] = vec->vec[1]; mat[14] = vec->vec[2]; - return newMatrixObject(mat, 4, 4, Py_NEW); + retval = newMatrixObject( mat, 4, 4 ); + + PyMem_Free( mat ); + return retval; } -//----------------------------------Mathutils.ScaleMatrix() ------------- + + +//*************************************************************************** +// Function: M_Mathutils_ScaleMatrix +// Python equivalent: Blender.Mathutils.ScaleMatrix +//*************************************************************************** //mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc. -//creates a scaling matrix -PyObject *M_Mathutils_ScaleMatrix(PyObject * self, PyObject * args) +static PyObject *M_Mathutils_ScaleMatrix( PyObject * self, PyObject * args ) { + float factor; + int matSize; VectorObject *vec = NULL; - float norm = 0.0f, factor; - int matSize, x; - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - - if(!PyArg_ParseTuple - (args, "fi|O!", &factor, &matSize, &vector_Type, &vec)) { - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Mathutils.ScaleMatrix(): expected float int and optional vector\n"); + float *mat; + float norm = 0.0f; + int x; + PyObject *retval; + + if( !PyArg_ParseTuple + ( args, "fi|O!", &factor, &matSize, &vector_Type, &vec ) ) { + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, + "expected float int and optional vector\n" ) ); } - if(matSize != 2 && matSize != 3 && matSize != 4) - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.ScaleMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n"); - if(vec) { - if(vec->size > 2 && matSize == 2) - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.ScaleMatrix(): please use 2D vectors when scaling in 2D\n"); + if( matSize != 2 && matSize != 3 && matSize != 4 ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "can only return a 2x2 3x3 or 4x4 matrix\n" ); + if( vec ) { + if( vec->size > 2 && matSize == 2 ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "please use 2D vectors when scaling in 2D\n" ); } - if(vec == NULL) { //scaling along axis - if(matSize == 2) { + mat = PyMem_Malloc( matSize * matSize * sizeof( float ) ); + + if( vec == NULL ) { //scaling along axis + if( matSize == 2 ) { mat[0] = factor; + mat[1] = 0.0f; + mat[2] = 0.0f; mat[3] = factor; } else { mat[0] = factor; + mat[1] = 0.0f; + mat[2] = 0.0f; + mat[3] = 0.0f; mat[4] = factor; + mat[5] = 0.0f; + mat[6] = 0.0f; + mat[7] = 0.0f; mat[8] = factor; } - } else { //scaling in arbitrary direction + } else { //scaling in arbitrary direction + //normalize arbitrary axis - for(x = 0; x < vec->size; x++) { + for( x = 0; x < vec->size; x++ ) { norm += vec->vec[x] * vec->vec[x]; } - norm = (float) sqrt(norm); - for(x = 0; x < vec->size; x++) { + norm = ( float ) sqrt( norm ); + for( x = 0; x < vec->size; x++ ) { vec->vec[x] /= norm; } - if(matSize == 2) { - mat[0] = 1 +((factor - 1) *(vec->vec[0] * vec->vec[0])); - mat[1] =((factor - 1) *(vec->vec[0] * vec->vec[1])); - mat[2] =((factor - 1) *(vec->vec[0] * vec->vec[1])); - mat[3] = 1 + ((factor - 1) *(vec->vec[1] * vec->vec[1])); + if( matSize == 2 ) { + mat[0] = 1 + + ( ( factor - + 1 ) * ( vec->vec[0] * vec->vec[0] ) ); + mat[1] = ( ( factor - + 1 ) * ( vec->vec[0] * vec->vec[1] ) ); + mat[2] = ( ( factor - + 1 ) * ( vec->vec[0] * vec->vec[1] ) ); + mat[3] = 1 + + ( ( factor - + 1 ) * ( vec->vec[1] * vec->vec[1] ) ); } else { - mat[0] = 1 + ((factor - 1) *(vec->vec[0] * vec->vec[0])); - mat[1] =((factor - 1) *(vec->vec[0] * vec->vec[1])); - mat[2] =((factor - 1) *(vec->vec[0] * vec->vec[2])); - mat[3] =((factor - 1) *(vec->vec[0] * vec->vec[1])); - mat[4] = 1 + ((factor - 1) *(vec->vec[1] * vec->vec[1])); - mat[5] =((factor - 1) *(vec->vec[1] * vec->vec[2])); - mat[6] =((factor - 1) *(vec->vec[0] * vec->vec[2])); - mat[7] =((factor - 1) *(vec->vec[1] * vec->vec[2])); - mat[8] = 1 + ((factor - 1) *(vec->vec[2] * vec->vec[2])); + mat[0] = 1 + + ( ( factor - + 1 ) * ( vec->vec[0] * vec->vec[0] ) ); + mat[1] = ( ( factor - + 1 ) * ( vec->vec[0] * vec->vec[1] ) ); + mat[2] = ( ( factor - + 1 ) * ( vec->vec[0] * vec->vec[2] ) ); + mat[3] = ( ( factor - + 1 ) * ( vec->vec[0] * vec->vec[1] ) ); + mat[4] = 1 + + ( ( factor - + 1 ) * ( vec->vec[1] * vec->vec[1] ) ); + mat[5] = ( ( factor - + 1 ) * ( vec->vec[1] * vec->vec[2] ) ); + mat[6] = ( ( factor - + 1 ) * ( vec->vec[0] * vec->vec[2] ) ); + mat[7] = ( ( factor - + 1 ) * ( vec->vec[1] * vec->vec[2] ) ); + mat[8] = 1 + + ( ( factor - + 1 ) * ( vec->vec[2] * vec->vec[2] ) ); } } - if(matSize == 4) { + if( matSize == 4 ) { //resize matrix + mat[15] = 1.0f; + mat[14] = 0.0f; + mat[13] = 0.0f; + mat[12] = 0.0f; + mat[11] = 0.0f; mat[10] = mat[8]; mat[9] = mat[7]; mat[8] = mat[6]; @@ -702,94 +959,152 @@ PyObject *M_Mathutils_ScaleMatrix(PyObject * self, PyObject * args) mat[3] = 0.0f; } //pass to matrix creation - return newMatrixObject(mat, matSize, matSize, Py_NEW); + retval = newMatrixObject( mat, matSize, matSize ); + + PyMem_Free( mat ); + return retval; } -//----------------------------------Mathutils.OrthoProjectionMatrix() --- + +//*************************************************************************** +// Function: M_Mathutils_OrthoProjectionMatrix +// Python equivalent: Blender.Mathutils.OrthoProjectionMatrix +//*************************************************************************** //mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc. -//creates an ortho projection matrix -PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * args) +static PyObject *M_Mathutils_OrthoProjectionMatrix( PyObject * self, + PyObject * args ) { - VectorObject *vec = NULL; char *plane; - int matSize, x; + int matSize; + float *mat; + VectorObject *vec = NULL; float norm = 0.0f; - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - - if(!PyArg_ParseTuple - (args, "si|O!", &plane, &matSize, &vector_Type, &vec)) { - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Mathutils.OrthoProjectionMatrix(): expected string and int and optional vector\n"); + int x; + PyObject *retval; + + if( !PyArg_ParseTuple + ( args, "si|O!", &plane, &matSize, &vector_Type, &vec ) ) { + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, + "expected string and int and optional vector\n" ) ); } - if(matSize != 2 && matSize != 3 && matSize != 4) - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.OrthoProjectionMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n"); - if(vec) { - if(vec->size > 2 && matSize == 2) - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.OrthoProjectionMatrix(): please use 2D vectors when scaling in 2D\n"); + if( matSize != 2 && matSize != 3 && matSize != 4 ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "can only return a 2x2 3x3 or 4x4 matrix\n" ); + if( vec ) { + if( vec->size > 2 && matSize == 2 ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "please use 2D vectors when scaling in 2D\n" ); } - if(vec == NULL) { //ortho projection onto cardinal plane - if(((strcmp(plane, "x") == 0) - || (strcmp(plane, "X") == 0)) && matSize == 2) { + if( vec == NULL ) { //ortho projection onto cardinal plane + if( ( ( strcmp( plane, "x" ) == 0 ) + || ( strcmp( plane, "X" ) == 0 ) ) && matSize == 2 ) { + mat = PyMem_Malloc( matSize * matSize * + sizeof( float ) ); mat[0] = 1.0f; - } else if(((strcmp(plane, "y") == 0) - || (strcmp(plane, "Y") == 0)) - && matSize == 2) { + mat[1] = 0.0f; + mat[2] = 0.0f; + mat[3] = 0.0f; + } else if( ( ( strcmp( plane, "y" ) == 0 ) + || ( strcmp( plane, "Y" ) == 0 ) ) + && matSize == 2 ) { + mat = PyMem_Malloc( matSize * matSize * + sizeof( float ) ); + mat[0] = 0.0f; + mat[1] = 0.0f; + mat[2] = 0.0f; mat[3] = 1.0f; - } else if(((strcmp(plane, "xy") == 0) - || (strcmp(plane, "XY") == 0)) - && matSize > 2) { + } else if( ( ( strcmp( plane, "xy" ) == 0 ) + || ( strcmp( plane, "XY" ) == 0 ) ) + && matSize > 2 ) { + mat = PyMem_Malloc( matSize * matSize * + sizeof( float ) ); mat[0] = 1.0f; + mat[1] = 0.0f; + mat[2] = 0.0f; + mat[3] = 0.0f; mat[4] = 1.0f; - } else if(((strcmp(plane, "xz") == 0) - || (strcmp(plane, "XZ") == 0)) - && matSize > 2) { + mat[5] = 0.0f; + mat[6] = 0.0f; + mat[7] = 0.0f; + mat[8] = 0.0f; + } else if( ( ( strcmp( plane, "xz" ) == 0 ) + || ( strcmp( plane, "XZ" ) == 0 ) ) + && matSize > 2 ) { + mat = PyMem_Malloc( matSize * matSize * + sizeof( float ) ); mat[0] = 1.0f; + mat[1] = 0.0f; + mat[2] = 0.0f; + mat[3] = 0.0f; + mat[4] = 0.0f; + mat[5] = 0.0f; + mat[6] = 0.0f; + mat[7] = 0.0f; mat[8] = 1.0f; - } else if(((strcmp(plane, "yz") == 0) - || (strcmp(plane, "YZ") == 0)) - && matSize > 2) { + } else if( ( ( strcmp( plane, "yz" ) == 0 ) + || ( strcmp( plane, "YZ" ) == 0 ) ) + && matSize > 2 ) { + mat = PyMem_Malloc( matSize * matSize * + sizeof( float ) ); + mat[0] = 0.0f; + mat[1] = 0.0f; + mat[2] = 0.0f; + mat[3] = 0.0f; mat[4] = 1.0f; + mat[5] = 0.0f; + mat[6] = 0.0f; + mat[7] = 0.0f; mat[8] = 1.0f; } else { - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.OrthoProjectionMatrix(): unknown plane - expected: x, y, xy, xz, yz\n"); + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "unknown plane - expected: x, y, xy, xz, yz\n" ); } - } else { //arbitrary plane + } else { //arbitrary plane //normalize arbitrary axis - for(x = 0; x < vec->size; x++) { + for( x = 0; x < vec->size; x++ ) { norm += vec->vec[x] * vec->vec[x]; } - norm = (float) sqrt(norm); - for(x = 0; x < vec->size; x++) { + norm = ( float ) sqrt( norm ); + + for( x = 0; x < vec->size; x++ ) { vec->vec[x] /= norm; } - if(((strcmp(plane, "r") == 0) - || (strcmp(plane, "R") == 0)) && matSize == 2) { - mat[0] = 1 - (vec->vec[0] * vec->vec[0]); - mat[1] = -(vec->vec[0] * vec->vec[1]); - mat[2] = -(vec->vec[0] * vec->vec[1]); - mat[3] = 1 - (vec->vec[1] * vec->vec[1]); - } else if(((strcmp(plane, "r") == 0) - || (strcmp(plane, "R") == 0)) - && matSize > 2) { - mat[0] = 1 - (vec->vec[0] * vec->vec[0]); - mat[1] = -(vec->vec[0] * vec->vec[1]); - mat[2] = -(vec->vec[0] * vec->vec[2]); - mat[3] = -(vec->vec[0] * vec->vec[1]); - mat[4] = 1 - (vec->vec[1] * vec->vec[1]); - mat[5] = -(vec->vec[1] * vec->vec[2]); - mat[6] = -(vec->vec[0] * vec->vec[2]); - mat[7] = -(vec->vec[1] * vec->vec[2]); - mat[8] = 1 - (vec->vec[2] * vec->vec[2]); + + if( ( ( strcmp( plane, "r" ) == 0 ) + || ( strcmp( plane, "R" ) == 0 ) ) && matSize == 2 ) { + mat = PyMem_Malloc( matSize * matSize * + sizeof( float ) ); + mat[0] = 1 - ( vec->vec[0] * vec->vec[0] ); + mat[1] = -( vec->vec[0] * vec->vec[1] ); + mat[2] = -( vec->vec[0] * vec->vec[1] ); + mat[3] = 1 - ( vec->vec[1] * vec->vec[1] ); + } else if( ( ( strcmp( plane, "r" ) == 0 ) + || ( strcmp( plane, "R" ) == 0 ) ) + && matSize > 2 ) { + mat = PyMem_Malloc( matSize * matSize * + sizeof( float ) ); + mat[0] = 1 - ( vec->vec[0] * vec->vec[0] ); + mat[1] = -( vec->vec[0] * vec->vec[1] ); + mat[2] = -( vec->vec[0] * vec->vec[2] ); + mat[3] = -( vec->vec[0] * vec->vec[1] ); + mat[4] = 1 - ( vec->vec[1] * vec->vec[1] ); + mat[5] = -( vec->vec[1] * vec->vec[2] ); + mat[6] = -( vec->vec[0] * vec->vec[2] ); + mat[7] = -( vec->vec[1] * vec->vec[2] ); + mat[8] = 1 - ( vec->vec[2] * vec->vec[2] ); } else { - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.OrthoProjectionMatrix(): unknown plane - expected: 'r' expected for axis designation\n"); + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "unknown plane - expected: 'r' expected for axis designation\n" ); } } - if(matSize == 4) { + + if( matSize == 4 ) { //resize matrix + mat[15] = 1.0f; + mat[14] = 0.0f; + mat[13] = 0.0f; + mat[12] = 0.0f; + mat[11] = 0.0f; mat[10] = mat[8]; mat[9] = mat[7]; mat[8] = mat[6]; @@ -800,62 +1115,95 @@ PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * args) mat[3] = 0.0f; } //pass to matrix creation - return newMatrixObject(mat, matSize, matSize, Py_NEW); + retval = newMatrixObject( mat, matSize, matSize ); + + PyMem_Free( mat ); + return retval; } -//----------------------------------Mathutils.ShearMatrix() ------------- -//creates a shear matrix -PyObject *M_Mathutils_ShearMatrix(PyObject * self, PyObject * args) + +//*************************************************************************** +// Function: M_Mathutils_ShearMatrix +// Python equivalent: Blender.Mathutils.ShearMatrix +//*************************************************************************** +static PyObject *M_Mathutils_ShearMatrix( PyObject * self, PyObject * args ) { + float factor; int matSize; char *plane; - float factor; - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + float *mat; + PyObject *retval; - if(!PyArg_ParseTuple(args, "sfi", &plane, &factor, &matSize)) { - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Mathutils.ShearMatrix(): expected string float and int\n"); + if( !PyArg_ParseTuple( args, "sfi", &plane, &factor, &matSize ) ) { + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected string float and int\n" ) ); } - if(matSize != 2 && matSize != 3 && matSize != 4) - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.ShearMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n"); - if(((strcmp(plane, "x") == 0) || (strcmp(plane, "X") == 0)) - && matSize == 2) { + if( matSize != 2 && matSize != 3 && matSize != 4 ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "can only return a 2x2 3x3 or 4x4 matrix\n" ); + + if( ( ( strcmp( plane, "x" ) == 0 ) || ( strcmp( plane, "X" ) == 0 ) ) + && matSize == 2 ) { + mat = PyMem_Malloc( matSize * matSize * sizeof( float ) ); mat[0] = 1.0f; + mat[1] = 0.0f; mat[2] = factor; mat[3] = 1.0f; - } else if(((strcmp(plane, "y") == 0) - || (strcmp(plane, "Y") == 0)) && matSize == 2) { + } else if( ( ( strcmp( plane, "y" ) == 0 ) + || ( strcmp( plane, "Y" ) == 0 ) ) && matSize == 2 ) { + mat = PyMem_Malloc( matSize * matSize * sizeof( float ) ); mat[0] = 1.0f; mat[1] = factor; + mat[2] = 0.0f; mat[3] = 1.0f; - } else if(((strcmp(plane, "xy") == 0) - || (strcmp(plane, "XY") == 0)) && matSize > 2) { + } else if( ( ( strcmp( plane, "xy" ) == 0 ) + || ( strcmp( plane, "XY" ) == 0 ) ) && matSize > 2 ) { + mat = PyMem_Malloc( matSize * matSize * sizeof( float ) ); mat[0] = 1.0f; + mat[1] = 0.0f; + mat[2] = 0.0f; + mat[3] = 0.0f; mat[4] = 1.0f; + mat[5] = 0.0f; mat[6] = factor; mat[7] = factor; - } else if(((strcmp(plane, "xz") == 0) - || (strcmp(plane, "XZ") == 0)) && matSize > 2) { + mat[8] = 0.0f; + } else if( ( ( strcmp( plane, "xz" ) == 0 ) + || ( strcmp( plane, "XZ" ) == 0 ) ) && matSize > 2 ) { + mat = PyMem_Malloc( matSize * matSize * sizeof( float ) ); mat[0] = 1.0f; + mat[1] = 0.0f; + mat[2] = 0.0f; mat[3] = factor; mat[4] = 1.0f; mat[5] = factor; + mat[6] = 0.0f; + mat[7] = 0.0f; mat[8] = 1.0f; - } else if(((strcmp(plane, "yz") == 0) - || (strcmp(plane, "YZ") == 0)) && matSize > 2) { + } else if( ( ( strcmp( plane, "yz" ) == 0 ) + || ( strcmp( plane, "YZ" ) == 0 ) ) && matSize > 2 ) { + mat = PyMem_Malloc( matSize * matSize * sizeof( float ) ); mat[0] = 1.0f; mat[1] = factor; mat[2] = factor; + mat[3] = 0.0f; mat[4] = 1.0f; + mat[5] = 0.0f; + mat[6] = 0.0f; + mat[7] = 0.0f; mat[8] = 1.0f; } else { - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.ShearMatrix(): expected: x, y, xy, xz, yz or wrong matrix size for shearing plane\n"); + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "expected: x, y, xy, xz, yz or wrong matrix size for shearing plane\n" ); } - if(matSize == 4) { + + if( matSize == 4 ) { //resize matrix + mat[15] = 1.0f; + mat[14] = 0.0f; + mat[13] = 0.0f; + mat[12] = 0.0f; + mat[11] = 0.0f; mat[10] = mat[8]; mat[9] = mat[7]; mat[8] = mat[6]; @@ -866,405 +1214,388 @@ PyObject *M_Mathutils_ShearMatrix(PyObject * self, PyObject * args) mat[3] = 0.0f; } //pass to matrix creation - return newMatrixObject(mat, matSize, matSize, Py_NEW); + retval = newMatrixObject( mat, matSize, matSize ); + + PyMem_Free( mat ); + return retval; } -//----------------------------------QUATERNION FUNCTIONS----------------- -//----------------------------------Mathutils.Quaternion() -------------- -PyObject *M_Mathutils_Quaternion(PyObject * self, PyObject * args) + +//*************************************************************************** +//Begin Matrix Utils + +static PyObject *M_Mathutils_CopyMat( PyObject * self, PyObject * args ) { - PyObject *listObject = NULL, *n, *q, *f; - int size, i; - float quat[4]; - double norm = 0.0f, angle = 0.0f; + MatrixObject *matrix; + float *mat; + int x, y, z; + PyObject *retval; - size = PySequence_Length(args); - if (size == 1 || size == 2) { //seq? - listObject = PySequence_GetItem(args, 0); - if (PySequence_Check(listObject)) { - size = PySequence_Length(listObject); - if ((size == 4 && PySequence_Length(args) !=1) || - (size == 3 && PySequence_Length(args) !=2) || (size >4 || size < 3)) { - // invalid args/size - Py_XDECREF(listObject); - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - } - if(size == 3){ //get angle in axis/angle - n = PyNumber_Float(PySequence_GetItem(args, 1)); - if(n == NULL) { // parsed item not a number or getItem fail - Py_XDECREF(listObject); - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - } - angle = PyFloat_AS_DOUBLE(n); - Py_DECREF(n); - } - }else{ - listObject = PySequence_GetItem(args, 1); - if (PySequence_Check(listObject)) { - size = PySequence_Length(listObject); - if (size != 3) { - // invalid args/size - Py_XDECREF(listObject); - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - } - n = PyNumber_Float(PySequence_GetItem(args, 0)); - if(n == NULL) { // parsed item not a number or getItem fail - Py_XDECREF(listObject); - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - } - angle = PyFloat_AS_DOUBLE(n); - Py_DECREF(n); - } else { // argument was not a sequence - Py_XDECREF(listObject); - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - } - } - } else if (size == 0) { //returns a new empty quat - return (PyObject *) newQuaternionObject(NULL, Py_NEW); - } else { - listObject = EXPP_incr_ret(args); - } + if( !PyArg_ParseTuple( args, "O!", &matrix_Type, &matrix ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected matrix\n" ) ); - if (size == 3) { // invalid quat size - if(PySequence_Length(args) != 2){ - Py_XDECREF(listObject); - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - } - }else{ - if(size != 4){ - Py_XDECREF(listObject); - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); + mat = PyMem_Malloc( matrix->rowSize * matrix->colSize * + sizeof( float ) ); + + z = 0; + for( x = 0; x < matrix->rowSize; x++ ) { + for( y = 0; y < matrix->colSize; y++ ) { + mat[z] = matrix->matrix[x][y]; + z++; } } - for (i=0; irowSize, + matrix->colSize ); + PyMem_Free( mat ); + return retval; +} + +static PyObject *M_Mathutils_MatMultVec( PyObject * self, PyObject * args ) +{ + + PyObject *ob1 = NULL; + PyObject *ob2 = NULL; + MatrixObject *mat; + VectorObject *vec; + PyObject *retval; + float *vecNew; + int x, y; + int z = 0; + float dot = 0.0f; + + //get pyObjects + if( !PyArg_ParseTuple + ( args, "O!O!", &matrix_Type, &ob1, &vector_Type, &ob2 ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, + "matrix and vector object expected - in that order\n" ) ); + + mat = ( MatrixObject * ) ob1; + vec = ( VectorObject * ) ob2; + + if( mat->rowSize != vec->size ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "matrix row size and vector size must be the same\n" ) ); + + vecNew = PyMem_Malloc( vec->size * sizeof( float ) ); + + for( x = 0; x < mat->rowSize; x++ ) { + for( y = 0; y < mat->colSize; y++ ) { + dot += mat->matrix[x][y] * vec->vec[y]; } - quat[i] = PyFloat_AS_DOUBLE(f); - EXPP_decr2(f, q); + vecNew[z] = dot; + z++; + dot = 0; } - if(size == 3){ //calculate the quat based on axis/angle - norm = sqrt(quat[0] * quat[0] + quat[1] * quat[1] + quat[2] * quat[2]); - quat[0] /= norm; - quat[1] /= norm; - quat[2] /= norm; - - angle = angle * (Py_PI / 180); - quat[3] =(float) (sin(angle/ 2.0f)) * quat[2]; - quat[2] =(float) (sin(angle/ 2.0f)) * quat[1]; - quat[1] =(float) (sin(angle/ 2.0f)) * quat[0]; - quat[0] =(float) (cos(angle/ 2.0f)); + + retval = ( PyObject * ) newVectorObject( vecNew, vec->size ); + + PyMem_Free( vecNew ); + return retval; +} + +//*************************************************************************** +// Function: M_Mathutils_Quaternion +// Python equivalent: Blender.Mathutils.Quaternion +//*************************************************************************** +static PyObject *M_Mathutils_Quaternion( PyObject * self, PyObject * args ) +{ + PyObject *listObject; + float *vec = NULL; + float *quat = NULL; + float angle = 0.0f; + int x; + float norm; + PyObject *retval; + + if( !PyArg_ParseTuple + ( args, "O!|f", &PyList_Type, &listObject, &angle ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, + "expected list and optional float\n" ) ); + + if( PyList_Size( listObject ) != 4 && PyList_Size( listObject ) != 3 ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "3 or 4 expected floats for the quaternion\n" ) ); + + vec = PyMem_Malloc( PyList_Size( listObject ) * sizeof( float ) ); + for( x = 0; x < PyList_Size( listObject ); x++ ) { + if( !PyArg_Parse + ( PyList_GetItem( listObject, x ), "f", &vec[x] ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "python list not parseable\n" ); } - Py_DECREF(listObject); - return (PyObject *) newQuaternionObject(quat, Py_NEW); + + if( PyList_Size( listObject ) == 3 ) { //an axis of rotation + norm = ( float ) sqrt( vec[0] * vec[0] + vec[1] * vec[1] + + vec[2] * vec[2] ); + + vec[0] /= norm; + vec[1] /= norm; + vec[2] /= norm; + + angle = angle * ( float ) ( Py_PI / 180 ); + quat = PyMem_Malloc( 4 * sizeof( float ) ); + quat[0] = ( float ) ( cos( ( double ) ( angle ) / 2 ) ); + quat[1] = + ( float ) ( sin( ( double ) ( angle ) / 2 ) ) * vec[0]; + quat[2] = + ( float ) ( sin( ( double ) ( angle ) / 2 ) ) * vec[1]; + quat[3] = + ( float ) ( sin( ( double ) ( angle ) / 2 ) ) * vec[2]; + + retval = newQuaternionObject( quat ); + } else + retval = newQuaternionObject( vec ); + + /* freeing a NULL ptr is ok */ + PyMem_Free( vec ); + PyMem_Free( quat ); + + return retval; } -//----------------------------------Mathutils.CrossQuats() ---------------- -//quaternion multiplication - associate not commutative -PyObject *M_Mathutils_CrossQuats(PyObject * self, PyObject * args) + +//*************************************************************************** +//Begin Quaternion Utils + +static PyObject *M_Mathutils_CopyQuat( PyObject * self, PyObject * args ) { - QuaternionObject *quatU = NULL, *quatV = NULL; - float quat[4]; + QuaternionObject *quatU; + float *quat = NULL; + PyObject *retval; - if(!PyArg_ParseTuple(args, "O!O!", &quaternion_Type, &quatU, - &quaternion_Type, &quatV)) - return EXPP_ReturnPyObjError(PyExc_TypeError,"Mathutils.CrossQuats(): expected Quaternion types"); - QuatMul(quat, quatU->quat, quatV->quat); + if( !PyArg_ParseTuple( args, "O!", &quaternion_Type, &quatU ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected Quaternion type" ) ); - return (PyObject*) newQuaternionObject(quat, Py_NEW); + quat = PyMem_Malloc( 4 * sizeof( float ) ); + quat[0] = quatU->quat[0]; + quat[1] = quatU->quat[1]; + quat[2] = quatU->quat[2]; + quat[3] = quatU->quat[3]; + + retval = ( PyObject * ) newQuaternionObject( quat ); + PyMem_Free( quat ); + return retval; } -//----------------------------------Mathutils.DotQuats() ---------------- -//returns the dot product of 2 quaternions -PyObject *M_Mathutils_DotQuats(PyObject * self, PyObject * args) + +static PyObject *M_Mathutils_CrossQuats( PyObject * self, PyObject * args ) { - QuaternionObject *quatU = NULL, *quatV = NULL; - double dot = 0.0f; + QuaternionObject *quatU; + QuaternionObject *quatV; + float *quat = NULL; + PyObject *retval; + + if( !PyArg_ParseTuple( args, "O!O!", &quaternion_Type, &quatU, + &quaternion_Type, &quatV ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected Quaternion types" ) ); + quat = PyMem_Malloc( 4 * sizeof( float ) ); + QuatMul( quat, quatU->quat, quatV->quat ); + + retval = ( PyObject * ) newQuaternionObject( quat ); + PyMem_Free( quat ); + return retval; +} + +static PyObject *M_Mathutils_DotQuats( PyObject * self, PyObject * args ) +{ + QuaternionObject *quatU; + QuaternionObject *quatV; int x; + float dot = 0.0f; - if(!PyArg_ParseTuple(args, "O!O!", &quaternion_Type, &quatU, - &quaternion_Type, &quatV)) - return EXPP_ReturnPyObjError(PyExc_TypeError, "Mathutils.DotQuats(): expected Quaternion types"); + if( !PyArg_ParseTuple( args, "O!O!", &quaternion_Type, &quatU, + &quaternion_Type, &quatV ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected Quaternion types" ) ); - for(x = 0; x < 4; x++) { + for( x = 0; x < 4; x++ ) { dot += quatU->quat[x] * quatV->quat[x]; } - return PyFloat_FromDouble(dot); + + return PyFloat_FromDouble( ( double ) ( dot ) ); } -//----------------------------------Mathutils.DifferenceQuats() --------- -//returns the difference between 2 quaternions -PyObject *M_Mathutils_DifferenceQuats(PyObject * self, PyObject * args) + +static PyObject *M_Mathutils_DifferenceQuats( PyObject * self, + PyObject * args ) { - QuaternionObject *quatU = NULL, *quatV = NULL; - float quat[4], tempQuat[4]; - double dot = 0.0f; + QuaternionObject *quatU; + QuaternionObject *quatV; + float *quat = NULL; + float *tempQuat = NULL; + PyObject *retval; int x; + float dot = 0.0f; - if(!PyArg_ParseTuple(args, "O!O!", &quaternion_Type, - &quatU, &quaternion_Type, &quatV)) - return EXPP_ReturnPyObjError(PyExc_TypeError, "Mathutils.DifferenceQuats(): expected Quaternion types"); + if( !PyArg_ParseTuple( args, "O!O!", &quaternion_Type, + &quatU, &quaternion_Type, &quatV ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected Quaternion types" ) ); + + quat = PyMem_Malloc( 4 * sizeof( float ) ); + tempQuat = PyMem_Malloc( 4 * sizeof( float ) ); tempQuat[0] = quatU->quat[0]; tempQuat[1] = -quatU->quat[1]; tempQuat[2] = -quatU->quat[2]; tempQuat[3] = -quatU->quat[3]; - dot = sqrt(tempQuat[0] * tempQuat[0] + tempQuat[1] * tempQuat[1] + - tempQuat[2] * tempQuat[2] + tempQuat[3] * tempQuat[3]); + dot = ( float ) sqrt( ( double ) tempQuat[0] * ( double ) tempQuat[0] + + ( double ) tempQuat[1] * ( double ) tempQuat[1] + + ( double ) tempQuat[2] * ( double ) tempQuat[2] + + ( double ) tempQuat[3] * + ( double ) tempQuat[3] ); - for(x = 0; x < 4; x++) { - tempQuat[x] /= (dot * dot); + for( x = 0; x < 4; x++ ) { + tempQuat[x] /= ( dot * dot ); } - QuatMul(quat, tempQuat, quatV->quat); - return (PyObject *) newQuaternionObject(quat, Py_NEW); + QuatMul( quat, tempQuat, quatV->quat ); + + retval = ( PyObject * ) newQuaternionObject( quat ); + + PyMem_Free( quat ); + PyMem_Free( tempQuat ); + return retval; } -//----------------------------------Mathutils.Slerp() ------------------ -//attemps to interpolate 2 quaternions and return the result -PyObject *M_Mathutils_Slerp(PyObject * self, PyObject * args) + +static PyObject *M_Mathutils_Slerp( PyObject * self, PyObject * args ) { - QuaternionObject *quatU = NULL, *quatV = NULL; - float quat[4], quat_u[4], quat_v[4], param; - double x, y, dot, sinT, angle, IsinT, val; - int flag = 0, z; - - if(!PyArg_ParseTuple(args, "O!O!f", &quaternion_Type, - &quatU, &quaternion_Type, &quatV, ¶m)) - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Mathutils.Slerp(): expected Quaternion types and float"); - - if(param > 1.0f || param < 0.0f) - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.Slerp(): interpolation factor must be between 0.0 and 1.0"); - - //copy quats - for(z = 0; z < 4; z++){ - quat_u[z] = quatU->quat[z]; - quat_v[z] = quatV->quat[z]; - } + QuaternionObject *quatU; + QuaternionObject *quatV; + float *quat = NULL; + PyObject *retval; + float param, x, y, cosD, sinD, deltaD, IsinD, val; + int flag, z; - //dot product - dot = quat_u[0] * quat_v[0] + quat_u[1] * quat_v[1] + - quat_u[2] * quat_v[2] + quat_u[3] * quat_v[3]; - - //if negative negate a quat (shortest arc) - if(dot < 0.0f) { - quat_v[0] = -quat_v[0]; - quat_v[1] = -quat_v[1]; - quat_v[2] = -quat_v[2]; - quat_v[3] = -quat_v[3]; - dot = -dot; + if( !PyArg_ParseTuple( args, "O!O!f", &quaternion_Type, + &quatU, &quaternion_Type, &quatV, ¶m ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected Quaternion types and float" ) ); + + quat = PyMem_Malloc( 4 * sizeof( float ) ); + + cosD = quatU->quat[0] * quatV->quat[0] + + quatU->quat[1] * quatV->quat[1] + + quatU->quat[2] * quatV->quat[2] + + quatU->quat[3] * quatV->quat[3]; + + flag = 0; + if( cosD < 0.0f ) { + flag = 1; + cosD = -cosD; } - if(dot > .99999f) { //very close + if( cosD > .99999f ) { x = 1.0f - param; y = param; } else { - //calculate sin of angle - sinT = sqrt(1.0f - (dot * dot)); - //calculate angle - angle = atan2(sinT, dot); - //caluculate inverse of sin(theta) - IsinT = 1.0f / sinT; - x = sin((1.0f - param) * angle) * IsinT; - y = sin(param * angle) * IsinT; + sinD = ( float ) sqrt( 1.0f - cosD * cosD ); + deltaD = ( float ) atan2( sinD, cosD ); + IsinD = 1.0f / sinD; + x = ( float ) sin( ( 1.0f - param ) * deltaD ) * IsinD; + y = ( float ) sin( param * deltaD ) * IsinD; } - //interpolate - quat[0] = quat_u[0] * x + quat_v[0] * y; - quat[1] = quat_u[1] * x + quat_v[1] * y; - quat[2] = quat_u[2] * x + quat_v[2] * y; - quat[3] = quat_u[3] * x + quat_v[3] * y; - - return (PyObject *) newQuaternionObject(quat, Py_NEW); + for( z = 0; z < 4; z++ ) { + val = quatV->quat[z]; + if( val ) + val = -val; + quat[z] = ( quatU->quat[z] * x ) + ( val * y ); + } + retval = ( PyObject * ) newQuaternionObject( quat ); + PyMem_Free( quat ); + return retval; } -//----------------------------------EULER FUNCTIONS---------------------- -//----------------------------------Mathutils.Euler() ------------------- -//makes a new euler for you to play with -PyObject *M_Mathutils_Euler(PyObject * self, PyObject * args) + +//*************************************************************************** +// Function: M_Mathutils_Euler +// Python equivalent: Blender.Mathutils.Euler +//*************************************************************************** +static PyObject *M_Mathutils_Euler( PyObject * self, PyObject * args ) { + PyObject *listObject; + float *vec = NULL; + PyObject *retval; + int x; - PyObject *listObject = NULL; - int size, i; - float eul[3]; + if( !PyArg_ParseTuple( args, "O!", &PyList_Type, &listObject ) ) + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "expected list\n" ) ); - size = PySequence_Length(args); - if (size == 1) { - listObject = PySequence_GetItem(args, 0); - if (PySequence_Check(listObject)) { - size = PySequence_Length(listObject); - } else { // Single argument was not a sequence - Py_XDECREF(listObject); - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Mathutils.Euler(): 3d numeric sequence expected\n"); - } - } else if (size == 0) { - //returns a new empty 3d euler - return (PyObject *) newEulerObject(NULL, Py_NEW); - } else { - listObject = EXPP_incr_ret(args); - } - if (size != 3) { // Invalid euler size - Py_XDECREF(listObject); - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Mathutils.Euler(): 3d numeric sequence expected\n"); - } - for (i=0; ieul[0]; + eul[1] = eulU->eul[1]; + eul[2] = eulU->eul[2]; + + retval = ( PyObject * ) newEulerObject( eul ); + PyMem_Free( eul ); + return retval; } -//----------------------------------Mathutils.RotateEuler() ------------ -//rotates a euler a certain amount and returns the result -//should return a unique euler rotation (i.e. no 720 degree pitches :) -PyObject *M_Mathutils_RotateEuler(PyObject * self, PyObject * args) + +static PyObject *M_Mathutils_RotateEuler( PyObject * self, PyObject * args ) { - EulerObject *Eul = NULL; + EulerObject *Eul; float angle; char *axis; + int x; - if(!PyArg_ParseTuple(args, "O!fs", &euler_Type, &Eul, &angle, &axis)) - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Mathutils.RotateEuler(): expected euler type & float & string"); - - printf("Mathutils.RotateEuler(): Deprecated:use Euler.rotate() to rotate a euler\n"); - printf("Method will be removed in 2 releases\n"); - Euler_Rotate(Eul, Py_BuildValue("fs", angle, axis)); - return EXPP_incr_ret(Py_None); -} -//----------------------------------Mathutils.MatMultVec() -------------- -//COLUMN VECTOR Multiplication (Matrix X Vector) -PyObject *M_Mathutils_MatMultVec(PyObject * self, PyObject * args) -{ - MatrixObject *mat = NULL; - VectorObject *vec = NULL; - PyObject *retObj = NULL; + if( !PyArg_ParseTuple + ( args, "O!fs", &euler_Type, &Eul, &angle, &axis ) ) + return ( EXPP_ReturnPyObjError + ( PyExc_TypeError, + "expected euler type & float & string" ) ); - //get pyObjects - if(!PyArg_ParseTuple(args, "O!O!", &matrix_Type, &mat, &vector_Type, &vec)) - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Mathutils.MatMultVec(): MatMultVec() expects a matrix and a vector object - in that order\n"); - - printf("Mathutils.MatMultVec(): Deprecated: use matrix * vec to perform column vector multiplication\n"); - printf("Method will be removed in 2 releases\n"); - EXPP_incr2((PyObject*)vec, (PyObject*)mat); - retObj = column_vector_multiplication(mat, vec); - if(!retObj){ - return NULL; + angle *= ( float ) ( Py_PI / 180 ); + for( x = 0; x < 3; x++ ) { + Eul->eul[x] *= ( float ) ( Py_PI / 180 ); + } + euler_rot( Eul->eul, angle, *axis ); + for( x = 0; x < 3; x++ ) { + Eul->eul[x] *= ( float ) ( 180 / Py_PI ); } - EXPP_decr2((PyObject*)vec, (PyObject*)mat); - return retObj; + return EXPP_incr_ret( Py_None ); } -//----------------------------------Mathutils.VecMultMat() --------------- -//ROW VECTOR Multiplication - Vector X Matrix -PyObject *M_Mathutils_VecMultMat(PyObject * self, PyObject * args) -{ - MatrixObject *mat = NULL; - VectorObject *vec = NULL; - PyObject *retObj = NULL; - //get pyObjects - if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec, &matrix_Type, &mat)) - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Mathutils.VecMultMat(): VecMultMat() expects a vector and matrix object - in that order\n"); - - printf("Mathutils.VecMultMat(): Deprecated: use vec * matrix to perform row vector multiplication\n"); - printf("Method will be removed in 2 releases\n"); - EXPP_incr2((PyObject*)vec, (PyObject*)mat); - retObj = row_vector_multiplication(vec, mat); - if(!retObj){ - return NULL; - } - - EXPP_decr2((PyObject*)vec, (PyObject*)mat); - return retObj; +//*************************************************************************** +// Function: Mathutils_Init +//*************************************************************************** +PyObject *Mathutils_Init( void ) +{ + PyObject *mod = + Py_InitModule3( "Blender.Mathutils", M_Mathutils_methods, + M_Mathutils_doc ); + return ( mod ); } -//####################################################################### -//#############################DEPRECATED################################ \ No newline at end of file diff --git a/source/blender/python/api2_2x/Mathutils.h b/source/blender/python/api2_2x/Mathutils.h index 1365693e691..7d34187656e 100644 --- a/source/blender/python/api2_2x/Mathutils.h +++ b/source/blender/python/api2_2x/Mathutils.h @@ -29,48 +29,14 @@ * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ -//Include this file for access to vector, quat, matrix, euler, etc... #ifndef EXPP_Mathutils_H #define EXPP_Mathutils_H -#include -#include "vector.h" -#include "matrix.h" -#include "quat.h" -#include "euler.h" + + #include "Types.h" PyObject *Mathutils_Init( void ); -PyObject *row_vector_multiplication(VectorObject* vec, MatrixObject * mat); -PyObject *column_vector_multiplication(MatrixObject * mat, VectorObject* vec); - -PyObject *M_Mathutils_Rand(PyObject * self, PyObject * args); -PyObject *M_Mathutils_Vector(PyObject * self, PyObject * args); -PyObject *M_Mathutils_CrossVecs(PyObject * self, PyObject * args); -PyObject *M_Mathutils_DotVecs(PyObject * self, PyObject * args); -PyObject *M_Mathutils_AngleBetweenVecs(PyObject * self, PyObject * args); -PyObject *M_Mathutils_MidpointVecs(PyObject * self, PyObject * args); -PyObject *M_Mathutils_ProjectVecs(PyObject * self, PyObject * args); -PyObject *M_Mathutils_Matrix(PyObject * self, PyObject * args); -PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args); -PyObject *M_Mathutils_TranslationMatrix(PyObject * self, PyObject * args); -PyObject *M_Mathutils_ScaleMatrix(PyObject * self, PyObject * args); -PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * args); -PyObject *M_Mathutils_ShearMatrix(PyObject * self, PyObject * args); -PyObject *M_Mathutils_Quaternion(PyObject * self, PyObject * args); -PyObject *M_Mathutils_CrossQuats(PyObject * self, PyObject * args); -PyObject *M_Mathutils_DotQuats(PyObject * self, PyObject * args); -PyObject *M_Mathutils_DifferenceQuats(PyObject * self, PyObject * args); -PyObject *M_Mathutils_Slerp(PyObject * self, PyObject * args); -PyObject *M_Mathutils_Euler(PyObject * self, PyObject * args); -//DEPRECATED -PyObject *M_Mathutils_CopyMat(PyObject * self, PyObject * args); -PyObject *M_Mathutils_CopyVec(PyObject * self, PyObject * args); -PyObject *M_Mathutils_CopyQuat(PyObject * self, PyObject * args); -PyObject *M_Mathutils_CopyEuler(PyObject * self, PyObject * args); -PyObject *M_Mathutils_RotateEuler(PyObject * self, PyObject * args); -PyObject *M_Mathutils_MatMultVec(PyObject * self, PyObject * args); -PyObject *M_Mathutils_VecMultMat(PyObject * self, PyObject * args); #endif /* EXPP_Mathutils_H */ diff --git a/source/blender/python/api2_2x/NMesh.c b/source/blender/python/api2_2x/NMesh.c index b735204613e..61e4a6f513c 100644 --- a/source/blender/python/api2_2x/NMesh.c +++ b/source/blender/python/api2_2x/NMesh.c @@ -58,15 +58,14 @@ #include "BLI_blenlib.h" #include "BLI_arithb.h" #include "MEM_guardedalloc.h" -#include "BKE_utildefines.h" #include "blendef.h" #include "mydevice.h" #include "Object.h" +#include "vector.h" #include "constant.h" #include "gen_utils.h" -#include "Mathutils.h" /* only used for ob.oopsloc at the moment */ #include "DNA_oops_types.h" @@ -760,11 +759,12 @@ static PyObject *NMVert_getattr( PyObject * self, char *name ) BPy_NMVert *mv = ( BPy_NMVert * ) self; if( !strcmp( name, "co" ) || !strcmp( name, "loc" ) ) - return newVectorObject(mv->co,3,Py_WRAP); + return newVectorProxy( mv->co, 3 ); + else if( strcmp( name, "no" ) == 0 ) - return newVectorObject(mv->no,3,Py_WRAP); + return newVectorProxy( mv->no, 3 ); else if( strcmp( name, "uvco" ) == 0 ) - return newVectorObject(mv->uvco,3,Py_WRAP); + return newVectorProxy( mv->uvco, 3 ); else if( strcmp( name, "index" ) == 0 ) return PyInt_FromLong( mv->index ); else if( strcmp( name, "sel" ) == 0 ) diff --git a/source/blender/python/api2_2x/Object.c b/source/blender/python/api2_2x/Object.c index 2f92aef0505..facd578521d 100644 --- a/source/blender/python/api2_2x/Object.c +++ b/source/blender/python/api2_2x/Object.c @@ -59,7 +59,6 @@ #include "Ipo.h" #include "Lattice.h" #include "modules.h" -#include "Mathutils.h" #include "constant.h" /* only used for oops location get/set at the moment */ @@ -647,14 +646,14 @@ PyObject *M_Object_New( PyObject * self, PyObject * args ) object->dupend = 100; /* Gameengine defaults */ - object->mass = 1.0f; - object->inertia = 1.0f; - object->formfactor = 0.4f; - object->damping = 0.04f; - object->rdamping = 0.1f; - object->anisotropicFriction[0] = 1.0f; - object->anisotropicFriction[1] = 1.0f; - object->anisotropicFriction[2] = 1.0f; + object->mass = 1.0; + object->inertia = 1.0; + object->formfactor = 0.4; + object->damping = 0.04; + object->rdamping = 0.1; + object->anisotropicFriction[0] = 1.0; + object->anisotropicFriction[1] = 1.0; + object->anisotropicFriction[2] = 1.0; object->gameflag = OB_PROP; object->lay = 1; // Layer, by default visible @@ -1115,20 +1114,21 @@ static PyObject *Object_getDrawType( BPy_Object * self ) static PyObject *Object_getEuler( BPy_Object * self ) { - float eul[3]; + EulerObject *eul; - eul[0] = self->object->rot[0]; - eul[1] = self->object->rot[1]; - eul[2] = self->object->rot[2]; + eul = ( EulerObject * ) newEulerObject( NULL ); + eul->eul[0] = self->object->rot[0]; + eul->eul[1] = self->object->rot[1]; + eul->eul[2] = self->object->rot[2]; - return ( PyObject * ) newEulerObject( eul, Py_WRAP ); + return ( PyObject * ) eul; } static PyObject *Object_getInverseMatrix( BPy_Object * self ) { MatrixObject *inverse = - ( MatrixObject * ) newMatrixObject( NULL, 4, 4, Py_NEW); + ( MatrixObject * ) newMatrixObject( NULL, 4, 4 ); Mat4Invert( (float ( * )[4])*inverse->matrix, self->object->obmat ); return ( ( PyObject * ) inverse ); @@ -1175,29 +1175,35 @@ static PyObject *Object_getMaterials( BPy_Object * self, PyObject * args ) static PyObject *Object_getMatrix( BPy_Object * self, PyObject * args ) { - float matrix[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + PyObject *matrix; char *space = "worldspace"; /* default to world */ if( !PyArg_ParseTuple( args, "|s", &space ) ) { return ( EXPP_ReturnPyObjError( PyExc_AttributeError, "expected a string or nothing" ) ); } + //new matrix + matrix = newMatrixObject( NULL, 4, 4 ); + if( BLI_streq( space, "worldspace" ) ) { /* Worldspace matrix */ disable_where_script( 1 ); where_is_object( self->object ); disable_where_script( 0 ); + Mat4CpyMat4((float ( * )[4]) *( ( MatrixObject * ) matrix )->matrix, + self->object->obmat ); } else if( BLI_streq( space, "localspace" ) ) { /* Localspace matrix */ - object_to_mat4( self->object, (float (*)[4])matrix ); - return newMatrixObject(matrix,4,4,Py_NEW); - } else if( BLI_streq( space, "old_worldspace" ) ) { + object_to_mat4( self->object, + ( float ( * )[4] ) *( ( MatrixObject * ) matrix )->matrix ); /* old behavior, prior to 2.34, check this method's doc string: */ + } else if( BLI_streq( space, "old_worldspace" ) ) { + Mat4CpyMat4( (float ( * )[4]) *( ( MatrixObject * ) matrix )->matrix, + self->object->obmat ); } else { return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, "wrong parameter, expected nothing or either 'worldspace' (default),\n\ 'localspace' or 'old_worldspace'" ) ); } - return newMatrixObject((float*)self->object->obmat,4,4,Py_WRAP); + return matrix; } static PyObject *Object_getName( BPy_Object * self ) @@ -1379,7 +1385,7 @@ static PyObject *Object_getBoundBox( BPy_Object * self ) does not have its own memory, we must create vectors that allocate space */ - vector = newVectorObject( NULL, 3, Py_NEW); + vector = newVectorObject( NULL, 3 ); memcpy( ( ( VectorObject * ) vector )->vec, tmpvec, 3 * sizeof( float ) ); PyList_SET_ITEM( bbox, i, vector ); @@ -1400,7 +1406,7 @@ static PyObject *Object_getBoundBox( BPy_Object * self ) /* create vectors referencing object bounding box coords */ for( i = 0; i < 8; i++ ) { - vector = newVectorObject( vec, 3, Py_WRAP ); + vector = newVectorObject( vec, 3 ); PyList_SET_ITEM( bbox, i, vector ); vec += 3; } @@ -3917,18 +3923,17 @@ int setupSB(Object* ob){ } if(ob->soft){ - ob->soft->nodemass = 1.0f; - ob->soft->grav = 0.0f; - ob->soft->mediafrict = 0.5f; - ob->soft->rklimit = 0.1f; - ob->soft->goalspring = 0.5f; - ob->soft->goalfrict = 0.0f; - ob->soft->mingoal = 0.0f; - ob->soft->maxgoal = 1.0f; - ob->soft->inspring = 0.5f; - ob->soft->infrict = 0.5f; - ob->soft->defgoal = 0.7f; - + ob->soft->nodemass = 1.0; + ob->soft->grav = 0.0; + ob->soft->mediafrict = 0.5; + ob->soft->rklimit = 0.1; + ob->soft->goalspring = 0.5; + ob->soft->goalfrict = 0.0; + ob->soft->mingoal = 0.0; + ob->soft->maxgoal = 1.0; + ob->soft->inspring = 0.5; + ob->soft->infrict = 0.5; + ob->soft->defgoal = 0.7; return 1; } else { diff --git a/source/blender/python/api2_2x/Object.h b/source/blender/python/api2_2x/Object.h index 416d1ed3a3d..c1b3025a386 100644 --- a/source/blender/python/api2_2x/Object.h +++ b/source/blender/python/api2_2x/Object.h @@ -33,6 +33,7 @@ #ifndef EXPP_OBJECT_H #define EXPP_OBJECT_H +#include #include #include #include @@ -59,7 +60,10 @@ #include #include "gen_utils.h" - +#include "vector.h" +#include "matrix.h" +#include "euler.h" +#include "quat.h" /* The Object PyType Object defined in Object.c */ extern PyTypeObject Object_Type; diff --git a/source/blender/python/api2_2x/Types.c b/source/blender/python/api2_2x/Types.c index 0c10787d380..a4722c17c6e 100644 --- a/source/blender/python/api2_2x/Types.c +++ b/source/blender/python/api2_2x/Types.c @@ -57,7 +57,6 @@ void types_InitAll( void ) CurNurb_Type.ob_type = &PyType_Type; Curve_Type.ob_type = &PyType_Type; Effect_Type.ob_type = &PyType_Type; - Font_Type.ob_type = &PyType_Type; Image_Type.ob_type = &PyType_Type; Ipo_Type.ob_type = &PyType_Type; IpoCurve_Type.ob_type = &PyType_Type; diff --git a/source/blender/python/api2_2x/Window.c b/source/blender/python/api2_2x/Window.c index f9029730eef..41a7ad7c910 100644 --- a/source/blender/python/api2_2x/Window.c +++ b/source/blender/python/api2_2x/Window.c @@ -830,7 +830,7 @@ static PyObject *M_Window_GetViewMatrix( PyObject * self ) viewmat = ( PyObject * ) newMatrixObject( ( float * ) G.vd->viewmat, 4, - 4, Py_WRAP ); + 4 ); if( !viewmat ) return EXPP_ReturnPyObjError( PyExc_MemoryError, @@ -854,7 +854,7 @@ static PyObject *M_Window_GetPerspMatrix( PyObject * self ) perspmat = ( PyObject * ) newMatrixObject( ( float * ) G.vd->persmat, 4, - 4, Py_WRAP); + 4 ); if( !perspmat ) return EXPP_ReturnPyObjError( PyExc_MemoryError, diff --git a/source/blender/python/api2_2x/euler.c b/source/blender/python/api2_2x/euler.c index 20f3895442b..6b72460ccd4 100644 --- a/source/blender/python/api2_2x/euler.c +++ b/source/blender/python/api2_2x/euler.c @@ -29,385 +29,329 @@ * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ -#include -#include -#include "Mathutils.h" -#include "gen_utils.h" +#include "euler.h" -//-------------------------DOC STRINGS --------------------------- +//doc strings char Euler_Zero_doc[] = "() - set all values in the euler to 0"; -char Euler_Unique_doc[] ="() - sets the euler rotation a unique shortest arc rotation - tests for gimbal lock"; -char Euler_ToMatrix_doc[] = "() - returns a rotation matrix representing the euler rotation"; -char Euler_ToQuat_doc[] = "() - returns a quaternion representing the euler rotation"; -char Euler_Rotate_doc[] = "() - rotate a euler by certain amount around an axis of rotation"; -//-----------------------METHOD DEFINITIONS ---------------------- +char Euler_Unique_doc[] = + "() - sets the euler rotation a unique shortest arc rotation - tests for gimbal lock"; +char Euler_ToMatrix_doc[] = + "() - returns a rotation matrix representing the euler rotation"; +char Euler_ToQuat_doc[] = + "() - returns a quaternion representing the euler rotation"; + +//methods table struct PyMethodDef Euler_methods[] = { - {"zero", (PyCFunction) Euler_Zero, METH_NOARGS, Euler_Zero_doc}, - {"unique", (PyCFunction) Euler_Unique, METH_NOARGS, Euler_Unique_doc}, - {"toMatrix", (PyCFunction) Euler_ToMatrix, METH_NOARGS, Euler_ToMatrix_doc}, - {"toQuat", (PyCFunction) Euler_ToQuat, METH_NOARGS, Euler_ToQuat_doc}, - {"rotate", (PyCFunction) Euler_Rotate, METH_VARARGS, Euler_Rotate_doc}, + {"zero", ( PyCFunction ) Euler_Zero, METH_NOARGS, + Euler_Zero_doc}, + {"unique", ( PyCFunction ) Euler_Unique, METH_NOARGS, + Euler_Unique_doc}, + {"toMatrix", ( PyCFunction ) Euler_ToMatrix, METH_NOARGS, + Euler_ToMatrix_doc}, + {"toQuat", ( PyCFunction ) Euler_ToQuat, METH_NOARGS, + Euler_ToQuat_doc}, {NULL, NULL, 0, NULL} }; -//-----------------------------METHODS---------------------------- -//----------------------------Euler.toQuat()---------------------- -//return a quaternion representation of the euler -PyObject *Euler_ToQuat(EulerObject * self) + +/*****************************/ +// Euler Python Object +/*****************************/ + +//euler methods +PyObject *Euler_ToQuat( EulerObject * self ) { - float eul[3]; - float quat[4]; + float *quat; int x; - for(x = 0; x < 3; x++) { - eul[x] = self->eul[x] * ((float)Py_PI / 180); + for( x = 0; x < 3; x++ ) { + self->eul[x] *= ( float ) ( Py_PI / 180 ); + } + quat = PyMem_Malloc( 4 * sizeof( float ) ); + EulToQuat( self->eul, quat ); + for( x = 0; x < 3; x++ ) { + self->eul[x] *= ( float ) ( 180 / Py_PI ); } - EulToQuat(eul, quat); - if(self->data.blend_data) - return (PyObject *) newQuaternionObject(quat, Py_WRAP); - else - return (PyObject *) newQuaternionObject(quat, Py_NEW); + return ( PyObject * ) newQuaternionObject( quat ); } -//----------------------------Euler.toMatrix()--------------------- -//return a matrix representation of the euler -PyObject *Euler_ToMatrix(EulerObject * self) + +PyObject *Euler_ToMatrix( EulerObject * self ) { - float eul[3]; - float mat[9] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; + float *mat; int x; - for(x = 0; x < 3; x++) { - eul[x] = self->eul[x] * ((float)Py_PI / 180); + for( x = 0; x < 3; x++ ) { + self->eul[x] *= ( float ) ( Py_PI / 180 ); + } + mat = PyMem_Malloc( 3 * 3 * sizeof( float ) ); + EulToMat3( self->eul, ( float ( * )[3] ) mat ); + for( x = 0; x < 3; x++ ) { + self->eul[x] *= ( float ) ( 180 / Py_PI ); } - EulToMat3(eul, (float (*)[3]) mat); - if(self->data.blend_data) - return (PyObject *) newMatrixObject(mat, 3, 3 , Py_WRAP); - else - return (PyObject *) newMatrixObject(mat, 3, 3 , Py_NEW); + return ( PyObject * ) newMatrixObject( mat, 3, 3 ); } -//----------------------------Euler.unique()----------------------- -//sets the x,y,z values to a unique euler rotation -PyObject *Euler_Unique(EulerObject * self) + +PyObject *Euler_Unique( EulerObject * self ) { - double heading, pitch, bank; - double pi2 = Py_PI * 2.0f; - double piO2 = Py_PI / 2.0f; - double Opi2 = 1.0f / pi2; + float heading, pitch, bank; + float pi2 = ( float ) Py_PI * 2.0f; + float piO2 = ( float ) Py_PI / 2.0f; + float Opi2 = 1.0f / pi2; //radians - heading = self->eul[0] * (float)Py_PI / 180; - pitch = self->eul[1] * (float)Py_PI / 180; - bank = self->eul[2] * (float)Py_PI / 180; + heading = self->eul[0] * ( float ) ( Py_PI / 180 ); + pitch = self->eul[1] * ( float ) ( Py_PI / 180 ); + bank = self->eul[2] * ( float ) ( Py_PI / 180 ); //wrap heading in +180 / -180 - pitch += Py_PI; - pitch -= floor(pitch * Opi2) * pi2; - pitch -= Py_PI; - - - if(pitch < -piO2) { - pitch = -Py_PI - pitch; - heading += Py_PI; - bank += Py_PI; - } else if(pitch > piO2) { - pitch = Py_PI - pitch; - heading += Py_PI; - bank += Py_PI; + pitch += ( float ) Py_PI; + pitch -= ( float ) floor( pitch * Opi2 ) * pi2; + pitch -= ( float ) Py_PI; + + + if( pitch < -piO2 ) { + pitch = ( float ) -Py_PI - pitch; + heading += ( float ) Py_PI; + bank += ( float ) Py_PI; + } else if( pitch > piO2 ) { + pitch = ( float ) Py_PI - pitch; + heading += ( float ) Py_PI; + bank += ( float ) Py_PI; } //gimbal lock test - if(fabs(pitch) > piO2 - 1e-4) { + if( fabs( pitch ) > piO2 - 1e-4 ) { heading += bank; bank = 0.0f; } else { - bank += Py_PI; - bank -= (floor(bank * Opi2)) * pi2; - bank -= Py_PI; + bank += ( float ) Py_PI; + bank -= ( float ) ( floor( bank * Opi2 ) ) * pi2; + bank -= ( float ) Py_PI; } - heading += Py_PI; - heading -= (floor(heading * Opi2)) * pi2; - heading -= Py_PI; + heading += ( float ) Py_PI; + heading -= ( float ) ( floor( heading * Opi2 ) ) * pi2; + heading -= ( float ) Py_PI; //back to degrees - self->eul[0] = heading * 180 / (float)Py_PI; - self->eul[1] = pitch * 180 / (float)Py_PI; - self->eul[2] = bank * 180 / (float)Py_PI; + self->eul[0] = heading * ( float ) ( 180 / Py_PI ); + self->eul[1] = pitch * ( float ) ( 180 / Py_PI ); + self->eul[2] = bank * ( float ) ( 180 / Py_PI ); - return (PyObject*)self; + return EXPP_incr_ret( Py_None ); } -//----------------------------Euler.zero()------------------------- -//sets the euler to 0,0,0 -PyObject *Euler_Zero(EulerObject * self) + +PyObject *Euler_Zero( EulerObject * self ) { self->eul[0] = 0.0; self->eul[1] = 0.0; self->eul[2] = 0.0; - return (PyObject*)self; + return EXPP_incr_ret( Py_None ); } -//----------------------------Euler.rotate()----------------------- -//rotates a euler a certain amount and returns the result -//should return a unique euler rotation (i.e. no 720 degree pitches :) -PyObject *Euler_Rotate(EulerObject * self, PyObject *args) -{ - float angle = 0.0f; - char *axis; - int x; - if(!PyArg_ParseTuple(args, "fs", &angle, &axis)){ - return EXPP_ReturnPyObjError(PyExc_TypeError, - "euler.rotate():expected angle (float) and axis (x,y,z)"); - } - if(!STREQ3(axis,"x","y","z")){ - return EXPP_ReturnPyObjError(PyExc_TypeError, - "euler.rotate(): expected axis to be 'x', 'y' or 'z'"); - } - - //covert to radians - angle *= ((float)Py_PI / 180); - for(x = 0; x < 3; x++) { - self->eul[x] *= ((float)Py_PI / 180); - } - euler_rot(self->eul, angle, *axis); - //convert back from radians - for(x = 0; x < 3; x++) { - self->eul[x] *= (180 / (float)Py_PI); - } +static void Euler_dealloc( EulerObject * self ) +{ + /* since we own this memory... */ + PyMem_Free( self->eul ); - return (PyObject*)self; + PyObject_DEL( self ); } -//----------------------------dealloc()(internal) ------------------ -//free the py_object -static void Euler_dealloc(EulerObject * self) + +static PyObject *Euler_getattr( EulerObject * self, char *name ) { - //only free py_data - if(self->data.py_data){ - PyMem_Free(self->data.py_data); + if( ELEM3( name[0], 'x', 'y', 'z' ) && name[1] == 0 ) { + return PyFloat_FromDouble( self->eul[name[0] - 'x'] ); } - PyObject_DEL(self); + return Py_FindMethod( Euler_methods, ( PyObject * ) self, name ); } -//----------------------------getattr()(internal) ------------------ -//object.attribute access (get) -static PyObject *Euler_getattr(EulerObject * self, char *name) -{ - int x; - - if(STREQ(name,"x")){ - return PyFloat_FromDouble(self->eul[0]); - }else if(STREQ(name, "y")){ - return PyFloat_FromDouble(self->eul[1]); - }else if(STREQ(name, "z")){ - return PyFloat_FromDouble(self->eul[2]); - } - return Py_FindMethod(Euler_methods, (PyObject *) self, name); -} -//----------------------------setattr()(internal) ------------------ -//object.attribute access (set) -static int Euler_setattr(EulerObject * self, char *name, PyObject * e) +static int Euler_setattr( EulerObject * self, char *name, PyObject * e ) { - PyObject *f = NULL; + float val; - f = PyNumber_Float(e); - if(f == NULL) { // parsed item not a number - return EXPP_ReturnIntError(PyExc_TypeError, - "euler.attribute = x: argument not a number\n"); - } - - if(STREQ(name,"x")){ - self->eul[0] = PyFloat_AS_DOUBLE(f); - }else if(STREQ(name, "y")){ - self->eul[1] = PyFloat_AS_DOUBLE(f); - }else if(STREQ(name, "z")){ - self->eul[2] = PyFloat_AS_DOUBLE(f); - }else{ - Py_DECREF(f); - return EXPP_ReturnIntError(PyExc_AttributeError, - "euler.attribute = x: unknown attribute\n"); - } + if( !PyArg_Parse( e, "f", &val ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "unable to parse float argument\n" ); - Py_DECREF(f); - return 0; + if( ELEM3( name[0], 'x', 'y', 'z' ) && name[1] == 0 ) { + self->eul[name[0] - 'x'] = val; + return 0; + } else + return -1; } -//----------------------------print object (internal)-------------- -//print the object to screen -static PyObject *Euler_repr(EulerObject * self) -{ - int i; - char buffer[48], str[1024]; - - BLI_strncpy(str,"[",1024); - for(i = 0; i < 3; i++){ - if(i < (2)){ - sprintf(buffer, "%.6f, ", self->eul[i]); - strcat(str,buffer); - }else{ - sprintf(buffer, "%.6f", self->eul[i]); - strcat(str,buffer); - } - } - strcat(str, "](euler)"); - return EXPP_incr_ret(PyString_FromString(str)); -} -//---------------------SEQUENCE PROTOCOLS------------------------ -//----------------------------len(object)------------------------ -//sequence length -static int Euler_len(EulerObject * self) +/* Eulers Sequence methods */ +static PyObject *Euler_item( EulerObject * self, int i ) { - return 3; -} -//----------------------------object[]--------------------------- -//sequence accessor (get) -static PyObject *Euler_item(EulerObject * self, int i) -{ - if(i < 0 || i >= 3) - return EXPP_ReturnPyObjError(PyExc_IndexError, - "euler[attribute]: array index out of range\n"); - - return Py_BuildValue("f", self->eul[i]); + if( i < 0 || i >= 3 ) + return EXPP_ReturnPyObjError( PyExc_IndexError, + "array index out of range\n" ); + return Py_BuildValue( "f", self->eul[i] ); } -//----------------------------object[]------------------------- -//sequence accessor (set) -static int Euler_ass_item(EulerObject * self, int i, PyObject * ob) -{ - PyObject *f = NULL; - f = PyNumber_Float(ob); - if(f == NULL) { // parsed item not a number - return EXPP_ReturnIntError(PyExc_TypeError, - "euler[attribute] = x: argument not a number\n"); - } - - if(i < 0 || i >= 3){ - Py_DECREF(f); - return EXPP_ReturnIntError(PyExc_IndexError, - "euler[attribute] = x: array assignment index out of range\n"); - } - self->eul[i] = PyFloat_AS_DOUBLE(f); - Py_DECREF(f); - return 0; -} -//----------------------------object[z:y]------------------------ -//sequence slice (get) -static PyObject *Euler_slice(EulerObject * self, int begin, int end) +static PyObject *Euler_slice( EulerObject * self, int begin, int end ) { - PyObject *list = NULL; + PyObject *list; int count; - CLAMP(begin, 0, 3); - CLAMP(end, 0, 3); - begin = MIN2(begin,end); + if( begin < 0 ) + begin = 0; + if( end > 3 ) + end = 3; + if( begin > end ) + begin = end; - list = PyList_New(end - begin); - for(count = begin; count < end; count++) { - PyList_SetItem(list, count - begin, - PyFloat_FromDouble(self->eul[count])); - } + list = PyList_New( end - begin ); + for( count = begin; count < end; count++ ) { + PyList_SetItem( list, count - begin, + PyFloat_FromDouble( self->eul[count] ) ); + } return list; } -//----------------------------object[z:y]------------------------ -//sequence slice (set) -static int Euler_ass_slice(EulerObject * self, int begin, int end, - PyObject * seq) + +static int Euler_ass_item( EulerObject * self, int i, PyObject * ob ) { - int i, y, size = 0; - float eul[3]; + if( i < 0 || i >= 3 ) + return EXPP_ReturnIntError( PyExc_IndexError, + "array assignment index out of range\n" ); - CLAMP(begin, 0, 3); - CLAMP(end, 0, 3); - begin = MIN2(begin,end); + if( !PyNumber_Check( ob ) ) + return EXPP_ReturnIntError( PyExc_IndexError, + "Euler member must be a number\n" ); - size = PySequence_Length(seq); - if(size != (end - begin)){ - return EXPP_ReturnIntError(PyExc_TypeError, - "euler[begin:end] = []: size mismatch in slice assignment\n"); + if( !PyFloat_Check( ob ) && !PyInt_Check( ob ) ) { + return EXPP_ReturnIntError( PyExc_TypeError, + "int or float expected\n" ); + } else { + self->eul[i] = ( float ) PyFloat_AsDouble( ob ); } + return 0; +} - for (i = 0; i < size; i++) { - PyObject *e, *f; - - e = PySequence_GetItem(seq, i); - if (e == NULL) { // Failed to read sequence - return EXPP_ReturnIntError(PyExc_RuntimeError, - "euler[begin:end] = []: unable to read sequence\n"); - } - f = PyNumber_Float(e); - if(f == NULL) { // parsed item not a number - Py_DECREF(e); - return EXPP_ReturnIntError(PyExc_TypeError, - "euler[begin:end] = []: sequence argument not a number\n"); +static int Euler_ass_slice( EulerObject * self, int begin, int end, + PyObject * seq ) +{ + int count, z; + + if( begin < 0 ) + begin = 0; + if( end > 3 ) + end = 3; + if( begin > end ) + begin = end; + + if( !PySequence_Check( seq ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "illegal argument type for built-in operation\n" ); + if( PySequence_Length( seq ) != ( end - begin ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "size mismatch in slice assignment\n" ); + + z = 0; + for( count = begin; count < end; count++ ) { + PyObject *ob = PySequence_GetItem( seq, z ); + z++; + + if( !PyFloat_Check( ob ) && !PyInt_Check( ob ) ) { + Py_DECREF( ob ); + return -1; + } else { + if( !PyArg_Parse( ob, "f", &self->eul[count] ) ) { + Py_DECREF( ob ); + return -1; + } } - eul[i] = PyFloat_AS_DOUBLE(f); - EXPP_decr2(f,e); - } - //parsed well - now set in vector - for(y = 0; y < 3; y++){ - self->eul[begin + y] = eul[y]; } return 0; } -//-----------------PROTCOL DECLARATIONS-------------------------- + +static PyObject *Euler_repr( EulerObject * self ) +{ + int i, maxindex = 3 - 1; + char ftoa[24]; + PyObject *str1, *str2; + + str1 = PyString_FromString( "[" ); + + for( i = 0; i < maxindex; i++ ) { + sprintf( ftoa, "%.4f, ", self->eul[i] ); + str2 = PyString_FromString( ftoa ); + if( !str1 || !str2 ) + goto error; + PyString_ConcatAndDel( &str1, str2 ); + } + + sprintf( ftoa, "%.4f]\n", self->eul[maxindex] ); + str2 = PyString_FromString( ftoa ); + if( !str1 || !str2 ) + goto error; + PyString_ConcatAndDel( &str1, str2 ); + + if( str1 ) + return str1; + + error: + Py_XDECREF( str1 ); + Py_XDECREF( str2 ); + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create PyString!\n" ); +} + static PySequenceMethods Euler_SeqMethods = { - (inquiry) Euler_len, /* sq_length */ - (binaryfunc) 0, /* sq_concat */ - (intargfunc) 0, /* sq_repeat */ - (intargfunc) Euler_item, /* sq_item */ - (intintargfunc) Euler_slice, /* sq_slice */ - (intobjargproc) Euler_ass_item, /* sq_ass_item */ - (intintobjargproc) Euler_ass_slice, /* sq_ass_slice */ + ( inquiry ) 0, /* sq_length */ + ( binaryfunc ) 0, /* sq_concat */ + ( intargfunc ) 0, /* sq_repeat */ + ( intargfunc ) Euler_item, /* sq_item */ + ( intintargfunc ) Euler_slice, /* sq_slice */ + ( intobjargproc ) Euler_ass_item, /* sq_ass_item */ + ( intintobjargproc ) Euler_ass_slice, /* sq_ass_slice */ }; -//------------------PY_OBECT DEFINITION-------------------------- + PyTypeObject euler_Type = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size */ - "euler", /*tp_name */ - sizeof(EulerObject), /*tp_basicsize */ - 0, /*tp_itemsize */ - (destructor) Euler_dealloc, /*tp_dealloc */ - (printfunc) 0, /*tp_print */ - (getattrfunc) Euler_getattr, /*tp_getattr */ - (setattrfunc) Euler_setattr, /*tp_setattr */ - 0, /*tp_compare */ - (reprfunc) Euler_repr, /*tp_repr */ - 0, /*tp_as_number */ - &Euler_SeqMethods, /*tp_as_sequence */ + PyObject_HEAD_INIT( NULL ) + 0, /*ob_size */ + "euler", /*tp_name */ + sizeof( EulerObject ), /*tp_basicsize */ + 0, /*tp_itemsize */ + ( destructor ) Euler_dealloc, /*tp_dealloc */ + ( printfunc ) 0, /*tp_print */ + ( getattrfunc ) Euler_getattr, /*tp_getattr */ + ( setattrfunc ) Euler_setattr, /*tp_setattr */ + 0, /*tp_compare */ + ( reprfunc ) Euler_repr, /*tp_repr */ + 0, /*tp_as_number */ + &Euler_SeqMethods, /*tp_as_sequence */ }; -//------------------------newEulerObject (internal)------------- -//creates a new euler object -/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER - (i.e. it was allocated elsewhere by MEM_mallocN()) - pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON - (i.e. it must be created here with PyMEM_malloc())*/ -PyObject *newEulerObject(float *eul, int type) + +PyObject *newEulerObject( float *eul ) { EulerObject *self; int x; euler_Type.ob_type = &PyType_Type; - self = PyObject_NEW(EulerObject, &euler_Type); - self->data.blend_data = NULL; - self->data.py_data = NULL; - - if(type == Py_WRAP){ - self->data.blend_data = eul; - self->eul = self->data.blend_data; - }else if (type == Py_NEW){ - self->data.py_data = PyMem_Malloc(3 * sizeof(float)); - self->eul = self->data.py_data; - if(!eul) { //new empty - for(x = 0; x < 3; x++) { - self->eul[x] = 0.0f; - } - }else{ - for(x = 0; x < 3; x++){ - self->eul[x] = eul[x]; - } + + self = PyObject_NEW( EulerObject, &euler_Type ); + + /* + we own the self->eul memory and will free it later. + if we received an input arg, copy to our internal array + */ + + self->eul = PyMem_Malloc( 3 * sizeof( float ) ); + if( ! self->eul ) + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "newEulerObject:PyMem_Malloc failed" ); + + if( !eul ) { + for( x = 0; x < 3; x++ ) { + self->eul[x] = 0.0f; + } + } else{ + for( x = 0; x < 3; x++){ + self->eul[x] = eul[x]; } - }else{ //bad type - return NULL; } - return (PyObject *) EXPP_incr_ret((PyObject *)self); -} + return ( PyObject * ) self; +} diff --git a/source/blender/python/api2_2x/euler.h b/source/blender/python/api2_2x/euler.h index 1b5dca26df7..1c3b21f7ffc 100644 --- a/source/blender/python/api2_2x/euler.h +++ b/source/blender/python/api2_2x/euler.h @@ -1,3 +1,4 @@ + /* * $Id$ * @@ -34,28 +35,33 @@ #ifndef EXPP_euler_h #define EXPP_euler_h +#include "Python.h" +#include "gen_utils.h" +#include "Types.h" +#include +#include "quat.h" +#include "matrix.h" +#include "BKE_utildefines.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +/*****************************/ +// Euler Python Object +/*****************************/ + #define EulerObject_Check(v) ((v)->ob_type == &euler_Type) typedef struct { - PyObject_VAR_HEAD - struct{ - float *py_data; //python managed - float *blend_data; //blender managed - }data; - float *eul; //1D array of data (alias) + PyObject_VAR_HEAD float *eul; } EulerObject; -/*struct data contains a pointer to the actual data that the -object uses. It can use either PyMem allocated data (which will -be stored in py_data) or be a wrapper for data allocated through -blender (stored in blend_data). This is an either/or struct not both*/ - //prototypes +PyObject *newEulerObject( float *eul ); PyObject *Euler_Zero( EulerObject * self ); PyObject *Euler_Unique( EulerObject * self ); PyObject *Euler_ToMatrix( EulerObject * self ); PyObject *Euler_ToQuat( EulerObject * self ); -PyObject *Euler_Rotate( EulerObject * self, PyObject *args ); -PyObject *newEulerObject( float *eul, int type ); #endif /* EXPP_euler_h */ diff --git a/source/blender/python/api2_2x/gen_utils.c b/source/blender/python/api2_2x/gen_utils.c index 4144cac4d59..ba6878b0a5d 100644 --- a/source/blender/python/api2_2x/gen_utils.c +++ b/source/blender/python/api2_2x/gen_utils.c @@ -120,31 +120,6 @@ int EXPP_ReturnIntError( PyObject * type, char *error_msg ) /* Description: This function increments the reference count of the given */ /* Python object (usually Py_None) and returns it. */ /*****************************************************************************/ -void EXPP_incr2( PyObject * ob1, PyObject * ob2 ) -{ - Py_INCREF( ob1 ); - Py_INCREF( ob2 ); -} - -void EXPP_incr3( PyObject * ob1, PyObject * ob2, PyObject * ob3 ) -{ - Py_INCREF( ob1 ); - Py_INCREF( ob2 ); - Py_INCREF( ob3 ); -} - -void EXPP_decr2( PyObject * ob1, PyObject * ob2 ) -{ - Py_DECREF( ob1 ); - Py_DECREF( ob2 ); -} - -void EXPP_decr3( PyObject * ob1, PyObject * ob2, PyObject * ob3 ) -{ - Py_DECREF( ob1 ); - Py_DECREF( ob2 ); - Py_DECREF( ob3 ); -} PyObject *EXPP_incr_ret( PyObject * object ) { diff --git a/source/blender/python/api2_2x/gen_utils.h b/source/blender/python/api2_2x/gen_utils.h index 0a890333f72..91021d970b9 100644 --- a/source/blender/python/api2_2x/gen_utils.h +++ b/source/blender/python/api2_2x/gen_utils.h @@ -50,8 +50,6 @@ #include #define Py_PI 3.14159265358979323846 -#define Py_WRAP 1024 -#define Py_NEW 2048 /* Py_RETURN_NONE @@ -74,10 +72,6 @@ char *event_to_name( short event ); float EXPP_ClampFloat( float value, float min, float max ); int EXPP_ClampInt( int value, int min, int max ); -void EXPP_incr2( PyObject * ob1, PyObject * ob2 ); -void EXPP_incr3( PyObject * ob1, PyObject * ob2, PyObject * ob3 ); -void EXPP_decr2( PyObject * ob1, PyObject * ob2 ); -void EXPP_decr3( PyObject * ob1, PyObject * ob2, PyObject * ob3 ); PyObject *EXPP_incr_ret( PyObject * object ); PyObject *EXPP_incr_ret_True(void); PyObject *EXPP_incr_ret_False(void); diff --git a/source/blender/python/api2_2x/matrix.c b/source/blender/python/api2_2x/matrix.c index abea09b5f12..b50df287061 100644 --- a/source/blender/python/api2_2x/matrix.c +++ b/source/blender/python/api2_2x/matrix.c @@ -28,804 +28,1010 @@ * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ -#include -#include -#include "Mathutils.h" -#include "gen_utils.h" +#include "matrix.h" -//-------------------------DOC STRINGS --------------------------- +//doc strings char Matrix_Zero_doc[] = "() - set all values in the matrix to 0"; -char Matrix_Identity_doc[] = "() - set the square matrix to it's identity matrix"; +char Matrix_Identity_doc[] = + "() - set the square matrix to it's identity matrix"; char Matrix_Transpose_doc[] = "() - set the matrix to it's transpose"; char Matrix_Determinant_doc[] = "() - return the determinant of the matrix"; -char Matrix_Invert_doc[] = "() - set the matrix to it's inverse if an inverse is possible"; -char Matrix_TranslationPart_doc[] = "() - return a vector encompassing the translation of the matrix"; -char Matrix_RotationPart_doc[] = "() - return a vector encompassing the rotation of the matrix"; +char Matrix_Invert_doc[] = + "() - set the matrix to it's inverse if an inverse is possible"; +char Matrix_TranslationPart_doc[] = + "() - return a vector encompassing the translation of the matrix"; +char Matrix_RotationPart_doc[] = + "() - return a vector encompassing the rotation of the matrix"; char Matrix_Resize4x4_doc[] = "() - resize the matrix to a 4x4 square matrix"; char Matrix_toEuler_doc[] = "() - convert matrix to a euler angle rotation"; char Matrix_toQuat_doc[] = "() - convert matrix to a quaternion rotation"; -//-----------------------METHOD DEFINITIONS ---------------------- + +//methods table struct PyMethodDef Matrix_methods[] = { - {"zero", (PyCFunction) Matrix_Zero, METH_NOARGS, Matrix_Zero_doc}, - {"identity", (PyCFunction) Matrix_Identity, METH_NOARGS, Matrix_Identity_doc}, - {"transpose", (PyCFunction) Matrix_Transpose, METH_NOARGS, Matrix_Transpose_doc}, - {"determinant", (PyCFunction) Matrix_Determinant, METH_NOARGS, Matrix_Determinant_doc}, - {"invert", (PyCFunction) Matrix_Invert, METH_NOARGS, Matrix_Invert_doc}, - {"translationPart", (PyCFunction) Matrix_TranslationPart, METH_NOARGS, Matrix_TranslationPart_doc}, - {"rotationPart", (PyCFunction) Matrix_RotationPart, METH_NOARGS, Matrix_RotationPart_doc}, - {"resize4x4", (PyCFunction) Matrix_Resize4x4, METH_NOARGS, Matrix_Resize4x4_doc}, - {"toEuler", (PyCFunction) Matrix_toEuler, METH_NOARGS, Matrix_toEuler_doc}, - {"toQuat", (PyCFunction) Matrix_toQuat, METH_NOARGS, Matrix_toQuat_doc}, + {"zero", ( PyCFunction ) Matrix_Zero, METH_NOARGS, + Matrix_Zero_doc}, + {"identity", ( PyCFunction ) Matrix_Identity, METH_NOARGS, + Matrix_Identity_doc}, + {"transpose", ( PyCFunction ) Matrix_Transpose, METH_NOARGS, + Matrix_Transpose_doc}, + {"determinant", ( PyCFunction ) Matrix_Determinant, METH_NOARGS, + Matrix_Determinant_doc}, + {"invert", ( PyCFunction ) Matrix_Invert, METH_NOARGS, + Matrix_Invert_doc}, + {"translationPart", ( PyCFunction ) Matrix_TranslationPart, + METH_NOARGS, + Matrix_TranslationPart_doc}, + {"rotationPart", ( PyCFunction ) Matrix_RotationPart, METH_NOARGS, + Matrix_RotationPart_doc}, + {"resize4x4", ( PyCFunction ) Matrix_Resize4x4, METH_NOARGS, + Matrix_Resize4x4_doc}, + {"toEuler", ( PyCFunction ) Matrix_toEuler, METH_NOARGS, + Matrix_toEuler_doc}, + {"toQuat", ( PyCFunction ) Matrix_toQuat, METH_NOARGS, + Matrix_toQuat_doc}, {NULL, NULL, 0, NULL} }; -//-----------------------------METHODS---------------------------- -//---------------------------Matrix.toQuat() --------------------- -PyObject *Matrix_toQuat(MatrixObject * self) + +/*****************************/ +// Matrix Python Object +/*****************************/ + +PyObject *Matrix_toQuat( MatrixObject * self ) { - float quat[4]; - - //must be 3-4 cols, 3-4 rows, square matrix - if(self->colSize < 3 || self->rowSize < 3 || (self->colSize != self->rowSize)) { - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix.toQuat(): inappropriate matrix size - expects 3x3 or 4x4 matrix\n"); - } - if(self->colSize == 3){ - Mat3ToQuat((float (*)[3])*self->matrix, quat); - }else{ - Mat4ToQuat((float (*)[4])*self->matrix, quat); + float *quat, *mat; + + if( self->colSize < 3 ) { + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "inappropriate matrix size\n" ); + } else if( self->colSize > 2 ) { //3 or 4 col + if( self->rowSize < 3 ) //3 or 4 row + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "inappropriate matrix size\n" ); + + mat = PyMem_Malloc( 3 * 3 * sizeof( float ) ); + if( mat == NULL ) { + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating matrix\n\n" ) ); + } + mat[0] = self->matrix[0][0]; + mat[1] = self->matrix[0][1]; + mat[2] = self->matrix[0][2]; + mat[3] = self->matrix[1][0]; + mat[4] = self->matrix[1][1]; + mat[5] = self->matrix[1][2]; + mat[6] = self->matrix[2][0]; + mat[7] = self->matrix[2][1]; + mat[8] = self->matrix[2][2]; } - - if(self->data.blend_data) - return (PyObject *) newQuaternionObject(quat, Py_WRAP); - else - return (PyObject *) newQuaternionObject(quat, Py_NEW); + quat = PyMem_Malloc( 4 * sizeof( float ) ); + if( quat == NULL ) { + PyMem_Free( mat ); + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating quat\n\n" ) ); + } + Mat3ToQuat( ( float ( * )[3] ) mat, quat ); + + return ( PyObject * ) newQuaternionObject( quat ); } -//---------------------------Matrix.toEuler() -------------------- -PyObject *Matrix_toEuler(MatrixObject * self) + + +PyObject *Matrix_toEuler( MatrixObject * self ) { - float eul[3]; + float *eul, *mat; int x; - //must be 3-4 cols, 3-4 rows, square matrix - if(self->colSize !=3 || self->rowSize != 3) { - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix.toQuat(): inappropriate matrix size - expects 3x3 matrix\n"); - } - Mat3ToEul((float (*)[3])*self->matrix, eul); - //have to convert to degrees - for(x = 0; x < 3; x++) { - eul[x] *= (float) (180 / Py_PI); - } - if(self->data.blend_data) - return (PyObject *) newEulerObject(eul, Py_WRAP); - else - return (PyObject *) newEulerObject(eul, Py_NEW); + if( self->colSize < 3 ) { + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "inappropriate matrix size\n" ); + } else if( self->colSize > 2 ) { //3 or 4 col + if( self->rowSize < 3 ) //3 or 4 row + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "inappropriate matrix size\n" ); + + mat = PyMem_Malloc( 3 * 3 * sizeof( float ) ); + if( mat == NULL ) { + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating mat\n\n" ) ); + } + mat[0] = self->matrix[0][0]; + mat[1] = self->matrix[0][1]; + mat[2] = self->matrix[0][2]; + mat[3] = self->matrix[1][0]; + mat[4] = self->matrix[1][1]; + mat[5] = self->matrix[1][2]; + mat[6] = self->matrix[2][0]; + mat[7] = self->matrix[2][1]; + mat[8] = self->matrix[2][2]; + } + eul = PyMem_Malloc( 3 * sizeof( float ) ); + if( eul == NULL ) { + PyMem_Free( mat ); + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating eul\n\n" ) ); + } + Mat3ToEul( ( float ( * )[3] ) mat, eul ); + + for( x = 0; x < 3; x++ ) { + eul[x] *= ( float ) ( 180 / Py_PI ); + } + + return ( PyObject * ) newEulerObject( eul ); } -//---------------------------Matrix.resize4x4() ------------------ -PyObject *Matrix_Resize4x4(MatrixObject * self) + +PyObject *Matrix_Resize4x4( MatrixObject * self ) { - int x, first_row_elem, curr_pos, new_pos, blank_columns, blank_rows; + float *mat; + int x, row, col; + + if( self->colSize == 4 && self->rowSize == 4 ) + return EXPP_incr_ret( Py_None ); - if(self->data.blend_data){ - return EXPP_ReturnPyObjError(PyExc_TypeError, - "cannot resize wrapped data - only python matrices\n"); + mat = PyMem_Malloc( 4 * 4 * sizeof( float ) ); + if( mat == NULL ) { + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating mat\n\n" ) ); + } + for( x = 0; x < 16; x++ ) { + mat[x] = 0.0f; } - self->data.py_data = PyMem_Realloc(self->data.py_data, (sizeof(float) * 16)); - if(self->data.py_data == NULL) { - return EXPP_ReturnPyObjError(PyExc_MemoryError, - "matrix.resize4x4(): problem allocating pointer space\n\n"); + if( self->colSize == 2 ) { //2x2, 2x3, 2x4 + mat[0] = self->matrix[0][0]; + mat[1] = self->matrix[0][1]; + mat[4] = self->matrix[1][0]; + mat[5] = self->matrix[1][1]; + if( self->rowSize > 2 ) { + mat[8] = self->matrix[2][0]; + mat[9] = self->matrix[2][1]; + } + if( self->rowSize > 3 ) { + mat[12] = self->matrix[3][0]; + mat[13] = self->matrix[3][1]; + } + mat[10] = 1.0f; + mat[15] = 1.0f; + } else if( self->colSize == 3 ) { //3x2, 3x3, 3x4 + mat[0] = self->matrix[0][0]; + mat[1] = self->matrix[0][1]; + mat[2] = self->matrix[0][2]; + mat[4] = self->matrix[1][0]; + mat[5] = self->matrix[1][1]; + mat[6] = self->matrix[1][2]; + if( self->rowSize > 2 ) { + mat[8] = self->matrix[2][0]; + mat[9] = self->matrix[2][1]; + mat[10] = self->matrix[2][2]; + } + if( self->rowSize > 3 ) { + mat[12] = self->matrix[3][0]; + mat[13] = self->matrix[3][1]; + mat[14] = self->matrix[3][2]; + } + if( self->rowSize == 2 ) + mat[10] = 1.0f; + mat[15] = 1.0f; + } else if( self->colSize == 4 ) { //2x4, 3x4 + mat[0] = self->matrix[0][0]; + mat[1] = self->matrix[0][1]; + mat[2] = self->matrix[0][2]; + mat[3] = self->matrix[0][3]; + mat[4] = self->matrix[1][0]; + mat[5] = self->matrix[1][1]; + mat[6] = self->matrix[1][2]; + mat[7] = self->matrix[1][3]; + if( self->rowSize > 2 ) { + mat[8] = self->matrix[2][0]; + mat[9] = self->matrix[2][1]; + mat[10] = self->matrix[2][2]; + mat[11] = self->matrix[2][3]; + } + if( self->rowSize == 2 ) + mat[10] = 1.0f; + mat[15] = 1.0f; } - self->contigPtr = self->data.py_data; //force - self->matrix = PyMem_Realloc(self->matrix, (sizeof(float) * 4)); - if(self->matrix == NULL) { - return EXPP_ReturnPyObjError(PyExc_MemoryError, - "matrix.resize4x4(): problem allocating pointer space\n\n"); + + PyMem_Free( self->matrix ); + PyMem_Free( self->contigPtr ); + self->contigPtr = PyMem_Malloc( 4 * 4 * sizeof( float ) ); + if( self->contigPtr == NULL ) { + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating array space\n\n" ) ); } - //set row pointers - for(x = 0; x < 4; x++) { - self->matrix[x] = self->contigPtr + (x * 4); + self->matrix = PyMem_Malloc( 4 * sizeof( float * ) ); + if( self->matrix == NULL ) { + PyMem_Free( self->contigPtr ); + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating pointer space\n\n" ) ); } - //move data to new spot in array + clean - for(blank_rows = (4 - self->rowSize); blank_rows > 0; blank_rows--){ - for(x = 0; x < 4; x++){ - self->contigPtr[(4 * (self->rowSize + (blank_rows - 1))) + x] = 0.0f; - } + for( x = 0; x < 4; x++ ) { + self->matrix[x] = self->contigPtr + ( x * 4 ); } - for(x = 1; x <= self->rowSize; x++){ - first_row_elem = (self->colSize * (self->rowSize - x)); - curr_pos = (first_row_elem + (self->colSize -1)); - new_pos = (4 * (self->rowSize - x )) + (curr_pos - first_row_elem); - for(blank_columns = (4 - self->colSize); blank_columns > 0; blank_columns--){ - self->contigPtr[new_pos + blank_columns] = 0.0f; - } - for(curr_pos; curr_pos >= first_row_elem; curr_pos--){ - self->contigPtr[new_pos] = self->contigPtr[curr_pos]; - new_pos--; + + for( row = 0; row < 4; row++ ) { + for( col = 0; col < 4; col++ ) { + self->matrix[row][col] = mat[( row * 4 ) + col]; } } - self->rowSize = 4; + PyMem_Free( mat ); + self->colSize = 4; - return (PyObject*)self; + self->rowSize = 4; + + return EXPP_incr_ret( Py_None ); } -//---------------------------Matrix.translationPart() ------------ -PyObject *Matrix_TranslationPart(MatrixObject * self) + +PyObject *Matrix_TranslationPart( MatrixObject * self ) { - float vec[4]; + float *vec = NULL; + PyObject *retval; - if(self->colSize < 3 && self->rowSize < 4){ - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix.translationPart: inappropriate matrix size\n"); - } + if( self->colSize < 3 ) { + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "inappropriate matrix size\n" ); + } else if( self->colSize > 2 ) { //3 or 4 columns + if( self->rowSize < 4 ) //all 4 rows + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "inappropriate matrix size\n" ); - vec[0] = self->matrix[3][0]; - vec[1] = self->matrix[3][1]; - vec[2] = self->matrix[3][2]; + vec = PyMem_Malloc( 3 * sizeof( float ) ); + if( vec == NULL ) { + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating vec\n\n" ) ); + } + vec[0] = self->matrix[3][0]; + vec[1] = self->matrix[3][1]; + vec[2] = self->matrix[3][2]; + } - return newVectorObject(vec, 3, Py_NEW); + retval = ( PyObject * ) newVectorObject( vec, 3 ); + PyMem_Free( vec ); + return retval; } -//---------------------------Matrix.rotationPart() --------------- -PyObject *Matrix_RotationPart(MatrixObject * self) + +PyObject *Matrix_RotationPart( MatrixObject * self ) { - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + float *mat; - if(self->colSize < 3 && self->rowSize < 3){ - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix.rotationPart: inappropriate matrix size\n"); - } + if( self->colSize < 3 ) { + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "inappropriate matrix size\n" ); + } else if( self->colSize > 2 ) { //3 or 4 col + if( self->rowSize < 3 ) //3 or 4 row + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "inappropriate matrix size\n" ); - mat[0] = self->matrix[0][0]; - mat[1] = self->matrix[0][1]; - mat[2] = self->matrix[0][2]; - mat[3] = self->matrix[1][0]; - mat[4] = self->matrix[1][1]; - mat[5] = self->matrix[1][2]; - mat[6] = self->matrix[2][0]; - mat[7] = self->matrix[2][1]; - mat[8] = self->matrix[2][2]; + mat = PyMem_Malloc( 3 * 3 * sizeof( float ) ); + if( mat == NULL ) { + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating mat\n\n" ) ); + } + mat[0] = self->matrix[0][0]; + mat[1] = self->matrix[0][1]; + mat[2] = self->matrix[0][2]; + mat[3] = self->matrix[1][0]; + mat[4] = self->matrix[1][1]; + mat[5] = self->matrix[1][2]; + mat[6] = self->matrix[2][0]; + mat[7] = self->matrix[2][1]; + mat[8] = self->matrix[2][2]; + } - return newMatrixObject(mat, 3, 3, Py_NEW); + return ( PyObject * ) newMatrixObject( mat, 3, 3 ); } -//---------------------------Matrix.invert() --------------------- -PyObject *Matrix_Invert(MatrixObject * self) + +PyObject *Matrix_Invert( MatrixObject * self ) { - - int x, y, z = 0; - float det = 0.0f; - PyObject *f = NULL; - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + float det; + int x, y, z; + float *mat = NULL; + float t; - if(self->rowSize != self->colSize){ - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix.invert: only square matrices are supported\n"); - } + if( self->rowSize != self->colSize ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "only square matrices are supported\n" ); //calculate the determinant - f = Matrix_Determinant(self); - det = PyFloat_AS_DOUBLE(f); + if( self->rowSize == 2 ) { + det = Det2x2( self->matrix[0][0], self->matrix[0][1], + self->matrix[1][0], self->matrix[1][1] ); + } else if( self->rowSize == 3 ) { + det = Det3x3( self->matrix[0][0], self->matrix[0][1], + self->matrix[0][2], self->matrix[1][0], + self->matrix[1][1], self->matrix[1][2], + self->matrix[2][0], self->matrix[2][1], + self->matrix[2][2] ); + } else if( self->rowSize == 4 ) { + det = Det4x4( (float ( * )[4]) *self->matrix ); + } else { + return EXPP_ReturnPyObjError( PyExc_StandardError, + "error calculating determinant for inverse()\n" ); + } + + if( det != 0 ) { - if(det != 0) { //calculate the classical adjoint - if(self->rowSize == 2) { + if( self->rowSize == 2 ) { + mat = PyMem_Malloc( self->rowSize * self->colSize * + sizeof( float ) ); + if( mat == NULL ) { + return ( EXPP_ReturnPyObjError + ( PyExc_MemoryError, + "problem allocating mat\n\n" ) ); + } mat[0] = self->matrix[1][1]; mat[1] = -self->matrix[1][0]; mat[2] = -self->matrix[0][1]; mat[3] = self->matrix[0][0]; - } else if(self->rowSize == 3) { - Mat3Adj((float (*)[3]) mat,(float (*)[3]) *self->matrix); - } else if(self->rowSize == 4) { - Mat4Adj((float (*)[4]) mat, (float (*)[4]) *self->matrix); + } else if( self->rowSize == 3 ) { + mat = PyMem_Malloc( self->rowSize * self->colSize * + sizeof( float ) ); + if( mat == NULL ) { + return ( EXPP_ReturnPyObjError + ( PyExc_MemoryError, + "problem allocating mat\n\n" ) ); + } + Mat3Adj( ( float ( * )[3] ) mat,( float ( * )[3] ) *self->matrix ); + } else if( self->rowSize == 4 ) { + mat = PyMem_Malloc( self->rowSize * self->colSize * + sizeof( float ) ); + if( mat == NULL ) { + return ( EXPP_ReturnPyObjError + ( PyExc_MemoryError, + "problem allocating mat\n\n" ) ); + } + Mat4Adj( ( float ( * )[4] ) mat, ( float ( * )[4] ) *self->matrix ); } //divide by determinate - for(x = 0; x < (self->rowSize * self->colSize); x++) { + for( x = 0; x < ( self->rowSize * self->colSize ); x++ ) { mat[x] /= det; } + //set values - for(x = 0; x < self->rowSize; x++) { - for(y = 0; y < self->colSize; y++) { + z = 0; + for( x = 0; x < self->rowSize; x++ ) { + for( y = 0; y < self->colSize; y++ ) { self->matrix[x][y] = mat[z]; z++; } } + //transpose - Matrix_Transpose(self); + if( self->rowSize == 2 ) { + t = self->matrix[1][0]; + self->matrix[1][0] = self->matrix[0][1]; + self->matrix[0][1] = t; + +/* + Note: is the code below correct? + transposing mat and not copying into self->matrix? + s. swaney 11-oct-2004 +*/ + } else if( self->rowSize == 3 ) { + Mat3Transp( ( float ( * )[3] ) mat ); + } else if( self->rowSize == 4 ) { + Mat4Transp( ( float ( * )[4] ) mat ); + } } else { - printf("Matrix.invert: matrix does not have an inverse\n"); + printf( "matrix does not have an inverse - none attempted\n" ); } - return (PyObject*)self; + PyMem_Free( mat ); + return EXPP_incr_ret( Py_None ); } -//---------------------------Matrix.determinant() ---------------- -PyObject *Matrix_Determinant(MatrixObject * self) + + +PyObject *Matrix_Determinant( MatrixObject * self ) { - float det = 0.0f; - - if(self->rowSize != self->colSize){ - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix.determinant: only square matrices are supported\n"); - } - - if(self->rowSize == 2) { - det = Det2x2(self->matrix[0][0], self->matrix[0][1], - self->matrix[1][0], self->matrix[1][1]); - } else if(self->rowSize == 3) { - det = Det3x3(self->matrix[0][0], self->matrix[0][1], - self->matrix[0][2], self->matrix[1][0], - self->matrix[1][1], self->matrix[1][2], - self->matrix[2][0], self->matrix[2][1], - self->matrix[2][2]); + float det; + + if( self->rowSize != self->colSize ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "only square matrices are supported\n" ); + + if( self->rowSize == 2 ) { + det = Det2x2( self->matrix[0][0], self->matrix[0][1], + self->matrix[1][0], self->matrix[1][1] ); + } else if( self->rowSize == 3 ) { + det = Det3x3( self->matrix[0][0], self->matrix[0][1], + self->matrix[0][2], self->matrix[1][0], + self->matrix[1][1], self->matrix[1][2], + self->matrix[2][0], self->matrix[2][1], + self->matrix[2][2] ); + } else if( self->rowSize == 4 ) { + det = Det4x4( (float ( * )[4]) *self->matrix ); } else { - det = Det4x4((float (*)[4]) *self->matrix); + return EXPP_ReturnPyObjError( PyExc_StandardError, + "error in determinant()\n" ); } return PyFloat_FromDouble( (double) det ); } //---------------------------Matrix.transpose() ------------------ -PyObject *Matrix_Transpose(MatrixObject * self) + +PyObject *Matrix_Transpose( MatrixObject * self ) + { - float t = 0.0f; + float t; - if(self->rowSize != self->colSize){ - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix.transpose: only square matrices are supported\n"); - } + if( self->rowSize != self->colSize ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "only square matrices are supported\n" ); - if(self->rowSize == 2) { + if( self->rowSize == 2 ) { t = self->matrix[1][0]; self->matrix[1][0] = self->matrix[0][1]; self->matrix[0][1] = t; - } else if(self->rowSize == 3) { - Mat3Transp((float (*)[3])*self->matrix); - } else { - Mat4Transp((float (*)[4])*self->matrix); - } + } else if( self->rowSize == 3 ) { + Mat3Transp( (float ( * )[3])*self->matrix ); + } else if( self->rowSize == 4 ) { + Mat4Transp( (float ( * )[4])*self->matrix ); + } else + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "unable to transpose matrix\n" ) ); - return (PyObject*)self; + return EXPP_incr_ret( Py_None ); } -//---------------------------Matrix.zero() ----------------------- -PyObject *Matrix_Zero(MatrixObject * self) + +PyObject *Matrix_Zero( MatrixObject * self ) { int row, col; - for(row = 0; row < self->rowSize; row++) { - for(col = 0; col < self->colSize; col++) { + for( row = 0; row < self->rowSize; row++ ) { + for( col = 0; col < self->colSize; col++ ) { self->matrix[row][col] = 0.0f; } } - return (PyObject*)self; + return EXPP_incr_ret( Py_None ); } -//---------------------------Matrix.identity(() ------------------ -PyObject *Matrix_Identity(MatrixObject * self) + +PyObject *Matrix_Identity( MatrixObject * self ) { - if(self->rowSize != self->colSize){ - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix.identity: only square matrices are supported\n"); - } + if( self->rowSize != self->colSize ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "only square matrices supported\n" ) ); - if(self->rowSize == 2) { + if( self->rowSize == 2 ) { self->matrix[0][0] = 1.0f; self->matrix[0][1] = 0.0f; self->matrix[1][0] = 0.0f; self->matrix[1][1] = 1.0f; - } else if(self->rowSize == 3) { - Mat3One((float (*)[3]) *self->matrix); - } else { - Mat4One((float (*)[4]) *self->matrix); - } + } else if( self->rowSize == 3 ) { + Mat3One( ( float ( * )[3] ) *self->matrix ); + } else if( self->rowSize == 4 ) { + Mat4One( ( float ( * )[4] ) *self->matrix ); + } else + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "unable to create identity matrix\n" ) ); - return (PyObject*)self; + return EXPP_incr_ret( Py_None ); } -//----------------------------dealloc()(internal) ---------------- -//free the py_object -static void Matrix_dealloc(MatrixObject * self) + +static void Matrix_dealloc( MatrixObject * self ) { - Py_XDECREF(self->coerced_object); - PyMem_Free(self->matrix); - //only free py_data - if(self->data.py_data){ - PyMem_Free(self->data.py_data); - } - PyObject_DEL(self); + PyMem_Free( self->contigPtr ); + PyMem_Free( self->matrix ); + + PyObject_DEL( self ); } -//----------------------------getattr()(internal) ---------------- -//object.attribute access (get) -static PyObject *Matrix_getattr(MatrixObject * self, char *name) + +static PyObject *Matrix_getattr( MatrixObject * self, char *name ) { - if(STREQ(name, "rowSize")) { - return PyInt_FromLong((long) self->rowSize); - } else if(STREQ(name, "colSize")) { - return PyInt_FromLong((long) self->colSize); + if( strcmp( name, "rowSize" ) == 0 ) { + return PyInt_FromLong( ( long ) self->rowSize ); + } else if( strcmp( name, "colSize" ) == 0 ) { + return PyInt_FromLong( ( long ) self->colSize ); } - return Py_FindMethod(Matrix_methods, (PyObject *) self, name); + return Py_FindMethod( Matrix_methods, ( PyObject * ) self, name ); } -//----------------------------setattr()(internal) ---------------- -//object.attribute access (set) -static int Matrix_setattr(MatrixObject * self, char *name, PyObject * v) + +static int Matrix_setattr( MatrixObject * self, char *name, PyObject * v ) { /* This is not supported. */ - return (-1); + return ( -1 ); } -//----------------------------print object (internal)------------- -//print the object to screen -static PyObject *Matrix_repr(MatrixObject * self) + +static PyObject *Matrix_repr( MatrixObject * self ) { + PyObject *repr, *str; int x, y; - char buffer[48], str[1024]; - - BLI_strncpy(str,"",1024); - for(x = 0; x < self->rowSize; x++){ - sprintf(buffer, "[", x); - strcat(str,buffer); - for(y = 0; y < (self->colSize - 1); y++) { - sprintf(buffer, "%.6f, ", self->matrix[x][y]); - strcat(str,buffer); - } - if(x < (self->rowSize-1)){ - sprintf(buffer, "%.6f](matrix [row %d])\n", self->matrix[x][y], x); - strcat(str,buffer); - }else{ - sprintf(buffer, "%.6f](matrix [row %d])", self->matrix[x][y], x); - strcat(str,buffer); + char ftoa[24]; + + repr = PyString_FromString( "" ); + if( !repr ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "Attribute error in PyMatrix (repr)\n" ) ); + + for( x = 0; x < self->rowSize; x++ ) { + str = PyString_FromString( "[" ); + PyString_ConcatAndDel( &repr, str ); + + for( y = 0; y < ( self->colSize - 1 ); y++ ) { + sprintf( ftoa, "%.4f, ", self->matrix[x][y] ); + str = PyString_FromString( ftoa ); + PyString_ConcatAndDel( &repr, str ); } + sprintf( ftoa, "%.4f]\n", self->matrix[x][y] ); + str = PyString_FromString( ftoa ); + PyString_ConcatAndDel( &repr, str ); } - - return EXPP_incr_ret(PyString_FromString(str)); + return repr; } -//---------------------SEQUENCE PROTOCOLS------------------------ -//----------------------------len(object)------------------------ -//sequence length -static int Matrix_len(MatrixObject * self) -{ - return (self->colSize * self->rowSize); -} -//----------------------------object[]--------------------------- -//sequence accessor (get) -//the wrapped vector gives direct access to the matrix data -static PyObject *Matrix_item(MatrixObject * self, int i) +//no support for matrix[x][y] so have to return by sequence index +//will return a row from the matrix to support previous API +//compatability +static PyObject *Matrix_item( MatrixObject * self, int i ) { - if(i < 0 || i >= self->rowSize) - return EXPP_ReturnPyObjError(PyExc_IndexError, - "matrix[attribute]: array index out of range\n"); + float *vec = NULL; + PyObject *retval; + int x; + + if( i < 0 || i >= self->rowSize ) + return EXPP_ReturnPyObjError( PyExc_IndexError, + "matrix row index out of range\n" ); + + vec = PyMem_Malloc( self->colSize * sizeof( float ) ); + if( vec == NULL ) { + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating vec\n\n" ) ); + } + for( x = 0; x < self->colSize; x++ ) { + vec[x] = self->matrix[i][x]; + } - return newVectorObject(self->matrix[i], self->colSize, Py_WRAP); + retval =( PyObject * ) newVectorObject( vec, self->colSize ); + PyMem_Free( vec ); + return retval; } -//----------------------------object[]------------------------- -//sequence accessor (set) -static int Matrix_ass_item(MatrixObject * self, int i, PyObject * ob) + +static PyObject *Matrix_slice( MatrixObject * self, int begin, int end ) { - int y, x, size = 0; - float vec[4]; + PyObject *list; + int count, maxsize, x, y; - if(i > self->rowSize || i < 0){ - return EXPP_ReturnIntError(PyExc_TypeError, - "matrix[attribute] = x: bad row\n"); - } + maxsize = self->colSize * self->rowSize; + if( begin < 0 ) + begin = 0; + if( end > maxsize ) + end = maxsize; + if( begin > end ) + begin = end; - if(PySequence_Check(ob)){ - size = PySequence_Length(ob); - if(size != self->colSize){ - return EXPP_ReturnIntError(PyExc_TypeError, - "matrix[attribute] = x: bad sequence size\n"); - } - for (x = 0; x < size; x++) { - PyObject *m, *f; + list = PyList_New( end - begin ); - m = PySequence_GetItem(ob, x); - if (m == NULL) { // Failed to read sequence - return EXPP_ReturnIntError(PyExc_RuntimeError, - "matrix[attribute] = x: unable to read sequence\n"); - } - f = PyNumber_Float(m); - if(f == NULL) { // parsed item not a number - Py_DECREF(m); - return EXPP_ReturnIntError(PyExc_TypeError, - "matrix[attribute] = x: sequence argument not a number\n"); - } - vec[x] = PyFloat_AS_DOUBLE(f); - EXPP_decr2(m, f); - } - //parsed well - now set in matrix - for(y = 0; y < size; y++){ - self->matrix[i][y] = vec[y]; - } - return 0; - }else{ - return EXPP_ReturnIntError(PyExc_TypeError, - "matrix[attribute] = x: expects a sequence of column size\n"); + for( count = begin; count < end; count++ ) { + x = ( int ) floor( ( double ) ( count / self->colSize ) ); + y = count % self->colSize; + PyList_SetItem( list, count - begin, + PyFloat_FromDouble( self->matrix[x][y] ) ); } + + return list; } -//----------------------------object[z:y]------------------------ -//sequence slice (get) -static PyObject *Matrix_slice(MatrixObject * self, int begin, int end) -{ - PyObject *list = NULL; - int count; +static int Matrix_ass_item( MatrixObject * self, int i, PyObject * ob ) +{ + int maxsize, x, y; - CLAMP(begin, 0, self->rowSize); - CLAMP(end, 0, self->rowSize); - begin = MIN2(begin,end); + maxsize = self->colSize * self->rowSize; + if( i < 0 || i >= maxsize ) + return EXPP_ReturnIntError( PyExc_IndexError, + "array assignment index out of range\n" ); + if( !PyInt_Check( ob ) && !PyFloat_Check( ob ) ) + return EXPP_ReturnIntError( PyExc_IndexError, + "matrix member must be a number\n" ); - list = PyList_New(end - begin); - for(count = begin; count < end; count++) { - PyList_SetItem(list, count - begin, - newVectorObject(self->matrix[count], self->colSize, Py_WRAP)); - } + x = ( int ) floor( ( double ) ( i / self->colSize ) ); + y = i % self->colSize; + self->matrix[x][y] = ( float ) PyFloat_AsDouble( ob ); - return EXPP_incr_ret(list); + return 0; } -//----------------------------object[z:y]------------------------ -//sequence slice (set) -static int Matrix_ass_slice(MatrixObject * self, int begin, int end, - PyObject * seq) + +static int Matrix_ass_slice( MatrixObject * self, int begin, int end, + PyObject * seq ) { - int i, x, y, size, sub_size; - float mat[16]; - - CLAMP(begin, 0, self->rowSize); - CLAMP(end, 0, self->rowSize); - begin = MIN2(begin,end); - - if(PySequence_Check(seq)){ - size = PySequence_Length(seq); - if(size != (end - begin)){ - return EXPP_ReturnIntError(PyExc_TypeError, - "matrix[begin:end] = []: size mismatch in slice assignment\n"); - } - //parse sub items - for (i = 0; i < size; i++) { - //parse each sub sequence - PyObject *subseq; - subseq = PySequence_GetItem(seq, i); - if (subseq == NULL) { // Failed to read sequence - return EXPP_ReturnIntError(PyExc_RuntimeError, - "matrix[begin:end] = []: unable to read sequence\n"); - } - if(PySequence_Check(subseq)){ - //subsequence is also a sequence - sub_size = PySequence_Length(subseq); - if(sub_size != self->colSize){ - return EXPP_ReturnIntError(PyExc_TypeError, - "matrix[begin:end] = []: size mismatch in slice assignment\n"); - } - for (y = 0; y < sub_size; y++) { - PyObject *m, *f; - m = PySequence_GetItem(subseq, y); - if (m == NULL) { // Failed to read sequence - return EXPP_ReturnIntError(PyExc_RuntimeError, - "matrix[begin:end] = []: unable to read sequence\n"); - } - f = PyNumber_Float(m); - if(f == NULL) { // parsed item not a number - Py_DECREF(m); - return EXPP_ReturnIntError(PyExc_TypeError, - "matrix[begin:end] = []: sequence argument not a number\n"); - } - mat[(i * self->colSize) + y] = PyFloat_AS_DOUBLE(f); - EXPP_decr2(f, m); - } - }else{ - Py_DECREF(subseq); - return EXPP_ReturnIntError(PyExc_TypeError, - "matrix[begin:end] = []: illegal argument type for built-in operation\n"); - } - } - //parsed well - now set in matrix - for(x = 0; x < (size * sub_size); x++){ - self->matrix[begin + (int)floor(x / self->colSize)][x % self->colSize] = mat[x]; + int count, maxsize, x, y, z; + + maxsize = self->colSize * self->rowSize; + if( begin < 0 ) + begin = 0; + if( end > maxsize ) + end = maxsize; + if( begin > end ) + begin = end; + + if( !PySequence_Check( seq ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "illegal argument type for built-in operation\n" ); + if( PySequence_Length( seq ) != ( end - begin ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "size mismatch in slice assignment\n" ); + + z = 0; + for( count = begin; count < end; count++ ) { + PyObject *ob = PySequence_GetItem( seq, z ); + z++; + if( !PyInt_Check( ob ) && !PyFloat_Check( ob ) ) + return EXPP_ReturnIntError( PyExc_IndexError, + "list member must be a number\n" ); + + x = ( int ) floor( ( double ) ( count / self->colSize ) ); + y = count % self->colSize; + if( !PyArg_Parse( ob, "f", &self->matrix[x][y] ) ) { + Py_DECREF( ob ); + return -1; } - return 0; - }else{ - return EXPP_ReturnIntError(PyExc_TypeError, - "matrix[begin:end] = []: illegal argument type for built-in operation\n"); } + return 0; } -//------------------------NUMERIC PROTOCOLS---------------------- -//------------------------obj + obj------------------------------ -static PyObject *Matrix_add(PyObject * m1, PyObject * m2) + +static int Matrix_len( MatrixObject * self ) { - int x, y; - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - MatrixObject *mat1 = NULL, *mat2 = NULL; + return ( self->colSize * self->rowSize ); +} - EXPP_incr2(m1, m2); - mat1 = (MatrixObject*)m1; - mat2 = (MatrixObject*)m2; +static PyObject *Matrix_add( PyObject * m1, PyObject * m2 ) +{ + float *mat; + int matSize, rowSize, colSize, x, y; - if(mat1->coerced_object || mat2->coerced_object){ - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix addition: arguments not valid for this operation....\n"); - } - if(mat1->rowSize != mat2->rowSize || mat1->colSize != mat2->colSize){ - EXPP_decr2((PyObject*)mat1, (PyObject*)mat2); - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix addition: matrices must have the same dimensions for this operation\n"); - } + if( ( !Matrix_CheckPyObject( m1 ) ) + || ( !Matrix_CheckPyObject( m2 ) ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "unsupported type for this operation\n" ); + + if( ( ( MatrixObject * ) m1 )->flag > 0 + || ( ( MatrixObject * ) m2 )->flag > 0 ) + return EXPP_ReturnPyObjError( PyExc_ArithmeticError, + "cannot add scalar to a matrix\n" ); - for(x = 0; x < mat1->rowSize; x++) { - for(y = 0; y < mat1->colSize; y++) { - mat[((x * mat1->colSize) + y)] = mat1->matrix[x][y] + mat2->matrix[x][y]; + if( ( ( MatrixObject * ) m1 )->rowSize != + ( ( MatrixObject * ) m2 )->rowSize + || ( ( MatrixObject * ) m1 )->colSize != + ( ( MatrixObject * ) m2 )->colSize ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "matrices must be the same same for this operation\n" ); + + rowSize = ( ( ( MatrixObject * ) m1 )->rowSize ); + colSize = ( ( ( MatrixObject * ) m1 )->colSize ); + matSize = rowSize * colSize; + + mat = PyMem_Malloc( matSize * sizeof( float ) ); + if( mat == NULL ) { + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating mat\n\n" ) ); + } + for( x = 0; x < rowSize; x++ ) { + for( y = 0; y < colSize; y++ ) { + mat[( ( x * rowSize ) + y )] = + ( ( MatrixObject * ) m1 )->matrix[x][y] + + ( ( MatrixObject * ) m2 )->matrix[x][y]; } } - EXPP_decr2((PyObject*)mat1, (PyObject*)mat2); - return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW); + return newMatrixObject( mat, rowSize, colSize ); } -//------------------------obj - obj------------------------------ -//subtraction -static PyObject *Matrix_sub(PyObject * m1, PyObject * m2) + +static PyObject *Matrix_sub( PyObject * m1, PyObject * m2 ) { - int x, y; - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - MatrixObject *mat1 = NULL, *mat2 = NULL; + float *mat; + int matSize, rowSize, colSize, x, y; - EXPP_incr2(m1, m2); - mat1 = (MatrixObject*)m1; - mat2 = (MatrixObject*)m2; + if( ( !Matrix_CheckPyObject( m1 ) ) + || ( !Matrix_CheckPyObject( m2 ) ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "unsupported type for this operation\n" ); - if(mat1->coerced_object || mat2->coerced_object){ - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix addition: arguments not valid for this operation....\n"); - } - if(mat1->rowSize != mat2->rowSize || mat1->colSize != mat2->colSize){ - EXPP_decr2((PyObject*)mat1, (PyObject*)mat2); - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix addition: matrices must have the same dimensions for this operation\n"); - } + if( ( ( MatrixObject * ) m1 )->flag > 0 + || ( ( MatrixObject * ) m2 )->flag > 0 ) + return EXPP_ReturnPyObjError( PyExc_ArithmeticError, + "cannot subtract a scalar from a matrix\n" ); + + if( ( ( MatrixObject * ) m1 )->rowSize != + ( ( MatrixObject * ) m2 )->rowSize + || ( ( MatrixObject * ) m1 )->colSize != + ( ( MatrixObject * ) m2 )->colSize ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "matrices must be the same same for this operation\n" ); + + rowSize = ( ( ( MatrixObject * ) m1 )->rowSize ); + colSize = ( ( ( MatrixObject * ) m1 )->colSize ); + matSize = rowSize * colSize; - for(x = 0; x < mat1->rowSize; x++) { - for(y = 0; y < mat1->colSize; y++) { - mat[((x * mat1->colSize) + y)] = mat1->matrix[x][y] - mat2->matrix[x][y]; + mat = PyMem_Malloc( matSize * sizeof( float ) ); + if( mat == NULL ) { + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating mat\n\n" ) ); + } + for( x = 0; x < rowSize; x++ ) { + for( y = 0; y < colSize; y++ ) { + mat[( ( x * rowSize ) + y )] = + ( ( MatrixObject * ) m1 )->matrix[x][y] - + ( ( MatrixObject * ) m2 )->matrix[x][y]; } } - EXPP_decr2((PyObject*)mat1, (PyObject*)mat2); - return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW); + return newMatrixObject( mat, rowSize, colSize ); } -//------------------------obj * obj------------------------------ -//mulplication -static PyObject *Matrix_mul(PyObject * m1, PyObject * m2) + +static PyObject *Matrix_mul( PyObject * m1, PyObject * m2 ) { - int x, y, z; - float scalar; - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - double dot = 0.0f; - MatrixObject *mat1 = NULL, *mat2 = NULL; - PyObject *f = NULL, *retObj = NULL; - VectorObject *vec = NULL; - - EXPP_incr2(m1, m2); - mat1 = (MatrixObject*)m1; - mat2 = (MatrixObject*)m2; - - if(mat1->coerced_object){ - if (PyFloat_Check(mat1->coerced_object) || - PyInt_Check(mat1->coerced_object)){ // FLOAT/INT * MATRIX - f = PyNumber_Float(mat1->coerced_object); - if(f == NULL) { // parsed item not a number - EXPP_decr2((PyObject*)mat1, (PyObject*)mat2); - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Matrix multiplication: arguments not acceptable for this operation\n"); - } - scalar = PyFloat_AS_DOUBLE(f); - for(x = 0; x < mat2->rowSize; x++) { - for(y = 0; y < mat2->colSize; y++) { - mat[((x * mat2->colSize) + y)] = scalar * mat2->matrix[x][y]; - } - } - EXPP_decr2((PyObject*)mat1, (PyObject*)mat2); - return newMatrixObject(mat, mat2->rowSize, mat2->colSize, Py_NEW); + PyObject *retval; + int matSizeV, rowSizeV, colSizeV, rowSizeW, colSizeW, matSizeW, x, y,z; + MatrixObject *matV; + MatrixObject *matW; + float *mat = NULL; + float dot = 0; + + + if( ( !Matrix_CheckPyObject( m1 ) ) + || ( !Matrix_CheckPyObject( m2 ) ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "unsupported type for this operation\n" ); + + //get some vars + rowSizeV = ( ( ( MatrixObject * ) m1 )->rowSize ); + colSizeV = ( ( ( MatrixObject * ) m1 )->colSize ); + matSizeV = rowSizeV * colSizeV; + rowSizeW = ( ( ( MatrixObject * ) m2 )->rowSize ); + colSizeW = ( ( ( MatrixObject * ) m2 )->colSize ); + matSizeW = rowSizeW * colSizeW; + matV = ( ( MatrixObject * ) m1 ); + matW = ( ( MatrixObject * ) m2 ); + + //coerced int or float for scalar multiplication + if( matW->flag > 1 || matW->flag > 2 ) { + + if( rowSizeV != rowSizeW && colSizeV != colSizeW ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "Matrix dimension error during scalar multiplication\n" ); + + mat = PyMem_Malloc( matSizeV * sizeof( float ) ); + if( mat == NULL ) { + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating mat\n\n" ) ); } - }else{ - if(mat2->coerced_object){ - if(VectorObject_Check(mat2->coerced_object)){ //MATRIX * VECTOR - vec = (VectorObject*)EXPP_incr_ret(mat2->coerced_object); - retObj = column_vector_multiplication(mat1, vec); - EXPP_decr3((PyObject*)mat1, (PyObject*)mat2, (PyObject*)vec); - return retObj; - }else if (PyFloat_Check(mat2->coerced_object) || - PyInt_Check(mat2->coerced_object)){ // MATRIX * FLOAT/INT - f = PyNumber_Float(mat2->coerced_object); - if(f == NULL) { // parsed item not a number - EXPP_decr2((PyObject*)mat1, (PyObject*)mat2); - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Matrix multiplication: arguments not acceptable for this operation\n"); - } - scalar = PyFloat_AS_DOUBLE(f); - for(x = 0; x < mat1->rowSize; x++) { - for(y = 0; y < mat1->colSize; y++) { - mat[((x * mat1->colSize) + y)] = scalar * mat1->matrix[x][y]; - } - } - EXPP_decr2((PyObject*)mat1, (PyObject*)mat2); - return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW); - } - }else{ //MATRIX * MATRIX - if(mat1->colSize != mat2->rowSize){ - EXPP_decr2((PyObject*)mat1, (PyObject*)mat2); - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix multiplication: matrix A rowsize must equal matrix B colsize\n"); + for( x = 0; x < rowSizeV; x++ ) { + for( y = 0; y < colSizeV; y++ ) { + mat[( ( x * rowSizeV ) + y )] = + matV->matrix[x][y] * + matW->matrix[x][y]; } - for(x = 0; x < mat1->rowSize; x++) { - for(y = 0; y < mat2->colSize; y++) { - for(z = 0; z < mat1->colSize; z++) { - dot += (mat1->matrix[x][z] * mat2->matrix[z][y]); - } - mat[((x * mat1->rowSize) + y)] = dot; - dot = 0.0f; + } + retval = ( PyObject* ) newMatrixObject( mat, rowSizeV, colSizeV ); + PyMem_Free( mat ); + return retval; + } else if( matW->flag == 0 && matV->flag == 0 ) { //true matrix multiplication + if( colSizeV != rowSizeW ) { + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "Matrix multiplication undefined...\n" ); + } + + mat = PyMem_Malloc( ( rowSizeV * colSizeW ) * + sizeof( float ) ); + if( mat == NULL ) { + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating mat\n\n" ) ); + } + for( x = 0; x < rowSizeV; x++ ) { + for( y = 0; y < colSizeW; y++ ) { + for( z = 0; z < colSizeV; z++ ) { + dot += ( matV->matrix[x][z] * + matW->matrix[z][y] ); } + mat[( ( x * rowSizeV ) + y )] = dot; + dot = 0; } - return newMatrixObject(mat, mat1->rowSize, mat2->colSize, Py_NEW); } - } - - EXPP_decr2((PyObject*)mat1, (PyObject*)mat2); - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Matrix multiplication: arguments not acceptable for this operation\n"); + retval = ( PyObject* ) newMatrixObject( mat, rowSizeV, colSizeW ); + PyMem_Free( mat ); + return retval; + } else + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "Error in matrix_mul...\n" ); } -//------------------------coerce(obj, obj)----------------------- + //coercion of unknown types to type MatrixObject for numeric protocols -/*Coercion() is called whenever a math operation has 2 operands that - it doesn't understand how to evaluate. 2+Matrix for example. We want to - evaluate some of these operations like: (vector * 2), however, for math - to proceed, the unknown operand must be cast to a type that python math will - understand. (e.g. in the case above case, 2 must be cast to a vector and - then call vector.multiply(vector, scalar_cast_as_vector)*/ -static int Matrix_coerce(PyObject ** m1, PyObject ** m2) +static int Matrix_coerce( PyObject ** m1, PyObject ** m2 ) { - int x; - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - PyObject *coerced = NULL; - - if(!MatrixObject_Check(*m2)) { - if(VectorObject_Check(*m2) || PyFloat_Check(*m2) || PyInt_Check(*m2)) { - coerced = EXPP_incr_ret(*m2); - *m2 = newMatrixObject(NULL,3,3,Py_NEW); - ((MatrixObject*)*m2)->coerced_object = coerced; - }else{ - return EXPP_ReturnIntError(PyExc_TypeError, - "matrix.coerce(): unknown operand - can't coerce for numeric protocols\n"); + long *tempI; + double *tempF; + float *mat; + int x, matSize; + + matSize = + ( ( ( MatrixObject * ) * m1 )->rowSize ) * + ( ( ( MatrixObject * ) * m1 )->rowSize ); + if( Matrix_CheckPyObject( *m1 ) ) { + if( Matrix_CheckPyObject( *m2 ) ) { //matrix & matrix + Py_INCREF( *m1 ); + Py_INCREF( *m2 ); + return 0; + } else { + if( VectorObject_Check( *m2 ) ) { //matrix & vector? + printf( "use MatMultVec() for column vector multiplication\n" ); + Py_INCREF( *m1 ); + return 0; + } else if( PyNumber_Check( *m2 ) ) { //& scalar? + if( PyInt_Check( *m2 ) ) { //it's a int + tempI = PyMem_Malloc( 1 * + sizeof( long ) ); + if( tempI == NULL ) { + return ( EXPP_ReturnIntError + ( PyExc_MemoryError, + "problem allocating tempI\n\n" ) ); + } + *tempI = PyInt_AsLong( *m2 ); + mat = PyMem_Malloc( matSize * + sizeof( float ) ); + if( mat == NULL ) { + PyMem_Free( tempI ); + return ( EXPP_ReturnIntError + ( PyExc_MemoryError, + "problem allocating mat\n\n" ) ); + } + for( x = 0; x < matSize; x++ ) { + mat[x] = ( float ) *tempI; + } + PyMem_Free( tempI ); + *m2 = newMatrixObject( mat, + ( ( ( MatrixObject * ) * m1 )->rowSize ), ( ( ( MatrixObject * ) * m1 )->colSize ) ); + ( ( MatrixObject * ) * m2 )->flag = 1; //int coercion + PyMem_Free( mat ); + Py_INCREF( *m1 ); + return 0; + } else if( PyFloat_Check( *m2 ) ) { //it's a float + tempF = PyMem_Malloc( 1 * + sizeof + ( double ) ); + if( tempF == NULL ) { + return ( EXPP_ReturnIntError + ( PyExc_MemoryError, + "problem allocating tempF\n\n" ) ); + } + *tempF = PyFloat_AsDouble( *m2 ); + mat = PyMem_Malloc( matSize * + sizeof( float ) ); + if( mat == NULL ) { + PyMem_Free( tempF ); + return ( EXPP_ReturnIntError + ( PyExc_MemoryError, + "problem allocating mat\n\n" ) ); + } + for( x = 0; x < matSize; x++ ) { + mat[x] = ( float ) *tempF; + } + PyMem_Free( tempF ); + *m2 = newMatrixObject( mat, + ( ( ( MatrixObject * ) * m1 )->rowSize ), ( ( ( MatrixObject * ) * m1 )->colSize ) ); + ( ( MatrixObject * ) * m2 )->flag = 2; //float coercion + PyMem_Free( mat ); + Py_INCREF( *m1 ); + return 0; + } + } + //unknom2n type or numeric cast failure + printf( "attempting matrix operation m2ith unsupported type...\n" ); + Py_INCREF( *m1 ); + return 0; //operation m2ill type check } + } else { + //1st not Matrix + printf( "numeric protocol failure...\n" ); + return -1; //this should not occur - fail } - Py_INCREF(*m2); - Py_INCREF(*m1); - return 0; + return -1; } -//-----------------PROTCOL DECLARATIONS-------------------------- + +//****************************************************************** +// Matrix definition +//****************************************************************** static PySequenceMethods Matrix_SeqMethods = { - (inquiry) Matrix_len, /* sq_length */ - (binaryfunc) 0, /* sq_concat */ - (intargfunc) 0, /* sq_repeat */ - (intargfunc) Matrix_item, /* sq_item */ - (intintargfunc) Matrix_slice, /* sq_slice */ - (intobjargproc) Matrix_ass_item, /* sq_ass_item */ - (intintobjargproc) Matrix_ass_slice, /* sq_ass_slice */ + ( inquiry ) Matrix_len, /* sq_length */ + ( binaryfunc ) 0, /* sq_concat */ + ( intargfunc ) 0, /* sq_repeat */ + ( intargfunc ) Matrix_item, /* sq_item */ + ( intintargfunc ) Matrix_slice, /* sq_slice */ + ( intobjargproc ) Matrix_ass_item, /* sq_ass_item */ + ( intintobjargproc ) Matrix_ass_slice, /* sq_ass_slice */ }; + static PyNumberMethods Matrix_NumMethods = { - (binaryfunc) Matrix_add, /* __add__ */ - (binaryfunc) Matrix_sub, /* __sub__ */ - (binaryfunc) Matrix_mul, /* __mul__ */ - (binaryfunc) 0, /* __div__ */ - (binaryfunc) 0, /* __mod__ */ - (binaryfunc) 0, /* __divmod__ */ - (ternaryfunc) 0, /* __pow__ */ - (unaryfunc) 0, /* __neg__ */ - (unaryfunc) 0, /* __pos__ */ - (unaryfunc) 0, /* __abs__ */ - (inquiry) 0, /* __nonzero__ */ - (unaryfunc) 0, /* __invert__ */ - (binaryfunc) 0, /* __lshift__ */ - (binaryfunc) 0, /* __rshift__ */ - (binaryfunc) 0, /* __and__ */ - (binaryfunc) 0, /* __xor__ */ - (binaryfunc) 0, /* __or__ */ - (coercion) Matrix_coerce, /* __coerce__ */ - (unaryfunc) 0, /* __int__ */ - (unaryfunc) 0, /* __long__ */ - (unaryfunc) 0, /* __float__ */ - (unaryfunc) 0, /* __oct__ */ - (unaryfunc) 0, /* __hex__ */ + ( binaryfunc ) Matrix_add, /* __add__ */ + ( binaryfunc ) Matrix_sub, /* __sub__ */ + ( binaryfunc ) Matrix_mul, /* __mul__ */ + ( binaryfunc ) 0, /* __div__ */ + ( binaryfunc ) 0, /* __mod__ */ + ( binaryfunc ) 0, /* __divmod__ */ + ( ternaryfunc ) 0, /* __pow__ */ + ( unaryfunc ) 0, /* __neg__ */ + ( unaryfunc ) 0, /* __pos__ */ + ( unaryfunc ) 0, /* __abs__ */ + ( inquiry ) 0, /* __nonzero__ */ + ( unaryfunc ) 0, /* __invert__ */ + ( binaryfunc ) 0, /* __lshift__ */ + ( binaryfunc ) 0, /* __rshift__ */ + ( binaryfunc ) 0, /* __and__ */ + ( binaryfunc ) 0, /* __xor__ */ + ( binaryfunc ) 0, /* __or__ */ + ( coercion ) Matrix_coerce, /* __coerce__ */ + ( unaryfunc ) 0, /* __int__ */ + ( unaryfunc ) 0, /* __long__ */ + ( unaryfunc ) 0, /* __float__ */ + ( unaryfunc ) 0, /* __oct__ */ + ( unaryfunc ) 0, /* __hex__ */ }; -//------------------PY_OBECT DEFINITION-------------------------- + PyTypeObject matrix_Type = { - PyObject_HEAD_INIT(NULL) /* required python macro */ - 0, /*ob_size */ - "Matrix", /*tp_name */ - sizeof(MatrixObject), /*tp_basicsize */ - 0, /*tp_itemsize */ - (destructor) Matrix_dealloc, /*tp_dealloc */ - (printfunc) 0, /*tp_print */ - (getattrfunc) Matrix_getattr, /*tp_getattr */ - (setattrfunc) Matrix_setattr, /*tp_setattr */ - 0, /*tp_compare */ - (reprfunc) Matrix_repr, /*tp_repr */ - &Matrix_NumMethods, /*tp_as_number */ - &Matrix_SeqMethods, /*tp_as_sequence */ + PyObject_HEAD_INIT( NULL ) /* required python macro */ + 0, /*ob_size */ + "Matrix", /*tp_name */ + sizeof( MatrixObject ), /*tp_basicsize */ + 0, /*tp_itemsize */ + ( destructor ) Matrix_dealloc, /*tp_dealloc */ + ( printfunc ) 0, /*tp_print */ + ( getattrfunc ) Matrix_getattr, /*tp_getattr */ + ( setattrfunc ) Matrix_setattr, /*tp_setattr */ + 0, /*tp_compare */ + ( reprfunc ) Matrix_repr, /*tp_repr */ + &Matrix_NumMethods, /*tp_as_number */ + &Matrix_SeqMethods, /*tp_as_sequence */ }; -//------------------------newMatrixObject (internal)------------- -//creates a new matrix object -//self->matrix self->contiguous_ptr (reference to data.xxx) -// [0]------------->[0] -// [1] -// [2] -// [1]------------->[3] -// [4] -// [5] -// .... -//self->matrix[1][1] = self->contiguous_ptr[4] = self->data.xxx_data[4] -/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER - (i.e. it was allocated elsewhere by MEM_mallocN()) - pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON - (i.e. it must be created here with PyMEM_malloc())*/ -PyObject *newMatrixObject(float *mat, int rowSize, int colSize, int type) + +//****************************************************************** +//Function: newMatrixObject +//****************************************************************** +PyObject *newMatrixObject( float *mat, int rowSize, int colSize ) { MatrixObject *self; - int x, row, col; + int row, col, x; - //matrix objects can be any 2-4row x 2-4col matrix - if(rowSize < 2 || rowSize > 4 || colSize < 2 || colSize > 4){ - return EXPP_ReturnPyObjError(PyExc_RuntimeError, - "matrix(): row and column sizes must be between 2 and 4\n"); + if( rowSize < 2 || rowSize > 4 || colSize < 2 || colSize > 4 ) + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "row and column sizes must be between 2 and 4\n" ) ); + + self = PyObject_NEW( MatrixObject, &matrix_Type ); + + //generate contigous memory space + self->contigPtr = PyMem_Malloc( rowSize * colSize * sizeof( float ) ); + if( self->contigPtr == NULL ) { + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating array space\n\n" ) ); + } + //create pointer array + self->matrix = PyMem_Malloc( rowSize * sizeof( float * ) ); + if( self->matrix == NULL ) { + PyMem_Free( self->contigPtr ); + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating pointer space\n\n" ) ); + } + //pointer array points to contigous memory + for( x = 0; x < rowSize; x++ ) { + self->matrix[x] = self->contigPtr + ( x * colSize ); } - matrix_Type.ob_type = &PyType_Type; - self = PyObject_NEW(MatrixObject, &matrix_Type); - self->data.blend_data = NULL; - self->data.py_data = NULL; - self->rowSize = rowSize; - self->colSize = colSize; - self->coerced_object = NULL; - - if(type == Py_WRAP){ - self->data.blend_data = mat; - self->contigPtr = self->data.blend_data; - //create pointer array - self->matrix = PyMem_Malloc(rowSize * sizeof(float *)); - if(self->matrix == NULL) { //allocation failure - return EXPP_ReturnPyObjError( PyExc_MemoryError, - "matrix(): problem allocating pointer space\n"); - } - //pointer array points to contigous memory - for(x = 0; x < rowSize; x++) { - self->matrix[x] = self->contigPtr + (x * colSize); - } - }else if (type == Py_NEW){ - self->data.py_data = PyMem_Malloc(rowSize * colSize * sizeof(float)); - if(self->data.py_data == NULL) { //allocation failure - return EXPP_ReturnPyObjError( PyExc_MemoryError, - "matrix(): problem allocating pointer space\n"); - } - self->contigPtr = self->data.py_data; - //create pointer array - self->matrix = PyMem_Malloc(rowSize * sizeof(float *)); - if(self->matrix == NULL) { //allocation failure - PyMem_Free(self->data.py_data); - return EXPP_ReturnPyObjError( PyExc_MemoryError, - "matrix(): problem allocating pointer space\n"); - } - //pointer array points to contigous memory - for(x = 0; x < rowSize; x++) { - self->matrix[x] = self->contigPtr + (x * colSize); + if( mat ) { //if a float array passed + for( row = 0; row < rowSize; row++ ) { + for( col = 0; col < colSize; col++ ) { + self->matrix[row][col] = + mat[( row * colSize ) + col]; + } } - //parse - if(mat) { //if a float array passed - for(row = 0; row < rowSize; row++) { - for(col = 0; col < colSize; col++) { - self->matrix[row][col] = mat[(row * colSize) + col]; - } + } else { //or if NULL passed + for( row = 0; row < rowSize; row++ ) { + for( col = 0; col < colSize; col++ ) { + self->matrix[row][col] = 0.0f; } - } else { //or if no arguments are passed return identity matrix - Matrix_Identity(self); } - }else{ //bad type - return NULL; } - return (PyObject *) EXPP_incr_ret((PyObject *)self); + + //set size vars of matrix + self->rowSize = rowSize; + self->colSize = colSize; + + //set coercion flag + self->flag = 0; + + return ( ( PyObject * ) self ); } diff --git a/source/blender/python/api2_2x/matrix.h b/source/blender/python/api2_2x/matrix.h index 9c114867786..b40ec978159 100644 --- a/source/blender/python/api2_2x/matrix.h +++ b/source/blender/python/api2_2x/matrix.h @@ -33,31 +33,37 @@ #ifndef EXPP_matrix_h #define EXPP_matrix_h -#define MatrixObject_Check(v) ((v)->ob_type == &matrix_Type) +#include "Python.h" +#include "BLI_arithb.h" +#include "vector.h" +#include "gen_utils.h" +#include "Types.h" +#include "quat.h" +#include "euler.h" +#define Matrix_CheckPyObject(v) ((v)->ob_type == &matrix_Type) + +/*****************************/ +/* Matrix Python Object */ +/*****************************/ typedef float **ptRow; + typedef struct _Matrix { - PyObject_VAR_HEAD - struct{ - float *py_data; //python managed - float *blend_data; //blender managed - }data; - ptRow matrix; //ptr to the contigPtr (accessor) - float *contigPtr; //1D array of data (alias) + PyObject_VAR_HEAD /* standard python macro */ + ptRow matrix; + float *contigPtr; int rowSize; int colSize; - PyObject *coerced_object; + int flag; + //0 - no coercion + //1 - coerced from int + //2 - coerced from float } MatrixObject; -/*coerced_object is a pointer to the object that it was -coerced from when a dummy vector needs to be created from -the coerce() function for numeric protocol operations*/ - -/*struct data contains a pointer to the actual data that the -object uses. It can use either PyMem allocated data (which will -be stored in py_data) or be a wrapper for data allocated through -blender (stored in blend_data). This is an either/or struct not both*/ -//prototypes +/*****************************************************************************/ +/* Python API function prototypes. */ +/*****************************************************************************/ +PyObject *newMatrixObject( float *mat, int rowSize, int colSize ); PyObject *Matrix_Zero( MatrixObject * self ); PyObject *Matrix_Identity( MatrixObject * self ); PyObject *Matrix_Transpose( MatrixObject * self ); @@ -68,6 +74,5 @@ PyObject *Matrix_RotationPart( MatrixObject * self ); PyObject *Matrix_Resize4x4( MatrixObject * self ); PyObject *Matrix_toEuler( MatrixObject * self ); PyObject *Matrix_toQuat( MatrixObject * self ); -PyObject *newMatrixObject(float *mat, int rowSize, int colSize, int type); #endif /* EXPP_matrix_H */ diff --git a/source/blender/python/api2_2x/quat.c b/source/blender/python/api2_2x/quat.c index 3d6961c78eb..35ef90aca2d 100644 --- a/source/blender/python/api2_2x/quat.c +++ b/source/blender/python/api2_2x/quat.c @@ -29,571 +29,545 @@ * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ -#include -#include -#include "Mathutils.h" -#include "gen_utils.h" - -//-------------------------DOC STRINGS --------------------------- -char Quaternion_Identity_doc[] = "() - set the quaternion to it's identity (1, vector)"; -char Quaternion_Negate_doc[] = "() - set all values in the quaternion to their negative"; +#include "quat.h" + +//doc strings +char Quaternion_Identity_doc[] = + "() - set the quaternion to it's identity (1, vector)"; +char Quaternion_Negate_doc[] = + "() - set all values in the quaternion to their negative"; char Quaternion_Conjugate_doc[] = "() - set the quaternion to it's conjugate"; char Quaternion_Inverse_doc[] = "() - set the quaternion to it's inverse"; -char Quaternion_Normalize_doc[] = "() - normalize the vector portion of the quaternion"; -char Quaternion_ToEuler_doc[] = "() - return a euler rotation representing the quaternion"; -char Quaternion_ToMatrix_doc[] = "() - return a rotation matrix representing the quaternion"; -//-----------------------METHOD DEFINITIONS ---------------------- +char Quaternion_Normalize_doc[] = + "() - normalize the vector portion of the quaternion"; +char Quaternion_ToEuler_doc[] = + "() - return a euler rotation representing the quaternion"; +char Quaternion_ToMatrix_doc[] = + "() - return a rotation matrix representing the quaternion"; + +//methods table struct PyMethodDef Quaternion_methods[] = { - {"identity", (PyCFunction) Quaternion_Identity, METH_NOARGS, Quaternion_Identity_doc}, - {"negate", (PyCFunction) Quaternion_Negate, METH_NOARGS, Quaternion_Negate_doc}, - {"conjugate", (PyCFunction) Quaternion_Conjugate, METH_NOARGS, Quaternion_Conjugate_doc}, - {"inverse", (PyCFunction) Quaternion_Inverse, METH_NOARGS, Quaternion_Inverse_doc}, - {"normalize", (PyCFunction) Quaternion_Normalize, METH_NOARGS, Quaternion_Normalize_doc}, - {"toEuler", (PyCFunction) Quaternion_ToEuler, METH_NOARGS, Quaternion_ToEuler_doc}, - {"toMatrix", (PyCFunction) Quaternion_ToMatrix, METH_NOARGS, Quaternion_ToMatrix_doc}, + {"identity", ( PyCFunction ) Quaternion_Identity, METH_NOARGS, + Quaternion_Identity_doc}, + {"negate", ( PyCFunction ) Quaternion_Negate, METH_NOARGS, + Quaternion_Negate_doc}, + {"conjugate", ( PyCFunction ) Quaternion_Conjugate, METH_NOARGS, + Quaternion_Conjugate_doc}, + {"inverse", ( PyCFunction ) Quaternion_Inverse, METH_NOARGS, + Quaternion_Inverse_doc}, + {"normalize", ( PyCFunction ) Quaternion_Normalize, METH_NOARGS, + Quaternion_Normalize_doc}, + {"toEuler", ( PyCFunction ) Quaternion_ToEuler, METH_NOARGS, + Quaternion_ToEuler_doc}, + {"toMatrix", ( PyCFunction ) Quaternion_ToMatrix, METH_NOARGS, + Quaternion_ToMatrix_doc}, {NULL, NULL, 0, NULL} }; -//-----------------------------METHODS------------------------------ -//----------------------------Quaternion.toEuler()------------------ -//return the quat as a euler -PyObject *Quaternion_ToEuler(QuaternionObject * self) + +/* ****** prototypes ********** */ +PyObject *Quaternion_add( PyObject * q1, PyObject * q2 ); +PyObject *Quaternion_sub( PyObject * q1, PyObject * q2 ); +PyObject *Quaternion_mul( PyObject * q1, PyObject * q2 ); +int Quaternion_coerce( PyObject ** q1, PyObject ** q2 ); + + +/*****************************/ +// Quaternion Python Object +/*****************************/ + +PyObject *Quaternion_ToEuler( QuaternionObject * self ) { - float eul[3]; + float *eul; int x; - QuatToEul(self->quat, eul); - for(x = 0; x < 3; x++) { - eul[x] *= (180 / (float)Py_PI); + eul = PyMem_Malloc( 3 * sizeof( float ) ); + QuatToEul( self->quat, eul ); + + for( x = 0; x < 3; x++ ) { + eul[x] *= ( float ) ( 180 / Py_PI ); } - if(self->data.blend_data) - return newEulerObject(eul, Py_WRAP); - else - return newEulerObject(eul, Py_NEW); + return ( PyObject * ) newEulerObject( eul ); } -//----------------------------Quaternion.toMatrix()------------------ -//return the quat as a matrix -PyObject *Quaternion_ToMatrix(QuaternionObject * self) + +PyObject *Quaternion_ToMatrix( QuaternionObject * self ) { - float mat[9] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; - QuatToMat3(self->quat, (float (*)[3]) mat); + float *mat; + + mat = PyMem_Malloc( 3 * 3 * sizeof( float ) ); + QuatToMat3( self->quat, ( float ( * )[3] ) mat ); - if(self->data.blend_data) - return newMatrixObject(mat, 3, 3, Py_WRAP); - else - return newMatrixObject(mat, 3, 3, Py_NEW); + return ( PyObject * ) newMatrixObject( mat, 3, 3 ); } -//----------------------------Quaternion.normalize()---------------- + //normalize the axis of rotation of [theta,vector] -PyObject *Quaternion_Normalize(QuaternionObject * self) +PyObject *Quaternion_Normalize( QuaternionObject * self ) { - NormalQuat(self->quat); - return (PyObject*)self; + NormalQuat( self->quat ); + return EXPP_incr_ret( Py_None ); } -//----------------------------Quaternion.inverse()------------------ -//invert the quat -PyObject *Quaternion_Inverse(QuaternionObject * self) + +PyObject *Quaternion_Inverse( QuaternionObject * self ) { - double mag = 0.0f; + float mag = 0.0f; int x; - for(x = 1; x < 4; x++) { + for( x = 1; x < 4; x++ ) { self->quat[x] = -self->quat[x]; } - for(x = 0; x < 4; x++) { - mag += (self->quat[x] * self->quat[x]); + for( x = 0; x < 4; x++ ) { + mag += ( self->quat[x] * self->quat[x] ); } - mag = sqrt(mag); - for(x = 0; x < 4; x++) { - self->quat[x] /= (mag * mag); + mag = ( float ) sqrt( mag ); + for( x = 0; x < 4; x++ ) { + self->quat[x] /= ( mag * mag ); } - return (PyObject*)self; + return EXPP_incr_ret( Py_None ); } -//----------------------------Quaternion.identity()----------------- -//generate the identity quaternion -PyObject *Quaternion_Identity(QuaternionObject * self) + +PyObject *Quaternion_Identity( QuaternionObject * self ) { self->quat[0] = 1.0; self->quat[1] = 0.0; self->quat[2] = 0.0; self->quat[3] = 0.0; - return (PyObject*)self; + return EXPP_incr_ret( Py_None ); } -//----------------------------Quaternion.negate()------------------- -//negate the quat -PyObject *Quaternion_Negate(QuaternionObject * self) + +PyObject *Quaternion_Negate( QuaternionObject * self ) { int x; - for(x = 0; x < 4; x++) { + + for( x = 0; x < 4; x++ ) { self->quat[x] = -self->quat[x]; } - return (PyObject*)self; + return EXPP_incr_ret( Py_None ); } -//----------------------------Quaternion.conjugate()---------------- -//negate the vector part -PyObject *Quaternion_Conjugate(QuaternionObject * self) + +PyObject *Quaternion_Conjugate( QuaternionObject * self ) { int x; - for(x = 1; x < 4; x++) { + + for( x = 1; x < 4; x++ ) { self->quat[x] = -self->quat[x]; } - return (PyObject*)self; + return EXPP_incr_ret( Py_None ); } -//----------------------------dealloc()(internal) ------------------ -//free the py_object -static void Quaternion_dealloc(QuaternionObject * self) + +static void Quaternion_dealloc( QuaternionObject * self ) { - //only free py_data - if(self->data.py_data){ - PyMem_Free(self->data.py_data); - } - PyObject_DEL(self); + PyMem_Free( self->quat ); + PyObject_DEL( self ); } -//----------------------------getattr()(internal) ------------------ -//object.attribute access (get) -static PyObject *Quaternion_getattr(QuaternionObject * self, char *name) + +static PyObject *Quaternion_getattr( QuaternionObject * self, char *name ) { - int x; double mag = 0.0f; - float vec[3]; - - if(STREQ(name,"w")){ - return PyFloat_FromDouble(self->quat[0]); - }else if(STREQ(name, "x")){ - return PyFloat_FromDouble(self->quat[1]); - }else if(STREQ(name, "y")){ - return PyFloat_FromDouble(self->quat[2]); - }else if(STREQ(name, "z")){ - return PyFloat_FromDouble(self->quat[3]); + float *vec = NULL; + int x; + PyObject *retval; + + if( ELEM4( name[0], 'w', 'x', 'y', 'z' ) && name[1] == 0 ) { + return PyFloat_FromDouble( self->quat[name[0] - 'w'] ); } - if(STREQ(name, "magnitude")) { - for(x = 0; x < 4; x++) { + if( strcmp( name, "magnitude" ) == 0 ) { + for( x = 0; x < 4; x++ ) { mag += self->quat[x] * self->quat[x]; } - mag = sqrt(mag); - return PyFloat_FromDouble(mag); + mag = ( float ) sqrt( mag ); + return PyFloat_FromDouble( mag ); } - if(STREQ(name, "angle")) { + if( strcmp( name, "angle" ) == 0 ) { + mag = self->quat[0]; - mag = 2 * (acos(mag)); - mag *= (180 / Py_PI); - return PyFloat_FromDouble(mag); + mag = 2 * ( acos( mag ) ); + mag *= ( 180 / Py_PI ); + return PyFloat_FromDouble( mag ); } - if(STREQ(name, "axis")) { - mag = self->quat[0] * (Py_PI / 180); - mag = 2 * (acos(mag)); - mag = sin(mag / 2); - for(x = 0; x < 3; x++) { - vec[x] = (self->quat[x + 1] / mag); + if( strcmp( name, "axis" ) == 0 ) { + + mag = ( double ) ( self->quat[0] * ( Py_PI / 180 ) ); + mag = 2 * ( acos( mag ) ); + mag = sin( mag / 2 ); + vec = PyMem_Malloc( 3 * sizeof( float ) ); + for( x = 0; x < 3; x++ ) { + vec[x] = ( self->quat[x + 1] / ( ( float ) ( mag ) ) ); } - Normalise(vec); - return (PyObject *) newVectorObject(vec, 3, Py_NEW); + Normalise( vec ); + retval = ( PyObject * ) newVectorObject( vec, 3 ); + PyMem_Free( vec ); + return retval; } - - return Py_FindMethod(Quaternion_methods, (PyObject *) self, name); + return Py_FindMethod( Quaternion_methods, ( PyObject * ) self, name ); } -//----------------------------setattr()(internal) ------------------ -//object.attribute access (set) -static int Quaternion_setattr(QuaternionObject * self, char *name, PyObject * q) -{ - PyObject *f = NULL; - - f = PyNumber_Float(q); - if(f == NULL) { // parsed item not a number - return EXPP_ReturnIntError(PyExc_TypeError, - "quaternion.attribute = x: argument not a number\n"); - } - if(STREQ(name,"w")){ - self->quat[0] = PyFloat_AS_DOUBLE(f); - }else if(STREQ(name, "x")){ - self->quat[1] = PyFloat_AS_DOUBLE(f); - }else if(STREQ(name, "y")){ - self->quat[2] = PyFloat_AS_DOUBLE(f); - }else if(STREQ(name, "z")){ - self->quat[3] = PyFloat_AS_DOUBLE(f); - }else{ - Py_DECREF(f); - return EXPP_ReturnIntError(PyExc_AttributeError, - "quaternion.attribute = x: unknown attribute\n"); +static int Quaternion_setattr( QuaternionObject * self, char *name, + PyObject * v ) +{ + float val; + + if( !PyFloat_Check( v ) && !PyInt_Check( v ) ) { + return EXPP_ReturnIntError( PyExc_TypeError, + "int or float expected\n" ); + } else { + if( !PyArg_Parse( v, "f", &val ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "unable to parse float argument\n" ); } + if( ELEM4( name[0], 'w', 'x', 'y', 'z' ) && name[1] == 0 ) { + self->quat[name[0] - 'w'] = val; + } else + return -1; - Py_DECREF(f); return 0; } -//----------------------------print object (internal)-------------- -//print the object to screen -static PyObject *Quaternion_repr(QuaternionObject * self) -{ - int i; - char buffer[48], str[1024]; - - BLI_strncpy(str,"[",1024); - for(i = 0; i < 4; i++){ - if(i < (3)){ - sprintf(buffer, "%.6f, ", self->quat[i]); - strcat(str,buffer); - }else{ - sprintf(buffer, "%.6f", self->quat[i]); - strcat(str,buffer); - } - } - strcat(str, "](quaternion)"); - return EXPP_incr_ret(PyString_FromString(str)); -} -//---------------------SEQUENCE PROTOCOLS------------------------ -//----------------------------len(object)------------------------ -//sequence length -static int Quaternion_len(QuaternionObject * self) +/* Quaternions Sequence methods */ +static PyObject *Quaternion_item( QuaternionObject * self, int i ) { - return 4; + if( i < 0 || i >= 4 ) + return EXPP_ReturnPyObjError( PyExc_IndexError, + "array index out of range\n" ); + + return Py_BuildValue( "f", self->quat[i] ); } -//----------------------------object[]--------------------------- -//sequence accessor (get) -static PyObject *Quaternion_item(QuaternionObject * self, int i) + +static PyObject *Quaternion_slice( QuaternionObject * self, int begin, + int end ) { - if(i < 0 || i >= 4) - return EXPP_ReturnPyObjError(PyExc_IndexError, - "quaternion[attribute]: array index out of range\n"); + PyObject *list; + int count; - return Py_BuildValue("f", self->quat[i]); + if( begin < 0 ) + begin = 0; + if( end > 4 ) + end = 4; + if( begin > end ) + begin = end; -} -//----------------------------object[]------------------------- -//sequence accessor (set) -static int Quaternion_ass_item(QuaternionObject * self, int i, PyObject * ob) -{ - PyObject *f = NULL; + list = PyList_New( end - begin ); - f = PyNumber_Float(ob); - if(f == NULL) { // parsed item not a number - return EXPP_ReturnIntError(PyExc_TypeError, - "quaternion[attribute] = x: argument not a number\n"); + for( count = begin; count < end; count++ ) { + PyList_SetItem( list, count - begin, + PyFloat_FromDouble( self->quat[count] ) ); } + return list; +} - if(i < 0 || i >= 4){ - Py_DECREF(f); - return EXPP_ReturnIntError(PyExc_IndexError, - "quaternion[attribute] = x: array assignment index out of range\n"); +static int Quaternion_ass_item( QuaternionObject * self, int i, PyObject * ob ) +{ + if( i < 0 || i >= 4 ) + return EXPP_ReturnIntError( PyExc_IndexError, + "array assignment index out of range\n" ); + if( !PyNumber_Check( ob ) ) + return EXPP_ReturnIntError( PyExc_IndexError, + "Quaternion member must be a number\n" ); + + if( !PyFloat_Check( ob ) && !PyInt_Check( ob ) ) { + return EXPP_ReturnIntError( PyExc_TypeError, + "int or float expected\n" ); + } else { + self->quat[i] = ( float ) PyFloat_AsDouble( ob ); } - self->quat[i] = PyFloat_AS_DOUBLE(f); - Py_DECREF(f); return 0; } -//----------------------------object[z:y]------------------------ -//sequence slice (get) -static PyObject *Quaternion_slice(QuaternionObject * self, int begin, int end) -{ - PyObject *list = NULL; - int count; - CLAMP(begin, 0, 4); - CLAMP(end, 0, 4); - begin = MIN2(begin,end); - - list = PyList_New(end - begin); - for(count = begin; count < end; count++) { - PyList_SetItem(list, count - begin, - PyFloat_FromDouble(self->quat[count])); +static int Quaternion_ass_slice( QuaternionObject * self, int begin, int end, + PyObject * seq ) +{ + int count, z; + + if( begin < 0 ) + begin = 0; + if( end > 4 ) + end = 4; + if( begin > end ) + begin = end; + + if( !PySequence_Check( seq ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "illegal argument type for built-in operation\n" ); + if( PySequence_Length( seq ) != ( end - begin ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "size mismatch in slice assignment\n" ); + + z = 0; + for( count = begin; count < end; count++ ) { + PyObject *ob = PySequence_GetItem( seq, z ); + z++; + + if( !PyFloat_Check( ob ) && !PyInt_Check( ob ) ) { + Py_DECREF( ob ); + return -1; + } else { + if( !PyArg_Parse( ob, "f", &self->quat[count] ) ) { + Py_DECREF( ob ); + return -1; + } + } } - - return list; + return 0; } -//----------------------------object[z:y]------------------------ -//sequence slice (set) -static int Quaternion_ass_slice(QuaternionObject * self, int begin, int end, - PyObject * seq) -{ - int i, y, size = 0; - float quat[4]; - CLAMP(begin, 0, 4); - CLAMP(end, 0, 4); - begin = MIN2(begin,end); - - size = PySequence_Length(seq); - if(size != (end - begin)){ - return EXPP_ReturnIntError(PyExc_TypeError, - "quaternion[begin:end] = []: size mismatch in slice assignment\n"); +static PyObject *Quaternion_repr( QuaternionObject * self ) +{ + int i, maxindex = 4 - 1; + char ftoa[24]; + PyObject *str1, *str2; + + str1 = PyString_FromString( "[" ); + + for( i = 0; i < maxindex; i++ ) { + sprintf( ftoa, "%.4f, ", self->quat[i] ); + str2 = PyString_FromString( ftoa ); + if( !str1 || !str2 ) + goto error; + PyString_ConcatAndDel( &str1, str2 ); } - for (i = 0; i < size; i++) { - PyObject *q, *f; + sprintf( ftoa, "%.4f]", self->quat[maxindex] ); + str2 = PyString_FromString( ftoa ); + if( !str1 || !str2 ) + goto error; + PyString_ConcatAndDel( &str1, str2 ); - q = PySequence_GetItem(seq, i); - if (q == NULL) { // Failed to read sequence - return EXPP_ReturnIntError(PyExc_RuntimeError, - "quaternion[begin:end] = []: unable to read sequence\n"); - } - f = PyNumber_Float(q); - if(f == NULL) { // parsed item not a number - Py_DECREF(q); - return EXPP_ReturnIntError(PyExc_TypeError, - "quaternion[begin:end] = []: sequence argument not a number\n"); - } - quat[i] = PyFloat_AS_DOUBLE(f); - EXPP_decr2(f,q); - } - //parsed well - now set in vector - for(y = 0; y < size; y++){ - self->quat[begin + y] = quat[y]; - } - return 0; + if( str1 ) + return str1; + + error: + Py_XDECREF( str1 ); + Py_XDECREF( str2 ); + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create PyString!\n" ); } -//------------------------NUMERIC PROTOCOLS---------------------- -//------------------------obj + obj------------------------------ -//addition -static PyObject *Quaternion_add(PyObject * q1, PyObject * q2) + + +PyObject *Quaternion_add( PyObject * q1, PyObject * q2 ) { + float *quat = NULL; + PyObject *retval; int x; - float quat[4]; - QuaternionObject *quat1 = NULL, *quat2 = NULL; - - EXPP_incr2(q1, q2); - quat1 = (QuaternionObject*)q1; - quat2 = (QuaternionObject*)q2; - if(quat1->coerced_object || quat2->coerced_object){ - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Quaternion addition: arguments not valid for this operation....\n"); - } - for(x = 0; x < 4; x++) { - quat[x] = quat1->quat[x] + quat2->quat[x]; + if( ( !QuaternionObject_Check( q1 ) ) + || ( !QuaternionObject_Check( q2 ) ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "unsupported type for this operation\n" ); + if( ( ( QuaternionObject * ) q1 )->flag > 0 + || ( ( QuaternionObject * ) q2 )->flag > 0 ) + return EXPP_ReturnPyObjError( PyExc_ArithmeticError, + "cannot add a scalar and a quat\n" ); + + quat = PyMem_Malloc( 4 * sizeof( float ) ); + for( x = 0; x < 4; x++ ) { + quat[x] = + ( ( ( QuaternionObject * ) q1 )->quat[x] ) + + ( ( ( QuaternionObject * ) q2 )->quat[x] ); } - EXPP_decr2((PyObject*)quat1, (PyObject*)quat2); - return (PyObject *) newQuaternionObject(quat, Py_NEW); + retval = ( PyObject * ) newQuaternionObject( quat ); + PyMem_Free( quat ); + return retval; } -//------------------------obj - obj------------------------------ -//subtraction -static PyObject *Quaternion_sub(PyObject * q1, PyObject * q2) + +PyObject *Quaternion_sub( PyObject * q1, PyObject * q2 ) { + float *quat = NULL; + PyObject *retval; int x; - float quat[4]; - QuaternionObject *quat1 = NULL, *quat2 = NULL; - - EXPP_incr2(q1, q2); - quat1 = (QuaternionObject*)q1; - quat2 = (QuaternionObject*)q2; - if(quat1->coerced_object || quat2->coerced_object){ - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Quaternion addition: arguments not valid for this operation....\n"); - } - for(x = 0; x < 4; x++) { - quat[x] = quat1->quat[x] - quat2->quat[x]; + if( ( !QuaternionObject_Check( q1 ) ) + || ( !QuaternionObject_Check( q2 ) ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "unsupported type for this operation\n" ); + if( ( ( QuaternionObject * ) q1 )->flag > 0 + || ( ( QuaternionObject * ) q2 )->flag > 0 ) + return EXPP_ReturnPyObjError( PyExc_ArithmeticError, + "cannot subtract a scalar and a quat\n" ); + + quat = PyMem_Malloc( 4 * sizeof( float ) ); + for( x = 0; x < 4; x++ ) { + quat[x] = + ( ( ( QuaternionObject * ) q1 )->quat[x] ) - + ( ( ( QuaternionObject * ) q2 )->quat[x] ); } + retval = ( PyObject * ) newQuaternionObject( quat ); - EXPP_decr2((PyObject*)quat1, (PyObject*)quat2); - return (PyObject *) newQuaternionObject(quat, Py_NEW); + PyMem_Free( quat ); + return retval; } -//------------------------obj * obj------------------------------ -//mulplication -static PyObject *Quaternion_mul(PyObject * q1, PyObject * q2) + +PyObject *Quaternion_mul( PyObject * q1, PyObject * q2 ) { + float *quat = NULL; + PyObject *retval; int x; - float quat[4], scalar, newVec[3]; - double dot = 0.0f; - QuaternionObject *quat1 = NULL, *quat2 = NULL; - PyObject *f = NULL; - VectorObject *vec = NULL; - - EXPP_incr2(q1, q2); - quat1 = (QuaternionObject*)q1; - quat2 = (QuaternionObject*)q2; - - if(quat1->coerced_object){ - if (PyFloat_Check(quat1->coerced_object) || - PyInt_Check(quat1->coerced_object)){ // FLOAT/INT * QUAT - f = PyNumber_Float(quat1->coerced_object); - if(f == NULL) { // parsed item not a number - EXPP_decr2((PyObject*)quat1, (PyObject*)quat2); - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Quaternion multiplication: arguments not acceptable for this operation\n"); - } - scalar = PyFloat_AS_DOUBLE(f); - for(x = 0; x < 4; x++) { - quat[x] = quat2->quat[x] * scalar; - } - EXPP_decr2((PyObject*)quat1, (PyObject*)quat2); - return (PyObject *) newQuaternionObject(quat, Py_NEW); - } - }else{ - if(quat2->coerced_object){ - if (PyFloat_Check(quat2->coerced_object) || - PyInt_Check(quat2->coerced_object)){ // QUAT * FLOAT/INT - f = PyNumber_Float(quat2->coerced_object); - if(f == NULL) { // parsed item not a number - EXPP_decr2((PyObject*)quat1, (PyObject*)quat2); - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Quaternion multiplication: arguments not acceptable for this operation\n"); - } - scalar = PyFloat_AS_DOUBLE(f); - for(x = 0; x < 4; x++) { - quat[x] = quat1->quat[x] * scalar; - } - EXPP_decr2((PyObject*)quat1, (PyObject*)quat2); - return (PyObject *) newQuaternionObject(quat, Py_NEW); - }else if(VectorObject_Check(quat2->coerced_object)){ //QUAT * VEC - vec = (VectorObject*)EXPP_incr_ret(quat2->coerced_object); - if(vec->size != 3){ - EXPP_decr2((PyObject*)quat1, (PyObject*)quat2); - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Quaternion multiplication: only 3D vector rotations currently supported\n"); - } - newVec[0] = quat1->quat[0]*quat1->quat[0]*vec->vec[0] + - 2*quat1->quat[2]*quat1->quat[0]*vec->vec[2] - - 2*quat1->quat[3]*quat1->quat[0]*vec->vec[1] + - quat1->quat[1]*quat1->quat[1]*vec->vec[0] + - 2*quat1->quat[2]*quat1->quat[1]*vec->vec[1] + - 2*quat1->quat[3]*quat1->quat[1]*vec->vec[2] - - quat1->quat[3]*quat1->quat[3]*vec->vec[0] - - quat1->quat[2]*quat1->quat[2]*vec->vec[0]; - newVec[1] = 2*quat1->quat[1]*quat1->quat[2]*vec->vec[0] + - quat1->quat[2]*quat1->quat[2]*vec->vec[1] + - 2*quat1->quat[3]*quat1->quat[2]*vec->vec[2] + - 2*quat1->quat[0]*quat1->quat[3]*vec->vec[0] - - quat1->quat[3]*quat1->quat[3]*vec->vec[1] + - quat1->quat[0]*quat1->quat[0]*vec->vec[1] - - 2*quat1->quat[1]*quat1->quat[0]*vec->vec[2] - - quat1->quat[1]*quat1->quat[1]*vec->vec[1]; - newVec[2] = 2*quat1->quat[1]*quat1->quat[3]*vec->vec[0] + - 2*quat1->quat[2]*quat1->quat[3]*vec->vec[1] + - quat1->quat[3]*quat1->quat[3]*vec->vec[2] - - 2*quat1->quat[0]*quat1->quat[2]*vec->vec[0] - - quat1->quat[2]*quat1->quat[2]*vec->vec[2] + - 2*quat1->quat[0]*quat1->quat[1]*vec->vec[1] - - quat1->quat[1]*quat1->quat[1]*vec->vec[2] + - quat1->quat[0]*quat1->quat[0]*vec->vec[2]; - EXPP_decr3((PyObject*)quat1, (PyObject*)quat2, (PyObject*)vec); - return newVectorObject(newVec,3,Py_NEW); - } - }else{ //QUAT * QUAT (dot product) - for(x = 0; x < 4; x++) { - dot += quat1->quat[x] * quat1->quat[x]; - } - EXPP_decr2((PyObject*)quat1, (PyObject*)quat2); - return PyFloat_FromDouble(dot); - } + + if( ( !QuaternionObject_Check( q1 ) ) + || ( !QuaternionObject_Check( q2 ) ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "unsupported type for this operation\n" ); + if( ( ( QuaternionObject * ) q1 )->flag == 0 + && ( ( QuaternionObject * ) q2 )->flag == 0 ) + return EXPP_ReturnPyObjError( PyExc_ArithmeticError, + "please use the dot or cross product to multiply quaternions\n" ); + + quat = PyMem_Malloc( 4 * sizeof( float ) ); + //scalar mult by quat + for( x = 0; x < 4; x++ ) { + quat[x] = + ( ( QuaternionObject * ) q1 )->quat[x] * + ( ( QuaternionObject * ) q2 )->quat[x]; } + retval = ( PyObject * ) newQuaternionObject( quat ); - EXPP_decr2((PyObject*)quat1, (PyObject*)quat2); - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Quaternion multiplication: arguments not acceptable for this operation\n"); + PyMem_Free( quat ); + return retval; } -//------------------------coerce(obj, obj)----------------------- + //coercion of unknown types to type QuaternionObject for numeric protocols -/*Coercion() is called whenever a math operation has 2 operands that - it doesn't understand how to evaluate. 2+Matrix for example. We want to - evaluate some of these operations like: (vector * 2), however, for math - to proceed, the unknown operand must be cast to a type that python math will - understand. (e.g. in the case above case, 2 must be cast to a vector and - then call vector.multiply(vector, scalar_cast_as_vector)*/ -static int Quaternion_coerce(PyObject ** q1, PyObject ** q2) +int Quaternion_coerce( PyObject ** q1, PyObject ** q2 ) { + long *tempI = NULL; + double *tempF = NULL; + float *quat = NULL; int x; - float quat[4]; - PyObject *coerced = NULL; - - if(!QuaternionObject_Check(*q2)) { - if(VectorObject_Check(*q2) || PyFloat_Check(*q2) || PyInt_Check(*q2)) { - coerced = EXPP_incr_ret(*q2); - *q2 = newQuaternionObject(NULL,Py_NEW); - ((QuaternionObject*)*q2)->coerced_object = coerced; - }else{ - return EXPP_ReturnIntError(PyExc_TypeError, - "quaternion.coerce(): unknown operand - can't coerce for numeric protocols\n"); + + if( QuaternionObject_Check( *q1 ) ) { + if( QuaternionObject_Check( *q2 ) ) { //two Quaternions + Py_INCREF( *q1 ); + Py_INCREF( *q2 ); + return 0; + } else { + if( PyNumber_Check( *q2 ) ) { + if( PyInt_Check( *q2 ) ) { //cast scalar to Quaternion + tempI = PyMem_Malloc( 1 * + sizeof( long ) ); + *tempI = PyInt_AsLong( *q2 ); + quat = PyMem_Malloc( 4 * + sizeof( float ) ); + for( x = 0; x < 4; x++ ) { + quat[x] = ( float ) *tempI; + } + PyMem_Free( tempI ); + *q2 = newQuaternionObject( quat ); + PyMem_Free( quat ); + ( ( QuaternionObject * ) * q2 )->flag = 1; //int coercion + Py_INCREF( *q1 ); /* fixme: is this needed? */ + return 0; + } else if( PyFloat_Check( *q2 ) ) { //cast scalar to Quaternion + tempF = PyMem_Malloc( 1 * + sizeof + ( double ) ); + *tempF = PyFloat_AsDouble( *q2 ); + quat = PyMem_Malloc( 4 * + sizeof( float ) ); + for( x = 0; x < 4; x++ ) { + quat[x] = ( float ) *tempF; + } + PyMem_Free( tempF ); + *q2 = newQuaternionObject( quat ); + PyMem_Free( quat ); + ( ( QuaternionObject * ) * q2 )->flag = 2; //float coercion + Py_INCREF( *q1 ); /* fixme: is this needed? */ + return 0; + } + } + //unknown type or numeric cast failure + printf( "attempting quaternion operation with unsupported type...\n" ); + Py_INCREF( *q1 ); /* fixme: is this needed? */ + return 0; //operation will type check } + } else { + printf( "numeric protocol failure...\n" ); + return -1; //this should not occur - fail } - EXPP_incr2(*q1, *q2); - return 0; + return -1; } -//-----------------PROTCOL DECLARATIONS-------------------------- + static PySequenceMethods Quaternion_SeqMethods = { - (inquiry) Quaternion_len, /* sq_length */ - (binaryfunc) 0, /* sq_concat */ - (intargfunc) 0, /* sq_repeat */ - (intargfunc) Quaternion_item, /* sq_item */ - (intintargfunc) Quaternion_slice, /* sq_slice */ - (intobjargproc) Quaternion_ass_item, /* sq_ass_item */ - (intintobjargproc) Quaternion_ass_slice, /* sq_ass_slice */ + ( inquiry ) 0, /* sq_length */ + ( binaryfunc ) 0, /* sq_concat */ + ( intargfunc ) 0, /* sq_repeat */ + ( intargfunc ) Quaternion_item, /* sq_item */ + ( intintargfunc ) Quaternion_slice, /* sq_slice */ + ( intobjargproc ) Quaternion_ass_item, /* sq_ass_item */ + ( intintobjargproc ) Quaternion_ass_slice, /* sq_ass_slice */ }; + static PyNumberMethods Quaternion_NumMethods = { - (binaryfunc) Quaternion_add, /* __add__ */ - (binaryfunc) Quaternion_sub, /* __sub__ */ - (binaryfunc) Quaternion_mul, /* __mul__ */ - (binaryfunc) 0, /* __div__ */ - (binaryfunc) 0, /* __mod__ */ - (binaryfunc) 0, /* __divmod__ */ - (ternaryfunc) 0, /* __pow__ */ - (unaryfunc) 0, /* __neg__ */ - (unaryfunc) 0, /* __pos__ */ - (unaryfunc) 0, /* __abs__ */ - (inquiry) 0, /* __nonzero__ */ - (unaryfunc) 0, /* __invert__ */ - (binaryfunc) 0, /* __lshift__ */ - (binaryfunc) 0, /* __rshift__ */ - (binaryfunc) 0, /* __and__ */ - (binaryfunc) 0, /* __xor__ */ - (binaryfunc) 0, /* __or__ */ - (coercion) Quaternion_coerce, /* __coerce__ */ - (unaryfunc) 0, /* __int__ */ - (unaryfunc) 0, /* __long__ */ - (unaryfunc) 0, /* __float__ */ - (unaryfunc) 0, /* __oct__ */ - (unaryfunc) 0, /* __hex__ */ + ( binaryfunc ) Quaternion_add, /* __add__ */ + ( binaryfunc ) Quaternion_sub, /* __sub__ */ + ( binaryfunc ) Quaternion_mul, /* __mul__ */ + ( binaryfunc ) 0, /* __div__ */ + ( binaryfunc ) 0, /* __mod__ */ + ( binaryfunc ) 0, /* __divmod__ */ + ( ternaryfunc ) 0, /* __pow__ */ + ( unaryfunc ) 0, /* __neg__ */ + ( unaryfunc ) 0, /* __pos__ */ + ( unaryfunc ) 0, /* __abs__ */ + ( inquiry ) 0, /* __nonzero__ */ + ( unaryfunc ) 0, /* __invert__ */ + ( binaryfunc ) 0, /* __lshift__ */ + ( binaryfunc ) 0, /* __rshift__ */ + ( binaryfunc ) 0, /* __and__ */ + ( binaryfunc ) 0, /* __xor__ */ + ( binaryfunc ) 0, /* __or__ */ + ( coercion ) Quaternion_coerce, /* __coerce__ */ + ( unaryfunc ) 0, /* __int__ */ + ( unaryfunc ) 0, /* __long__ */ + ( unaryfunc ) 0, /* __float__ */ + ( unaryfunc ) 0, /* __oct__ */ + ( unaryfunc ) 0, /* __hex__ */ }; -//------------------PY_OBECT DEFINITION-------------------------- + PyTypeObject quaternion_Type = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size */ - "quaternion", /*tp_name */ - sizeof(QuaternionObject), /*tp_basicsize */ - 0, /*tp_itemsize */ - (destructor) Quaternion_dealloc, /*tp_dealloc */ - (printfunc) 0, /*tp_print */ - (getattrfunc) Quaternion_getattr, /*tp_getattr */ - (setattrfunc) Quaternion_setattr, /*tp_setattr */ - 0, /*tp_compare */ - (reprfunc) Quaternion_repr, /*tp_repr */ - &Quaternion_NumMethods, /*tp_as_number */ - &Quaternion_SeqMethods, /*tp_as_sequence */ + PyObject_HEAD_INIT( NULL ) + 0, /*ob_size */ + "quaternion", /*tp_name */ + sizeof( QuaternionObject ), /*tp_basicsize */ + 0, /*tp_itemsize */ + ( destructor ) Quaternion_dealloc, /*tp_dealloc */ + ( printfunc ) 0, /*tp_print */ + ( getattrfunc ) Quaternion_getattr, /*tp_getattr */ + ( setattrfunc ) Quaternion_setattr, /*tp_setattr */ + 0, /*tp_compare */ + ( reprfunc ) Quaternion_repr, /*tp_repr */ + &Quaternion_NumMethods, /*tp_as_number */ + &Quaternion_SeqMethods, /*tp_as_sequence */ }; -//------------------------newQuaternionObject (internal)------------- -//creates a new quaternion object -/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER - (i.e. it was allocated elsewhere by MEM_mallocN()) - pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON - (i.e. it must be created here with PyMEM_malloc())*/ -PyObject *newQuaternionObject(float *quat, int type) + +/** Creates a new quaternion object. + * + * Memory for a new quaternion is allocated. The quaternion copies the given + * list of parameters or initializes to the identity, if a NULL + * pointer is given as parameter. The memory will be freed in the dealloc + * routine. + * + * @param quat Pointer to a list of floats for the quanternion parameters w, x, y, z. + * @return Quaternion Python object. + * @see Quaternion_Identity + */ +PyObject *newQuaternionObject( float *quat ) { QuaternionObject *self; int x; quaternion_Type.ob_type = &PyType_Type; - self = PyObject_NEW(QuaternionObject, &quaternion_Type); - self->data.blend_data = NULL; - self->data.py_data = NULL; - self->coerced_object = NULL; - - if(type == Py_WRAP){ - self->data.blend_data = quat; - self->quat = self->data.blend_data; - }else if (type == Py_NEW){ - self->data.py_data = PyMem_Malloc(4 * sizeof(float)); - self->quat = self->data.py_data; - if(!quat) { //new empty - Quaternion_Identity(self); - }else{ - for(x = 0; x < 4; x++){ - self->quat[x] = quat[x]; - } + + self = PyObject_NEW( QuaternionObject, &quaternion_Type ); + + self->quat = PyMem_Malloc( 4 * sizeof( float ) ); + + if( !quat ) { + Quaternion_Identity(self); + } else { + for( x = 0; x < 4; x++ ) { + self->quat[x] = quat[x]; } - }else{ //bad type - return NULL; } - return (PyObject *) EXPP_incr_ret((PyObject *)self); + self->flag = 0; + + return ( PyObject * ) self; } diff --git a/source/blender/python/api2_2x/quat.h b/source/blender/python/api2_2x/quat.h index 8be94ef3f42..a04e0ee7c37 100644 --- a/source/blender/python/api2_2x/quat.h +++ b/source/blender/python/api2_2x/quat.h @@ -34,27 +34,34 @@ #ifndef EXPP_quat_h #define EXPP_quat_h +#include "Python.h" +#include "gen_utils.h" +#include "Types.h" +#include +#include "euler.h" +#include "matrix.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +/*****************************/ +// Quaternion Python Object +/*****************************/ + #define QuaternionObject_Check(v) ((v)->ob_type == &quaternion_Type) typedef struct { - PyObject_VAR_HEAD - struct{ - float *py_data; //python managed - float *blend_data; //blender managed - }data; - float *quat; //1D array of data (alias) - PyObject *coerced_object; + PyObject_VAR_HEAD float *quat; + int flag; + //0 - no coercion + //1 - coerced from int + //2 - coerced from float } QuaternionObject; -/*coerced_object is a pointer to the object that it was -coerced from when a dummy vector needs to be created from -the coerce() function for numeric protocol operations*/ -/*struct data contains a pointer to the actual data that the -object uses. It can use either PyMem allocated data (which will -be stored in py_data) or be a wrapper for data allocated through -blender (stored in blend_data). This is an either/or struct not both*/ //prototypes +PyObject *newQuaternionObject( float *quat ); PyObject *Quaternion_Identity( QuaternionObject * self ); PyObject *Quaternion_Negate( QuaternionObject * self ); PyObject *Quaternion_Conjugate( QuaternionObject * self ); @@ -62,6 +69,5 @@ PyObject *Quaternion_Inverse( QuaternionObject * self ); PyObject *Quaternion_Normalize( QuaternionObject * self ); PyObject *Quaternion_ToEuler( QuaternionObject * self ); PyObject *Quaternion_ToMatrix( QuaternionObject * self ); -PyObject *newQuaternionObject( float *quat, int type ); #endif /* EXPP_quat_h */ diff --git a/source/blender/python/api2_2x/vector.c b/source/blender/python/api2_2x/vector.c index f9dfe47b693..9e65de3c46d 100644 --- a/source/blender/python/api2_2x/vector.c +++ b/source/blender/python/api2_2x/vector.c @@ -28,652 +28,707 @@ * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ -#include -#include "Mathutils.h" -#include "gen_utils.h" +#include "vector.h" -//-------------------------DOC STRINGS --------------------------- +//doc strings char Vector_Zero_doc[] = "() - set all values in the vector to 0"; char Vector_Normalize_doc[] = "() - normalize the vector"; char Vector_Negate_doc[] = "() - changes vector to it's additive inverse"; char Vector_Resize2D_doc[] = "() - resize a vector to [x,y]"; char Vector_Resize3D_doc[] = "() - resize a vector to [x,y,z]"; char Vector_Resize4D_doc[] = "() - resize a vector to [x,y,z,w]"; -//-----------------------METHOD DEFINITIONS ---------------------- + +//method table struct PyMethodDef Vector_methods[] = { - {"zero", (PyCFunction) Vector_Zero, METH_NOARGS, Vector_Zero_doc}, - {"normalize", (PyCFunction) Vector_Normalize, METH_NOARGS, Vector_Normalize_doc}, - {"negate", (PyCFunction) Vector_Negate, METH_NOARGS, Vector_Negate_doc}, - {"resize2D", (PyCFunction) Vector_Resize2D, METH_NOARGS, Vector_Resize2D_doc}, - {"resize3D", (PyCFunction) Vector_Resize3D, METH_NOARGS, Vector_Resize2D_doc}, - {"resize4D", (PyCFunction) Vector_Resize4D, METH_NOARGS, Vector_Resize2D_doc}, + {"zero", ( PyCFunction ) Vector_Zero, METH_NOARGS, + Vector_Zero_doc}, + {"normalize", ( PyCFunction ) Vector_Normalize, METH_NOARGS, + Vector_Normalize_doc}, + {"negate", ( PyCFunction ) Vector_Negate, METH_NOARGS, + Vector_Negate_doc}, + {"resize2D", ( PyCFunction ) Vector_Resize2D, METH_NOARGS, + Vector_Resize2D_doc}, + {"resize3D", ( PyCFunction ) Vector_Resize3D, METH_NOARGS, + Vector_Resize2D_doc}, + {"resize4D", ( PyCFunction ) Vector_Resize4D, METH_NOARGS, + Vector_Resize2D_doc}, {NULL, NULL, 0, NULL} }; -//-----------------------------METHODS---------------------------- -//----------------------------Vector.zero() ---------------------- -//set the vector data to 0,0,0 -PyObject *Vector_Zero(VectorObject * self) + +/******prototypes*************/ +PyObject *Vector_add( PyObject * v1, PyObject * v2 ); +PyObject *Vector_sub( PyObject * v1, PyObject * v2 ); +PyObject *Vector_mul( PyObject * v1, PyObject * v2 ); +PyObject *Vector_div( PyObject * v1, PyObject * v2 ); +int Vector_coerce( PyObject ** v1, PyObject ** v2 ); + + +/*****************************/ +// Vector Python Object +/*****************************/ + +//object methods +PyObject *Vector_Zero( VectorObject * self ) { int x; - for(x = 0; x < self->size; x++) { + for( x = 0; x < self->size; x++ ) { self->vec[x] = 0.0f; } - return (PyObject*)self; + + return EXPP_incr_ret( Py_None ); } -//----------------------------Vector.normalize() ----------------- -//normalize the vector data to a unit vector -PyObject *Vector_Normalize(VectorObject * self) + +PyObject *Vector_Normalize( VectorObject * self ) { + float norm; int x; - float norm = 0.0f; - for(x = 0; x < self->size; x++) { + norm = 0.0f; + for( x = 0; x < self->size; x++ ) { norm += self->vec[x] * self->vec[x]; } - norm = (float) sqrt(norm); - for(x = 0; x < self->size; x++) { + norm = ( float ) sqrt( norm ); + for( x = 0; x < self->size; x++ ) { self->vec[x] /= norm; } - return (PyObject*)self; + + return EXPP_incr_ret( Py_None ); } -//----------------------------Vector.negate() -------------------- -//set the vector to it's negative -x, -y, -z -PyObject *Vector_Negate(VectorObject * self) + +PyObject *Vector_Negate( VectorObject * self ) { int x; - for(x = 0; x < self->size; x++) { - self->vec[x] = -(self->vec[x]); - } - return (PyObject*)self; -} -//----------------------------Vector.resize2D() ------------------ -//resize the vector to x,y -PyObject *Vector_Resize2D(VectorObject * self) -{ - if(self->data.blend_data){ - return EXPP_ReturnPyObjError(PyExc_TypeError, - "vector.resize2d(): cannot resize wrapped data - only python vectors\n"); + for( x = 0; x < self->size; x++ ) { + self->vec[x] = -( self->vec[x] ); } - self->data.py_data = - PyMem_Realloc(self->data.py_data, (sizeof(float) * 2)); - if(self->data.py_data == NULL) { - return EXPP_ReturnPyObjError(PyExc_MemoryError, - "vector.resize2d(): problem allocating pointer space\n\n"); - } - self->vec = self->data.py_data; //force - self->size = 2; - return (PyObject*)self; + return EXPP_incr_ret( Py_None ); } -//----------------------------Vector.resize3D() ------------------ -//resize the vector to x,y,z -PyObject *Vector_Resize3D(VectorObject * self) + +PyObject *Vector_Resize2D( VectorObject * self ) { - if(self->data.blend_data){ - return EXPP_ReturnPyObjError(PyExc_TypeError, - "vector.resize3d(): cannot resize wrapped data - only python vectors\n"); - } + float x, y; - self->data.py_data = - PyMem_Realloc(self->data.py_data, (sizeof(float) * 3)); - if(self->data.py_data == NULL) { - return EXPP_ReturnPyObjError(PyExc_MemoryError, - "vector.resize3d(): problem allocating pointer space\n\n"); + if( self->size == 4 || self->size == 3 ) { + x = self->vec[0]; + y = self->vec[1]; + PyMem_Free( self->vec ); + self->vec = PyMem_Malloc( 2 * sizeof( float ) ); + self->vec[0] = x; + self->vec[1] = y; + self->size = 2; } - self->vec = self->data.py_data; //force - if(self->size == 2){ - self->data.py_data[2] = 0.0f; - } - self->size = 3; - return (PyObject*)self; + + return EXPP_incr_ret( Py_None ); } -//----------------------------Vector.resize4D() ------------------ -//resize the vector to x,y,z,w -PyObject *Vector_Resize4D(VectorObject * self) -{ - if(self->data.blend_data){ - return EXPP_ReturnPyObjError(PyExc_TypeError, - "vector.resize4d(): cannot resize wrapped data - only python vectors\n"); - } - self->data.py_data = - PyMem_Realloc(self->data.py_data, (sizeof(float) * 4)); - if(self->data.py_data == NULL) { - return EXPP_ReturnPyObjError(PyExc_MemoryError, - "vector.resize4d(): problem allocating pointer space\n\n"); - } - self->vec = self->data.py_data; //force - if(self->size == 2){ - self->data.py_data[2] = 0.0f; - self->data.py_data[3] = 0.0f; - }else if(self->size == 3){ - self->data.py_data[3] = 0.0f; - } - self->size = 4; - return (PyObject*)self; +PyObject *Vector_Resize3D( VectorObject * self ) +{ + float x, y, z; + + if( self->size == 2 ) { + x = self->vec[0]; + y = self->vec[1]; + PyMem_Free( self->vec ); + self->vec = PyMem_Malloc( 3 * sizeof( float ) ); + self->vec[0] = x; + self->vec[1] = y; + self->vec[2] = 0.0f; + self->size = 3; + } else if( self->size == 4 ) { + x = self->vec[0]; + y = self->vec[1]; + z = self->vec[2]; + PyMem_Free( self->vec ); + self->vec = PyMem_Malloc( 3 * sizeof( float ) ); + self->vec[0] = x; + self->vec[1] = y; + self->vec[2] = z; + self->size = 3; + } + + return EXPP_incr_ret( Py_None ); } -//----------------------------dealloc()(internal) ---------------- -//free the py_object -static void Vector_dealloc(VectorObject * self) + +PyObject *Vector_Resize4D( VectorObject * self ) { - //only free py_data - if(self->data.py_data){ - PyMem_Free(self->data.py_data); - } - PyObject_DEL(self); + float x, y, z; + + if( self->size == 2 ) { + x = self->vec[0]; + y = self->vec[1]; + PyMem_Free( self->vec ); + self->vec = PyMem_Malloc( 4 * sizeof( float ) ); + self->vec[0] = x; + self->vec[1] = y; + self->vec[2] = 0.0f; + self->vec[3] = 1.0f; + self->size = 4; + } else if( self->size == 3 ) { + x = self->vec[0]; + y = self->vec[1]; + z = self->vec[2]; + PyMem_Free( self->vec ); + self->vec = PyMem_Malloc( 4 * sizeof( float ) ); + self->vec[0] = x; + self->vec[1] = y; + self->vec[2] = z; + self->vec[3] = 1.0f; + self->size = 4; + } + + return EXPP_incr_ret( Py_None ); } -//----------------------------getattr()(internal) ---------------- -//object.attribute access (get) -static PyObject *Vector_getattr(VectorObject * self, char *name) + +static void Vector_dealloc( VectorObject * self ) { - int x; - double dot = 0.0f; - - if(STREQ(name,"x")){ - return PyFloat_FromDouble(self->vec[0]); - }else if(STREQ(name, "y")){ - return PyFloat_FromDouble(self->vec[1]); - }else if(STREQ(name, "z")){ - if(self->size > 2){ - return PyFloat_FromDouble(self->vec[2]); - }else{ - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "vector.z: illegal attribute access\n"); - } - }else if(STREQ(name, "w")){ - if(self->size > 3){ - return PyFloat_FromDouble(self->vec[3]); - }else{ - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "vector.w: illegal attribute access\n"); - } - }else if(STREQ2(name, "length", "magnitude")) { - for(x = 0; x < self->size; x++){ - dot += (self->vec[x] * self->vec[x]); - } - return PyFloat_FromDouble(sqrt(dot)); - } + /* if we own this memory we must delete it */ + if( self->delete_pymem ) + PyMem_Free( self->vec ); - return Py_FindMethod(Vector_methods, (PyObject *) self, name); + PyObject_DEL( self ); } -//----------------------------setattr()(internal) ---------------- -//object.attribute access (set) -static int Vector_setattr(VectorObject * self, char *name, PyObject * v) -{ - PyObject *f = NULL; - f = PyNumber_Float(v); - if(f == NULL) { // parsed item not a number - return EXPP_ReturnIntError(PyExc_TypeError, - "vector.attribute = x: argument not a number\n"); - } +static PyObject *Vector_getattr( VectorObject * self, char *name ) +{ + if( self->size == 4 && ELEM4( name[0], 'x', 'y', 'z', 'w' ) + && name[1] == 0 ) { + if( ( name[0] ) == ( 'w' ) ) { + return PyFloat_FromDouble( self->vec[3] ); + } else { + return PyFloat_FromDouble( self->vec[name[0] - 'x'] ); + } + } else if( self->size == 3 && ELEM3( name[0], 'x', 'y', 'z' ) + && name[1] == 0 ) + return PyFloat_FromDouble( self->vec[name[0] - 'x'] ); + else if( self->size == 2 && ELEM( name[0], 'x', 'y' ) && name[1] == 0 ) + return PyFloat_FromDouble( self->vec[name[0] - 'x'] ); + + if( ( strcmp( name, "length" ) == 0 ) ) { + if( self->size == 4 ) { + return PyFloat_FromDouble( sqrt + ( self->vec[0] * + self->vec[0] + + self->vec[1] * + self->vec[1] + + self->vec[2] * + self->vec[2] + + self->vec[3] * + self->vec[3] ) ); + } else if( self->size == 3 ) { + return PyFloat_FromDouble( sqrt + ( self->vec[0] * + self->vec[0] + + self->vec[1] * + self->vec[1] + + self->vec[2] * + self->vec[2] ) ); + } else if( self->size == 2 ) { + return PyFloat_FromDouble( sqrt + ( self->vec[0] * + self->vec[0] + + self->vec[1] * + self->vec[1] ) ); + } else + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "can only return the length of a 2D ,3D or 4D vector\n" ); + } + + return Py_FindMethod( Vector_methods, ( PyObject * ) self, name ); +} - if(STREQ(name,"x")){ - self->vec[0] = PyFloat_AS_DOUBLE(f); - }else if(STREQ(name, "y")){ - self->vec[1] = PyFloat_AS_DOUBLE(f); - }else if(STREQ(name, "z")){ - if(self->size > 2){ - self->vec[2] = PyFloat_AS_DOUBLE(f); - }else{ - Py_DECREF(f); - return EXPP_ReturnIntError(PyExc_AttributeError, - "vector.z = x: illegal attribute access\n"); +static int Vector_setattr( VectorObject * self, char *name, PyObject * v ) +{ + float val; + int valTemp; + + if( !PyFloat_Check( v ) ) { + if( !PyInt_Check( v ) ) { + return EXPP_ReturnIntError( PyExc_TypeError, + "int or float expected\n" ); + } else { + if( !PyArg_Parse( v, "i", &valTemp ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "unable to parse int argument\n" ); + val = ( float ) valTemp; } - }else if(STREQ(name, "w")){ - if(self->size > 3){ - self->vec[3] = PyFloat_AS_DOUBLE(f); - }else{ - Py_DECREF(f); - return EXPP_ReturnIntError(PyExc_AttributeError, - "vector.w = x: illegal attribute access\n"); + } else { + if( !PyArg_Parse( v, "f", &val ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "unable to parse float argument\n" ); + } + if( self->size == 4 && ELEM4( name[0], 'x', 'y', 'z', 'w' ) + && name[1] == 0 ) { + if( ( name[0] ) == ( 'w' ) ) { + self->vec[3] = val; + } else { + self->vec[name[0] - 'x'] = val; } - }else{ - Py_DECREF(f); - return EXPP_ReturnIntError(PyExc_AttributeError, - "vector.attribute = x: unknown attribute\n"); - } + } else if( self->size == 3 && ELEM3( name[0], 'x', 'y', 'z' ) + && name[1] == 0 ) + self->vec[name[0] - 'x'] = val; + else if( self->size == 2 && ELEM( name[0], 'x', 'y' ) && name[1] == 0 ) + self->vec[name[0] - 'x'] = val; + else + return -1; - Py_DECREF(f); return 0; } -//----------------------------print object (internal)------------- -//print the object to screen -static PyObject *Vector_repr(VectorObject * self) -{ - int i; - char buffer[48], str[1024]; - - BLI_strncpy(str,"[",1024); - for(i = 0; i < self->size; i++){ - if(i < (self->size - 1)){ - sprintf(buffer, "%.6f, ", self->vec[i]); - strcat(str,buffer); - }else{ - sprintf(buffer, "%.6f", self->vec[i]); - strcat(str,buffer); - } - } - strcat(str, "](vector)"); - return EXPP_incr_ret(PyString_FromString(str)); -} -//---------------------SEQUENCE PROTOCOLS------------------------ -//----------------------------len(object)------------------------ -//sequence length -static int Vector_len(VectorObject * self) +/* Vectors Sequence methods */ +static int Vector_len( VectorObject * self ) { return self->size; } -//----------------------------object[]--------------------------- -//sequence accessor (get) -static PyObject *Vector_item(VectorObject * self, int i) -{ - if(i < 0 || i >= self->size) - return EXPP_ReturnPyObjError(PyExc_IndexError, - "vector[attribute]: array index out of range\n"); - - return Py_BuildValue("f", self->vec[i]); -} -//----------------------------object[]------------------------- -//sequence accessor (set) -static int Vector_ass_item(VectorObject * self, int i, PyObject * ob) +static PyObject *Vector_item( VectorObject * self, int i ) { - PyObject *f = NULL; + if( i < 0 || i >= self->size ) + return EXPP_ReturnPyObjError( PyExc_IndexError, + "array index out of range\n" ); - f = PyNumber_Float(ob); - if(f == NULL) { // parsed item not a number - return EXPP_ReturnIntError(PyExc_TypeError, - "vector[attribute] = x: argument not a number\n"); - } + return Py_BuildValue( "f", self->vec[i] ); - if(i < 0 || i >= self->size){ - Py_DECREF(f); - return EXPP_ReturnIntError(PyExc_IndexError, - "vector[attribute] = x: array assignment index out of range\n"); - } - self->vec[i] = PyFloat_AS_DOUBLE(f); - Py_DECREF(f); - return 0; } -//----------------------------object[z:y]------------------------ -//sequence slice (get) -static PyObject *Vector_slice(VectorObject * self, int begin, int end) + +static PyObject *Vector_slice( VectorObject * self, int begin, int end ) { - PyObject *list = NULL; + PyObject *list; int count; - CLAMP(begin, 0, self->size); - CLAMP(end, 0, self->size); - begin = MIN2(begin,end); + if( begin < 0 ) + begin = 0; + if( end > self->size ) + end = self->size; + if( begin > end ) + begin = end; + + list = PyList_New( end - begin ); - list = PyList_New(end - begin); - for(count = begin; count < end; count++) { - PyList_SetItem(list, count - begin, - PyFloat_FromDouble(self->vec[count])); + for( count = begin; count < end; count++ ) { + PyList_SetItem( list, count - begin, + PyFloat_FromDouble( self->vec[count] ) ); } return list; } -//----------------------------object[z:y]------------------------ -//sequence slice (set) -static int Vector_ass_slice(VectorObject * self, int begin, int end, - PyObject * seq) -{ - int i, y, size = 0; - float vec[4]; - - CLAMP(begin, 0, self->size); - CLAMP(end, 0, self->size); - begin = MIN2(begin,end); - size = PySequence_Length(seq); - if(size != (end - begin)){ - return EXPP_ReturnIntError(PyExc_TypeError, - "vector[begin:end] = []: size mismatch in slice assignment\n"); - } +static int Vector_ass_item( VectorObject * self, int i, PyObject * ob ) +{ + if( i < 0 || i >= self->size ) + return EXPP_ReturnIntError( PyExc_IndexError, + "array assignment index out of range\n" ); + if( !PyInt_Check( ob ) && !PyFloat_Check( ob ) ) + return EXPP_ReturnIntError( PyExc_IndexError, + "vector member must be a number\n" ); - for (i = 0; i < size; i++) { - PyObject *v, *f; + self->vec[i] = ( float ) PyFloat_AsDouble( ob ); - v = PySequence_GetItem(seq, i); - if (v == NULL) { // Failed to read sequence - return EXPP_ReturnIntError(PyExc_RuntimeError, - "vector[begin:end] = []: unable to read sequence\n"); - } - f = PyNumber_Float(v); - if(f == NULL) { // parsed item not a number - Py_DECREF(v); - return EXPP_ReturnIntError(PyExc_TypeError, - "vector[begin:end] = []: sequence argument not a number\n"); - } - vec[i] = PyFloat_AS_DOUBLE(f); - EXPP_decr2(f,v); - } - //parsed well - now set in vector - for(y = 0; y < size; y++){ - self->vec[begin + y] = vec[y]; - } return 0; } -//------------------------NUMERIC PROTOCOLS---------------------- -//------------------------obj + obj------------------------------ -//addition -static PyObject *Vector_add(PyObject * v1, PyObject * v2) -{ - int x, size; - float vec[4]; - VectorObject *vec1 = NULL, *vec2 = NULL; - - EXPP_incr2(v1, v2); - vec1 = (VectorObject*)v1; - vec2 = (VectorObject*)v2; - if(vec1->coerced_object || vec2->coerced_object){ - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Vector addition: arguments not valid for this operation....\n"); - } - if(vec1->size != vec2->size){ - EXPP_decr2((PyObject*)vec1, (PyObject*)vec2); - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Vector addition: vectors must have the same dimensions for this operation\n"); - } - - size = vec1->size; - for(x = 0; x < size; x++) { - vec[x] = vec1->vec[x] + vec2->vec[x]; +static int Vector_ass_slice( VectorObject * self, int begin, int end, + PyObject * seq ) +{ + int count, z; + + if( begin < 0 ) + begin = 0; + if( end > self->size ) + end = self->size; + if( begin > end ) + begin = end; + + if( !PySequence_Check( seq ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "illegal argument type for built-in operation\n" ); + if( PySequence_Length( seq ) != ( end - begin ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "size mismatch in slice assignment\n" ); + + z = 0; + for( count = begin; count < end; count++ ) { + PyObject *ob = PySequence_GetItem( seq, z ); + z++; + if( !PyInt_Check( ob ) && !PyFloat_Check( ob ) ) + return EXPP_ReturnIntError( PyExc_IndexError, + "list member must be a number\n" ); + + if( !PyArg_Parse( ob, "f", &self->vec[count] ) ) { + Py_DECREF( ob ); + return -1; + } } - EXPP_decr2((PyObject*)vec1, (PyObject*)vec2); - return (PyObject *) newVectorObject(vec, size, Py_NEW); + return 0; } -//------------------------obj - obj------------------------------ -//subtraction -static PyObject *Vector_sub(PyObject * v1, PyObject * v2) -{ - int x, size; - float vec[4]; - VectorObject *vec1 = NULL, *vec2 = NULL; - - EXPP_incr2(v1, v2); - vec1 = (VectorObject*)v1; - vec2 = (VectorObject*)v2; - if(vec1->coerced_object || vec2->coerced_object){ - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Vector subtraction: arguments not valid for this operation....\n"); - } - if(vec1->size != vec2->size){ - EXPP_decr2((PyObject*)vec1, (PyObject*)vec2); - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Vector subtraction: vectors must have the same dimensions for this operation\n"); - } +static PyObject *Vector_repr( VectorObject * self ) +{ + int i, maxindex = self->size - 1; + char ftoa[24]; + PyObject *str1, *str2; + + str1 = PyString_FromString( "[" ); + + for( i = 0; i < maxindex; i++ ) { + sprintf( ftoa, "%.4f, ", self->vec[i] ); + str2 = PyString_FromString( ftoa ); + if( !str1 || !str2 ) + goto error; + PyString_ConcatAndDel( &str1, str2 ); + } + + sprintf( ftoa, "%.4f]", self->vec[maxindex] ); + str2 = PyString_FromString( ftoa ); + if( !str1 || !str2 ) + goto error; + PyString_ConcatAndDel( &str1, str2 ); + + if( str1 ) + return str1; + + error: + Py_XDECREF( str1 ); + Py_XDECREF( str2 ); + return EXPP_ReturnPyObjError( PyExc_MemoryError, + "couldn't create PyString!\n" ); +} - size = vec1->size; - for(x = 0; x < size; x++) { - vec[x] = vec1->vec[x] - vec2->vec[x]; - } - EXPP_decr2((PyObject*)vec1, (PyObject*)vec2); - return (PyObject *) newVectorObject(vec, size, Py_NEW); -} -//------------------------obj * obj------------------------------ -//mulplication -static PyObject *Vector_mul(PyObject * v1, PyObject * v2) +PyObject *Vector_add( PyObject * v1, PyObject * v2 ) { - int x, size; - float vec[4], scalar, newVec[3]; - double dot = 0.0f; - VectorObject *vec1 = NULL, *vec2 = NULL; - PyObject *f = NULL, *retObj = NULL; - MatrixObject *mat = NULL; - QuaternionObject *quat = NULL; - - EXPP_incr2(v1, v2); - vec1 = (VectorObject*)v1; - vec2 = (VectorObject*)v2; - - if(vec1->coerced_object){ - if (PyFloat_Check(vec1->coerced_object) || - PyInt_Check(vec1->coerced_object)){ // FLOAT/INT * VECTOR - f = PyNumber_Float(vec1->coerced_object); - if(f == NULL) { // parsed item not a number - EXPP_decr2((PyObject*)vec1, (PyObject*)vec2); - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Vector multiplication: arguments not acceptable for this operation\n"); - } - scalar = PyFloat_AS_DOUBLE(f); - size = vec2->size; - for(x = 0; x < size; x++) { - vec[x] = vec2->vec[x] * scalar; - } - EXPP_decr2((PyObject*)vec1, (PyObject*)vec2); - return (PyObject *) newVectorObject(vec, size, Py_NEW); - } - }else{ - if(vec2->coerced_object){ - if(MatrixObject_Check(vec2->coerced_object)){ //VECTOR * MATRIX - mat = (MatrixObject*)EXPP_incr_ret(vec2->coerced_object); - retObj = row_vector_multiplication(vec1, mat); - EXPP_decr3((PyObject*)vec1, (PyObject*)vec2, (PyObject*)mat); - return retObj; - }else if (PyFloat_Check(vec2->coerced_object) || - PyInt_Check(vec2->coerced_object)){ // VECTOR * FLOAT/INT - f = PyNumber_Float(vec2->coerced_object); - if(f == NULL) { // parsed item not a number - EXPP_decr2((PyObject*)vec1, (PyObject*)vec2); - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Vector multiplication: arguments not acceptable for this operation\n"); - } - scalar = PyFloat_AS_DOUBLE(f); - size = vec1->size; - for(x = 0; x < size; x++) { - vec[x] = vec1->vec[x] * scalar; - } - EXPP_decr2((PyObject*)vec1, (PyObject*)vec2); - return (PyObject *) newVectorObject(vec, size, Py_NEW); - }else if(QuaternionObject_Check(vec2->coerced_object)){ //QUAT * VEC - quat = (QuaternionObject*)EXPP_incr_ret(vec2->coerced_object); - if(vec1->size != 3){ - EXPP_decr2((PyObject*)vec1, (PyObject*)vec2); - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Vector multiplication: only 3D vector rotations (with quats) currently supported\n"); - } - newVec[0] = quat->quat[0]*quat->quat[0]*vec1->vec[0] + - 2*quat->quat[2]*quat->quat[0]*vec1->vec[2] - - 2*quat->quat[3]*quat->quat[0]*vec1->vec[1] + - quat->quat[1]*quat->quat[1]*vec1->vec[0] + - 2*quat->quat[2]*quat->quat[1]*vec1->vec[1] + - 2*quat->quat[3]*quat->quat[1]*vec1->vec[2] - - quat->quat[3]*quat->quat[3]*vec1->vec[0] - - quat->quat[2]*quat->quat[2]*vec1->vec[0]; - newVec[1] = 2*quat->quat[1]*quat->quat[2]*vec1->vec[0] + - quat->quat[2]*quat->quat[2]*vec1->vec[1] + - 2*quat->quat[3]*quat->quat[2]*vec1->vec[2] + - 2*quat->quat[0]*quat->quat[3]*vec1->vec[0] - - quat->quat[3]*quat->quat[3]*vec1->vec[1] + - quat->quat[0]*quat->quat[0]*vec1->vec[1] - - 2*quat->quat[1]*quat->quat[0]*vec1->vec[2] - - quat->quat[1]*quat->quat[1]*vec1->vec[1]; - newVec[2] = 2*quat->quat[1]*quat->quat[3]*vec1->vec[0] + - 2*quat->quat[2]*quat->quat[3]*vec1->vec[1] + - quat->quat[3]*quat->quat[3]*vec1->vec[2] - - 2*quat->quat[0]*quat->quat[2]*vec1->vec[0] - - quat->quat[2]*quat->quat[2]*vec1->vec[2] + - 2*quat->quat[0]*quat->quat[1]*vec1->vec[1] - - quat->quat[1]*quat->quat[1]*vec1->vec[2] + - quat->quat[0]*quat->quat[0]*vec1->vec[2]; - EXPP_decr3((PyObject*)vec1, (PyObject*)vec2, (PyObject*)quat); - return newVectorObject(newVec,3,Py_NEW); - } - }else{ //VECTOR * VECTOR - if(vec1->size != vec2->size){ - EXPP_decr2((PyObject*)vec1, (PyObject*)vec2); - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Vector multiplication: vectors must have the same dimensions for this operation\n"); - } - size = vec1->size; - //dot product - for(x = 0; x < size; x++) { - dot += vec1->vec[x] * vec2->vec[x]; - } - EXPP_decr2((PyObject*)vec1, (PyObject*)vec2); - return PyFloat_FromDouble(dot); - } - } - - EXPP_decr2((PyObject*)vec1, (PyObject*)vec2); - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Vector multiplication: arguments not acceptable for this operation\n"); + float *vec; + int x; + PyObject *retval; + + if( ( !VectorObject_Check( v1 ) ) || ( !VectorObject_Check( v2 ) ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "unsupported type for this operation\n" ); + if( ( ( VectorObject * ) v1 )->flag != 0 + || ( ( VectorObject * ) v2 )->flag != 0 ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "cannot add a scalar to a vector\n" ); + if( ( ( VectorObject * ) v1 )->size != + ( ( VectorObject * ) v2 )->size ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "vectors must have the same dimensions for this operation\n" ); + + vec = PyMem_Malloc( ( ( ( VectorObject * ) v1 )->size ) * + sizeof( float ) ); + + for( x = 0; x < ( ( VectorObject * ) v1 )->size; x++ ) { + vec[x] = ( ( VectorObject * ) v1 )->vec[x] + + ( ( VectorObject * ) v2 )->vec[x]; + } + + retval = ( PyObject * ) newVectorObject( vec, + ( ( ( VectorObject * ) v1 )-> + size ) ); + PyMem_Free( vec ); + return retval; } -//------------------------obj / obj------------------------------ -//division -static PyObject *Vector_div(PyObject * v1, PyObject * v2) -{ - int x, size; - float vec[4]; - VectorObject *vec1 = NULL, *vec2 = NULL; - EXPP_incr2(v1, v2); - vec1 = (VectorObject*)v1; - vec2 = (VectorObject*)v2; - - if(vec1->coerced_object || vec2->coerced_object){ - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Vector division: arguments not valid for this operation....\n"); - } - if(vec1->size != vec2->size){ - EXPP_decr2((PyObject*)vec1, (PyObject*)vec2); - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Vector division: vectors must have the same dimensions for this operation\n"); - } +PyObject *Vector_sub( PyObject * v1, PyObject * v2 ) +{ + float *vec; + int x; + PyObject *retval; + + if( ( !VectorObject_Check( v1 ) ) || ( !VectorObject_Check( v2 ) ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "unsupported type for this operation\n" ); + if( ( ( VectorObject * ) v1 )->flag != 0 + || ( ( VectorObject * ) v2 )->flag != 0 ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "cannot subtract a scalar from a vector\n" ); + if( ( ( VectorObject * ) v1 )->size != + ( ( VectorObject * ) v2 )->size ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "vectors must have the same dimensions for this operation\n" ); + + vec = PyMem_Malloc( ( ( ( VectorObject * ) v1 )->size ) * + sizeof( float ) ); + + for( x = 0; x < ( ( VectorObject * ) v1 )->size; x++ ) { + vec[x] = ( ( VectorObject * ) v1 )->vec[x] - + ( ( VectorObject * ) v2 )->vec[x]; + } + + retval = ( PyObject * ) newVectorObject( vec, + ( ( ( VectorObject * ) v1 )-> + size ) ); + PyMem_Free( vec ); + return retval; +} - size = vec1->size; - for(x = 0; x < size; x++) { - vec[x] = vec1->vec[x] / vec2->vec[x]; - } +PyObject *Vector_mul( PyObject * v1, PyObject * v2 ) +{ + float *vec; + int x; + PyObject *retval; + + if( ( !VectorObject_Check( v1 ) ) || ( !VectorObject_Check( v2 ) ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "unsupported type for this operation\n" ); + if( ( ( VectorObject * ) v1 )->flag == 0 + && ( ( VectorObject * ) v2 )->flag == 0 ) + return EXPP_ReturnPyObjError( PyExc_ArithmeticError, + "please use the dot product or the cross product to multiply vectors\n" ); + if( ( ( VectorObject * ) v1 )->size != + ( ( VectorObject * ) v2 )->size ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "vector dimension error during Vector_mul\n" ); + + vec = PyMem_Malloc( ( ( ( VectorObject * ) v1 )->size ) * + sizeof( float ) ); + + for( x = 0; x < ( ( VectorObject * ) v1 )->size; x++ ) { + vec[x] = ( ( VectorObject * ) v1 )->vec[x] * + ( ( VectorObject * ) v2 )->vec[x]; + } + + retval = ( PyObject * ) newVectorObject( vec, + ( ( ( VectorObject * ) v1 )-> + size ) ); + PyMem_Free( vec ); + return retval; +} - EXPP_decr2((PyObject*)vec1, (PyObject*)vec2); - return (PyObject *) newVectorObject(vec, size, Py_NEW); +PyObject *Vector_div( PyObject * v1, PyObject * v2 ) +{ + float *vec; + int x; + PyObject *retval; + + if( ( !VectorObject_Check( v1 ) ) || ( !VectorObject_Check( v2 ) ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "unsupported type for this operation\n" ); + if( ( ( VectorObject * ) v1 )->flag == 0 + && ( ( VectorObject * ) v2 )->flag == 0 ) + return EXPP_ReturnPyObjError( PyExc_ArithmeticError, + "cannot divide two vectors\n" ); + if( ( ( VectorObject * ) v1 )->flag != 0 + && ( ( VectorObject * ) v2 )->flag == 0 ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "cannot divide a scalar by a vector\n" ); + if( ( ( VectorObject * ) v1 )->size != + ( ( VectorObject * ) v2 )->size ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "vector dimension error during Vector_mul\n" ); + + vec = PyMem_Malloc( ( ( ( VectorObject * ) v1 )->size ) * + sizeof( float ) ); + + for( x = 0; x < ( ( VectorObject * ) v1 )->size; x++ ) { + vec[x] = ( ( VectorObject * ) v1 )->vec[x] / + ( ( VectorObject * ) v2 )->vec[x]; + } + + retval = ( PyObject * ) newVectorObject( vec, + ( ( ( VectorObject * ) v1 )-> + size ) ); + PyMem_Free( vec ); + return retval; } -//------------------------coerce(obj, obj)----------------------- + //coercion of unknown types to type VectorObject for numeric protocols -/*Coercion() is called whenever a math operation has 2 operands that - it doesn't understand how to evaluate. 2+Matrix for example. We want to - evaluate some of these operations like: (vector * 2), however, for math - to proceed, the unknown operand must be cast to a type that python math will - understand. (e.g. in the case above case, 2 must be cast to a vector and - then call vector.multiply(vector, scalar_cast_as_vector)*/ -static int Vector_coerce(PyObject ** v1, PyObject ** v2) +int Vector_coerce( PyObject ** v1, PyObject ** v2 ) { + long *tempI; + double *tempF; + float *vec; int x; - float vec[4]; - PyObject *coerced = NULL; - - if(!VectorObject_Check(*v2)) { - if(MatrixObject_Check(*v2) || PyFloat_Check(*v2) || PyInt_Check(*v2) || QuaternionObject_Check(*v2)) { - coerced = EXPP_incr_ret(*v2); - *v2 = newVectorObject(NULL,3,Py_NEW); - ((VectorObject*)*v2)->coerced_object = coerced; - }else{ - return EXPP_ReturnIntError(PyExc_TypeError, - "vector.coerce(): unknown operand - can't coerce for numeric protocols\n"); + + if( VectorObject_Check( *v1 ) ) { + if( VectorObject_Check( *v2 ) ) { //two vectors + Py_INCREF( *v1 ); /* fixme: wahy are we bumping the ref count? */ + Py_INCREF( *v2 ); + return 0; + } else { + if( Matrix_CheckPyObject( *v2 ) ) { + printf( "vector/matrix numeric protocols unsupported...\n" ); + Py_INCREF( *v1 ); + return 0; //operation will type check + } else if( PyNumber_Check( *v2 ) ) { + if( PyInt_Check( *v2 ) ) { //cast scalar to vector + tempI = PyMem_Malloc( 1 * + sizeof( long ) ); + *tempI = PyInt_AsLong( *v2 ); + vec = PyMem_Malloc( ( ( ( VectorObject + * ) * + v1 )->size ) * + sizeof( float ) ); + for( x = 0; + x < ( ( ( VectorObject * ) * v1 )->size ); + x++ ) { + vec[x] = ( float ) *tempI; + } + PyMem_Free( tempI ); + *v2 = newVectorObject( vec, + ( ( ( VectorObject * ) * v1 )->size ) ); + ( ( VectorObject * ) * v2 )->flag = 1; //int coercion + Py_INCREF( *v1 ); + return 0; + } else if( PyFloat_Check( *v2 ) ) { //cast scalar to vector + tempF = PyMem_Malloc( 1 * + sizeof + ( double ) ); + *tempF = PyFloat_AsDouble( *v2 ); + vec = PyMem_Malloc( ( ( ( VectorObject + * ) * + v1 )->size ) * + sizeof( float ) ); + for( x = 0; + x < + ( ( ( VectorObject * ) * + v1 )->size ); x++ ) { + vec[x] = ( float ) *tempF; + } + PyMem_Free( tempF ); + *v2 = newVectorObject( vec, + ( ( ( VectorObject * ) * v1 )->size ) ); + ( ( VectorObject * ) * v2 )->flag = 2; //float coercion + Py_INCREF( *v1 ); + return 0; + } + } + //unknown type or numeric cast failure + printf( "attempting vector operation with unsupported type...\n" ); + Py_INCREF( *v1 ); + return 0; //operation will type check } + } else { + printf( "numeric protocol failure...\n" ); + return -1; //this should not occur - fail } - EXPP_incr2(*v1, *v2); - return 0; + return -1; } -//-----------------PROTCOL DECLARATIONS-------------------------- + + static PySequenceMethods Vector_SeqMethods = { - (inquiry) Vector_len, /* sq_length */ - (binaryfunc) 0, /* sq_concat */ - (intargfunc) 0, /* sq_repeat */ - (intargfunc) Vector_item, /* sq_item */ - (intintargfunc) Vector_slice, /* sq_slice */ - (intobjargproc) Vector_ass_item, /* sq_ass_item */ - (intintobjargproc) Vector_ass_slice, /* sq_ass_slice */ + ( inquiry ) Vector_len, /* sq_length */ + ( binaryfunc ) 0, /* sq_concat */ + ( intargfunc ) 0, /* sq_repeat */ + ( intargfunc ) Vector_item, /* sq_item */ + ( intintargfunc ) Vector_slice, /* sq_slice */ + ( intobjargproc ) Vector_ass_item, /* sq_ass_item */ + ( intintobjargproc ) Vector_ass_slice, /* sq_ass_slice */ }; + static PyNumberMethods Vector_NumMethods = { - (binaryfunc) Vector_add, /* __add__ */ - (binaryfunc) Vector_sub, /* __sub__ */ - (binaryfunc) Vector_mul, /* __mul__ */ - (binaryfunc) Vector_div, /* __div__ */ - (binaryfunc) 0, /* __mod__ */ - (binaryfunc) 0, /* __divmod__ */ - (ternaryfunc) 0, /* __pow__ */ - (unaryfunc) 0, /* __neg__ */ - (unaryfunc) 0, /* __pos__ */ - (unaryfunc) 0, /* __abs__ */ - (inquiry) 0, /* __nonzero__ */ - (unaryfunc) 0, /* __invert__ */ - (binaryfunc) 0, /* __lshift__ */ - (binaryfunc) 0, /* __rshift__ */ - (binaryfunc) 0, /* __and__ */ - (binaryfunc) 0, /* __xor__ */ - (binaryfunc) 0, /* __or__ */ - (coercion) Vector_coerce, /* __coerce__ */ - (unaryfunc) 0, /* __int__ */ - (unaryfunc) 0, /* __long__ */ - (unaryfunc) 0, /* __float__ */ - (unaryfunc) 0, /* __oct__ */ - (unaryfunc) 0, /* __hex__ */ + ( binaryfunc ) Vector_add, /* __add__ */ + ( binaryfunc ) Vector_sub, /* __sub__ */ + ( binaryfunc ) Vector_mul, /* __mul__ */ + ( binaryfunc ) Vector_div, /* __div__ */ + ( binaryfunc ) 0, /* __mod__ */ + ( binaryfunc ) 0, /* __divmod__ */ + ( ternaryfunc ) 0, /* __pow__ */ + ( unaryfunc ) 0, /* __neg__ */ + ( unaryfunc ) 0, /* __pos__ */ + ( unaryfunc ) 0, /* __abs__ */ + ( inquiry ) 0, /* __nonzero__ */ + ( unaryfunc ) 0, /* __invert__ */ + ( binaryfunc ) 0, /* __lshift__ */ + ( binaryfunc ) 0, /* __rshift__ */ + ( binaryfunc ) 0, /* __and__ */ + ( binaryfunc ) 0, /* __xor__ */ + ( binaryfunc ) 0, /* __or__ */ + ( coercion ) Vector_coerce, /* __coerce__ */ + ( unaryfunc ) 0, /* __int__ */ + ( unaryfunc ) 0, /* __long__ */ + ( unaryfunc ) 0, /* __float__ */ + ( unaryfunc ) 0, /* __oct__ */ + ( unaryfunc ) 0, /* __hex__ */ }; -//------------------PY_OBECT DEFINITION-------------------------- + PyTypeObject vector_Type = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size */ - "vector", /*tp_name */ - sizeof(VectorObject), /*tp_basicsize */ - 0, /*tp_itemsize */ - (destructor) Vector_dealloc, /*tp_dealloc */ - (printfunc) 0, /*tp_print */ - (getattrfunc) Vector_getattr, /*tp_getattr */ - (setattrfunc) Vector_setattr, /*tp_setattr */ - 0, /*tp_compare */ - (reprfunc) Vector_repr, /*tp_repr */ - &Vector_NumMethods, /*tp_as_number */ - &Vector_SeqMethods, /*tp_as_sequence */ + PyObject_HEAD_INIT( NULL ) 0, /*ob_size */ + "vector", /*tp_name */ + sizeof( VectorObject ), /*tp_basicsize */ + 0, /*tp_itemsize */ + ( destructor ) Vector_dealloc, /*tp_dealloc */ + ( printfunc ) 0, /*tp_print */ + ( getattrfunc ) Vector_getattr, /*tp_getattr */ + ( setattrfunc ) Vector_setattr, /*tp_setattr */ + 0, /*tp_compare */ + ( reprfunc ) Vector_repr, /*tp_repr */ + &Vector_NumMethods, /*tp_as_number */ + &Vector_SeqMethods, /*tp_as_sequence */ }; -//------------------------newVectorObject (internal)------------- -//creates a new vector object -/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER - (i.e. it was allocated elsewhere by MEM_mallocN()) - pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON - (i.e. it must be created here with PyMEM_malloc())*/ -PyObject *newVectorObject(float *vec, int size, int type) + + +/* + * create a Vector Object( vec, size ) + * + * Note: Vector now uses copy semantics like STL containers. + * Memory for vec member is allocated on python stack. + * We own this memory and will free it later. + * + * size arg is number of floats to alloc. + * + * if vec arg is NULL + * fill our vec with zeros + * initialize 4d vectors to zero in homogenous coords. + * else + * vec param is copied into our local memory and always freed. + */ + +PyObject *newVectorObject( float *vec, int size ) { VectorObject *self; int x; vector_Type.ob_type = &PyType_Type; - self = PyObject_NEW(VectorObject, &vector_Type); - self->data.blend_data = NULL; - self->data.py_data = NULL; - self->size = size; - self->coerced_object = NULL; - - if(type == Py_WRAP){ - self->data.blend_data = vec; - self->vec = self->data.blend_data; - }else if (type == Py_NEW){ - self->data.py_data = PyMem_Malloc(size * sizeof(float)); - self->vec = self->data.py_data; - if(!vec) { //new empty - for(x = 0; x < size; x++){ - self->vec[x] = 0.0f; - } - if(size == 4) /* do the homogenous thing */ - self->vec[3] = 1.0f; - }else{ - for(x = 0; x < size; x++){ - self->vec[x] = vec[x]; - } + + self = PyObject_NEW( VectorObject, &vector_Type ); + + self->vec = PyMem_Malloc( size * sizeof( float ) ); + self->delete_pymem = 1; /* must free this alloc later */ + + if( !vec ) { + for( x = 0; x < size; x++ ) { + self->vec[x] = 0.0f; + } + if( size == 4 ) /* do the homogenous thing */ + self->vec[3] = 1.0f; + } else { + for( x = 0; x < size; x++ ){ + self->vec[x] = vec[x]; } - }else{ //bad type - return NULL; } - return (PyObject *) EXPP_incr_ret((PyObject *)self); + + self->size = size; + self->flag = 0; + + return ( PyObject * ) self; } + +/* + create a Vector that is a proxy for blender data. + we do not own this data, we NEVER free it. + Note: users must deal with bad pointer issue +*/ + +PyObject *newVectorProxy( float *vec, int size) +{ + VectorObject *proxy; + + proxy = PyObject_NEW( VectorObject, &vector_Type ); + + proxy->delete_pymem = 0; /* must NOT free this alloc later */ + + if( !vec || size < 1 ) { + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "cannot creat zero length vector proxy" ); + } + + proxy->vec = vec; + proxy->size = size; + proxy->flag = 0; + + return ( PyObject * ) proxy; +} + diff --git a/source/blender/python/api2_2x/vector.h b/source/blender/python/api2_2x/vector.h index 048fa1df8bc..40e5851359a 100644 --- a/source/blender/python/api2_2x/vector.h +++ b/source/blender/python/api2_2x/vector.h @@ -33,34 +33,40 @@ #ifndef EXPP_vector_h #define EXPP_vector_h +#include "Python.h" +#include "gen_utils.h" +#include "Types.h" +#include "matrix.h" +#include "BKE_utildefines.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +/*****************************/ +// Vector Python Object +/*****************************/ + #define VectorObject_Check(v) ((v)->ob_type == &vector_Type) typedef struct { - PyObject_VAR_HEAD - struct{ - float *py_data; //python managed - float *blend_data; //blender managed - }data; - float *vec; //1D array of data (alias) + PyObject_VAR_HEAD float *vec; int size; - PyObject *coerced_object; + int flag; + //0 - no coercion + //1 - coerced from int + //2 - coerced from float + int delete_pymem; /* flag to delete the memory vec points at */ } VectorObject; -/*coerced_object is a pointer to the object that it was -coerced from when a dummy vector needs to be created from -the coerce() function for numeric protocol operations*/ - -/*struct data contains a pointer to the actual data that the -object uses. It can use either PyMem allocated data (which will -be stored in py_data) or be a wrapper for data allocated through -blender (stored in blend_data). This is an either/or struct not both*/ //prototypes +PyObject *newVectorObject( float *vec, int size ); +PyObject *newVectorProxy( float *vec, int size ); PyObject *Vector_Zero( VectorObject * self ); PyObject *Vector_Normalize( VectorObject * self ); PyObject *Vector_Negate( VectorObject * self ); PyObject *Vector_Resize2D( VectorObject * self ); PyObject *Vector_Resize3D( VectorObject * self ); PyObject *Vector_Resize4D( VectorObject * self ); -PyObject *newVectorObject(float *vec, int size, int type); #endif /* EXPP_vector_h */ -- cgit v1.2.3