PyAPI Mathutils Vector callbacks, referencing other PyObjects rather then thin wrapping vectors which is crash prone.

in short, vectors can work as if they are thin wrapped but not crash blender if the original data is removed.

* RNA vector's return Mathutils vector types.
* BGE vectors for GameObject's localPosition, worldPosition, localPosition, localScale, worldScale, localInertia.
* Comment USE_MATHUTILS define to disable returning vectors.

Example...

* 2.49... *
 loc = gameOb.worldPosition
 loc[1] = 0
 gameOb.worldPosition = loc

* With vectors... *
 gameOb.worldPosition[1] = 0


* But this wont crash... *
 loc = gameOb.worldPosition
 gameOb.endObject()
 loc[1] = 0 # will raise an error that the objects removed.

This breaks games which assume return values are lists.

Will add this to eulers, matrix and quaternion types later.
This commit is contained in:
Campbell Barton 2009-06-22 04:26:48 +00:00
parent 1efffc1f56
commit bce3f7e019
13 changed files with 682 additions and 189 deletions

@ -164,6 +164,10 @@ static PyObject *M_Geometry_PolyFill( PyObject * self, PyObject * polyLineSeq )
for( index = 0; index<len_polypoints; ++index, fp+=3) { for( index = 0; index<len_polypoints; ++index, fp+=3) {
polyVec= PySequence_GetItem( polyLine, index ); polyVec= PySequence_GetItem( polyLine, index );
if(VectorObject_Check(polyVec)) { if(VectorObject_Check(polyVec)) {
if(!Vector_ReadCallback((VectorObject *)polyVec))
ls_error= 1;
fp[0] = ((VectorObject *)polyVec)->vec[0]; fp[0] = ((VectorObject *)polyVec)->vec[0];
fp[1] = ((VectorObject *)polyVec)->vec[1]; fp[1] = ((VectorObject *)polyVec)->vec[1];
if( ((VectorObject *)polyVec)->size > 2 ) if( ((VectorObject *)polyVec)->size > 2 )
@ -234,6 +238,9 @@ static PyObject *M_Geometry_LineIntersect2D( PyObject * self, PyObject * args )
return NULL; return NULL;
} }
if(!Vector_ReadCallback(line_a1) || !Vector_ReadCallback(line_a2) || !Vector_ReadCallback(line_b1) || !Vector_ReadCallback(line_b2))
return NULL;
a1x= line_a1->vec[0]; a1x= line_a1->vec[0];
a1y= line_a1->vec[1]; a1y= line_a1->vec[1];
a2x= line_a2->vec[0]; a2x= line_a2->vec[0];
@ -330,6 +337,10 @@ static PyObject *M_Geometry_ClosestPointOnLine( PyObject * self, PyObject * args
PyErr_SetString( PyExc_TypeError, "expected 3 vector types\n" ); PyErr_SetString( PyExc_TypeError, "expected 3 vector types\n" );
return NULL; return NULL;
} }
if(!Vector_ReadCallback(pt) || !Vector_ReadCallback(line_1) || !Vector_ReadCallback(line_2))
return NULL;
/* accept 2d verts */ /* accept 2d verts */
if (pt->size==3) { VECCOPY(pt_in, pt->vec);} if (pt->size==3) { VECCOPY(pt_in, pt->vec);}
else { pt_in[2]=0.0; VECCOPY2D(pt_in, pt->vec) } else { pt_in[2]=0.0; VECCOPY2D(pt_in, pt->vec) }
@ -363,6 +374,9 @@ static PyObject *M_Geometry_PointInTriangle2D( PyObject * self, PyObject * args
return NULL; return NULL;
} }
if(!Vector_ReadCallback(pt_vec) || !Vector_ReadCallback(tri_p1) || !Vector_ReadCallback(tri_p2) || !Vector_ReadCallback(tri_p3))
return NULL;
return PyLong_FromLong(IsectPT2Df(pt_vec->vec, tri_p1->vec, tri_p2->vec, tri_p3->vec)); return PyLong_FromLong(IsectPT2Df(pt_vec->vec, tri_p1->vec, tri_p2->vec, tri_p3->vec));
} }
@ -381,6 +395,9 @@ static PyObject *M_Geometry_PointInQuad2D( PyObject * self, PyObject * args )
return NULL; return NULL;
} }
if(!Vector_ReadCallback(pt_vec) || !Vector_ReadCallback(quad_p1) || !Vector_ReadCallback(quad_p2) || !Vector_ReadCallback(quad_p3) || !Vector_ReadCallback(quad_p4))
return NULL;
return PyLong_FromLong(IsectPQ2Df(pt_vec->vec, quad_p1->vec, quad_p2->vec, quad_p3->vec, quad_p4->vec)); return PyLong_FromLong(IsectPQ2Df(pt_vec->vec, quad_p1->vec, quad_p2->vec, quad_p3->vec, quad_p4->vec));
} }
@ -500,6 +517,9 @@ static PyObject *M_Geometry_BezierInterp( PyObject * self, PyObject * args )
return NULL; return NULL;
} }
if(!Vector_ReadCallback(vec_k1) || !Vector_ReadCallback(vec_h1) || !Vector_ReadCallback(vec_k2) || !Vector_ReadCallback(vec_h2))
return NULL;
dims= MAX4(vec_k1->size, vec_h1->size, vec_h2->size, vec_k2->size); dims= MAX4(vec_k1->size, vec_h1->size, vec_h2->size, vec_k2->size);
for(i=0; i < vec_k1->size; i++) k1[i]= vec_k1->vec[i]; for(i=0; i < vec_k1->size; i++) k1[i]= vec_k1->vec[i];

@ -141,77 +141,6 @@ PyObject *Mathutils_Init(const char *from)
} }
//-----------------------------METHODS---------------------------- //-----------------------------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)
{
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){
PyErr_SetString(PyExc_AttributeError, "matrix * vector: matrix row size and vector size must be the same");
return NULL;
}else{
vecCopy[3] = 1.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++] = (float)dot;
dot = 0.0f;
}
return 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, vec_size = vec->size;
if(mat->colSize != vec_size){
if(mat->rowSize == 4 && vec_size != 3){
PyErr_SetString(PyExc_AttributeError, "vector * matrix: matrix column size and the vector size must be the same");
return NULL;
}else{
vecCopy[3] = 1.0f;
}
}
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++] = (float)dot;
dot = 0.0f;
}
return newVectorObject(vecNew, vec_size, Py_NEW);
}
//-----------------quat_rotation (internal)----------- //-----------------quat_rotation (internal)-----------
//This function multiplies a vector/point * quat or vice versa //This function multiplies a vector/point * quat or vice versa
//to rotate the point/vector by the quaternion //to rotate the point/vector by the quaternion
@ -226,6 +155,10 @@ PyObject *quat_rotation(PyObject *arg1, PyObject *arg2)
quat = (QuaternionObject*)arg1; quat = (QuaternionObject*)arg1;
if(VectorObject_Check(arg2)){ if(VectorObject_Check(arg2)){
vec = (VectorObject*)arg2; vec = (VectorObject*)arg2;
if(!Vector_ReadCallback(vec))
return NULL;
rot[0] = quat->quat[0]*quat->quat[0]*vec->vec[0] + 2*quat->quat[2]*quat->quat[0]*vec->vec[2] - rot[0] = quat->quat[0]*quat->quat[0]*vec->vec[0] + 2*quat->quat[2]*quat->quat[0]*vec->vec[2] -
2*quat->quat[3]*quat->quat[0]*vec->vec[1] + quat->quat[1]*quat->quat[1]*vec->vec[0] + 2*quat->quat[3]*quat->quat[0]*vec->vec[1] + quat->quat[1]*quat->quat[1]*vec->vec[0] +
2*quat->quat[2]*quat->quat[1]*vec->vec[1] + 2*quat->quat[3]*quat->quat[1]*vec->vec[2] - 2*quat->quat[2]*quat->quat[1]*vec->vec[1] + 2*quat->quat[3]*quat->quat[1]*vec->vec[2] -
@ -242,6 +175,10 @@ PyObject *quat_rotation(PyObject *arg1, PyObject *arg2)
} }
}else if(VectorObject_Check(arg1)){ }else if(VectorObject_Check(arg1)){
vec = (VectorObject*)arg1; vec = (VectorObject*)arg1;
if(!Vector_ReadCallback(vec))
return NULL;
if(QuaternionObject_Check(arg2)){ if(QuaternionObject_Check(arg2)){
quat = (QuaternionObject*)arg2; quat = (QuaternionObject*)arg2;
rot[0] = quat->quat[0]*quat->quat[0]*vec->vec[0] + 2*quat->quat[2]*quat->quat[0]*vec->vec[2] - rot[0] = quat->quat[0]*quat->quat[0]*vec->vec[0] + 2*quat->quat[2]*quat->quat[0]*vec->vec[2] -
@ -308,6 +245,9 @@ static PyObject *M_Mathutils_AngleBetweenVecs(PyObject * self, PyObject * args)
if(vec1->size != vec2->size) if(vec1->size != vec2->size)
goto AttributeError1; //bad sizes goto AttributeError1; //bad sizes
if(!Vector_ReadCallback(vec1) || !Vector_ReadCallback(vec2))
return NULL;
//since size is the same.... //since size is the same....
size = vec1->size; size = vec1->size;
@ -353,6 +293,9 @@ static PyObject *M_Mathutils_MidpointVecs(PyObject * self, PyObject * args)
PyErr_SetString(PyExc_AttributeError, "Mathutils.MidpointVecs(): expects (2) vector objects of the same size\n"); PyErr_SetString(PyExc_AttributeError, "Mathutils.MidpointVecs(): expects (2) vector objects of the same size\n");
return NULL; return NULL;
} }
if(!Vector_ReadCallback(vec1) || !Vector_ReadCallback(vec2))
return NULL;
for(x = 0; x < vec1->size; x++) { for(x = 0; x < vec1->size; x++) {
vec[x] = 0.5f * (vec1->vec[x] + vec2->vec[x]); vec[x] = 0.5f * (vec1->vec[x] + vec2->vec[x]);
@ -377,6 +320,10 @@ static PyObject *M_Mathutils_ProjectVecs(PyObject * self, PyObject * args)
return NULL; return NULL;
} }
if(!Vector_ReadCallback(vec1) || !Vector_ReadCallback(vec2))
return NULL;
//since they are the same size... //since they are the same size...
size = vec1->size; size = vec1->size;
@ -439,6 +386,10 @@ static PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args)
PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): the arbitrary axis must be a 3D vector\n"); PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): the arbitrary axis must be a 3D vector\n");
return NULL; return NULL;
} }
if(!Vector_ReadCallback(vec))
return NULL;
} }
//convert to radians //convert to radians
angle = angle * (float) (Py_PI / 180); angle = angle * (float) (Py_PI / 180);
@ -538,6 +489,10 @@ static PyObject *M_Mathutils_TranslationMatrix(PyObject * self, VectorObject * v
PyErr_SetString(PyExc_TypeError, "Mathutils.TranslationMatrix(): vector must be 3D or 4D\n"); PyErr_SetString(PyExc_TypeError, "Mathutils.TranslationMatrix(): vector must be 3D or 4D\n");
return NULL; return NULL;
} }
if(!Vector_ReadCallback(vec))
return NULL;
//create a identity matrix and add translation //create a identity matrix and add translation
Mat4One((float(*)[4]) mat); Mat4One((float(*)[4]) mat);
mat[12] = vec->vec[0]; mat[12] = vec->vec[0];
@ -570,6 +525,10 @@ static PyObject *M_Mathutils_ScaleMatrix(PyObject * self, PyObject * args)
PyErr_SetString(PyExc_AttributeError, "Mathutils.ScaleMatrix(): please use 2D vectors when scaling in 2D\n"); PyErr_SetString(PyExc_AttributeError, "Mathutils.ScaleMatrix(): please use 2D vectors when scaling in 2D\n");
return NULL; return NULL;
} }
if(!Vector_ReadCallback(vec))
return NULL;
} }
if(vec == NULL) { //scaling along axis if(vec == NULL) { //scaling along axis
if(matSize == 2) { if(matSize == 2) {
@ -645,6 +604,10 @@ static PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * a
PyErr_SetString(PyExc_AttributeError, "Mathutils.OrthoProjectionMatrix(): please use 2D vectors when scaling in 2D\n"); PyErr_SetString(PyExc_AttributeError, "Mathutils.OrthoProjectionMatrix(): please use 2D vectors when scaling in 2D\n");
return NULL; return NULL;
} }
if(!Vector_ReadCallback(vec))
return NULL;
} }
if(vec == NULL) { //ortho projection onto cardinal plane if(vec == NULL) { //ortho projection onto cardinal plane
if(((strcmp(plane, "x") == 0) if(((strcmp(plane, "x") == 0)
@ -891,6 +854,9 @@ static PyObject *M_Mathutils_Intersect( PyObject * self, PyObject * args )
return NULL; return NULL;
} }
if(!Vector_ReadCallback(vec1) || !Vector_ReadCallback(vec2) || !Vector_ReadCallback(vec3) || !Vector_ReadCallback(ray) || !Vector_ReadCallback(ray_off))
return NULL;
VECCOPY(v1, vec1->vec); VECCOPY(v1, vec1->vec);
VECCOPY(v2, vec2->vec); VECCOPY(v2, vec2->vec);
VECCOPY(v3, vec3->vec); VECCOPY(v3, vec3->vec);
@ -959,6 +925,10 @@ static PyObject *M_Mathutils_LineIntersect( PyObject * self, PyObject * args )
PyErr_SetString( PyExc_TypeError,"vectors must be of the same size\n" ); PyErr_SetString( PyExc_TypeError,"vectors must be of the same size\n" );
return NULL; return NULL;
} }
if(!Vector_ReadCallback(vec1) || !Vector_ReadCallback(vec2) || !Vector_ReadCallback(vec3) || !Vector_ReadCallback(vec4))
return NULL;
if( vec1->size == 3 || vec1->size == 2) { if( vec1->size == 3 || vec1->size == 2) {
int result; int result;
@ -1029,6 +999,10 @@ static PyObject *M_Mathutils_QuadNormal( PyObject * self, PyObject * args )
PyErr_SetString( PyExc_TypeError, "only 3D vectors\n" ); PyErr_SetString( PyExc_TypeError, "only 3D vectors\n" );
return NULL; return NULL;
} }
if(!Vector_ReadCallback(vec1) || !Vector_ReadCallback(vec2) || !Vector_ReadCallback(vec3) || !Vector_ReadCallback(vec4))
return NULL;
VECCOPY(v1, vec1->vec); VECCOPY(v1, vec1->vec);
VECCOPY(v2, vec2->vec); VECCOPY(v2, vec2->vec);
VECCOPY(v3, vec3->vec); VECCOPY(v3, vec3->vec);
@ -1073,6 +1047,9 @@ static PyObject *M_Mathutils_TriangleNormal( PyObject * self, PyObject * args )
PyErr_SetString( PyExc_TypeError, "only 3D vectors\n" ); PyErr_SetString( PyExc_TypeError, "only 3D vectors\n" );
return NULL; return NULL;
} }
if(!Vector_ReadCallback(vec1) || !Vector_ReadCallback(vec2) || !Vector_ReadCallback(vec3))
return NULL;
VECCOPY(v1, vec1->vec); VECCOPY(v1, vec1->vec);
VECCOPY(v2, vec2->vec); VECCOPY(v2, vec2->vec);
@ -1105,6 +1082,9 @@ static PyObject *M_Mathutils_TriangleArea( PyObject * self, PyObject * args )
PyErr_SetString( PyExc_TypeError, "vectors must be of the same size\n" ); PyErr_SetString( PyExc_TypeError, "vectors must be of the same size\n" );
return NULL; return NULL;
} }
if(!Vector_ReadCallback(vec1) || !Vector_ReadCallback(vec2) || !Vector_ReadCallback(vec3))
return NULL;
if (vec1->size == 3) { if (vec1->size == 3) {
VECCOPY(v1, vec1->vec); VECCOPY(v1, vec1->vec);
@ -1154,8 +1134,8 @@ int EXPP_FloatsAreEqual(float A, float B, int floatSteps)
} }
/*---------------------- EXPP_VectorsAreEqual ------------------------- /*---------------------- EXPP_VectorsAreEqual -------------------------
Builds on EXPP_FloatsAreEqual to test vectors */ Builds on EXPP_FloatsAreEqual to test vectors */
int EXPP_VectorsAreEqual(float *vecA, float *vecB, int size, int floatSteps){ int EXPP_VectorsAreEqual(float *vecA, float *vecB, int size, int floatSteps)
{
int x; int x;
for (x=0; x< size; x++){ for (x=0; x< size; x++){
if (EXPP_FloatsAreEqual(vecA[x], vecB[x], floatSteps) == 0) if (EXPP_FloatsAreEqual(vecA[x], vecB[x], floatSteps) == 0)
@ -1165,6 +1145,81 @@ int EXPP_VectorsAreEqual(float *vecA, float *vecB, int size, int floatSteps){
} }
/* Mathutils Callbacks */
//####################################################################### /* for mathutils internal use only, eventually should re-alloc but to start with we only have a few users */
//#############################DEPRECATED################################ Mathutils_Callback *mathutils_callbacks[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
int Mathutils_RegisterCallback(Mathutils_Callback *cb)
{
int i;
/* find the first free slot */
for(i= 0; mathutils_callbacks[i]; i++) {
if(mathutils_callbacks[i]==cb) /* alredy registered? */
return i;
}
mathutils_callbacks[i] = cb;
return i;
}
int Vector_ReadCallback(VectorObject *self) {
if(self->user) {
Mathutils_Callback *cb= mathutils_callbacks[self->callback_type];
if(cb->get(self->user, self->subtype, self->vec)) {
return 1;
}
else {
PyErr_SetString(PyExc_SystemError, "Vector user has become invalid");
return 0;
}
}
return 1; /* no user continue silently */
}
int Vector_WriteCallback(VectorObject *self) {
if(self->user) {
Mathutils_Callback *cb= mathutils_callbacks[self->callback_type];
if(cb->set(self->user, self->subtype, self->vec)) {
return 1;
}
else {
PyErr_SetString(PyExc_SystemError, "Vector user has become invalid");
return 0;
}
}
return 1; /* no user continue silently */
}
int Vector_ReadIndexCallback(VectorObject *self, int index) {
if(self->user) {
Mathutils_Callback *cb= mathutils_callbacks[self->callback_type];
if(cb->get_index(self->user, self->subtype, self->vec, index)) {
return 1;
}
else {
PyErr_SetString(PyExc_SystemError, "Vector user has become invalid");
return 0;
}
}
return 1; /* no user continue silently */
}
int Vector_WriteIndexCallback(VectorObject *self, int index) {
if(self->user) {
Mathutils_Callback *cb= mathutils_callbacks[self->callback_type];
if(cb->set_index(self->user, self->subtype, self->vec, index)) {
return 1;
}
else {
PyErr_SetString(PyExc_SystemError, "Vector user has become invalid");
return 0;
}
}
return 1; /* no user continue silently */
}

@ -40,8 +40,6 @@
PyObject *Mathutils_Init( const char * from ); PyObject *Mathutils_Init( const char * from );
PyObject *row_vector_multiplication(VectorObject* vec, MatrixObject * mat);
PyObject *column_vector_multiplication(MatrixObject * mat, VectorObject* vec);
PyObject *quat_rotation(PyObject *arg1, PyObject *arg2); PyObject *quat_rotation(PyObject *arg1, PyObject *arg2);
int EXPP_FloatsAreEqual(float A, float B, int floatSteps); int EXPP_FloatsAreEqual(float A, float B, int floatSteps);
@ -49,8 +47,9 @@ int EXPP_VectorsAreEqual(float *vecA, float *vecB, int size, int floatSteps);
#define Py_PI 3.14159265358979323846 #define Py_PI 3.14159265358979323846
#define Py_WRAP 1024
#define Py_NEW 2048 #define Py_NEW 1
#define Py_WRAP 2
/* Mathutils is used by the BGE and Blender so have to define /* Mathutils is used by the BGE and Blender so have to define
@ -65,4 +64,20 @@ int EXPP_VectorsAreEqual(float *vecA, float *vecB, int size, int floatSteps);
#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True #define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True
#endif #endif
typedef struct Mathutils_Callback Mathutils_Callback;
struct Mathutils_Callback {
int (*check)(PyObject *user); /* checks the user is still valid */
int (*get)(PyObject *user, int subtype, float *vec_from); /* gets the vector from the user */
int (*set)(PyObject *user, int subtype, float *vec_to); /* sets the users vector values once the vector is modified */
int (*get_index)(PyObject *user, int subtype, float *vec_from, int index); /* same as above but only for an index */
int (*set_index)(PyObject *user, int subtype, float *vec_to, int index); /* same as above but only for an index */
};
int Mathutils_RegisterCallback(Mathutils_Callback *cb);
int Vector_ReadCallback(VectorObject *self);
int Vector_WriteCallback(VectorObject *self);
int Vector_ReadIndexCallback(VectorObject *self, int index);
int Vector_WriteIndexCallback(VectorObject *self, int index);
#endif /* EXPP_Mathutils_H */ #endif /* EXPP_Mathutils_H */

@ -31,6 +31,8 @@
#include "BLI_arithb.h" #include "BLI_arithb.h"
#include "BLI_blenlib.h" #include "BLI_blenlib.h"
static PyObject *column_vector_multiplication(MatrixObject * mat, VectorObject* vec); /* utility func */
/*-------------------------DOC STRINGS ---------------------------*/ /*-------------------------DOC STRINGS ---------------------------*/
static char Matrix_Zero_doc[] = "() - set all values in the matrix to 0"; static char Matrix_Zero_doc[] = "() - set all values in the matrix to 0";
static char Matrix_Identity_doc[] = "() - set the square matrix to it's identity matrix"; static char Matrix_Identity_doc[] = "() - set the square matrix to it's identity matrix";
@ -829,7 +831,7 @@ static PyObject *Matrix_mul(PyObject * m1, PyObject * m2)
else /* if(mat1) { */ { else /* if(mat1) { */ {
if(VectorObject_Check(m2)) { /* MATRIX*VECTOR */ if(VectorObject_Check(m2)) { /* MATRIX*VECTOR */
return column_vector_multiplication(mat1, (VectorObject *)m2); return column_vector_multiplication(mat1, (VectorObject *)m2); /* vector update done inside the function */
} }
else { else {
scalar= PyFloat_AsDouble(m2); scalar= PyFloat_AsDouble(m2);
@ -1056,3 +1058,41 @@ PyObject *newMatrixObject(float *mat, int rowSize, int colSize, int type)
} }
return (PyObject *) self; return (PyObject *) self;
} }
//----------------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!!!!
static PyObject *column_vector_multiplication(MatrixObject * mat, VectorObject* vec)
{
float vecNew[4], vecCopy[4];
double dot = 0.0f;
int x, y, z = 0;
if(!Vector_ReadCallback(vec))
return NULL;
if(mat->rowSize != vec->size){
if(mat->rowSize == 4 && vec->size != 3){
PyErr_SetString(PyExc_AttributeError, "matrix * vector: matrix row size and vector size must be the same");
return NULL;
}else{
vecCopy[3] = 1.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++] = (float)dot;
dot = 0.0f;
}
return newVectorObject(vecNew, vec->size, Py_NEW);
}

@ -570,7 +570,7 @@ static PyObject *Quaternion_mul(PyObject * q1, PyObject * q2)
PyErr_SetString(PyExc_TypeError, "Quaternion multiplication: only 3D vector rotations currently supported\n"); PyErr_SetString(PyExc_TypeError, "Quaternion multiplication: only 3D vector rotations currently supported\n");
return NULL; return NULL;
} }
return quat_rotation((PyObject*)quat1, (PyObject*)vec); return quat_rotation((PyObject*)quat1, (PyObject*)vec); /* vector updating done inside the func */
} }
scalar= PyFloat_AsDouble(q2); scalar= PyFloat_AsDouble(q2);

@ -39,6 +39,8 @@
#define SWIZZLE_VALID_AXIS 0x4 #define SWIZZLE_VALID_AXIS 0x4
#define SWIZZLE_AXIS 0x3 #define SWIZZLE_AXIS 0x3
static PyObject *row_vector_multiplication(VectorObject* vec, MatrixObject * mat); /* utility func */
/*-------------------------DOC STRINGS ---------------------------*/ /*-------------------------DOC STRINGS ---------------------------*/
static char Vector_Zero_doc[] = "() - set all values in the vector to 0"; static char Vector_Zero_doc[] = "() - set all values in the vector to 0";
static char Vector_Normalize_doc[] = "() - normalize the vector"; static char Vector_Normalize_doc[] = "() - normalize the vector";
@ -60,7 +62,7 @@ static PyObject *Vector_Resize2D( VectorObject * self );
static PyObject *Vector_Resize3D( VectorObject * self ); static PyObject *Vector_Resize3D( VectorObject * self );
static PyObject *Vector_Resize4D( VectorObject * self ); static PyObject *Vector_Resize4D( VectorObject * self );
static PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args ); static PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args );
static PyObject *Vector_Reflect( VectorObject * self, PyObject * value ); static PyObject *Vector_Reflect( VectorObject *self, VectorObject *value );
static PyObject *Vector_Cross( VectorObject * self, VectorObject * value ); static PyObject *Vector_Cross( VectorObject * self, VectorObject * value );
static PyObject *Vector_Dot( VectorObject * self, VectorObject * value ); static PyObject *Vector_Dot( VectorObject * self, VectorObject * value );
static PyObject *Vector_copy( VectorObject * self ); static PyObject *Vector_copy( VectorObject * self );
@ -141,6 +143,8 @@ static PyObject *Vector_Zero(VectorObject * self)
for(i = 0; i < self->size; i++) { for(i = 0; i < self->size; i++) {
self->vec[i] = 0.0f; self->vec[i] = 0.0f;
} }
Vector_WriteCallback(self);
Py_INCREF(self); Py_INCREF(self);
return (PyObject*)self; return (PyObject*)self;
} }
@ -151,6 +155,9 @@ static PyObject *Vector_Normalize(VectorObject * self)
int i; int i;
float norm = 0.0f; float norm = 0.0f;
if(!Vector_ReadCallback(self))
return NULL;
for(i = 0; i < self->size; i++) { for(i = 0; i < self->size; i++) {
norm += self->vec[i] * self->vec[i]; norm += self->vec[i] * self->vec[i];
} }
@ -158,6 +165,8 @@ static PyObject *Vector_Normalize(VectorObject * self)
for(i = 0; i < self->size; i++) { for(i = 0; i < self->size; i++) {
self->vec[i] /= norm; self->vec[i] /= norm;
} }
Vector_WriteCallback(self);
Py_INCREF(self); Py_INCREF(self);
return (PyObject*)self; return (PyObject*)self;
} }
@ -171,6 +180,11 @@ static PyObject *Vector_Resize2D(VectorObject * self)
PyErr_SetString(PyExc_TypeError, "vector.resize2d(): cannot resize wrapped data - only python vectors\n"); PyErr_SetString(PyExc_TypeError, "vector.resize2d(): cannot resize wrapped data - only python vectors\n");
return NULL; return NULL;
} }
if(self->user) {
PyErr_SetString(PyExc_TypeError, "vector.resize4d(): cannot resize a vector that has an owner");
return NULL;
}
self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 2)); self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 2));
if(self->vec == NULL) { if(self->vec == NULL) {
PyErr_SetString(PyExc_MemoryError, "vector.resize2d(): problem allocating pointer space\n\n"); PyErr_SetString(PyExc_MemoryError, "vector.resize2d(): problem allocating pointer space\n\n");
@ -189,6 +203,11 @@ static PyObject *Vector_Resize3D(VectorObject * self)
PyErr_SetString(PyExc_TypeError, "vector.resize3d(): cannot resize wrapped data - only python vectors\n"); PyErr_SetString(PyExc_TypeError, "vector.resize3d(): cannot resize wrapped data - only python vectors\n");
return NULL; return NULL;
} }
if(self->user) {
PyErr_SetString(PyExc_TypeError, "vector.resize4d(): cannot resize a vector that has an owner");
return NULL;
}
self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 3)); self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 3));
if(self->vec == NULL) { if(self->vec == NULL) {
PyErr_SetString(PyExc_MemoryError, "vector.resize3d(): problem allocating pointer space\n\n"); PyErr_SetString(PyExc_MemoryError, "vector.resize3d(): problem allocating pointer space\n\n");
@ -210,6 +229,11 @@ static PyObject *Vector_Resize4D(VectorObject * self)
PyErr_SetString(PyExc_TypeError, "vector.resize4d(): cannot resize wrapped data - only python vectors"); PyErr_SetString(PyExc_TypeError, "vector.resize4d(): cannot resize wrapped data - only python vectors");
return NULL; return NULL;
} }
if(self->user) {
PyErr_SetString(PyExc_TypeError, "vector.resize4d(): cannot resize a vector that has an owner");
return NULL;
}
self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 4)); self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 4));
if(self->vec == NULL) { if(self->vec == NULL) {
PyErr_SetString(PyExc_MemoryError, "vector.resize4d(): problem allocating pointer space\n\n"); PyErr_SetString(PyExc_MemoryError, "vector.resize4d(): problem allocating pointer space\n\n");
@ -241,6 +265,9 @@ static PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args )
PyErr_SetString( PyExc_TypeError, "only for 3D vectors\n" ); PyErr_SetString( PyExc_TypeError, "only for 3D vectors\n" );
return NULL; return NULL;
} }
if(!Vector_ReadCallback(self))
return NULL;
if (strack) { if (strack) {
if (strlen(strack) == 2) { if (strlen(strack) == 2) {
@ -342,9 +369,8 @@ static PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args )
return a reflected vector on the mirror normal return a reflected vector on the mirror normal
((2 * DotVecs(vec, mirror)) * mirror) - vec ((2 * DotVecs(vec, mirror)) * mirror) - vec
using arithb.c would be nice here */ using arithb.c would be nice here */
static PyObject *Vector_Reflect( VectorObject * self, PyObject * value ) static PyObject *Vector_Reflect( VectorObject * self, VectorObject * value )
{ {
VectorObject *mirrvec;
float mirror[3]; float mirror[3];
float vec[3]; float vec[3];
float reflect[4] = {0.0f, 0.0f, 0.0f, 0.0f}; float reflect[4] = {0.0f, 0.0f, 0.0f, 0.0f};
@ -358,11 +384,13 @@ static PyObject *Vector_Reflect( VectorObject * self, PyObject * value )
PyErr_SetString( PyExc_TypeError, "vec.reflect(value): expected a vector argument" ); PyErr_SetString( PyExc_TypeError, "vec.reflect(value): expected a vector argument" );
return NULL; return NULL;
} }
mirrvec = (VectorObject *)value;
mirror[0] = mirrvec->vec[0]; if(!Vector_ReadCallback(self) || !Vector_ReadCallback(value))
mirror[1] = mirrvec->vec[1]; return NULL;
if (mirrvec->size > 2) mirror[2] = mirrvec->vec[2];
mirror[0] = value->vec[0];
mirror[1] = value->vec[1];
if (value->size > 2) mirror[2] = value->vec[2];
else mirror[2] = 0.0; else mirror[2] = 0.0;
/* normalize, whos idea was it not to use arithb.c? :-/ */ /* normalize, whos idea was it not to use arithb.c? :-/ */
@ -403,6 +431,9 @@ static PyObject *Vector_Cross( VectorObject * self, VectorObject * value )
return NULL; return NULL;
} }
if(!Vector_ReadCallback(self) || !Vector_ReadCallback(value))
return NULL;
vecCross = (VectorObject *)newVectorObject(NULL, 3, Py_NEW); vecCross = (VectorObject *)newVectorObject(NULL, 3, Py_NEW);
Crossf(vecCross->vec, self->vec, value->vec); Crossf(vecCross->vec, self->vec, value->vec);
return (PyObject *)vecCross; return (PyObject *)vecCross;
@ -423,6 +454,9 @@ static PyObject *Vector_Dot( VectorObject * self, VectorObject * value )
return NULL; return NULL;
} }
if(!Vector_ReadCallback(self) || !Vector_ReadCallback(value))
return NULL;
for(x = 0; x < self->size; x++) { for(x = 0; x < self->size; x++) {
dot += self->vec[x] * value->vec[x]; dot += self->vec[x] * value->vec[x];
} }
@ -433,6 +467,9 @@ static PyObject *Vector_Dot( VectorObject * self, VectorObject * value )
return a copy of the vector */ return a copy of the vector */
static PyObject *Vector_copy(VectorObject * self) static PyObject *Vector_copy(VectorObject * self)
{ {
if(!Vector_ReadCallback(self))
return NULL;
return newVectorObject(self->vec, self->size, Py_NEW); return newVectorObject(self->vec, self->size, Py_NEW);
} }
@ -444,6 +481,7 @@ static void Vector_dealloc(VectorObject * self)
if(self->wrapped != Py_WRAP){ if(self->wrapped != Py_WRAP){
PyMem_Free(self->vec); PyMem_Free(self->vec);
} }
Py_XDECREF(self->user);
PyObject_DEL(self); PyObject_DEL(self);
} }
@ -454,6 +492,9 @@ static PyObject *Vector_repr(VectorObject * self)
int i; int i;
char buffer[48], str[1024]; char buffer[48], str[1024];
if(!Vector_ReadCallback(self))
return NULL;
BLI_strncpy(str,"[",1024); BLI_strncpy(str,"[",1024);
for(i = 0; i < self->size; i++){ for(i = 0; i < self->size; i++){
if(i < (self->size - 1)){ if(i < (self->size - 1)){
@ -484,6 +525,9 @@ static PyObject *Vector_item(VectorObject * self, int i)
return NULL; return NULL;
} }
if(!Vector_ReadIndexCallback(self, i))
return NULL;
return PyFloat_FromDouble(self->vec[i]); return PyFloat_FromDouble(self->vec[i]);
} }
@ -502,6 +546,9 @@ static int Vector_ass_item(VectorObject * self, int i, PyObject * ob)
return -1; return -1;
} }
self->vec[i] = scalar; self->vec[i] = scalar;
if(!Vector_WriteIndexCallback(self, i))
return -1;
return 0; return 0;
} }
@ -512,6 +559,9 @@ static PyObject *Vector_slice(VectorObject * self, int begin, int end)
PyObject *list = NULL; PyObject *list = NULL;
int count; int count;
if(!Vector_ReadCallback(self))
return NULL;
CLAMP(begin, 0, self->size); CLAMP(begin, 0, self->size);
if (end<0) end= self->size+end+1; if (end<0) end= self->size+end+1;
CLAMP(end, 0, self->size); CLAMP(end, 0, self->size);
@ -534,6 +584,9 @@ static int Vector_ass_slice(VectorObject * self, int begin, int end,
float vec[4], scalar; float vec[4], scalar;
PyObject *v; PyObject *v;
if(!Vector_ReadCallback(self))
return -1;
CLAMP(begin, 0, self->size); CLAMP(begin, 0, self->size);
if (end<0) end= self->size+end+1; if (end<0) end= self->size+end+1;
CLAMP(end, 0, self->size); CLAMP(end, 0, self->size);
@ -566,6 +619,10 @@ static int Vector_ass_slice(VectorObject * self, int begin, int end,
for(y = 0; y < size; y++){ for(y = 0; y < size; y++){
self->vec[begin + y] = vec[y]; self->vec[begin + y] = vec[y];
} }
if(!Vector_WriteCallback(self))
return -1;
return 0; return 0;
} }
/*------------------------NUMERIC PROTOCOLS---------------------- /*------------------------NUMERIC PROTOCOLS----------------------
@ -586,6 +643,10 @@ static PyObject *Vector_add(PyObject * v1, PyObject * v2)
/* make sure v1 is always the vector */ /* make sure v1 is always the vector */
if (vec1 && vec2 ) { if (vec1 && vec2 ) {
if(!Vector_ReadCallback(vec1) || !Vector_ReadCallback(vec2))
return NULL;
/*VECTOR + VECTOR*/ /*VECTOR + VECTOR*/
if(vec1->size != vec2->size) { if(vec1->size != vec2->size) {
PyErr_SetString(PyExc_AttributeError, "Vector addition: vectors must have the same dimensions for this operation\n"); PyErr_SetString(PyExc_AttributeError, "Vector addition: vectors must have the same dimensions for this operation\n");
@ -617,6 +678,10 @@ static PyObject *Vector_iadd(PyObject * v1, PyObject * v2)
/* make sure v1 is always the vector */ /* make sure v1 is always the vector */
if (vec1 && vec2 ) { if (vec1 && vec2 ) {
if(!Vector_ReadCallback(vec1) || !Vector_ReadCallback(vec2))
return NULL;
/*VECTOR + VECTOR*/ /*VECTOR + VECTOR*/
if(vec1->size != vec2->size) { if(vec1->size != vec2->size) {
PyErr_SetString(PyExc_AttributeError, "Vector addition: vectors must have the same dimensions for this operation\n"); PyErr_SetString(PyExc_AttributeError, "Vector addition: vectors must have the same dimensions for this operation\n");
@ -629,6 +694,7 @@ static PyObject *Vector_iadd(PyObject * v1, PyObject * v2)
return v1; return v1;
} }
Vector_WriteCallback(vec1);
PyErr_SetString(PyExc_AttributeError, "Vector addition: arguments not valid for this operation....\n"); PyErr_SetString(PyExc_AttributeError, "Vector addition: arguments not valid for this operation....\n");
return NULL; return NULL;
} }
@ -648,6 +714,9 @@ static PyObject *Vector_sub(PyObject * v1, PyObject * v2)
vec1 = (VectorObject*)v1; vec1 = (VectorObject*)v1;
vec2 = (VectorObject*)v2; vec2 = (VectorObject*)v2;
if(!Vector_ReadCallback(vec1) || !Vector_ReadCallback(vec2))
return NULL;
if(vec1->size != vec2->size) { if(vec1->size != vec2->size) {
PyErr_SetString(PyExc_AttributeError, "Vector subtraction: vectors must have the same dimensions for this operation\n"); PyErr_SetString(PyExc_AttributeError, "Vector subtraction: vectors must have the same dimensions for this operation\n");
return NULL; return NULL;
@ -663,7 +732,7 @@ static PyObject *Vector_sub(PyObject * v1, PyObject * v2)
subtraction*/ subtraction*/
static PyObject *Vector_isub(PyObject * v1, PyObject * v2) static PyObject *Vector_isub(PyObject * v1, PyObject * v2)
{ {
int i, size; int i;
VectorObject *vec1 = NULL, *vec2 = NULL; VectorObject *vec1 = NULL, *vec2 = NULL;
if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) { if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) {
@ -677,12 +746,15 @@ static PyObject *Vector_isub(PyObject * v1, PyObject * v2)
PyErr_SetString(PyExc_AttributeError, "Vector subtraction: vectors must have the same dimensions for this operation\n"); PyErr_SetString(PyExc_AttributeError, "Vector subtraction: vectors must have the same dimensions for this operation\n");
return NULL; return NULL;
} }
if(!Vector_ReadCallback(vec1) || !Vector_ReadCallback(vec2))
return NULL;
size = vec1->size;
for(i = 0; i < vec1->size; i++) { for(i = 0; i < vec1->size; i++) {
vec1->vec[i] = vec1->vec[i] - vec2->vec[i]; vec1->vec[i] = vec1->vec[i] - vec2->vec[i];
} }
Vector_WriteCallback(vec1);
Py_INCREF( v1 ); Py_INCREF( v1 );
return v1; return v1;
} }
@ -694,11 +766,17 @@ static PyObject *Vector_mul(PyObject * v1, PyObject * v2)
VectorObject *vec1 = NULL, *vec2 = NULL; VectorObject *vec1 = NULL, *vec2 = NULL;
float scalar; float scalar;
if VectorObject_Check(v1) if VectorObject_Check(v1) {
vec1= (VectorObject *)v1; vec1= (VectorObject *)v1;
if(!Vector_ReadCallback(vec1))
if VectorObject_Check(v2) return NULL;
}
if VectorObject_Check(v2) {
vec2= (VectorObject *)v2; vec2= (VectorObject *)v2;
if(!Vector_ReadCallback(vec2))
return NULL;
}
/* make sure v1 is always the vector */ /* make sure v1 is always the vector */
if (vec1 && vec2 ) { if (vec1 && vec2 ) {
@ -757,6 +835,9 @@ static PyObject *Vector_imul(PyObject * v1, PyObject * v2)
int i; int i;
float scalar; float scalar;
if(!Vector_ReadCallback(vec))
return NULL;
/* only support vec*=float and vec*=mat /* only support vec*=float and vec*=mat
vec*=vec result is a float so that wont work */ vec*=vec result is a float so that wont work */
if (MatrixObject_Check(v2)) { if (MatrixObject_Check(v2)) {
@ -787,22 +868,21 @@ static PyObject *Vector_imul(PyObject * v1, PyObject * v2)
} }
vec->vec[i] = (float)dot; vec->vec[i] = (float)dot;
} }
Py_INCREF( v1 );
return v1;
} }
else if (((scalar= PyFloat_AsDouble(v2)) == -1.0 && PyErr_Occurred())==0) { /* VEC*=FLOAT */ else if (((scalar= PyFloat_AsDouble(v2)) == -1.0 && PyErr_Occurred())==0) { /* VEC*=FLOAT */
for(i = 0; i < vec->size; i++) { for(i = 0; i < vec->size; i++) {
vec->vec[i] *= scalar; vec->vec[i] *= scalar;
} }
}
Py_INCREF( v1 ); else {
return v1; PyErr_SetString(PyExc_TypeError, "Vector multiplication: arguments not acceptable for this operation\n");
return NULL;
} }
PyErr_SetString(PyExc_TypeError, "Vector multiplication: arguments not acceptable for this operation\n"); Vector_WriteCallback(vec);
return NULL; Py_INCREF( v1 );
return v1;
} }
/*------------------------obj / obj------------------------------ /*------------------------obj / obj------------------------------
@ -819,6 +899,9 @@ static PyObject *Vector_div(PyObject * v1, PyObject * v2)
} }
vec1 = (VectorObject*)v1; /* vector */ vec1 = (VectorObject*)v1; /* vector */
if(!Vector_ReadCallback(vec1))
return NULL;
scalar = (float)PyFloat_AsDouble(v2); scalar = (float)PyFloat_AsDouble(v2);
if(scalar== -1.0f && PyErr_Occurred()) { /* parsed item not a number */ if(scalar== -1.0f && PyErr_Occurred()) { /* parsed item not a number */
PyErr_SetString(PyExc_TypeError, "Vector division: Vector must be divided by a float\n"); PyErr_SetString(PyExc_TypeError, "Vector division: Vector must be divided by a float\n");
@ -842,14 +925,10 @@ static PyObject *Vector_idiv(PyObject * v1, PyObject * v2)
{ {
int i; int i;
float scalar; float scalar;
VectorObject *vec1 = NULL; VectorObject *vec1 = (VectorObject*)v1;
/*if(!VectorObject_Check(v1)) { if(!Vector_ReadCallback(vec1))
PyErr_SetString(PyExc_TypeError, "Vector division: Vector must be divided by a float\n"); return NULL;
return -1;
}*/
vec1 = (VectorObject*)v1; /* vector */
scalar = (float)PyFloat_AsDouble(v2); scalar = (float)PyFloat_AsDouble(v2);
if(scalar==-1.0f && PyErr_Occurred()) { /* parsed item not a number */ if(scalar==-1.0f && PyErr_Occurred()) { /* parsed item not a number */
@ -864,6 +943,9 @@ static PyObject *Vector_idiv(PyObject * v1, PyObject * v2)
for(i = 0; i < vec1->size; i++) { for(i = 0; i < vec1->size; i++) {
vec1->vec[i] /= scalar; vec1->vec[i] /= scalar;
} }
Vector_WriteCallback(vec1);
Py_INCREF( v1 ); Py_INCREF( v1 );
return v1; return v1;
} }
@ -874,6 +956,10 @@ static PyObject *Vector_neg(VectorObject *self)
{ {
int i; int i;
float vec[4]; float vec[4];
if(!Vector_ReadCallback(self))
return NULL;
for(i = 0; i < self->size; i++){ for(i = 0; i < self->size; i++){
vec[i] = -self->vec[i]; vec[i] = -self->vec[i];
} }
@ -919,6 +1005,9 @@ static PyObject* Vector_richcmpr(PyObject *objectA, PyObject *objectB, int compa
vecA = (VectorObject*)objectA; vecA = (VectorObject*)objectA;
vecB = (VectorObject*)objectB; vecB = (VectorObject*)objectB;
if(!Vector_ReadCallback(vecA) || !Vector_ReadCallback(vecB))
return NULL;
if (vecA->size != vecB->size){ if (vecA->size != vecB->size){
if (comparison_type == Py_NE){ if (comparison_type == Py_NE){
Py_RETURN_TRUE; Py_RETURN_TRUE;
@ -1045,66 +1134,12 @@ static PyNumberMethods Vector_NumMethods = {
static PyObject *Vector_getAxis( VectorObject * self, void *type ) static PyObject *Vector_getAxis( VectorObject * self, void *type )
{ {
switch( (long)type ) { return Vector_item(self, (int)type);
case 'X': /* these are backwards, but that how it works */
return PyFloat_FromDouble(self->vec[0]);
case 'Y':
return PyFloat_FromDouble(self->vec[1]);
case 'Z': /* these are backwards, but that how it works */
if(self->size < 3) {
PyErr_SetString(PyExc_AttributeError, "vector.z: error, cannot get this axis for a 2D vector\n");
return NULL;
}
else {
return PyFloat_FromDouble(self->vec[2]);
}
case 'W':
if(self->size < 4) {
PyErr_SetString(PyExc_AttributeError, "vector.w: error, cannot get this axis for a 3D vector\n");
return NULL;
}
return PyFloat_FromDouble(self->vec[3]);
default:
{
PyErr_SetString( PyExc_RuntimeError, "undefined type in Vector_getAxis" );
return NULL;
}
}
} }
static int Vector_setAxis( VectorObject * self, PyObject * value, void * type ) static int Vector_setAxis( VectorObject * self, PyObject * value, void * type )
{ {
float param= (float)PyFloat_AsDouble( value ); return Vector_ass_item(self, (int)type, value);
if (param==-1 && PyErr_Occurred()) {
PyErr_SetString( PyExc_TypeError, "expected a number for the vector axis" );
return -1;
}
switch( (long)type ) {
case 'X': /* these are backwards, but that how it works */
self->vec[0]= param;
break;
case 'Y':
self->vec[1]= param;
break;
case 'Z': /* these are backwards, but that how it works */
if(self->size < 3) {
PyErr_SetString(PyExc_AttributeError, "vector.z: error, cannot get this axis for a 2D vector\n");
return -1;
}
self->vec[2]= param;
break;
case 'W':
if(self->size < 4) {
PyErr_SetString(PyExc_AttributeError, "vector.w: error, cannot get this axis for a 3D vector\n");
return -1;
}
self->vec[3]= param;
break;
}
return 0;
} }
/* vector.length */ /* vector.length */
@ -1113,6 +1148,9 @@ static PyObject *Vector_getLength( VectorObject * self, void *type )
double dot = 0.0f; double dot = 0.0f;
int i; int i;
if(!Vector_ReadCallback(self))
return NULL;
for(i = 0; i < self->size; i++){ for(i = 0; i < self->size; i++){
dot += (self->vec[i] * self->vec[i]); dot += (self->vec[i] * self->vec[i]);
} }
@ -1124,6 +1162,9 @@ static int Vector_setLength( VectorObject * self, PyObject * value )
double dot = 0.0f, param; double dot = 0.0f, param;
int i; int i;
if(!Vector_ReadCallback(self))
return -1;
param= PyFloat_AsDouble( value ); param= PyFloat_AsDouble( value );
if(param==-1.0 && PyErr_Occurred()) { if(param==-1.0 && PyErr_Occurred()) {
PyErr_SetString(PyExc_TypeError, "length must be set to a number"); PyErr_SetString(PyExc_TypeError, "length must be set to a number");
@ -1159,6 +1200,8 @@ static int Vector_setLength( VectorObject * self, PyObject * value )
self->vec[i]= self->vec[i] / (float)dot; self->vec[i]= self->vec[i] / (float)dot;
} }
Vector_WriteCallback(self); /* checked alredy */
return 0; return 0;
} }
@ -1170,6 +1213,16 @@ static PyObject *Vector_getWrapped( VectorObject * self, void *type )
Py_RETURN_FALSE; Py_RETURN_FALSE;
} }
static PyObject *Vector_getOwner( VectorObject * self, void *type )
{
if(self->user==NULL) {
Py_RETURN_NONE;
}
else {
Py_INCREF(self->user);
return self->user;
}
}
/* Get a new Vector according to the provided swizzle. This function has little /* Get a new Vector according to the provided swizzle. This function has little
error checking, as we are in control of the inputs: the closure is set by us error checking, as we are in control of the inputs: the closure is set by us
@ -1181,6 +1234,9 @@ static PyObject *Vector_getSwizzle(VectorObject * self, void *closure)
float vec[MAX_DIMENSIONS]; float vec[MAX_DIMENSIONS];
unsigned int swizzleClosure; unsigned int swizzleClosure;
if(!Vector_ReadCallback(self))
return NULL;
/* Unpack the axes from the closure into an array. */ /* Unpack the axes from the closure into an array. */
axisA = 0; axisA = 0;
swizzleClosure = (unsigned int) closure; swizzleClosure = (unsigned int) closure;
@ -1218,6 +1274,9 @@ static int Vector_setSwizzle(VectorObject * self, PyObject * value, void *closur
float vecTemp[MAX_DIMENSIONS]; float vecTemp[MAX_DIMENSIONS];
if(!Vector_ReadCallback(self))
return -1;
/* Check that the closure can be used with this vector: even 2D vectors have /* Check that the closure can be used with this vector: even 2D vectors have
swizzles defined for axes z and w, but they would be invalid. */ swizzles defined for axes z and w, but they would be invalid. */
swizzleClosure = (unsigned int) closure; swizzleClosure = (unsigned int) closure;
@ -1247,7 +1306,7 @@ static int Vector_setSwizzle(VectorObject * self, PyObject * value, void *closur
axisB++; axisB++;
} }
memcpy(self->vec, vecTemp, axisB * sizeof(float)); memcpy(self->vec, vecTemp, axisB * sizeof(float));
return 0; /* continue with Vector_WriteCallback at the end */
} }
else if (PyList_Check(value)) else if (PyList_Check(value))
{ {
@ -1273,7 +1332,7 @@ static int Vector_setSwizzle(VectorObject * self, PyObject * value, void *closur
axisB++; axisB++;
} }
memcpy(self->vec, vecTemp, axisB * sizeof(float)); memcpy(self->vec, vecTemp, axisB * sizeof(float));
return 0; /* continue with Vector_WriteCallback at the end */
} }
else if (((scalarVal = (float)PyFloat_AsDouble(value)) == -1.0 && PyErr_Occurred())==0) else if (((scalarVal = (float)PyFloat_AsDouble(value)) == -1.0 && PyErr_Occurred())==0)
{ {
@ -1286,13 +1345,17 @@ static int Vector_setSwizzle(VectorObject * self, PyObject * value, void *closur
swizzleClosure = swizzleClosure >> SWIZZLE_BITS_PER_AXIS; swizzleClosure = swizzleClosure >> SWIZZLE_BITS_PER_AXIS;
} }
return 0; /* continue with Vector_WriteCallback at the end */
} }
else else {
{
PyErr_SetString( PyExc_TypeError, "Expected a Vector, list or scalar value." ); PyErr_SetString( PyExc_TypeError, "Expected a Vector, list or scalar value." );
return -1; return -1;
} }
if(!Vector_WriteCallback(vecVal))
return -1;
else
return 0;
} }
/*****************************************************************************/ /*****************************************************************************/
@ -1302,19 +1365,19 @@ static PyGetSetDef Vector_getseters[] = {
{"x", {"x",
(getter)Vector_getAxis, (setter)Vector_setAxis, (getter)Vector_getAxis, (setter)Vector_setAxis,
"Vector X axis", "Vector X axis",
(void *)'X'}, (void *)0},
{"y", {"y",
(getter)Vector_getAxis, (setter)Vector_setAxis, (getter)Vector_getAxis, (setter)Vector_setAxis,
"Vector Y axis", "Vector Y axis",
(void *)'Y'}, (void *)1},
{"z", {"z",
(getter)Vector_getAxis, (setter)Vector_setAxis, (getter)Vector_getAxis, (setter)Vector_setAxis,
"Vector Z axis", "Vector Z axis",
(void *)'Z'}, (void *)2},
{"w", {"w",
(getter)Vector_getAxis, (setter)Vector_setAxis, (getter)Vector_getAxis, (setter)Vector_setAxis,
"Vector Z axis", "Vector Z axis",
(void *)'W'}, (void *)3},
{"length", {"length",
(getter)Vector_getLength, (setter)Vector_setLength, (getter)Vector_getLength, (setter)Vector_setLength,
"Vector Length", "Vector Length",
@ -1327,6 +1390,10 @@ static PyGetSetDef Vector_getseters[] = {
(getter)Vector_getWrapped, (setter)NULL, (getter)Vector_getWrapped, (setter)NULL,
"True when this wraps blenders internal data", "True when this wraps blenders internal data",
NULL}, NULL},
{"__owner__",
(getter)Vector_getOwner, (setter)NULL,
"Read only owner for vectors that depend on another object",
NULL},
/* autogenerated swizzle attrs, see python script below */ /* autogenerated swizzle attrs, see python script below */
{"xx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, Vector_swizzle_doc, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 36 */ {"xx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, Vector_swizzle_doc, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 36 */
@ -1843,20 +1910,72 @@ PyObject *newVectorObject(float *vec, int size, int type)
return (PyObject *) self; return (PyObject *) self;
} }
/* PyObject *newVectorObject_cb(PyObject *user, int size, int callback_type, int subtype)
#############################DEPRECATED################################ {
####################################################################### float dummy[4] = {0.0, 0.0, 0.0, 0.0}; /* the same vector is used because its set each time by the user callback, saves a little ram */
----------------------------Vector.negate() -------------------- VectorObject *self= newVectorObject(dummy, size, Py_NEW);
if(self) {
Py_INCREF(user);
self->user= user;
self->callback_type = (unsigned char)callback_type;
self->subtype = (unsigned char)subtype;
}
return self;
}
//-----------------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!!!!
static PyObject *row_vector_multiplication(VectorObject* vec, MatrixObject * mat)
{
float vecNew[4], vecCopy[4];
double dot = 0.0f;
int x, y, z = 0, vec_size = vec->size;
if(mat->colSize != vec_size){
if(mat->rowSize == 4 && vec_size != 3){
PyErr_SetString(PyExc_AttributeError, "vector * matrix: matrix column size and the vector size must be the same");
return NULL;
}else{
vecCopy[3] = 1.0f;
}
}
if(!Vector_ReadCallback(vec))
return NULL;
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++] = (float)dot;
dot = 0.0f;
}
return newVectorObject(vecNew, vec_size, Py_NEW);
}
/*----------------------------Vector.negate() --------------------
set the vector to it's negative -x, -y, -z */ set the vector to it's negative -x, -y, -z */
static PyObject *Vector_Negate(VectorObject * self) static PyObject *Vector_Negate(VectorObject * self)
{ {
int i; int i;
for(i = 0; i < self->size; i++) { if(!Vector_ReadCallback(self))
return NULL;
for(i = 0; i < self->size; i++)
self->vec[i] = -(self->vec[i]); self->vec[i] = -(self->vec[i]);
}
/*printf("Vector.negate(): Deprecated: use -vector instead\n");*/ Vector_WriteCallback(self); // alredy checked for error
Py_INCREF(self); Py_INCREF(self);
return (PyObject*)self; return (PyObject*)self;
} }
/*###################################################################
###########################DEPRECATED##############################*/

@ -39,12 +39,17 @@ extern PyTypeObject vector_Type;
typedef struct { typedef struct {
PyObject_VAR_HEAD PyObject_VAR_HEAD
float *vec; /*1D array of data (alias), wrapped status depends on wrapped status */ float *vec; /*1D array of data (alias), wrapped status depends on wrapped status */
short size; /* vec size 2,3 or 4 */ PyObject *user; /* if this vector references another object, otherwise NULL, *Note* this owns its reference */
short wrapped; /* is wrapped data? */ unsigned char size; /* vec size 2,3 or 4 */
unsigned char wrapped; /* wrapped data type? */
unsigned char callback_type; /* which user funcs do we adhere to, RNA, GameObject, etc */
unsigned char subtype; /* subtype: location, rotation... to avoid defining many new functions for every attribute of the same type */
} VectorObject; } VectorObject;
/*prototypes*/ /*prototypes*/
PyObject *newVectorObject(float *vec, int size, int type); PyObject *newVectorObject(float *vec, int size, int type);
PyObject *newVectorObject_cb(PyObject *user, int size, int callback_type, int subtype);
#endif /* EXPP_vector_h */ #endif /* EXPP_vector_h */

@ -39,6 +39,64 @@
#include "BKE_global.h" /* evil G.* */ #include "BKE_global.h" /* evil G.* */
#include "BKE_report.h" #include "BKE_report.h"
#define USE_MATHUTILS
#ifdef USE_MATHUTILS
#include "../generic/Mathutils.h" /* so we can have mathutils callbacks */
static int mathutils_rna_vector_cb_index= -1; /* index for our callbacks */
static int mathutils_rna_vector_check(PyObject *user)
{
return ((BPy_PropertyRNA *)user)->prop?1:0;
}
static int mathutils_rna_vector_get(BPy_PropertyRNA *self, int subtype, float *vec_from)
{
if(self->prop==NULL)
return 0;
RNA_property_float_get_array(&self->ptr, self->prop, vec_from);
return 1;
}
static int mathutils_rna_vector_set(BPy_PropertyRNA *self, int subtype, float *vec_to)
{
if(self->prop==NULL)
return 0;
RNA_property_float_set_array(&self->ptr, self->prop, vec_to);
return 1;
}
static int mathutils_rna_vector_get_index(BPy_PropertyRNA *self, int subtype, float *vec_from, int index)
{
if(self->prop==NULL)
return 0;
vec_from[index]= RNA_property_float_get_index(&self->ptr, self->prop, index);
return 1;
}
static int mathutils_rna_vector_set_index(BPy_PropertyRNA *self, int subtype, float *vec_to, int index)
{
if(self->prop==NULL)
return 0;
RNA_property_float_set_index(&self->ptr, self->prop, index, vec_to[index]);
return 1;
}
Mathutils_Callback mathutils_rna_vector_cb = {
mathutils_rna_vector_check,
mathutils_rna_vector_get,
mathutils_rna_vector_set,
mathutils_rna_vector_get_index,
mathutils_rna_vector_set_index
};
#endif
static int pyrna_struct_compare( BPy_StructRNA * a, BPy_StructRNA * b ) static int pyrna_struct_compare( BPy_StructRNA * a, BPy_StructRNA * b )
{ {
return (a->ptr.data==b->ptr.data) ? 0 : -1; return (a->ptr.data==b->ptr.data) ? 0 : -1;
@ -144,7 +202,22 @@ PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
if (len > 0) { if (len > 0) {
/* resolve the array from a new pytype */ /* resolve the array from a new pytype */
return pyrna_prop_CreatePyObject(ptr, prop); PyObject *ret = pyrna_prop_CreatePyObject(ptr, prop);
#ifdef USE_MATHUTILS
/* return a mathutils vector where possible */
if( RNA_property_type(prop)==PROP_FLOAT &&
RNA_property_subtype(prop)==PROP_VECTOR &&
len>=2 && len <= 4 )
{
PyObject *vec_cb= newVectorObject_cb(ret, len, mathutils_rna_vector_cb_index, 0);
Py_DECREF(ret); /* the vector owns now */
ret= vec_cb; /* return the vector instead */
}
#endif
return ret;
} }
/* see if we can coorce into a python type - PropertyType */ /* see if we can coorce into a python type - PropertyType */
@ -1674,6 +1747,10 @@ PyObject *BPY_rna_module( void )
{ {
PointerRNA ptr; PointerRNA ptr;
#ifdef USE_MATHUTILS // register mathutils callbacks, ok to run more then once.
mathutils_rna_vector_cb_index= Mathutils_RegisterCallback(&mathutils_rna_vector_cb);
#endif
/* This can't be set in the pytype struct because some compilers complain */ /* This can't be set in the pytype struct because some compilers complain */
pyrna_prop_Type.tp_getattro = PyObject_GenericGetAttr; pyrna_prop_Type.tp_getattro = PyObject_GenericGetAttr;
pyrna_prop_Type.tp_setattro = PyObject_GenericSetAttr; pyrna_prop_Type.tp_setattro = PyObject_GenericSetAttr;

@ -171,7 +171,7 @@ void PyObSpit(char *name, PyObject *var) {
else { else {
PyObject_Print(var, stderr, 0); PyObject_Print(var, stderr, 0);
fprintf(stderr, " ref:%d ", var->ob_refcnt); fprintf(stderr, " ref:%d ", var->ob_refcnt);
fprintf(stderr, " ptr:%ld", (long)var); fprintf(stderr, " ptr:%p", (void *)var);
fprintf(stderr, " type:"); fprintf(stderr, " type:");
if(Py_TYPE(var)) if(Py_TYPE(var))

@ -41,6 +41,8 @@
#include "MT_Vector3.h" #include "MT_Vector3.h"
#include "SG_QList.h" #include "SG_QList.h"
#define USE_MATHUTILS // Blender 2.5x api will use mathutils, for a while we might want to test without it
/*------------------------------ /*------------------------------
* Python defines * Python defines
------------------------------*/ ------------------------------*/

@ -1152,6 +1152,139 @@ CListValue* KX_GameObject::GetChildrenRecursive()
} }
#ifdef USE_MATHUTILS
extern "C" {
#include "../../blender/python/generic/Mathutils.h" /* so we can have mathutils callbacks */
}
/* These require an SGNode */
#define MATHUTILS_VEC_CB_POS_LOCAL 1
#define MATHUTILS_VEC_CB_POS_GLOBAL 2
#define MATHUTILS_VEC_CB_SCALE_LOCAL 3
#define MATHUTILS_VEC_CB_SCALE_GLOBAL 4
#define MATHUTILS_VEC_CB_INERTIA_LOCAL 5
static int mathutils_kxgameob_vector_cb_index= -1; /* index for our callbacks */
static int mathutils_kxgameob_vector_check(PyObject *self_v)
{
KX_GameObject* self= static_cast<KX_GameObject*>BGE_PROXY_REF(self_v);
if(self==NULL)
return 0;
return 1;
}
static int mathutils_kxgameob_vector_get(PyObject *self_v, int subtype, float *vec_from)
{
KX_GameObject* self= static_cast<KX_GameObject*>BGE_PROXY_REF(self_v);
if(self==NULL)
return 0;
switch(subtype) {
case MATHUTILS_VEC_CB_POS_LOCAL:
if(!self->GetSGNode()) return 0;
self->GetSGNode()->GetLocalPosition().getValue(vec_from);
break;
case MATHUTILS_VEC_CB_POS_GLOBAL:
if(!self->GetSGNode()) return 0;
self->GetSGNode()->GetWorldPosition().getValue(vec_from);
break;
case MATHUTILS_VEC_CB_SCALE_LOCAL:
if(!self->GetSGNode()) return 0;
self->GetSGNode()->GetLocalScale().getValue(vec_from);
break;
case MATHUTILS_VEC_CB_SCALE_GLOBAL:
self->NodeGetWorldScaling().getValue(vec_from);
break;
case MATHUTILS_VEC_CB_INERTIA_LOCAL:
if(!self->GetSGNode()) return 0;
self->GetPhysicsController()->GetLocalInertia().getValue(vec_from);
break;
}
return 1;
}
static int mathutils_kxgameob_vector_set(PyObject *self_v, int subtype, float *vec_to)
{
KX_GameObject* self= static_cast<KX_GameObject*>BGE_PROXY_REF(self_v);
if(self==NULL)
return 0;
/* first */
SG_Node* sg = self->GetSGNode();
if(sg==NULL)
return 0;
switch(subtype) {
case MATHUTILS_VEC_CB_POS_LOCAL:
self->NodeSetLocalPosition(MT_Point3(vec_to));
self->NodeUpdateGS(0.f);
break;
case MATHUTILS_VEC_CB_POS_GLOBAL:
self->NodeSetWorldPosition(MT_Point3(vec_to));
self->NodeUpdateGS(0.f);
break;
case MATHUTILS_VEC_CB_SCALE_LOCAL:
self->NodeSetLocalScale(MT_Point3(vec_to));
self->NodeUpdateGS(0.f);
break;
case MATHUTILS_VEC_CB_SCALE_GLOBAL:
break;
case MATHUTILS_VEC_CB_INERTIA_LOCAL:
/* read only */
break;
}
return 1;
}
static int mathutils_kxgameob_vector_get_index(PyObject *self_v, int subtype, float *vec_from, int index)
{
float f[4];
/* lazy, avoid repeteing the case statement */
if(!mathutils_kxgameob_vector_get(self_v, subtype, f))
return 0;
vec_from[index]= f[index];
return 1;
}
static int mathutils_kxgameob_vector_set_index(PyObject *self_v, int subtype, float *vec_to, int index)
{
float f= vec_to[index];
/* lazy, avoid repeteing the case statement */
if(!mathutils_kxgameob_vector_get(self_v, subtype, vec_to))
return 0;
vec_to[index]= f;
mathutils_kxgameob_vector_set(self_v, subtype, vec_to);
return 1;
}
Mathutils_Callback mathutils_kxgameob_vector_cb = {
mathutils_kxgameob_vector_check,
mathutils_kxgameob_vector_get,
mathutils_kxgameob_vector_set,
mathutils_kxgameob_vector_get_index,
mathutils_kxgameob_vector_set_index
};
void KX_GameObject_Mathutils_Callback_Init(void)
{
// register mathutils callbacks, ok to run more then once.
mathutils_kxgameob_vector_cb_index= Mathutils_RegisterCallback(&mathutils_kxgameob_vector_cb);
}
#endif // USE_MATHUTILS
/* ------- python stuff ---------------------------------------------------*/ /* ------- python stuff ---------------------------------------------------*/
PyMethodDef KX_GameObject::Methods[] = { PyMethodDef KX_GameObject::Methods[] = {
@ -1596,7 +1729,11 @@ int KX_GameObject::pyattr_set_visible(void *self_v, const KX_PYATTRIBUTE_DEF *at
PyObject* KX_GameObject::pyattr_get_worldPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) PyObject* KX_GameObject::pyattr_get_worldPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{ {
KX_GameObject* self= static_cast<KX_GameObject*>(self_v); KX_GameObject* self= static_cast<KX_GameObject*>(self_v);
#ifdef USE_MATHUTILS
return newVectorObject_cb((PyObject *)self_v, 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_POS_GLOBAL);
#else
return PyObjectFrom(self->NodeGetWorldPosition()); return PyObjectFrom(self->NodeGetWorldPosition());
#endif
} }
int KX_GameObject::pyattr_set_worldPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) int KX_GameObject::pyattr_set_worldPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
@ -1614,10 +1751,14 @@ int KX_GameObject::pyattr_set_worldPosition(void *self_v, const KX_PYATTRIBUTE_D
PyObject* KX_GameObject::pyattr_get_localPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) PyObject* KX_GameObject::pyattr_get_localPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{ {
KX_GameObject* self= static_cast<KX_GameObject*>(self_v); KX_GameObject* self= static_cast<KX_GameObject*>(self_v);
#ifdef USE_MATHUTILS
return newVectorObject_cb((PyObject *)self_v, 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_POS_LOCAL);
#else
if (self->GetSGNode()) if (self->GetSGNode())
return PyObjectFrom(self->GetSGNode()->GetLocalPosition()); return PyObjectFrom(self->GetSGNode()->GetLocalPosition());
else else
return PyObjectFrom(dummy_point); return PyObjectFrom(dummy_point);
#endif
} }
int KX_GameObject::pyattr_set_localPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) int KX_GameObject::pyattr_set_localPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
@ -1635,11 +1776,13 @@ int KX_GameObject::pyattr_set_localPosition(void *self_v, const KX_PYATTRIBUTE_D
PyObject* KX_GameObject::pyattr_get_localInertia(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) PyObject* KX_GameObject::pyattr_get_localInertia(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{ {
KX_GameObject* self= static_cast<KX_GameObject*>(self_v); KX_GameObject* self= static_cast<KX_GameObject*>(self_v);
#ifdef USE_MATHUTILS
return newVectorObject_cb((PyObject *)self_v, 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_INERTIA_LOCAL);
#else
if (self->GetPhysicsController()) if (self->GetPhysicsController())
{
return PyObjectFrom(self->GetPhysicsController()->GetLocalInertia()); return PyObjectFrom(self->GetPhysicsController()->GetLocalInertia());
}
return Py_BuildValue("fff", 0.0f, 0.0f, 0.0f); return Py_BuildValue("fff", 0.0f, 0.0f, 0.0f);
#endif
} }
PyObject* KX_GameObject::pyattr_get_worldOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) PyObject* KX_GameObject::pyattr_get_worldOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
@ -1694,16 +1837,24 @@ int KX_GameObject::pyattr_set_localOrientation(void *self_v, const KX_PYATTRIBUT
PyObject* KX_GameObject::pyattr_get_worldScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) PyObject* KX_GameObject::pyattr_get_worldScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{ {
KX_GameObject* self= static_cast<KX_GameObject*>(self_v); KX_GameObject* self= static_cast<KX_GameObject*>(self_v);
#ifdef USE_MATHUTILS
return newVectorObject_cb((PyObject *)self_v, 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_SCALE_GLOBAL);
#else
return PyObjectFrom(self->NodeGetWorldScaling()); return PyObjectFrom(self->NodeGetWorldScaling());
#endif
} }
PyObject* KX_GameObject::pyattr_get_localScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) PyObject* KX_GameObject::pyattr_get_localScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{ {
KX_GameObject* self= static_cast<KX_GameObject*>(self_v); KX_GameObject* self= static_cast<KX_GameObject*>(self_v);
#ifdef USE_MATHUTILS
return newVectorObject_cb((PyObject *)self_v, 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_SCALE_LOCAL);
#else
if (self->GetSGNode()) if (self->GetSGNode())
return PyObjectFrom(self->GetSGNode()->GetLocalScale()); return PyObjectFrom(self->GetSGNode()->GetLocalScale());
else else
return PyObjectFrom(dummy_scaling); return PyObjectFrom(dummy_scaling);
#endif
} }
int KX_GameObject::pyattr_set_localScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) int KX_GameObject::pyattr_set_localScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)

@ -63,6 +63,10 @@ struct Object;
/* utility conversion function */ /* utility conversion function */
bool ConvertPythonToGameObject(PyObject * value, KX_GameObject **object, bool py_none_ok, const char *error_prefix); bool ConvertPythonToGameObject(PyObject * value, KX_GameObject **object, bool py_none_ok, const char *error_prefix);
#ifdef USE_MATHUTILS
void KX_GameObject_Mathutils_Callback_Init(void);
#endif
/** /**
* KX_GameObject is the main class for dynamic objects. * KX_GameObject is the main class for dynamic objects.
*/ */

@ -231,6 +231,11 @@ void initPyTypes(void)
/* Normal python type */ /* Normal python type */
PyType_Ready(&KX_PythonSeq_Type); PyType_Ready(&KX_PythonSeq_Type);
#ifdef USE_MATHUTILS
/* Init mathutils callbacks */
KX_GameObject_Mathutils_Callback_Init();
#endif
} }
#endif #endif