Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2009-06-22 08:26:48 +0400
committerCampbell Barton <ideasman42@gmail.com>2009-06-22 08:26:48 +0400
commitbce3f7e019c174947a0f98063f39533eb59ab03e (patch)
treebb66802258a156dec4a39f20c900a750fd7b6b55
parent1efffc1f564af0597512699890d7be9f41a6aee2 (diff)
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.
-rw-r--r--source/blender/python/generic/Geometry.c20
-rw-r--r--source/blender/python/generic/Mathutils.c205
-rw-r--r--source/blender/python/generic/Mathutils.h23
-rw-r--r--source/blender/python/generic/matrix.c42
-rw-r--r--source/blender/python/generic/quat.c2
-rw-r--r--source/blender/python/generic/vector.c321
-rw-r--r--source/blender/python/generic/vector.h11
-rw-r--r--source/blender/python/intern/bpy_rna.c79
-rw-r--r--source/blender/python/intern/bpy_util.c2
-rw-r--r--source/gameengine/Expressions/PyObjectPlus.h2
-rw-r--r--source/gameengine/Ketsji/KX_GameObject.cpp155
-rw-r--r--source/gameengine/Ketsji/KX_GameObject.h4
-rw-r--r--source/gameengine/Ketsji/KX_PythonInitTypes.cpp5
13 files changed, 682 insertions, 189 deletions
diff --git a/source/blender/python/generic/Geometry.c b/source/blender/python/generic/Geometry.c
index d1e8b471f75..edc19523da3 100644
--- a/source/blender/python/generic/Geometry.c
+++ b/source/blender/python/generic/Geometry.c
@@ -164,6 +164,10 @@ static PyObject *M_Geometry_PolyFill( PyObject * self, PyObject * polyLineSeq )
for( index = 0; index<len_polypoints; ++index, fp+=3) {
polyVec= PySequence_GetItem( polyLine, index );
if(VectorObject_Check(polyVec)) {
+
+ if(!Vector_ReadCallback((VectorObject *)polyVec))
+ ls_error= 1;
+
fp[0] = ((VectorObject *)polyVec)->vec[0];
fp[1] = ((VectorObject *)polyVec)->vec[1];
if( ((VectorObject *)polyVec)->size > 2 )
@@ -234,6 +238,9 @@ static PyObject *M_Geometry_LineIntersect2D( PyObject * self, PyObject * args )
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];
a1y= line_a1->vec[1];
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" );
return NULL;
}
+
+ if(!Vector_ReadCallback(pt) || !Vector_ReadCallback(line_1) || !Vector_ReadCallback(line_2))
+ return NULL;
+
/* accept 2d verts */
if (pt->size==3) { VECCOPY(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;
}
+ 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));
}
@@ -381,6 +395,9 @@ static PyObject *M_Geometry_PointInQuad2D( PyObject * self, PyObject * args )
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));
}
@@ -500,6 +517,9 @@ static PyObject *M_Geometry_BezierInterp( PyObject * self, PyObject * args )
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);
for(i=0; i < vec_k1->size; i++) k1[i]= vec_k1->vec[i];
diff --git a/source/blender/python/generic/Mathutils.c b/source/blender/python/generic/Mathutils.c
index 3c34a369baf..d5af54ce68e 100644
--- a/source/blender/python/generic/Mathutils.c
+++ b/source/blender/python/generic/Mathutils.c
@@ -141,77 +141,6 @@ PyObject *Mathutils_Init(const char *from)
}
//-----------------------------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)-----------
//This function multiplies a vector/point * quat or vice versa
//to rotate the point/vector by the quaternion
@@ -226,6 +155,10 @@ PyObject *quat_rotation(PyObject *arg1, PyObject *arg2)
quat = (QuaternionObject*)arg1;
if(VectorObject_Check(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] -
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] -
@@ -242,6 +175,10 @@ PyObject *quat_rotation(PyObject *arg1, PyObject *arg2)
}
}else if(VectorObject_Check(arg1)){
vec = (VectorObject*)arg1;
+
+ if(!Vector_ReadCallback(vec))
+ return NULL;
+
if(QuaternionObject_Check(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] -
@@ -308,6 +245,9 @@ static PyObject *M_Mathutils_AngleBetweenVecs(PyObject * self, PyObject * args)
if(vec1->size != vec2->size)
goto AttributeError1; //bad sizes
+ if(!Vector_ReadCallback(vec1) || !Vector_ReadCallback(vec2))
+ return NULL;
+
//since size is the same....
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");
return NULL;
}
+
+ if(!Vector_ReadCallback(vec1) || !Vector_ReadCallback(vec2))
+ return NULL;
for(x = 0; x < vec1->size; 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;
}
+ if(!Vector_ReadCallback(vec1) || !Vector_ReadCallback(vec2))
+ return NULL;
+
+
//since they are the same 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");
return NULL;
}
+
+ if(!Vector_ReadCallback(vec))
+ return NULL;
+
}
//convert to radians
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");
return NULL;
}
+
+ if(!Vector_ReadCallback(vec))
+ return NULL;
+
//create a identity matrix and add translation
Mat4One((float(*)[4]) mat);
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");
return NULL;
}
+
+ if(!Vector_ReadCallback(vec))
+ return NULL;
+
}
if(vec == NULL) { //scaling along axis
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");
return NULL;
}
+
+ if(!Vector_ReadCallback(vec))
+ return NULL;
+
}
if(vec == NULL) { //ortho projection onto cardinal plane
if(((strcmp(plane, "x") == 0)
@@ -891,6 +854,9 @@ static PyObject *M_Mathutils_Intersect( PyObject * self, PyObject * args )
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(v2, vec2->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" );
return NULL;
}
+
+ if(!Vector_ReadCallback(vec1) || !Vector_ReadCallback(vec2) || !Vector_ReadCallback(vec3) || !Vector_ReadCallback(vec4))
+ return NULL;
+
if( vec1->size == 3 || vec1->size == 2) {
int result;
@@ -1029,6 +999,10 @@ static PyObject *M_Mathutils_QuadNormal( PyObject * self, PyObject * args )
PyErr_SetString( PyExc_TypeError, "only 3D vectors\n" );
return NULL;
}
+
+ if(!Vector_ReadCallback(vec1) || !Vector_ReadCallback(vec2) || !Vector_ReadCallback(vec3) || !Vector_ReadCallback(vec4))
+ return NULL;
+
VECCOPY(v1, vec1->vec);
VECCOPY(v2, vec2->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" );
return NULL;
}
+
+ if(!Vector_ReadCallback(vec1) || !Vector_ReadCallback(vec2) || !Vector_ReadCallback(vec3))
+ return NULL;
VECCOPY(v1, vec1->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" );
return NULL;
}
+
+ if(!Vector_ReadCallback(vec1) || !Vector_ReadCallback(vec2) || !Vector_ReadCallback(vec3))
+ return NULL;
if (vec1->size == 3) {
VECCOPY(v1, vec1->vec);
@@ -1154,8 +1134,8 @@ int EXPP_FloatsAreEqual(float A, float B, int floatSteps)
}
/*---------------------- EXPP_VectorsAreEqual -------------------------
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;
for (x=0; x< size; x++){
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 */
+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 */
+}
-//#######################################################################
-//#############################DEPRECATED################################
+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 */
+}
diff --git a/source/blender/python/generic/Mathutils.h b/source/blender/python/generic/Mathutils.h
index e8882c3dac2..07cf029b77c 100644
--- a/source/blender/python/generic/Mathutils.h
+++ b/source/blender/python/generic/Mathutils.h
@@ -40,8 +40,6 @@
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);
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_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
@@ -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
#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 */
diff --git a/source/blender/python/generic/matrix.c b/source/blender/python/generic/matrix.c
index e2ab1c3c653..e8e8bffd419 100644
--- a/source/blender/python/generic/matrix.c
+++ b/source/blender/python/generic/matrix.c
@@ -31,6 +31,8 @@
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
+static PyObject *column_vector_multiplication(MatrixObject * mat, VectorObject* vec); /* utility func */
+
/*-------------------------DOC STRINGS ---------------------------*/
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";
@@ -829,7 +831,7 @@ static PyObject *Matrix_mul(PyObject * m1, PyObject * m2)
else /* if(mat1) { */ {
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 {
scalar= PyFloat_AsDouble(m2);
@@ -1056,3 +1058,41 @@ PyObject *newMatrixObject(float *mat, int rowSize, int colSize, int type)
}
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);
+}
diff --git a/source/blender/python/generic/quat.c b/source/blender/python/generic/quat.c
index 4ad5d07b3b8..4ee984673e8 100644
--- a/source/blender/python/generic/quat.c
+++ b/source/blender/python/generic/quat.c
@@ -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");
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);
diff --git a/source/blender/python/generic/vector.c b/source/blender/python/generic/vector.c
index 562413c6967..ce11149e311 100644
--- a/source/blender/python/generic/vector.c
+++ b/source/blender/python/generic/vector.c
@@ -39,6 +39,8 @@
#define SWIZZLE_VALID_AXIS 0x4
#define SWIZZLE_AXIS 0x3
+static PyObject *row_vector_multiplication(VectorObject* vec, MatrixObject * mat); /* utility func */
+
/*-------------------------DOC STRINGS ---------------------------*/
static char Vector_Zero_doc[] = "() - set all values in the vector to 0";
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_Resize4D( VectorObject * self );
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_Dot( VectorObject * self, VectorObject * value );
static PyObject *Vector_copy( VectorObject * self );
@@ -141,6 +143,8 @@ static PyObject *Vector_Zero(VectorObject * self)
for(i = 0; i < self->size; i++) {
self->vec[i] = 0.0f;
}
+
+ Vector_WriteCallback(self);
Py_INCREF(self);
return (PyObject*)self;
}
@@ -151,6 +155,9 @@ static PyObject *Vector_Normalize(VectorObject * self)
int i;
float norm = 0.0f;
+ if(!Vector_ReadCallback(self))
+ return NULL;
+
for(i = 0; i < self->size; 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++) {
self->vec[i] /= norm;
}
+
+ Vector_WriteCallback(self);
Py_INCREF(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");
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));
if(self->vec == NULL) {
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");
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));
if(self->vec == NULL) {
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");
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));
if(self->vec == NULL) {
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" );
return NULL;
}
+
+ if(!Vector_ReadCallback(self))
+ return NULL;
if (strack) {
if (strlen(strack) == 2) {
@@ -342,9 +369,8 @@ static PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args )
return a reflected vector on the mirror normal
((2 * DotVecs(vec, mirror)) * mirror) - vec
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 vec[3];
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" );
return NULL;
}
- mirrvec = (VectorObject *)value;
- mirror[0] = mirrvec->vec[0];
- mirror[1] = mirrvec->vec[1];
- if (mirrvec->size > 2) mirror[2] = mirrvec->vec[2];
+ if(!Vector_ReadCallback(self) || !Vector_ReadCallback(value))
+ return NULL;
+
+ mirror[0] = value->vec[0];
+ mirror[1] = value->vec[1];
+ if (value->size > 2) mirror[2] = value->vec[2];
else mirror[2] = 0.0;
/* normalize, whos idea was it not to use arithb.c? :-/ */
@@ -403,6 +431,9 @@ static PyObject *Vector_Cross( VectorObject * self, VectorObject * value )
return NULL;
}
+ if(!Vector_ReadCallback(self) || !Vector_ReadCallback(value))
+ return NULL;
+
vecCross = (VectorObject *)newVectorObject(NULL, 3, Py_NEW);
Crossf(vecCross->vec, self->vec, value->vec);
return (PyObject *)vecCross;
@@ -423,6 +454,9 @@ static PyObject *Vector_Dot( VectorObject * self, VectorObject * value )
return NULL;
}
+ if(!Vector_ReadCallback(self) || !Vector_ReadCallback(value))
+ return NULL;
+
for(x = 0; x < self->size; 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 */
static PyObject *Vector_copy(VectorObject * self)
{
+ if(!Vector_ReadCallback(self))
+ return NULL;
+
return newVectorObject(self->vec, self->size, Py_NEW);
}
@@ -444,6 +481,7 @@ static void Vector_dealloc(VectorObject * self)
if(self->wrapped != Py_WRAP){
PyMem_Free(self->vec);
}
+ Py_XDECREF(self->user);
PyObject_DEL(self);
}
@@ -454,6 +492,9 @@ static PyObject *Vector_repr(VectorObject * self)
int i;
char buffer[48], str[1024];
+ if(!Vector_ReadCallback(self))
+ return NULL;
+
BLI_strncpy(str,"[",1024);
for(i = 0; i < self->size; i++){
if(i < (self->size - 1)){
@@ -484,6 +525,9 @@ static PyObject *Vector_item(VectorObject * self, int i)
return NULL;
}
+ if(!Vector_ReadIndexCallback(self, i))
+ return NULL;
+
return PyFloat_FromDouble(self->vec[i]);
}
@@ -502,6 +546,9 @@ static int Vector_ass_item(VectorObject * self, int i, PyObject * ob)
return -1;
}
self->vec[i] = scalar;
+
+ if(!Vector_WriteIndexCallback(self, i))
+ return -1;
return 0;
}
@@ -512,6 +559,9 @@ static PyObject *Vector_slice(VectorObject * self, int begin, int end)
PyObject *list = NULL;
int count;
+ if(!Vector_ReadCallback(self))
+ return NULL;
+
CLAMP(begin, 0, self->size);
if (end<0) end= self->size+end+1;
CLAMP(end, 0, self->size);
@@ -534,6 +584,9 @@ static int Vector_ass_slice(VectorObject * self, int begin, int end,
float vec[4], scalar;
PyObject *v;
+ if(!Vector_ReadCallback(self))
+ return -1;
+
CLAMP(begin, 0, self->size);
if (end<0) end= self->size+end+1;
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++){
self->vec[begin + y] = vec[y];
}
+
+ if(!Vector_WriteCallback(self))
+ return -1;
+
return 0;
}
/*------------------------NUMERIC PROTOCOLS----------------------
@@ -586,6 +643,10 @@ static PyObject *Vector_add(PyObject * v1, PyObject * v2)
/* make sure v1 is always the vector */
if (vec1 && vec2 ) {
+
+ if(!Vector_ReadCallback(vec1) || !Vector_ReadCallback(vec2))
+ return NULL;
+
/*VECTOR + VECTOR*/
if(vec1->size != vec2->size) {
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 */
if (vec1 && vec2 ) {
+
+ if(!Vector_ReadCallback(vec1) || !Vector_ReadCallback(vec2))
+ return NULL;
+
/*VECTOR + VECTOR*/
if(vec1->size != vec2->size) {
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;
}
+ Vector_WriteCallback(vec1);
PyErr_SetString(PyExc_AttributeError, "Vector addition: arguments not valid for this operation....\n");
return NULL;
}
@@ -648,6 +714,9 @@ static PyObject *Vector_sub(PyObject * v1, PyObject * v2)
vec1 = (VectorObject*)v1;
vec2 = (VectorObject*)v2;
+ if(!Vector_ReadCallback(vec1) || !Vector_ReadCallback(vec2))
+ return NULL;
+
if(vec1->size != vec2->size) {
PyErr_SetString(PyExc_AttributeError, "Vector subtraction: vectors must have the same dimensions for this operation\n");
return NULL;
@@ -663,7 +732,7 @@ static PyObject *Vector_sub(PyObject * v1, PyObject * v2)
subtraction*/
static PyObject *Vector_isub(PyObject * v1, PyObject * v2)
{
- int i, size;
+ int i;
VectorObject *vec1 = NULL, *vec2 = NULL;
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");
return NULL;
}
+
+ if(!Vector_ReadCallback(vec1) || !Vector_ReadCallback(vec2))
+ return NULL;
- size = vec1->size;
for(i = 0; i < vec1->size; i++) {
vec1->vec[i] = vec1->vec[i] - vec2->vec[i];
}
+ Vector_WriteCallback(vec1);
Py_INCREF( v1 );
return v1;
}
@@ -694,11 +766,17 @@ static PyObject *Vector_mul(PyObject * v1, PyObject * v2)
VectorObject *vec1 = NULL, *vec2 = NULL;
float scalar;
- if VectorObject_Check(v1)
+ if VectorObject_Check(v1) {
vec1= (VectorObject *)v1;
-
- if VectorObject_Check(v2)
+ if(!Vector_ReadCallback(vec1))
+ return NULL;
+ }
+ if VectorObject_Check(v2) {
vec2= (VectorObject *)v2;
+ if(!Vector_ReadCallback(vec2))
+ return NULL;
+ }
+
/* make sure v1 is always the vector */
if (vec1 && vec2 ) {
@@ -757,6 +835,9 @@ static PyObject *Vector_imul(PyObject * v1, PyObject * v2)
int i;
float scalar;
+ if(!Vector_ReadCallback(vec))
+ return NULL;
+
/* only support vec*=float and vec*=mat
vec*=vec result is a float so that wont work */
if (MatrixObject_Check(v2)) {
@@ -787,22 +868,21 @@ static PyObject *Vector_imul(PyObject * v1, PyObject * v2)
}
vec->vec[i] = (float)dot;
}
- Py_INCREF( v1 );
- return v1;
}
else if (((scalar= PyFloat_AsDouble(v2)) == -1.0 && PyErr_Occurred())==0) { /* VEC*=FLOAT */
for(i = 0; i < vec->size; i++) {
vec->vec[i] *= scalar;
}
-
- Py_INCREF( v1 );
- return v1;
-
+ }
+ else {
+ 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");
- return NULL;
+ Vector_WriteCallback(vec);
+ Py_INCREF( v1 );
+ return v1;
}
/*------------------------obj / obj------------------------------
@@ -819,6 +899,9 @@ static PyObject *Vector_div(PyObject * v1, PyObject * v2)
}
vec1 = (VectorObject*)v1; /* vector */
+ if(!Vector_ReadCallback(vec1))
+ return NULL;
+
scalar = (float)PyFloat_AsDouble(v2);
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");
@@ -842,14 +925,10 @@ static PyObject *Vector_idiv(PyObject * v1, PyObject * v2)
{
int i;
float scalar;
- VectorObject *vec1 = NULL;
+ VectorObject *vec1 = (VectorObject*)v1;
- /*if(!VectorObject_Check(v1)) {
- PyErr_SetString(PyExc_TypeError, "Vector division: Vector must be divided by a float\n");
- return -1;
- }*/
-
- vec1 = (VectorObject*)v1; /* vector */
+ if(!Vector_ReadCallback(vec1))
+ return NULL;
scalar = (float)PyFloat_AsDouble(v2);
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++) {
vec1->vec[i] /= scalar;
}
+
+ Vector_WriteCallback(vec1);
+
Py_INCREF( v1 );
return v1;
}
@@ -874,6 +956,10 @@ static PyObject *Vector_neg(VectorObject *self)
{
int i;
float vec[4];
+
+ if(!Vector_ReadCallback(self))
+ return NULL;
+
for(i = 0; i < self->size; i++){
vec[i] = -self->vec[i];
}
@@ -919,6 +1005,9 @@ static PyObject* Vector_richcmpr(PyObject *objectA, PyObject *objectB, int compa
vecA = (VectorObject*)objectA;
vecB = (VectorObject*)objectB;
+ if(!Vector_ReadCallback(vecA) || !Vector_ReadCallback(vecB))
+ return NULL;
+
if (vecA->size != vecB->size){
if (comparison_type == Py_NE){
Py_RETURN_TRUE;
@@ -1045,66 +1134,12 @@ static PyNumberMethods Vector_NumMethods = {
static PyObject *Vector_getAxis( VectorObject * self, void *type )
{
- switch( (long)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;
- }
- }
+ return Vector_item(self, (int)type);
}
static int Vector_setAxis( VectorObject * self, PyObject * value, void * type )
{
- float param= (float)PyFloat_AsDouble( 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;
+ return Vector_ass_item(self, (int)type, value);
}
/* vector.length */
@@ -1113,6 +1148,9 @@ static PyObject *Vector_getLength( VectorObject * self, void *type )
double dot = 0.0f;
int i;
+ if(!Vector_ReadCallback(self))
+ return NULL;
+
for(i = 0; i < self->size; 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;
int i;
+ if(!Vector_ReadCallback(self))
+ return -1;
+
param= PyFloat_AsDouble( value );
if(param==-1.0 && PyErr_Occurred()) {
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;
}
+ Vector_WriteCallback(self); /* checked alredy */
+
return 0;
}
@@ -1170,6 +1213,16 @@ static PyObject *Vector_getWrapped( VectorObject * self, void *type )
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
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];
unsigned int swizzleClosure;
+ if(!Vector_ReadCallback(self))
+ return NULL;
+
/* Unpack the axes from the closure into an array. */
axisA = 0;
swizzleClosure = (unsigned int) closure;
@@ -1218,6 +1274,9 @@ static int Vector_setSwizzle(VectorObject * self, PyObject * value, void *closur
float vecTemp[MAX_DIMENSIONS];
+ if(!Vector_ReadCallback(self))
+ return -1;
+
/* 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. */
swizzleClosure = (unsigned int) closure;
@@ -1247,7 +1306,7 @@ static int Vector_setSwizzle(VectorObject * self, PyObject * value, void *closur
axisB++;
}
memcpy(self->vec, vecTemp, axisB * sizeof(float));
- return 0;
+ /* continue with Vector_WriteCallback at the end */
}
else if (PyList_Check(value))
{
@@ -1273,7 +1332,7 @@ static int Vector_setSwizzle(VectorObject * self, PyObject * value, void *closur
axisB++;
}
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)
{
@@ -1286,13 +1345,17 @@ static int Vector_setSwizzle(VectorObject * self, PyObject * value, void *closur
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." );
return -1;
}
+
+ if(!Vector_WriteCallback(vecVal))
+ return -1;
+ else
+ return 0;
}
/*****************************************************************************/
@@ -1302,19 +1365,19 @@ static PyGetSetDef Vector_getseters[] = {
{"x",
(getter)Vector_getAxis, (setter)Vector_setAxis,
"Vector X axis",
- (void *)'X'},
+ (void *)0},
{"y",
(getter)Vector_getAxis, (setter)Vector_setAxis,
"Vector Y axis",
- (void *)'Y'},
+ (void *)1},
{"z",
(getter)Vector_getAxis, (setter)Vector_setAxis,
"Vector Z axis",
- (void *)'Z'},
+ (void *)2},
{"w",
(getter)Vector_getAxis, (setter)Vector_setAxis,
"Vector Z axis",
- (void *)'W'},
+ (void *)3},
{"length",
(getter)Vector_getLength, (setter)Vector_setLength,
"Vector Length",
@@ -1327,6 +1390,10 @@ static PyGetSetDef Vector_getseters[] = {
(getter)Vector_getWrapped, (setter)NULL,
"True when this wraps blenders internal data",
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 */
{"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;
}
-/*
- #############################DEPRECATED################################
- #######################################################################
- ----------------------------Vector.negate() --------------------
+PyObject *newVectorObject_cb(PyObject *user, int size, int callback_type, int subtype)
+{
+ 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 */
+ 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 */
static PyObject *Vector_Negate(VectorObject * self)
{
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]);
- }
- /*printf("Vector.negate(): Deprecated: use -vector instead\n");*/
+
+ Vector_WriteCallback(self); // alredy checked for error
+
Py_INCREF(self);
return (PyObject*)self;
}
-/*###################################################################
- ###########################DEPRECATED##############################*/
diff --git a/source/blender/python/generic/vector.h b/source/blender/python/generic/vector.h
index d2eb826ef10..12e035f55fa 100644
--- a/source/blender/python/generic/vector.h
+++ b/source/blender/python/generic/vector.h
@@ -39,12 +39,17 @@ extern PyTypeObject vector_Type;
typedef struct {
PyObject_VAR_HEAD
- float *vec; /*1D array of data (alias), wrapped status depends on wrapped status */
- short size; /* vec size 2,3 or 4 */
- short wrapped; /* is wrapped data? */
+ float *vec; /*1D array of data (alias), wrapped status depends on wrapped status */
+ PyObject *user; /* if this vector references another object, otherwise NULL, *Note* this owns its reference */
+ 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;
/*prototypes*/
PyObject *newVectorObject(float *vec, int size, int type);
+PyObject *newVectorObject_cb(PyObject *user, int size, int callback_type, int subtype);
#endif /* EXPP_vector_h */
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index f28f00e9c02..57c7144f949 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -39,6 +39,64 @@
#include "BKE_global.h" /* evil G.* */
#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 )
{
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) {
/* 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 */
@@ -1674,6 +1747,10 @@ PyObject *BPY_rna_module( void )
{
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 */
pyrna_prop_Type.tp_getattro = PyObject_GenericGetAttr;
pyrna_prop_Type.tp_setattro = PyObject_GenericSetAttr;
diff --git a/source/blender/python/intern/bpy_util.c b/source/blender/python/intern/bpy_util.c
index d837892fb4d..bce73b903c0 100644
--- a/source/blender/python/intern/bpy_util.c
+++ b/source/blender/python/intern/bpy_util.c
@@ -171,7 +171,7 @@ void PyObSpit(char *name, PyObject *var) {
else {
PyObject_Print(var, stderr, 0);
fprintf(stderr, " ref:%d ", var->ob_refcnt);
- fprintf(stderr, " ptr:%ld", (long)var);
+ fprintf(stderr, " ptr:%p", (void *)var);
fprintf(stderr, " type:");
if(Py_TYPE(var))
diff --git a/source/gameengine/Expressions/PyObjectPlus.h b/source/gameengine/Expressions/PyObjectPlus.h
index c002dccefe4..96c75b710a3 100644
--- a/source/gameengine/Expressions/PyObjectPlus.h
+++ b/source/gameengine/Expressions/PyObjectPlus.h
@@ -41,6 +41,8 @@
#include "MT_Vector3.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
------------------------------*/
diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp
index b266095c715..081549db686 100644
--- a/source/gameengine/Ketsji/KX_GameObject.cpp
+++ b/source/gameengine/Ketsji/KX_GameObject.cpp
@@ -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 ---------------------------------------------------*/
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)
{
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());
+#endif
}
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)
{
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())
return PyObjectFrom(self->GetSGNode()->GetLocalPosition());
else
return PyObjectFrom(dummy_point);
+#endif
}
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)
{
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())
- {
return PyObjectFrom(self->GetPhysicsController()->GetLocalInertia());
- }
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)
@@ -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)
{
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());
+#endif
}
PyObject* KX_GameObject::pyattr_get_localScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
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())
return PyObjectFrom(self->GetSGNode()->GetLocalScale());
else
return PyObjectFrom(dummy_scaling);
+#endif
}
int KX_GameObject::pyattr_set_localScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h
index ff5c8a01e6e..b01b0cae641 100644
--- a/source/gameengine/Ketsji/KX_GameObject.h
+++ b/source/gameengine/Ketsji/KX_GameObject.h
@@ -63,6 +63,10 @@ struct Object;
/* utility conversion function */
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.
*/
diff --git a/source/gameengine/Ketsji/KX_PythonInitTypes.cpp b/source/gameengine/Ketsji/KX_PythonInitTypes.cpp
index 83c4dcbb34c..05cb818fdd9 100644
--- a/source/gameengine/Ketsji/KX_PythonInitTypes.cpp
+++ b/source/gameengine/Ketsji/KX_PythonInitTypes.cpp
@@ -231,6 +231,11 @@ void initPyTypes(void)
/* Normal python type */
PyType_Ready(&KX_PythonSeq_Type);
+
+#ifdef USE_MATHUTILS
+ /* Init mathutils callbacks */
+ KX_GameObject_Mathutils_Callback_Init();
+#endif
}
#endif \ No newline at end of file