svn merge -r 31211:31313 https://svn.blender.org/svnroot/bf-blender/trunk/blender
[blender-staging.git] / source / blender / python / generic / mathutils_matrix.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * Contributor(s): Michel Selten & Joseph Gilbert
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 #include "mathutils.h"
29
30 #include "BKE_utildefines.h"
31 #include "BLI_math.h"
32 #include "BLI_blenlib.h"
33
34 static PyObject *column_vector_multiplication(MatrixObject * mat, VectorObject* vec); /* utility func */
35
36
37 /* matrix vector callbacks */
38 int mathutils_matrix_vector_cb_index= -1;
39
40 static int mathutils_matrix_vector_check(BaseMathObject *bmo)
41 {
42         MatrixObject *self= (MatrixObject *)bmo->cb_user;
43         return BaseMath_ReadCallback(self);
44 }
45
46 static int mathutils_matrix_vector_get(BaseMathObject *bmo, int subtype)
47 {
48         MatrixObject *self= (MatrixObject *)bmo->cb_user;
49         int i;
50
51         if(!BaseMath_ReadCallback(self))
52                 return 0;
53
54         for(i=0; i < self->colSize; i++)
55                 bmo->data[i]= self->matrix[subtype][i];
56
57         return 1;
58 }
59
60 static int mathutils_matrix_vector_set(BaseMathObject *bmo, int subtype)
61 {
62         MatrixObject *self= (MatrixObject *)bmo->cb_user;
63         int i;
64
65         if(!BaseMath_ReadCallback(self))
66                 return 0;
67
68         for(i=0; i < self->colSize; i++)
69                 self->matrix[subtype][i]= bmo->data[i];
70
71         BaseMath_WriteCallback(self);
72         return 1;
73 }
74
75 static int mathutils_matrix_vector_get_index(BaseMathObject *bmo, int subtype, int index)
76 {
77         MatrixObject *self= (MatrixObject *)bmo->cb_user;
78
79         if(!BaseMath_ReadCallback(self))
80                 return 0;
81
82         bmo->data[index]= self->matrix[subtype][index];
83         return 1;
84 }
85
86 static int mathutils_matrix_vector_set_index(BaseMathObject *bmo, int subtype, int index)
87 {
88         MatrixObject *self= (MatrixObject *)bmo->cb_user;
89
90         if(!BaseMath_ReadCallback(self))
91                 return 0;
92
93         self->matrix[subtype][index]= bmo->data[index];
94
95         BaseMath_WriteCallback(self);
96         return 1;
97 }
98
99 Mathutils_Callback mathutils_matrix_vector_cb = {
100         mathutils_matrix_vector_check,
101         mathutils_matrix_vector_get,
102         mathutils_matrix_vector_set,
103         mathutils_matrix_vector_get_index,
104         mathutils_matrix_vector_set_index
105 };
106 /* matrix vector callbacks, this is so you can do matrix[i][j] = val  */
107
108 //----------------------------------mathutils.Matrix() -----------------
109 //mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
110 //create a new matrix type
111 static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
112 {
113         PyObject *argObject, *m, *s;
114         MatrixObject *mat;
115         int argSize, seqSize = 0, i, j;
116         float matrix[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
117                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
118         float scalar;
119
120         argSize = PyTuple_GET_SIZE(args);
121         if(argSize > MATRIX_MAX_DIM) {  //bad arg nums
122                 PyErr_SetString(PyExc_AttributeError, "mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n");
123                 return NULL;
124         } else if (argSize == 0) { //return empty 4D matrix
125                 return (PyObject *) newMatrixObject(NULL, 4, 4, Py_NEW, NULL);
126         }else if (argSize == 1){
127                 //copy constructor for matrix objects
128                 argObject = PyTuple_GET_ITEM(args, 0);
129                 if(MatrixObject_Check(argObject)){
130                         mat = (MatrixObject*)argObject;
131                         if(!BaseMath_ReadCallback(mat))
132                                 return NULL;
133
134                         memcpy(matrix, mat->contigPtr, sizeof(float) * mat->rowSize * mat->colSize);
135                         argSize = mat->rowSize;
136                         seqSize = mat->colSize;
137                 }
138         }else{ //2-4 arguments (all seqs? all same size?)
139                 for(i =0; i < argSize; i++){
140                         argObject = PyTuple_GET_ITEM(args, i);
141                         if (PySequence_Check(argObject)) { //seq?
142                                 if(seqSize){ //0 at first
143                                         if(PySequence_Length(argObject) != seqSize){ //seq size not same
144                                                 PyErr_SetString(PyExc_AttributeError, "mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n");
145                                                 return NULL;
146                                         }
147                                 }
148                                 seqSize = PySequence_Length(argObject);
149                         }else{ //arg not a sequence
150                                 PyErr_SetString(PyExc_TypeError, "mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n");
151                                 return NULL;
152                         }
153                 }
154                 //all is well... let's continue parsing
155                 for (i = 0; i < argSize; i++){
156                         m = PyTuple_GET_ITEM(args, i);
157                         if (m == NULL) { // Failed to read sequence
158                                 PyErr_SetString(PyExc_RuntimeError, "mathutils.Matrix(): failed to parse arguments...\n");
159                                 return NULL;
160                         }
161
162                         for (j = 0; j < seqSize; j++) {
163                                 s = PySequence_GetItem(m, j);
164                                 if (s == NULL) { // Failed to read sequence
165                                         PyErr_SetString(PyExc_RuntimeError, "mathutils.Matrix(): failed to parse arguments...\n");
166                                         return NULL;
167                                 }
168                                 
169                                 scalar= (float)PyFloat_AsDouble(s);
170                                 Py_DECREF(s);
171                                 
172                                 if(scalar==-1 && PyErr_Occurred()) { // parsed item is not a number
173                                         PyErr_SetString(PyExc_AttributeError, "mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n");
174                                         return NULL;
175                                 }
176
177                                 matrix[(seqSize*i)+j]= scalar;
178                         }
179                 }
180         }
181         return newMatrixObject(matrix, argSize, seqSize, Py_NEW, NULL);
182 }
183
184 /*-----------------------CLASS-METHODS----------------------------*/
185
186 //----------------------------------mathutils.RotationMatrix() ----------
187 //mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
188 static char C_Matrix_Rotation_doc[] =
189 ".. classmethod:: Rotation(angle, size, axis)\n"
190 "\n"
191 "   Create a matrix representing a rotation.\n"
192 "\n"
193 "   :arg angle: The angle of rotation desired, in radians.\n"
194 "   :type angle: float\n"
195 "   :arg size: The size of the rotation matrix to construct [2, 4].\n"
196 "   :type size: int\n"
197 "   :arg axis: a string in ['X', 'Y', 'Z'] or a 3D Vector Object (optional when size is 2).\n"
198 "   :type axis: string or :class:`Vector`\n"
199 "   :return: A new rotation matrix.\n"
200 "   :rtype: :class:`Matrix`\n";
201
202 static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args)
203 {
204         VectorObject *vec= NULL;
205         char *axis= NULL;
206         int matSize;
207         float angle = 0.0f;
208         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
209                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
210
211         if(!PyArg_ParseTuple(args, "fi|O", &angle, &matSize, &vec)) {
212                 PyErr_SetString(PyExc_TypeError, "mathutils.RotationMatrix(angle, size, axis): expected float int and a string or vector\n");
213                 return NULL;
214         }
215
216         if(vec && !VectorObject_Check(vec)) {
217                 axis= _PyUnicode_AsString((PyObject *)vec);
218                 if(axis==NULL || axis[0]=='\0' || axis[1]!='\0' || axis[0] < 'X' || axis[0] > 'Z') {
219                         PyErr_SetString(PyExc_TypeError, "mathutils.RotationMatrix(): 3rd argument axis value must be a 3D vector or a string in 'X', 'Y', 'Z'\n");
220                         return NULL;
221                 }
222                 else {
223                         /* use the string */
224                         vec= NULL;
225                 }
226         }
227
228         while (angle<-(Py_PI*2))
229                 angle+=(Py_PI*2);
230         while (angle>(Py_PI*2))
231                 angle-=(Py_PI*2);
232         
233         if(matSize != 2 && matSize != 3 && matSize != 4) {
234                 PyErr_SetString(PyExc_AttributeError, "mathutils.RotationMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n");
235                 return NULL;
236         }
237         if(matSize == 2 && (vec != NULL)) {
238                 PyErr_SetString(PyExc_AttributeError, "mathutils.RotationMatrix(): cannot create a 2x2 rotation matrix around arbitrary axis\n");
239                 return NULL;
240         }
241         if((matSize == 3 || matSize == 4) && (axis == NULL) && (vec == NULL)) {
242                 PyErr_SetString(PyExc_AttributeError, "mathutils.RotationMatrix(): please choose an axis of rotation for 3d and 4d matrices\n");
243                 return NULL;
244         }
245         if(vec) {
246                 if(vec->size != 3) {
247                         PyErr_SetString(PyExc_AttributeError, "mathutils.RotationMatrix(): the vector axis must be a 3D vector\n");
248                         return NULL;
249                 }
250                 
251                 if(!BaseMath_ReadCallback(vec))
252                         return NULL;
253                 
254         }
255
256         /* check for valid vector/axis above */
257         if(vec) {
258                 axis_angle_to_mat3( (float (*)[3])mat,vec->vec, angle);
259         }
260         else if(matSize == 2) {
261                 //2D rotation matrix
262                 mat[0] = (float) cos (angle);
263                 mat[1] = (float) sin (angle);
264                 mat[2] = -((float) sin(angle));
265                 mat[3] = (float) cos(angle);
266         } else if(strcmp(axis, "X") == 0) {
267                 //rotation around X
268                 mat[0] = 1.0f;
269                 mat[4] = (float) cos(angle);
270                 mat[5] = (float) sin(angle);
271                 mat[7] = -((float) sin(angle));
272                 mat[8] = (float) cos(angle);
273         } else if(strcmp(axis, "Y") == 0) {
274                 //rotation around Y
275                 mat[0] = (float) cos(angle);
276                 mat[2] = -((float) sin(angle));
277                 mat[4] = 1.0f;
278                 mat[6] = (float) sin(angle);
279                 mat[8] = (float) cos(angle);
280         } else if(strcmp(axis, "Z") == 0) {
281                 //rotation around Z
282                 mat[0] = (float) cos(angle);
283                 mat[1] = (float) sin(angle);
284                 mat[3] = -((float) sin(angle));
285                 mat[4] = (float) cos(angle);
286                 mat[8] = 1.0f;
287         }
288         else {
289                 /* should never get here */
290                 PyErr_SetString(PyExc_AttributeError, "mathutils.RotationMatrix(): unknown error\n");
291                 return NULL;
292         }
293
294         if(matSize == 4) {
295                 //resize matrix
296                 mat[10] = mat[8];
297                 mat[9] = mat[7];
298                 mat[8] = mat[6];
299                 mat[7] = 0.0f;
300                 mat[6] = mat[5];
301                 mat[5] = mat[4];
302                 mat[4] = mat[3];
303                 mat[3] = 0.0f;
304         }
305         //pass to matrix creation
306         return newMatrixObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
307 }
308
309
310 static char C_Matrix_Translation_doc[] =
311 ".. classmethod:: Translation(vector)\n"
312 "\n"
313 "   Create a matrix representing a translation.\n"
314 "\n"
315 "   :arg vector: The translation vector.\n"
316 "   :type vector: :class:`Vector`\n"
317 "   :return: An identity matrix with a translation.\n"
318 "   :rtype: :class:`Matrix`\n";
319
320 static PyObject *C_Matrix_Translation(PyObject *cls, VectorObject * vec)
321 {
322         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
323                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
324         
325         if(!VectorObject_Check(vec)) {
326                 PyErr_SetString(PyExc_TypeError, "mathutils.TranslationMatrix(): expected vector\n");
327                 return NULL;
328         }
329         if(vec->size != 3 && vec->size != 4) {
330                 PyErr_SetString(PyExc_TypeError, "mathutils.TranslationMatrix(): vector must be 3D or 4D\n");
331                 return NULL;
332         }
333         
334         if(!BaseMath_ReadCallback(vec))
335                 return NULL;
336         
337         //create a identity matrix and add translation
338         unit_m4((float(*)[4]) mat);
339         mat[12] = vec->vec[0];
340         mat[13] = vec->vec[1];
341         mat[14] = vec->vec[2];
342
343         return newMatrixObject(mat, 4, 4, Py_NEW, (PyTypeObject *)cls);
344 }
345 //----------------------------------mathutils.ScaleMatrix() -------------
346 //mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
347 static char C_Matrix_Scale_doc[] =
348 ".. classmethod:: Scale(factor, size, axis)\n"
349 "\n"
350 "   Create a matrix representing a scaling.\n"
351 "\n"
352 "   :arg factor: The factor of scaling to apply.\n"
353 "   :type factor: float\n"
354 "   :arg size: The size of the scale matrix to construct [2, 4].\n"
355 "   :type size: int\n"
356 "   :arg axis: Direction to influence scale. (optional).\n"
357 "   :type axis: :class:`Vector`\n"
358 "   :return: A new scale matrix.\n"
359 "   :rtype: :class:`Matrix`\n";
360
361 static PyObject *C_Matrix_Scale(PyObject *cls, PyObject *args)
362 {
363         VectorObject *vec = NULL;
364         float norm = 0.0f, factor;
365         int matSize, x;
366         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
367                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
368
369         if(!PyArg_ParseTuple(args, "fi|O!", &factor, &matSize, &vector_Type, &vec)) {
370                 PyErr_SetString(PyExc_TypeError, "mathutils.ScaleMatrix(): expected float int and optional vector\n");
371                 return NULL;
372         }
373         if(matSize != 2 && matSize != 3 && matSize != 4) {
374                 PyErr_SetString(PyExc_AttributeError, "mathutils.ScaleMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n");
375                 return NULL;
376         }
377         if(vec) {
378                 if(vec->size > 2 && matSize == 2) {
379                         PyErr_SetString(PyExc_AttributeError, "mathutils.ScaleMatrix(): please use 2D vectors when scaling in 2D\n");
380                         return NULL;
381                 }
382                 
383                 if(!BaseMath_ReadCallback(vec))
384                         return NULL;
385                 
386         }
387         if(vec == NULL) {       //scaling along axis
388                 if(matSize == 2) {
389                         mat[0] = factor;
390                         mat[3] = factor;
391                 } else {
392                         mat[0] = factor;
393                         mat[4] = factor;
394                         mat[8] = factor;
395                 }
396         } else { //scaling in arbitrary direction
397                 //normalize arbitrary axis
398                 for(x = 0; x < vec->size; x++) {
399                         norm += vec->vec[x] * vec->vec[x];
400                 }
401                 norm = (float) sqrt(norm);
402                 for(x = 0; x < vec->size; x++) {
403                         vec->vec[x] /= norm;
404                 }
405                 if(matSize == 2) {
406                         mat[0] = 1 +((factor - 1) *(vec->vec[0] * vec->vec[0]));
407                         mat[1] =((factor - 1) *(vec->vec[0] * vec->vec[1]));
408                         mat[2] =((factor - 1) *(vec->vec[0] * vec->vec[1]));
409                         mat[3] = 1 + ((factor - 1) *(vec->vec[1] * vec->vec[1]));
410                 } else {
411                         mat[0] = 1 + ((factor - 1) *(vec->vec[0] * vec->vec[0]));
412                         mat[1] =((factor - 1) *(vec->vec[0] * vec->vec[1]));
413                         mat[2] =((factor - 1) *(vec->vec[0] * vec->vec[2]));
414                         mat[3] =((factor - 1) *(vec->vec[0] * vec->vec[1]));
415                         mat[4] = 1 + ((factor - 1) *(vec->vec[1] * vec->vec[1]));
416                         mat[5] =((factor - 1) *(vec->vec[1] * vec->vec[2]));
417                         mat[6] =((factor - 1) *(vec->vec[0] * vec->vec[2]));
418                         mat[7] =((factor - 1) *(vec->vec[1] * vec->vec[2]));
419                         mat[8] = 1 + ((factor - 1) *(vec->vec[2] * vec->vec[2]));
420                 }
421         }
422         if(matSize == 4) {
423                 //resize matrix
424                 mat[10] = mat[8];
425                 mat[9] = mat[7];
426                 mat[8] = mat[6];
427                 mat[7] = 0.0f;
428                 mat[6] = mat[5];
429                 mat[5] = mat[4];
430                 mat[4] = mat[3];
431                 mat[3] = 0.0f;
432         }
433         //pass to matrix creation
434         return newMatrixObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
435 }
436 //----------------------------------mathutils.OrthoProjectionMatrix() ---
437 //mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
438 static char C_Matrix_OrthoProjection_doc[] =
439 ".. classmethod:: OrthoProjection(plane, size, axis)\n"
440 "\n"
441 "   Create a matrix to represent an orthographic projection.\n"
442 "\n"
443 "   :arg plane: Can be any of the following: ['X', 'Y', 'XY', 'XZ', 'YZ', 'R'], where a single axis is for a 2D matrix and 'R' requires axis is given.\n"
444 "   :type plane: string\n"
445 "   :arg size: The size of the projection matrix to construct [2, 4].\n"
446 "   :type size: int\n"
447 "   :arg axis: Arbitrary perpendicular plane vector (optional).\n"
448 "   :type axis: :class:`Vector`\n"
449 "   :return: A new projection matrix.\n"
450 "   :rtype: :class:`Matrix`\n";
451 static PyObject *C_Matrix_OrthoProjection(PyObject *cls, PyObject *args)
452 {
453         VectorObject *vec = NULL;
454         char *plane;
455         int matSize, x;
456         float norm = 0.0f;
457         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
458                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
459         
460         if(!PyArg_ParseTuple(args, "si|O!", &plane, &matSize, &vector_Type, &vec)) {
461                 PyErr_SetString(PyExc_TypeError, "mathutils.OrthoProjectionMatrix(): expected string and int and optional vector\n");
462                 return NULL;
463         }
464         if(matSize != 2 && matSize != 3 && matSize != 4) {
465                 PyErr_SetString(PyExc_AttributeError,"mathutils.OrthoProjectionMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n");
466                 return NULL;
467         }
468         if(vec) {
469                 if(vec->size > 2 && matSize == 2) {
470                         PyErr_SetString(PyExc_AttributeError, "mathutils.OrthoProjectionMatrix(): please use 2D vectors when scaling in 2D\n");
471                         return NULL;
472                 }
473                 
474                 if(!BaseMath_ReadCallback(vec))
475                         return NULL;
476                 
477         }
478         if(vec == NULL) {       //ortho projection onto cardinal plane
479                 if((strcmp(plane, "X") == 0) && matSize == 2) {
480                         mat[0] = 1.0f;
481                 } else if((strcmp(plane, "Y") == 0) && matSize == 2) {
482                         mat[3] = 1.0f;
483                 } else if((strcmp(plane, "XY") == 0) && matSize > 2) {
484                         mat[0] = 1.0f;
485                         mat[4] = 1.0f;
486                 } else if((strcmp(plane, "XZ") == 0) && matSize > 2) {
487                         mat[0] = 1.0f;
488                         mat[8] = 1.0f;
489                 } else if((strcmp(plane, "YZ") == 0) && matSize > 2) {
490                         mat[4] = 1.0f;
491                         mat[8] = 1.0f;
492                 } else {
493                         PyErr_SetString(PyExc_AttributeError, "mathutils.OrthoProjectionMatrix(): unknown plane - expected: X, Y, XY, XZ, YZ\n");
494                         return NULL;
495                 }
496         } else { //arbitrary plane
497                 //normalize arbitrary axis
498                 for(x = 0; x < vec->size; x++) {
499                         norm += vec->vec[x] * vec->vec[x];
500                 }
501                 norm = (float) sqrt(norm);
502                 for(x = 0; x < vec->size; x++) {
503                         vec->vec[x] /= norm;
504                 }
505                 if((strcmp(plane, "R") == 0) && matSize == 2) {
506                         mat[0] = 1 - (vec->vec[0] * vec->vec[0]);
507                         mat[1] = -(vec->vec[0] * vec->vec[1]);
508                         mat[2] = -(vec->vec[0] * vec->vec[1]);
509                         mat[3] = 1 - (vec->vec[1] * vec->vec[1]);
510                 } else if((strcmp(plane, "R") == 0) && matSize > 2) {
511                         mat[0] = 1 - (vec->vec[0] * vec->vec[0]);
512                         mat[1] = -(vec->vec[0] * vec->vec[1]);
513                         mat[2] = -(vec->vec[0] * vec->vec[2]);
514                         mat[3] = -(vec->vec[0] * vec->vec[1]);
515                         mat[4] = 1 - (vec->vec[1] * vec->vec[1]);
516                         mat[5] = -(vec->vec[1] * vec->vec[2]);
517                         mat[6] = -(vec->vec[0] * vec->vec[2]);
518                         mat[7] = -(vec->vec[1] * vec->vec[2]);
519                         mat[8] = 1 - (vec->vec[2] * vec->vec[2]);
520                 } else {
521                         PyErr_SetString(PyExc_AttributeError, "mathutils.OrthoProjectionMatrix(): unknown plane - expected: 'r' expected for axis designation\n");
522                         return NULL;
523                 }
524         }
525         if(matSize == 4) {
526                 //resize matrix
527                 mat[10] = mat[8];
528                 mat[9] = mat[7];
529                 mat[8] = mat[6];
530                 mat[7] = 0.0f;
531                 mat[6] = mat[5];
532                 mat[5] = mat[4];
533                 mat[4] = mat[3];
534                 mat[3] = 0.0f;
535         }
536         //pass to matrix creation
537         return newMatrixObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
538 }
539
540 static char C_Matrix_Shear_doc[] =
541 ".. classmethod:: Shear(plane, factor, size)\n"
542 "\n"
543 "   Create a matrix to represent an shear transformation.\n"
544 "\n"
545 "   :arg plane: Can be any of the following: ['X', 'Y', 'XY', 'XZ', 'YZ'], where a single axis is for a 2D matrix.\n"
546 "   :type plane: string\n"
547 "   :arg factor: The factor of shear to apply.\n"
548 "   :type factor: float\n"
549 "   :arg size: The size of the shear matrix to construct [2, 4].\n"
550 "   :type size: int\n"
551 "   :return: A new shear matrix.\n"
552 "   :rtype: :class:`Matrix`\n";
553
554 static PyObject *C_Matrix_Shear(PyObject *cls, PyObject *args)
555 {
556         int matSize;
557         char *plane;
558         float factor;
559         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
560                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
561
562         if(!PyArg_ParseTuple(args, "sfi", &plane, &factor, &matSize)) {
563                 PyErr_SetString(PyExc_TypeError,"mathutils.ShearMatrix(): expected string float and int\n");
564                 return NULL;
565         }
566         if(matSize != 2 && matSize != 3 && matSize != 4) {
567                 PyErr_SetString(PyExc_AttributeError,"mathutils.ShearMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n");
568                 return NULL;
569         }
570
571         if((strcmp(plane, "X") == 0)
572                 && matSize == 2) {
573                 mat[0] = 1.0f;
574                 mat[2] = factor;
575                 mat[3] = 1.0f;
576         } else if((strcmp(plane, "Y") == 0) && matSize == 2) {
577                 mat[0] = 1.0f;
578                 mat[1] = factor;
579                 mat[3] = 1.0f;
580         } else if((strcmp(plane, "XY") == 0) && matSize > 2) {
581                 mat[0] = 1.0f;
582                 mat[4] = 1.0f;
583                 mat[6] = factor;
584                 mat[7] = factor;
585         } else if((strcmp(plane, "XZ") == 0) && matSize > 2) {
586                 mat[0] = 1.0f;
587                 mat[3] = factor;
588                 mat[4] = 1.0f;
589                 mat[5] = factor;
590                 mat[8] = 1.0f;
591         } else if((strcmp(plane, "YZ") == 0) && matSize > 2) {
592                 mat[0] = 1.0f;
593                 mat[1] = factor;
594                 mat[2] = factor;
595                 mat[4] = 1.0f;
596                 mat[8] = 1.0f;
597         } else {
598                 PyErr_SetString(PyExc_AttributeError, "mathutils.ShearMatrix(): expected: x, y, xy, xz, yz or wrong matrix size for shearing plane\n");
599                 return NULL;
600         }
601         if(matSize == 4) {
602                 //resize matrix
603                 mat[10] = mat[8];
604                 mat[9] = mat[7];
605                 mat[8] = mat[6];
606                 mat[7] = 0.0f;
607                 mat[6] = mat[5];
608                 mat[5] = mat[4];
609                 mat[4] = mat[3];
610                 mat[3] = 0.0f;
611         }
612         //pass to matrix creation
613         return newMatrixObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
614 }
615
616 /* assumes rowsize == colsize is checked and the read callback has run */
617 static float matrix_determinant(MatrixObject * self)
618 {
619         if(self->rowSize == 2) {
620                 return determinant_m2(self->matrix[0][0], self->matrix[0][1],
621                                          self->matrix[1][0], self->matrix[1][1]);
622         } else if(self->rowSize == 3) {
623                 return determinant_m3(self->matrix[0][0], self->matrix[0][1],
624                                          self->matrix[0][2], self->matrix[1][0],
625                                          self->matrix[1][1], self->matrix[1][2],
626                                          self->matrix[2][0], self->matrix[2][1],
627                                          self->matrix[2][2]);
628         } else {
629                 return determinant_m4((float (*)[4])self->contigPtr);
630         }
631 }
632
633
634 /*-----------------------------METHODS----------------------------*/
635 static char Matrix_toQuat_doc[] =
636 ".. method:: to_quat()\n"
637 "\n"
638 "   Return a quaternion representation of the rotation matrix.\n"
639 "\n"
640 "   :return: Quaternion representation of the rotation matrix.\n"
641 "   :rtype: :class:`Quaternion`\n";
642
643 static PyObject *Matrix_toQuat(MatrixObject * self)
644 {
645         float quat[4];
646
647         if(!BaseMath_ReadCallback(self))
648                 return NULL;
649         
650         /*must be 3-4 cols, 3-4 rows, square matrix*/
651         if(self->colSize < 3 || self->rowSize < 3 || (self->colSize != self->rowSize)) {
652                 PyErr_SetString(PyExc_AttributeError, "Matrix.to_quat(): inappropriate matrix size - expects 3x3 or 4x4 matrix");
653                 return NULL;
654         } 
655         if(self->colSize == 3){
656                 mat3_to_quat( quat,(float (*)[3])self->contigPtr);
657         }else{
658                 mat4_to_quat( quat,(float (*)[4])self->contigPtr);
659         }
660         
661         return newQuaternionObject(quat, Py_NEW, NULL);
662 }
663
664 /*---------------------------Matrix.toEuler() --------------------*/
665 static char Matrix_toEuler_doc[] =
666 ".. method:: to_euler(order, euler_compat)\n"
667 "\n"
668 "   Return an Euler representation of the rotation matrix (3x3 or 4x4 matrix only).\n"
669 "\n"
670 "   :arg order: Optional rotation order argument in ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX'].\n"
671 "   :type order: string\n"
672 "   :arg euler_compat: Optional euler argument the new euler will be made compatible with (no axis flipping between them). Useful for converting a series of matrices to animation curves.\n"
673 "   :type euler_compat: :class:`Euler`\n"
674 "   :return: Euler representation of the matrix.\n"
675 "   :rtype: :class:`Euler`\n";
676
677 PyObject *Matrix_toEuler(MatrixObject * self, PyObject *args)
678 {
679         char *order_str= NULL;
680         short order= EULER_ORDER_XYZ;
681         float eul[3], eul_compatf[3];
682         EulerObject *eul_compat = NULL;
683
684         float tmat[3][3];
685         float (*mat)[3];
686         
687         if(!BaseMath_ReadCallback(self))
688                 return NULL;
689         
690         if(!PyArg_ParseTuple(args, "|sO!:to_euler", &order_str, &euler_Type, &eul_compat))
691                 return NULL;
692         
693         if(eul_compat) {
694                 if(!BaseMath_ReadCallback(eul_compat))
695                         return NULL;
696
697                 copy_v3_v3(eul_compatf, eul_compat->eul);
698         }
699         
700         /*must be 3-4 cols, 3-4 rows, square matrix*/
701         if(self->colSize ==3 && self->rowSize ==3) {
702                 mat= (float (*)[3])self->contigPtr;
703         }else if (self->colSize ==4 && self->rowSize ==4) {
704                 copy_m3_m4(tmat, (float (*)[4])self->contigPtr);
705                 mat= tmat;
706         }else {
707                 PyErr_SetString(PyExc_AttributeError, "Matrix.to_euler(): inappropriate matrix size - expects 3x3 or 4x4 matrix\n");
708                 return NULL;
709         }
710
711         if(order_str) {
712                 order= euler_order_from_string(order_str, "Matrix.to_euler()");
713
714                 if(order == -1)
715                         return NULL;
716         }
717
718         if(eul_compat) {
719                 if(order == 1)  mat3_to_compatible_eul( eul, eul_compatf, mat);
720                 else                    mat3_to_compatible_eulO(eul, eul_compatf, order, mat);
721         }
722         else {
723                 if(order == 1)  mat3_to_eul(eul, mat);
724                 else                    mat3_to_eulO(eul, order, mat);
725         }
726
727         return newEulerObject(eul, order, Py_NEW, NULL);
728 }
729 /*---------------------------Matrix.resize4x4() ------------------*/
730 static char Matrix_Resize4x4_doc[] =
731 ".. method:: resize4x4()\n"
732 "\n"
733 "   Resize the matrix to 4x4.\n"
734 "\n"
735 "   :return: an instance of itself.\n"
736 "   :rtype: :class:`Matrix`\n";
737
738 PyObject *Matrix_Resize4x4(MatrixObject * self)
739 {
740         int x, first_row_elem, curr_pos, new_pos, blank_columns, blank_rows, index;
741
742         if(self->wrapped==Py_WRAP){
743                 PyErr_SetString(PyExc_TypeError, "cannot resize wrapped data - make a copy and resize that");
744                 return NULL;
745         }
746         if(self->cb_user){
747                 PyErr_SetString(PyExc_TypeError, "cannot resize owned data - make a copy and resize that");
748                 return NULL;
749         }
750         
751         self->contigPtr = PyMem_Realloc(self->contigPtr, (sizeof(float) * 16));
752         if(self->contigPtr == NULL) {
753                 PyErr_SetString(PyExc_MemoryError, "matrix.resize4x4(): problem allocating pointer space");
754                 return NULL;
755         }
756         /*set row pointers*/
757         for(x = 0; x < 4; x++) {
758                 self->matrix[x] = self->contigPtr + (x * 4);
759         }
760         /*move data to new spot in array + clean*/
761         for(blank_rows = (4 - self->rowSize); blank_rows > 0; blank_rows--){
762                 for(x = 0; x < 4; x++){
763                         index = (4 * (self->rowSize + (blank_rows - 1))) + x;
764                         if (index == 10 || index == 15){
765                                 self->contigPtr[index] = 1.0f;
766                         }else{
767                                 self->contigPtr[index] = 0.0f;
768                         }
769                 }
770         }
771         for(x = 1; x <= self->rowSize; x++){
772                 first_row_elem = (self->colSize * (self->rowSize - x));
773                 curr_pos = (first_row_elem + (self->colSize -1));
774                 new_pos = (4 * (self->rowSize - x )) + (curr_pos - first_row_elem);
775                 for(blank_columns = (4 - self->colSize); blank_columns > 0; blank_columns--){
776                         self->contigPtr[new_pos + blank_columns] = 0.0f;
777                 }
778                 for(curr_pos = curr_pos; curr_pos >= first_row_elem; curr_pos--){
779                         self->contigPtr[new_pos] = self->contigPtr[curr_pos];
780                         new_pos--;
781                 }
782         }
783         self->rowSize = 4;
784         self->colSize = 4;
785         
786         Py_INCREF(self);
787         return (PyObject *)self;
788 }
789
790 static char Matrix_to_4x4_doc[] =
791 ".. method:: to_4x4()\n"
792 "\n"
793 "   Return a 4x4 copy of this matrix.\n"
794 "\n"
795 "   :return: a new matrix.\n"
796 "   :rtype: :class:`Matrix`\n";
797 PyObject *Matrix_to_4x4(MatrixObject * self)
798 {
799         if(!BaseMath_ReadCallback(self))
800                 return NULL;
801
802         if(self->colSize==4 && self->rowSize==4) {
803                 return (PyObject *)newMatrixObject(self->contigPtr, 4, 4, Py_NEW, Py_TYPE(self));
804         }
805         else if(self->colSize==3 && self->rowSize==3) {
806                 float mat[4][4];
807                 copy_m4_m3(mat, (float (*)[3])self->contigPtr);
808                 return (PyObject *)newMatrixObject((float *)mat, 4, 4, Py_NEW, Py_TYPE(self));
809         }
810         /* TODO, 2x2 matrix */
811
812         PyErr_SetString(PyExc_TypeError, "Matrix.to_4x4(): inappropriate matrix size");
813         return NULL;
814 }
815
816 static char Matrix_to_3x3_doc[] =
817 ".. method:: to_3x3()\n"
818 "\n"
819 "   Return a 3x3 copy of this matrix.\n"
820 "\n"
821 "   :return: a new matrix.\n"
822 "   :rtype: :class:`Matrix`\n";
823 PyObject *Matrix_to_3x3(MatrixObject * self)
824 {
825         if(!BaseMath_ReadCallback(self))
826                 return NULL;
827
828         if(self->colSize==3 && self->rowSize==3) {
829                 return (PyObject *)newMatrixObject(self->contigPtr, 3, 3, Py_NEW, Py_TYPE(self));
830         }
831         else if(self->colSize==4 && self->rowSize==4) {
832                 float mat[3][3];
833                 copy_m3_m4(mat, (float (*)[4])self->contigPtr);
834                 return (PyObject *)newMatrixObject((float *)mat, 3, 3, Py_NEW, Py_TYPE(self));
835         }
836         /* TODO, 2x2 matrix */
837
838         PyErr_SetString(PyExc_TypeError, "Matrix.to_3x3(): inappropriate matrix size");
839         return NULL;
840 }
841
842 /*---------------------------Matrix.translationPart() ------------*/
843 static char Matrix_TranslationPart_doc[] =
844 ".. method:: translation_part()\n"
845 "\n"
846 "   Return a the translation part of a 4 row matrix.\n"
847 "\n"
848 "   :return: Return a the translation of a matrix.\n"
849 "   :rtype: :class:`Matrix`\n"
850 "\n"
851 "   .. note:: Note that the (4,4) element of a matrix can be used for uniform scaling too.\n";
852
853 PyObject *Matrix_TranslationPart(MatrixObject * self)
854 {
855         if(!BaseMath_ReadCallback(self))
856                 return NULL;
857         
858         if(self->colSize < 3 || self->rowSize < 4){
859                 PyErr_SetString(PyExc_AttributeError, "Matrix.translation_part(): inappropriate matrix size");
860                 return NULL;
861         }
862
863         return newVectorObject(self->matrix[3], 3, Py_NEW, NULL);
864 }
865 /*---------------------------Matrix.rotationPart() ---------------*/
866 static char Matrix_RotationPart_doc[] =
867 ".. method:: rotation_part()\n"
868 "\n"
869 "   Return the 3d submatrix corresponding to the linear term of the embedded affine transformation in 3d. This matrix represents rotation and scale.\n"
870 "\n"
871 "   :return: Return the 3d matrix for rotation and scale.\n"
872 "   :rtype: :class:`Matrix`\n"
873 "\n"
874 "   .. note:: Note that the (4,4) element of a matrix can be used for uniform scaling too.\n";
875
876 PyObject *Matrix_RotationPart(MatrixObject * self)
877 {
878         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
879                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
880
881         if(!BaseMath_ReadCallback(self))
882                 return NULL;
883
884         if(self->colSize < 3 || self->rowSize < 3){
885                 PyErr_SetString(PyExc_AttributeError, "Matrix.rotation_part(): inappropriate matrix size\n");
886                 return NULL;
887         }
888
889         mat[0] = self->matrix[0][0];
890         mat[1] = self->matrix[0][1];
891         mat[2] = self->matrix[0][2];
892         mat[3] = self->matrix[1][0];
893         mat[4] = self->matrix[1][1];
894         mat[5] = self->matrix[1][2];
895         mat[6] = self->matrix[2][0];
896         mat[7] = self->matrix[2][1];
897         mat[8] = self->matrix[2][2];
898
899         return newMatrixObject(mat, 3, 3, Py_NEW, Py_TYPE(self));
900 }
901 /*---------------------------Matrix.scalePart() --------------------*/
902 static char Matrix_scalePart_doc[] =
903 ".. method:: scale_part()\n"
904 "\n"
905 "   Return a the scale part of a 3x3 or 4x4 matrix.\n"
906 "\n"
907 "   :return: Return a the scale of a matrix.\n"
908 "   :rtype: :class:`Vector`\n"
909 "\n"
910 "   .. note:: This method does not return negative a scale on any axis because it is not possible to obtain this data from the matrix alone.\n";
911
912 PyObject *Matrix_scalePart(MatrixObject * self)
913 {
914         float scale[3], rot[3];
915         float mat[3][3], imat[3][3], tmat[3][3];
916
917         if(!BaseMath_ReadCallback(self))
918                 return NULL;
919         
920         /*must be 3-4 cols, 3-4 rows, square matrix*/
921         if(self->colSize == 4 && self->rowSize == 4)
922                 copy_m3_m4(mat, (float (*)[4])self->contigPtr);
923         else if(self->colSize == 3 && self->rowSize == 3)
924                 copy_m3_m3(mat, (float (*)[3])self->contigPtr);
925         else {
926                 PyErr_SetString(PyExc_AttributeError, "Matrix.scale_part(): inappropriate matrix size - expects 3x3 or 4x4 matrix\n");
927                 return NULL;
928         }
929         /* functionality copied from editobject.c apply_obmat */
930         mat3_to_eul( rot,mat);
931         eul_to_mat3( tmat,rot);
932         invert_m3_m3(imat, tmat);
933         mul_m3_m3m3(tmat, imat, mat);
934         
935         scale[0]= tmat[0][0];
936         scale[1]= tmat[1][1];
937         scale[2]= tmat[2][2];
938         return newVectorObject(scale, 3, Py_NEW, NULL);
939 }
940 /*---------------------------Matrix.invert() ---------------------*/
941 static char Matrix_Invert_doc[] =
942 ".. method:: invert()\n"
943 "\n"
944 "   Set the matrix to its inverse.\n"
945 "\n"
946 "   :return: an instance of itself.\n"
947 "   :rtype: :class:`Matrix`\n"
948 "\n"
949 "   .. note:: :exc:`ValueError` exception is raised.\n"
950 "\n"
951 "   .. seealso:: <http://en.wikipedia.org/wiki/Inverse_matrix>\n";
952
953 PyObject *Matrix_Invert(MatrixObject * self)
954 {
955         
956         int x, y, z = 0;
957         float det = 0.0f;
958         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
959                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
960
961         if(!BaseMath_ReadCallback(self))
962                 return NULL;
963
964         if(self->rowSize != self->colSize){
965                 PyErr_SetString(PyExc_AttributeError, "Matrix.invert(ed): only square matrices are supported");
966                 return NULL;
967         }
968
969         /*calculate the determinant*/
970         det = matrix_determinant(self);
971
972         if(det != 0) {
973                 /*calculate the classical adjoint*/
974                 if(self->rowSize == 2) {
975                         mat[0] = self->matrix[1][1];
976                         mat[1] = -self->matrix[0][1];
977                         mat[2] = -self->matrix[1][0];
978                         mat[3] = self->matrix[0][0];
979                 } else if(self->rowSize == 3) {
980                         adjoint_m3_m3((float (*)[3]) mat,(float (*)[3])self->contigPtr);
981                 } else if(self->rowSize == 4) {
982                         adjoint_m4_m4((float (*)[4]) mat, (float (*)[4])self->contigPtr);
983                 }
984                 /*divide by determinate*/
985                 for(x = 0; x < (self->rowSize * self->colSize); x++) {
986                         mat[x] /= det;
987                 }
988                 /*set values*/
989                 for(x = 0; x < self->rowSize; x++) {
990                         for(y = 0; y < self->colSize; y++) {
991                                 self->matrix[x][y] = mat[z];
992                                 z++;
993                         }
994                 }
995                 /*transpose
996                 Matrix_Transpose(self);*/
997         } else {
998                 PyErr_SetString(PyExc_ValueError, "matrix does not have an inverse");
999                 return NULL;
1000         }
1001         
1002         BaseMath_WriteCallback(self);
1003         Py_INCREF(self);
1004         return (PyObject *)self;
1005 }
1006
1007
1008 /*---------------------------Matrix.determinant() ----------------*/
1009 static char Matrix_Determinant_doc[] =
1010 ".. method:: determinant()\n"
1011 "\n"
1012 "   Return the determinant of a matrix.\n"
1013 "\n"
1014 "   :return: Return a the determinant of a matrix.\n"
1015 "   :rtype: float\n"
1016 "\n"
1017 "   .. seealso:: <http://en.wikipedia.org/wiki/Determinant>\n";
1018
1019 PyObject *Matrix_Determinant(MatrixObject * self)
1020 {
1021         if(!BaseMath_ReadCallback(self))
1022                 return NULL;
1023         
1024         if(self->rowSize != self->colSize){
1025                 PyErr_SetString(PyExc_AttributeError, "Matrix.determinant: only square matrices are supported");
1026                 return NULL;
1027         }
1028
1029         return PyFloat_FromDouble((double)matrix_determinant(self));
1030 }
1031 /*---------------------------Matrix.transpose() ------------------*/
1032 static char Matrix_Transpose_doc[] =
1033 ".. method:: transpose()\n"
1034 "\n"
1035 "   Set the matrix to its transpose.\n"
1036 "\n"
1037 "   :return: an instance of itself\n"
1038 "   :rtype: :class:`Matrix`\n"
1039 "\n"
1040 "   .. seealso:: <http://en.wikipedia.org/wiki/Transpose>\n";
1041
1042 PyObject *Matrix_Transpose(MatrixObject * self)
1043 {
1044         float t = 0.0f;
1045
1046         if(!BaseMath_ReadCallback(self))
1047                 return NULL;
1048         
1049         if(self->rowSize != self->colSize){
1050                 PyErr_SetString(PyExc_AttributeError, "Matrix.transpose(d): only square matrices are supported");
1051                 return NULL;
1052         }
1053
1054         if(self->rowSize == 2) {
1055                 t = self->matrix[1][0];
1056                 self->matrix[1][0] = self->matrix[0][1];
1057                 self->matrix[0][1] = t;
1058         } else if(self->rowSize == 3) {
1059                 transpose_m3((float (*)[3])self->contigPtr);
1060         } else {
1061                 transpose_m4((float (*)[4])self->contigPtr);
1062         }
1063
1064         BaseMath_WriteCallback(self);
1065         Py_INCREF(self);
1066         return (PyObject *)self;
1067 }
1068
1069
1070 /*---------------------------Matrix.zero() -----------------------*/
1071 static char Matrix_Zero_doc[] =
1072 ".. method:: zero()\n"
1073 "\n"
1074 "   Set all the matrix values to zero.\n"
1075 "\n"
1076 "   :return: an instance of itself\n"
1077 "   :rtype: :class:`Matrix`\n";
1078
1079 PyObject *Matrix_Zero(MatrixObject * self)
1080 {
1081         int row, col;
1082         
1083         for(row = 0; row < self->rowSize; row++) {
1084                 for(col = 0; col < self->colSize; col++) {
1085                         self->matrix[row][col] = 0.0f;
1086                 }
1087         }
1088         
1089         if(!BaseMath_WriteCallback(self))
1090                 return NULL;
1091         
1092         Py_INCREF(self);
1093         return (PyObject *)self;
1094 }
1095 /*---------------------------Matrix.identity(() ------------------*/
1096 static char Matrix_Identity_doc[] =
1097 ".. method:: identity()\n"
1098 "\n"
1099 "   Set the matrix to the identity matrix.\n"
1100 "\n"
1101 "   :return: an instance of itself\n"
1102 "   :rtype: :class:`Matrix`\n"
1103 "\n"
1104 "   .. note:: An object with zero location and rotation, a scale of one, will have an identity matrix.\n"
1105 "\n"
1106 "   .. seealso:: <http://en.wikipedia.org/wiki/Identity_matrix>\n";
1107
1108 PyObject *Matrix_Identity(MatrixObject * self)
1109 {
1110         if(!BaseMath_ReadCallback(self))
1111                 return NULL;
1112         
1113         if(self->rowSize != self->colSize){
1114                 PyErr_SetString(PyExc_AttributeError, "Matrix.identity: only square matrices are supported\n");
1115                 return NULL;
1116         }
1117
1118         if(self->rowSize == 2) {
1119                 self->matrix[0][0] = 1.0f;
1120                 self->matrix[0][1] = 0.0f;
1121                 self->matrix[1][0] = 0.0f;
1122                 self->matrix[1][1] = 1.0f;
1123         } else if(self->rowSize == 3) {
1124                 unit_m3((float (*)[3])self->contigPtr);
1125         } else {
1126                 unit_m4((float (*)[4])self->contigPtr);
1127         }
1128
1129         if(!BaseMath_WriteCallback(self))
1130                 return NULL;
1131         
1132         Py_INCREF(self);
1133         return (PyObject *)self;
1134 }
1135
1136 /*---------------------------Matrix.copy() ------------------*/
1137 static char Matrix_copy_doc[] =
1138 ".. method:: copy()\n"
1139 "\n"
1140 "   Returns a copy of this matrix.\n"
1141 "\n"
1142 "   :return: an instance of itself\n"
1143 "   :rtype: :class:`Matrix`\n";
1144
1145 PyObject *Matrix_copy(MatrixObject * self)
1146 {
1147         if(!BaseMath_ReadCallback(self))
1148                 return NULL;
1149         
1150         return (PyObject*)newMatrixObject((float (*))self->contigPtr, self->rowSize, self->colSize, Py_NEW, Py_TYPE(self));
1151 }
1152
1153 /*----------------------------print object (internal)-------------*/
1154 /*print the object to screen*/
1155 static PyObject *Matrix_repr(MatrixObject * self)
1156 {
1157         int x, y;
1158         char str[1024]="Matrix((", *str_p;
1159
1160         if(!BaseMath_ReadCallback(self))
1161                 return NULL;
1162
1163         str_p= &str[8];
1164
1165         for(x = 0; x < self->colSize; x++){
1166                 for(y = 0; y < (self->rowSize - 1); y++) {
1167                         str_p += sprintf(str_p, "%f, ", self->matrix[y][x]);
1168                 }
1169                 if(x < (self->colSize-1)){
1170                         str_p += sprintf(str_p, "%f), (", self->matrix[y][x]);
1171                 }
1172                 else{
1173                         str_p += sprintf(str_p, "%f)", self->matrix[y][x]);
1174                 }
1175         }
1176         strcat(str_p, ")");
1177
1178         return PyUnicode_FromString(str);
1179 }
1180 /*------------------------tp_richcmpr*/
1181 /*returns -1 execption, 0 false, 1 true*/
1182 static PyObject* Matrix_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
1183 {
1184         MatrixObject *matA = NULL, *matB = NULL;
1185         int result = 0;
1186
1187         if (!MatrixObject_Check(objectA) || !MatrixObject_Check(objectB)){
1188                 if (comparison_type == Py_NE){
1189                         Py_RETURN_TRUE;
1190                 }else{
1191                         Py_RETURN_FALSE;
1192                 }
1193         }
1194         matA = (MatrixObject*)objectA;
1195         matB = (MatrixObject*)objectB;
1196
1197         if(!BaseMath_ReadCallback(matA) || !BaseMath_ReadCallback(matB))
1198                 return NULL;
1199         
1200         if (matA->colSize != matB->colSize || matA->rowSize != matB->rowSize){
1201                 if (comparison_type == Py_NE){
1202                         Py_RETURN_TRUE;
1203                 }else{
1204                         Py_RETURN_FALSE;
1205                 }
1206         }
1207
1208         switch (comparison_type){
1209                 case Py_EQ:
1210                         /*contigPtr is basically a really long vector*/
1211                         result = EXPP_VectorsAreEqual(matA->contigPtr, matB->contigPtr,
1212                                 (matA->rowSize * matA->colSize), 1);
1213                         break;
1214                 case Py_NE:
1215                         result = EXPP_VectorsAreEqual(matA->contigPtr, matB->contigPtr,
1216                                 (matA->rowSize * matA->colSize), 1);
1217                         if (result == 0){
1218                                 result = 1;
1219                         }else{
1220                                 result = 0;
1221                         }
1222                         break;
1223                 default:
1224                         printf("The result of the comparison could not be evaluated");
1225                         break;
1226         }
1227         if (result == 1){
1228                 Py_RETURN_TRUE;
1229         }else{
1230                 Py_RETURN_FALSE;
1231         }
1232 }
1233
1234 /*---------------------SEQUENCE PROTOCOLS------------------------
1235   ----------------------------len(object)------------------------
1236   sequence length*/
1237 static int Matrix_len(MatrixObject * self)
1238 {
1239         return (self->rowSize);
1240 }
1241 /*----------------------------object[]---------------------------
1242   sequence accessor (get)
1243   the wrapped vector gives direct access to the matrix data*/
1244 static PyObject *Matrix_item(MatrixObject * self, int i)
1245 {
1246         if(!BaseMath_ReadCallback(self))
1247                 return NULL;
1248         
1249         if(i < 0 || i >= self->rowSize) {
1250                 PyErr_SetString(PyExc_IndexError, "matrix[attribute]: array index out of range");
1251                 return NULL;
1252         }
1253         return newVectorObject_cb((PyObject *)self, self->colSize, mathutils_matrix_vector_cb_index, i);
1254 }
1255 /*----------------------------object[]-------------------------
1256   sequence accessor (set)*/
1257 static int Matrix_ass_item(MatrixObject * self, int i, PyObject * ob)
1258 {
1259         int y, x, size = 0;
1260         float vec[4];
1261         PyObject *m, *f;
1262
1263         if(!BaseMath_ReadCallback(self))
1264                 return -1;
1265         
1266         if(i >= self->rowSize || i < 0){
1267                 PyErr_SetString(PyExc_TypeError, "matrix[attribute] = x: bad column\n");
1268                 return -1;
1269         }
1270
1271         if(PySequence_Check(ob)){
1272                 size = PySequence_Length(ob);
1273                 if(size != self->colSize){
1274                         PyErr_SetString(PyExc_TypeError, "matrix[attribute] = x: bad sequence size\n");
1275                         return -1;
1276                 }
1277                 for (x = 0; x < size; x++) {
1278                         m = PySequence_GetItem(ob, x);
1279                         if (m == NULL) { /*Failed to read sequence*/
1280                                 PyErr_SetString(PyExc_RuntimeError, "matrix[attribute] = x: unable to read sequence\n");
1281                                 return -1;
1282                         }
1283
1284                         f = PyNumber_Float(m);
1285                         if(f == NULL) { /*parsed item not a number*/
1286                                 Py_DECREF(m);
1287                                 PyErr_SetString(PyExc_TypeError, "matrix[attribute] = x: sequence argument not a number\n");
1288                                 return -1;
1289                         }
1290
1291                         vec[x] = (float)PyFloat_AS_DOUBLE(f);
1292                         Py_DECREF(m);
1293                         Py_DECREF(f);
1294                 }
1295                 /*parsed well - now set in matrix*/
1296                 for(y = 0; y < size; y++){
1297                         self->matrix[i][y] = vec[y];
1298                 }
1299                 
1300                 BaseMath_WriteCallback(self);
1301                 return 0;
1302         }else{
1303                 PyErr_SetString(PyExc_TypeError, "matrix[attribute] = x: expects a sequence of column size\n");
1304                 return -1;
1305         }
1306 }
1307 /*----------------------------object[z:y]------------------------
1308   sequence slice (get)*/
1309 static PyObject *Matrix_slice(MatrixObject * self, int begin, int end)
1310 {
1311
1312         PyObject *list = NULL;
1313         int count;
1314         
1315         if(!BaseMath_ReadCallback(self))
1316                 return NULL;
1317
1318         CLAMP(begin, 0, self->rowSize);
1319         CLAMP(end, 0, self->rowSize);
1320         begin = MIN2(begin,end);
1321
1322         list = PyList_New(end - begin);
1323         for(count = begin; count < end; count++) {
1324                 PyList_SetItem(list, count - begin,
1325                                 newVectorObject_cb((PyObject *)self, self->colSize, mathutils_matrix_vector_cb_index, count));
1326
1327         }
1328
1329         return list;
1330 }
1331 /*----------------------------object[z:y]------------------------
1332   sequence slice (set)*/
1333 static int Matrix_ass_slice(MatrixObject * self, int begin, int end, PyObject * seq)
1334 {
1335         int i, x, y, size, sub_size = 0;
1336         float mat[16], f;
1337         PyObject *subseq;
1338         PyObject *m;
1339
1340         if(!BaseMath_ReadCallback(self))
1341                 return -1;
1342         
1343         CLAMP(begin, 0, self->rowSize);
1344         CLAMP(end, 0, self->rowSize);
1345         begin = MIN2(begin,end);
1346
1347         if(PySequence_Check(seq)){
1348                 size = PySequence_Length(seq);
1349                 if(size != (end - begin)){
1350                         PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: size mismatch in slice assignment\n");
1351                         return -1;
1352                 }
1353                 /*parse sub items*/
1354                 for (i = 0; i < size; i++) {
1355                         /*parse each sub sequence*/
1356                         subseq = PySequence_GetItem(seq, i);
1357                         if (subseq == NULL) { /*Failed to read sequence*/
1358                                 PyErr_SetString(PyExc_RuntimeError, "matrix[begin:end] = []: unable to read sequence");
1359                                 return -1;
1360                         }
1361
1362                         if(PySequence_Check(subseq)){
1363                                 /*subsequence is also a sequence*/
1364                                 sub_size = PySequence_Length(subseq);
1365                                 if(sub_size != self->colSize){
1366                                         Py_DECREF(subseq);
1367                                         PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: size mismatch in slice assignment\n");
1368                                         return -1;
1369                                 }
1370                                 for (y = 0; y < sub_size; y++) {
1371                                         m = PySequence_GetItem(subseq, y);
1372                                         if (m == NULL) { /*Failed to read sequence*/
1373                                                 Py_DECREF(subseq);
1374                                                 PyErr_SetString(PyExc_RuntimeError, "matrix[begin:end] = []: unable to read sequence\n");
1375                                                 return -1;
1376                                         }
1377                                         
1378                                         f = PyFloat_AsDouble(m); /* faster to assume a float and raise an error after */
1379                                         if(f == -1 && PyErr_Occurred()) { /*parsed item not a number*/
1380                                                 Py_DECREF(m);
1381                                                 Py_DECREF(subseq);
1382                                                 PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: sequence argument not a number\n");
1383                                                 return -1;
1384                                         }
1385
1386                                         mat[(i * self->colSize) + y] = f;
1387                                         Py_DECREF(m);
1388                                 }
1389                         }else{
1390                                 Py_DECREF(subseq);
1391                                 PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: illegal argument type for built-in operation\n");
1392                                 return -1;
1393                         }
1394                         Py_DECREF(subseq);
1395                 }
1396                 /*parsed well - now set in matrix*/
1397                 for(x = 0; x < (size * sub_size); x++){
1398                         self->matrix[begin + (int)floor(x / self->colSize)][x % self->colSize] = mat[x];
1399                 }
1400                 
1401                 BaseMath_WriteCallback(self);
1402                 return 0;
1403         }else{
1404                 PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: illegal argument type for built-in operation\n");
1405                 return -1;
1406         }
1407 }
1408 /*------------------------NUMERIC PROTOCOLS----------------------
1409   ------------------------obj + obj------------------------------*/
1410 static PyObject *Matrix_add(PyObject * m1, PyObject * m2)
1411 {
1412         int x, y;
1413         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1414                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
1415         MatrixObject *mat1 = NULL, *mat2 = NULL;
1416
1417         mat1 = (MatrixObject*)m1;
1418         mat2 = (MatrixObject*)m2;
1419
1420         if(!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) {
1421                 PyErr_SetString(PyExc_AttributeError, "Matrix addition: arguments not valid for this operation....");
1422                 return NULL;
1423         }
1424         
1425         if(!BaseMath_ReadCallback(mat1) || !BaseMath_ReadCallback(mat2))
1426                 return NULL;
1427         
1428         if(mat1->rowSize != mat2->rowSize || mat1->colSize != mat2->colSize){
1429                 PyErr_SetString(PyExc_AttributeError, "Matrix addition: matrices must have the same dimensions for this operation");
1430                 return NULL;
1431         }
1432
1433         for(x = 0; x < mat1->rowSize; x++) {
1434                 for(y = 0; y < mat1->colSize; y++) {
1435                         mat[((x * mat1->colSize) + y)] = mat1->matrix[x][y] + mat2->matrix[x][y];
1436                 }
1437         }
1438
1439         return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW, NULL);
1440 }
1441 /*------------------------obj - obj------------------------------
1442   subtraction*/
1443 static PyObject *Matrix_sub(PyObject * m1, PyObject * m2)
1444 {
1445         int x, y;
1446         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1447                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
1448         MatrixObject *mat1 = NULL, *mat2 = NULL;
1449
1450         mat1 = (MatrixObject*)m1;
1451         mat2 = (MatrixObject*)m2;
1452
1453         if(!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) {
1454                 PyErr_SetString(PyExc_AttributeError, "Matrix addition: arguments not valid for this operation....");
1455                 return NULL;
1456         }
1457         
1458         if(!BaseMath_ReadCallback(mat1) || !BaseMath_ReadCallback(mat2))
1459                 return NULL;
1460         
1461         if(mat1->rowSize != mat2->rowSize || mat1->colSize != mat2->colSize){
1462                 PyErr_SetString(PyExc_AttributeError, "Matrix addition: matrices must have the same dimensions for this operation");
1463                 return NULL;
1464         }
1465
1466         for(x = 0; x < mat1->rowSize; x++) {
1467                 for(y = 0; y < mat1->colSize; y++) {
1468                         mat[((x * mat1->colSize) + y)] = mat1->matrix[x][y] - mat2->matrix[x][y];
1469                 }
1470         }
1471
1472         return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW, NULL);
1473 }
1474 /*------------------------obj * obj------------------------------
1475   mulplication*/
1476 static PyObject *Matrix_mul(PyObject * m1, PyObject * m2)
1477 {
1478         int x, y, z;
1479         float scalar;
1480         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1481                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
1482         double dot = 0.0f;
1483         MatrixObject *mat1 = NULL, *mat2 = NULL;
1484
1485         if(MatrixObject_Check(m1)) {
1486                 mat1 = (MatrixObject*)m1;
1487                 if(!BaseMath_ReadCallback(mat1))
1488                         return NULL;
1489         }
1490         if(MatrixObject_Check(m2)) {
1491                 mat2 = (MatrixObject*)m2;
1492                 if(!BaseMath_ReadCallback(mat2))
1493                         return NULL;
1494         }
1495
1496         if(mat1 && mat2) { /*MATRIX * MATRIX*/
1497                 if(mat1->rowSize != mat2->colSize){
1498                         PyErr_SetString(PyExc_AttributeError,"Matrix multiplication: matrix A rowsize must equal matrix B colsize");
1499                         return NULL;
1500                 }
1501                 for(x = 0; x < mat2->rowSize; x++) {
1502                         for(y = 0; y < mat1->colSize; y++) {
1503                                 for(z = 0; z < mat1->rowSize; z++) {
1504                                         dot += (mat1->matrix[z][y] * mat2->matrix[x][z]);
1505                                 }
1506                                 mat[((x * mat1->colSize) + y)] = (float)dot;
1507                                 dot = 0.0f;
1508                         }
1509                 }
1510                 
1511                 return newMatrixObject(mat, mat2->rowSize, mat1->colSize, Py_NEW, NULL);
1512         }
1513         
1514         if(mat1==NULL){
1515                 scalar=PyFloat_AsDouble(m1); // may not be a float...
1516                 if ((scalar == -1.0 && PyErr_Occurred())==0) { /*FLOAT/INT * MATRIX, this line annoys theeth, lets see if he finds it */
1517                         for(x = 0; x < mat2->rowSize; x++) {
1518                                 for(y = 0; y < mat2->colSize; y++) {
1519                                         mat[((x * mat2->colSize) + y)] = scalar * mat2->matrix[x][y];
1520                                 }
1521                         }
1522                         return newMatrixObject(mat, mat2->rowSize, mat2->colSize, Py_NEW, NULL);
1523                 }
1524                 
1525                 PyErr_SetString(PyExc_TypeError, "Matrix multiplication: arguments not acceptable for this operation");
1526                 return NULL;
1527         }
1528         else /* if(mat1) { */ {
1529                 
1530                 if(VectorObject_Check(m2)) { /* MATRIX*VECTOR */
1531                         return column_vector_multiplication(mat1, (VectorObject *)m2); /* vector update done inside the function */
1532                 }
1533                 else {
1534                         scalar= PyFloat_AsDouble(m2);
1535                         if ((scalar == -1.0 && PyErr_Occurred())==0) { /* MATRIX*FLOAT/INT */
1536                                 for(x = 0; x < mat1->rowSize; x++) {
1537                                         for(y = 0; y < mat1->colSize; y++) {
1538                                                 mat[((x * mat1->colSize) + y)] = scalar * mat1->matrix[x][y];
1539                                         }
1540                                 }
1541                                 return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW, NULL);
1542                         }
1543                 }
1544                 PyErr_SetString(PyExc_TypeError, "Matrix multiplication: arguments not acceptable for this operation");
1545                 return NULL;
1546         }
1547
1548         PyErr_SetString(PyExc_TypeError, "Matrix multiplication: arguments not acceptable for this operation\n");
1549         return NULL;
1550 }
1551 static PyObject* Matrix_inv(MatrixObject *self)
1552 {
1553         if(!BaseMath_ReadCallback(self))
1554                 return NULL;
1555         
1556         return Matrix_Invert(self);
1557 }
1558
1559 /*-----------------PROTOCOL DECLARATIONS--------------------------*/
1560 static PySequenceMethods Matrix_SeqMethods = {
1561         (lenfunc) Matrix_len,                                           /* sq_length */
1562         (binaryfunc) NULL,                                                      /* sq_concat */
1563         (ssizeargfunc) NULL,                                            /* sq_repeat */
1564         (ssizeargfunc) Matrix_item,                                     /* sq_item */
1565         (ssizessizeargfunc) Matrix_slice,                       /* sq_slice, deprecated TODO, replace */
1566         (ssizeobjargproc) Matrix_ass_item,                      /* sq_ass_item */
1567         (ssizessizeobjargproc) Matrix_ass_slice,        /* sq_ass_slice, deprecated TODO, replace */
1568         (objobjproc) NULL,                                                      /* sq_contains */
1569         (binaryfunc) NULL,                                                      /* sq_inplace_concat */
1570         (ssizeargfunc) NULL,                                            /* sq_inplace_repeat */
1571 };
1572
1573
1574 static PyObject *Matrix_subscript(MatrixObject* self, PyObject* item)
1575 {
1576         if (PyIndex_Check(item)) {
1577                 Py_ssize_t i;
1578                 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
1579                 if (i == -1 && PyErr_Occurred())
1580                         return NULL;
1581                 if (i < 0)
1582                         i += self->rowSize;
1583                 return Matrix_item(self, i);
1584         } else if (PySlice_Check(item)) {
1585                 Py_ssize_t start, stop, step, slicelength;
1586
1587                 if (PySlice_GetIndicesEx((PySliceObject*)item, self->rowSize, &start, &stop, &step, &slicelength) < 0)
1588                         return NULL;
1589
1590                 if (slicelength <= 0) {
1591                         return PyList_New(0);
1592                 }
1593                 else if (step == 1) {
1594                         return Matrix_slice(self, start, stop);
1595                 }
1596                 else {
1597                         PyErr_SetString(PyExc_TypeError, "slice steps not supported with matricies");
1598                         return NULL;
1599                 }
1600         }
1601         else {
1602                 PyErr_Format(PyExc_TypeError,
1603                                  "vector indices must be integers, not %.200s",
1604                                  item->ob_type->tp_name);
1605                 return NULL;
1606         }
1607 }
1608
1609 static int Matrix_ass_subscript(MatrixObject* self, PyObject* item, PyObject* value)
1610 {
1611         if (PyIndex_Check(item)) {
1612                 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
1613                 if (i == -1 && PyErr_Occurred())
1614                         return -1;
1615                 if (i < 0)
1616                         i += self->rowSize;
1617                 return Matrix_ass_item(self, i, value);
1618         }
1619         else if (PySlice_Check(item)) {
1620                 Py_ssize_t start, stop, step, slicelength;
1621
1622                 if (PySlice_GetIndicesEx((PySliceObject*)item, self->rowSize, &start, &stop, &step, &slicelength) < 0)
1623                         return -1;
1624
1625                 if (step == 1)
1626                         return Matrix_ass_slice(self, start, stop, value);
1627                 else {
1628                         PyErr_SetString(PyExc_TypeError, "slice steps not supported with matricies");
1629                         return -1;
1630                 }
1631         }
1632         else {
1633                 PyErr_Format(PyExc_TypeError,
1634                                  "matrix indices must be integers, not %.200s",
1635                                  item->ob_type->tp_name);
1636                 return -1;
1637         }
1638 }
1639
1640 static PyMappingMethods Matrix_AsMapping = {
1641         (lenfunc)Matrix_len,
1642         (binaryfunc)Matrix_subscript,
1643         (objobjargproc)Matrix_ass_subscript
1644 };
1645
1646
1647 static PyNumberMethods Matrix_NumMethods = {
1648                 (binaryfunc)    Matrix_add,     /*nb_add*/
1649                 (binaryfunc)    Matrix_sub,     /*nb_subtract*/
1650                 (binaryfunc)    Matrix_mul,     /*nb_multiply*/
1651                 0,                                                      /*nb_remainder*/
1652                 0,                                                      /*nb_divmod*/
1653                 0,                                                      /*nb_power*/
1654                 (unaryfunc)     0,      /*nb_negative*/
1655                 (unaryfunc)     0,      /*tp_positive*/
1656                 (unaryfunc)     0,      /*tp_absolute*/
1657                 (inquiry)       0,      /*tp_bool*/
1658                 (unaryfunc)     Matrix_inv,     /*nb_invert*/
1659                 0,                              /*nb_lshift*/
1660                 (binaryfunc)0,  /*nb_rshift*/
1661                 0,                              /*nb_and*/
1662                 0,                              /*nb_xor*/
1663                 0,                              /*nb_or*/
1664                 0,                              /*nb_int*/
1665                 0,                              /*nb_reserved*/
1666                 0,                              /*nb_float*/
1667                 0,                              /* nb_inplace_add */
1668                 0,                              /* nb_inplace_subtract */
1669                 0,                              /* nb_inplace_multiply */
1670                 0,                              /* nb_inplace_remainder */
1671                 0,                              /* nb_inplace_power */
1672                 0,                              /* nb_inplace_lshift */
1673                 0,                              /* nb_inplace_rshift */
1674                 0,                              /* nb_inplace_and */
1675                 0,                              /* nb_inplace_xor */
1676                 0,                              /* nb_inplace_or */
1677                 0,                              /* nb_floor_divide */
1678                 0,                              /* nb_true_divide */
1679                 0,                              /* nb_inplace_floor_divide */
1680                 0,                              /* nb_inplace_true_divide */
1681                 0,                              /* nb_index */
1682 };
1683
1684 static PyObject *Matrix_getRowSize( MatrixObject * self, void *type )
1685 {
1686         return PyLong_FromLong((long) self->rowSize);
1687 }
1688
1689 static PyObject *Matrix_getColSize( MatrixObject * self, void *type )
1690 {
1691         return PyLong_FromLong((long) self->colSize);
1692 }
1693
1694 static PyObject *Matrix_getMedianScale( MatrixObject * self, void *type )
1695 {
1696         float mat[3][3];
1697
1698         if(!BaseMath_ReadCallback(self))
1699                 return NULL;
1700
1701         /*must be 3-4 cols, 3-4 rows, square matrix*/
1702         if(self->colSize == 4 && self->rowSize == 4)
1703                 copy_m3_m4(mat, (float (*)[4])self->contigPtr);
1704         else if(self->colSize == 3 && self->rowSize == 3)
1705                 copy_m3_m3(mat, (float (*)[3])self->contigPtr);
1706         else {
1707                 PyErr_SetString(PyExc_AttributeError, "Matrix.median_scale: inappropriate matrix size - expects 3x3 or 4x4 matrix\n");
1708                 return NULL;
1709         }
1710     
1711         return PyFloat_FromDouble(mat3_to_scale(mat));
1712 }
1713
1714 static PyObject *Matrix_getIsNegative( MatrixObject * self, void *type )
1715 {
1716         if(!BaseMath_ReadCallback(self))
1717                 return NULL;
1718
1719         /*must be 3-4 cols, 3-4 rows, square matrix*/
1720         if(self->colSize == 4 && self->rowSize == 4)
1721                 return PyBool_FromLong(is_negative_m4((float (*)[4])self->contigPtr));
1722         else if(self->colSize == 3 && self->rowSize == 3)
1723                 return PyBool_FromLong(is_negative_m3((float (*)[3])self->contigPtr));
1724         else {
1725                 PyErr_SetString(PyExc_AttributeError, "Matrix.is_negative: inappropriate matrix size - expects 3x3 or 4x4 matrix\n");
1726                 return NULL;
1727         }
1728 }
1729
1730
1731 /*****************************************************************************/
1732 /* Python attributes get/set structure:                                      */
1733 /*****************************************************************************/
1734 static PyGetSetDef Matrix_getseters[] = {
1735         {"row_size", (getter)Matrix_getRowSize, (setter)NULL, "The row size of the matrix (readonly).\n\n:type: int", NULL},
1736         {"col_size", (getter)Matrix_getColSize, (setter)NULL, "The column size of the matrix (readonly).\n\n:type: int", NULL},
1737         {"median_scale", (getter)Matrix_getMedianScale, (setter)NULL, "The average scale applied to each axis (readonly).\n\n:type: float", NULL},
1738         {"is_negative", (getter)Matrix_getIsNegative, (setter)NULL, "True if this matrix results in a negative scale, 3x3 and 4x4 only, (readonly).\n\n:type: bool", NULL},
1739         {"is_wrapped", (getter)BaseMathObject_getWrapped, (setter)NULL, BaseMathObject_Wrapped_doc, NULL},
1740         {"owner",(getter)BaseMathObject_getOwner, (setter)NULL, BaseMathObject_Owner_doc, NULL},
1741         {NULL,NULL,NULL,NULL,NULL}  /* Sentinel */
1742 };
1743
1744 /*-----------------------METHOD DEFINITIONS ----------------------*/
1745 static struct PyMethodDef Matrix_methods[] = {
1746         {"zero", (PyCFunction) Matrix_Zero, METH_NOARGS, Matrix_Zero_doc},
1747         {"identity", (PyCFunction) Matrix_Identity, METH_NOARGS, Matrix_Identity_doc},
1748         {"transpose", (PyCFunction) Matrix_Transpose, METH_NOARGS, Matrix_Transpose_doc},
1749         {"determinant", (PyCFunction) Matrix_Determinant, METH_NOARGS, Matrix_Determinant_doc},
1750         {"invert", (PyCFunction) Matrix_Invert, METH_NOARGS, Matrix_Invert_doc},
1751         {"translation_part", (PyCFunction) Matrix_TranslationPart, METH_NOARGS, Matrix_TranslationPart_doc},
1752         {"rotation_part", (PyCFunction) Matrix_RotationPart, METH_NOARGS, Matrix_RotationPart_doc},
1753         {"scale_part", (PyCFunction) Matrix_scalePart, METH_NOARGS, Matrix_scalePart_doc},
1754         {"resize4x4", (PyCFunction) Matrix_Resize4x4, METH_NOARGS, Matrix_Resize4x4_doc},
1755         {"to_4x4", (PyCFunction) Matrix_to_4x4, METH_NOARGS, Matrix_to_4x4_doc},
1756         {"to_3x3", (PyCFunction) Matrix_to_3x3, METH_NOARGS, Matrix_to_3x3_doc},
1757         {"to_euler", (PyCFunction) Matrix_toEuler, METH_VARARGS, Matrix_toEuler_doc},
1758         {"to_quat", (PyCFunction) Matrix_toQuat, METH_NOARGS, Matrix_toQuat_doc},
1759         {"copy", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
1760         {"__copy__", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
1761         
1762         /* class methods */
1763         {"Rotation", (PyCFunction) C_Matrix_Rotation, METH_VARARGS | METH_CLASS, C_Matrix_Rotation_doc},
1764         {"Scale", (PyCFunction) C_Matrix_Scale, METH_VARARGS | METH_CLASS, C_Matrix_Scale_doc},
1765         {"Shear", (PyCFunction) C_Matrix_Shear, METH_VARARGS | METH_CLASS, C_Matrix_Shear_doc},
1766         {"Translation", (PyCFunction) C_Matrix_Translation, METH_O | METH_CLASS, C_Matrix_Translation_doc},
1767         {"OrthoProjection", (PyCFunction) C_Matrix_OrthoProjection,  METH_VARARGS | METH_CLASS, C_Matrix_OrthoProjection_doc},
1768         {NULL, NULL, 0, NULL}
1769 };
1770
1771 /*------------------PY_OBECT DEFINITION--------------------------*/
1772 static char matrix_doc[] =
1773 "This object gives access to Matrices in Blender.";
1774
1775 PyTypeObject matrix_Type = {
1776         PyVarObject_HEAD_INIT(NULL, 0)
1777         "matrix",                                               /*tp_name*/
1778         sizeof(MatrixObject),                   /*tp_basicsize*/
1779         0,                                                              /*tp_itemsize*/
1780         (destructor)BaseMathObject_dealloc,             /*tp_dealloc*/
1781         0,                                                              /*tp_print*/
1782         0,                                                              /*tp_getattr*/
1783         0,                                                              /*tp_setattr*/
1784         0,                                                              /*tp_compare*/
1785         (reprfunc) Matrix_repr,                 /*tp_repr*/
1786         &Matrix_NumMethods,                             /*tp_as_number*/
1787         &Matrix_SeqMethods,                             /*tp_as_sequence*/
1788         &Matrix_AsMapping,                              /*tp_as_mapping*/
1789         0,                                                              /*tp_hash*/
1790         0,                                                              /*tp_call*/
1791         0,                                                              /*tp_str*/
1792         0,                                                              /*tp_getattro*/
1793         0,                                                              /*tp_setattro*/
1794         0,                                                              /*tp_as_buffer*/
1795         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1796         matrix_doc,                                             /*tp_doc*/
1797         0,                                                              /*tp_traverse*/
1798         0,                                                              /*tp_clear*/
1799         (richcmpfunc)Matrix_richcmpr,   /*tp_richcompare*/
1800         0,                                                              /*tp_weaklistoffset*/
1801         0,                                                              /*tp_iter*/
1802         0,                                                              /*tp_iternext*/
1803         Matrix_methods,                                 /*tp_methods*/
1804         0,                                                              /*tp_members*/
1805         Matrix_getseters,                               /*tp_getset*/
1806         0,                                                              /*tp_base*/
1807         0,                                                              /*tp_dict*/
1808         0,                                                              /*tp_descr_get*/
1809         0,                                                              /*tp_descr_set*/
1810         0,                                                              /*tp_dictoffset*/
1811         0,                                                              /*tp_init*/
1812         0,                                                              /*tp_alloc*/
1813         Matrix_new,                                             /*tp_new*/
1814         0,                                                              /*tp_free*/
1815         0,                                                              /*tp_is_gc*/
1816         0,                                                              /*tp_bases*/
1817         0,                                                              /*tp_mro*/
1818         0,                                                              /*tp_cache*/
1819         0,                                                              /*tp_subclasses*/
1820         0,                                                              /*tp_weaklist*/
1821         0                                                               /*tp_del*/
1822 };
1823
1824 /*------------------------newMatrixObject (internal)-------------
1825 creates a new matrix object
1826 self->matrix     self->contiguous_ptr (reference to data.xxx)
1827            [0]------------->[0]
1828                                                 [1]
1829                                                 [2]
1830            [1]------------->[3]
1831                                                 [4]
1832                                                 [5]
1833                                  ....
1834 self->matrix[1][1] = self->contigPtr[4] */
1835
1836 /*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
1837  (i.e. it was allocated elsewhere by MEM_mallocN())
1838   pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
1839  (i.e. it must be created here with PyMEM_malloc())*/
1840 PyObject *newMatrixObject(float *mat, int rowSize, int colSize, int type, PyTypeObject *base_type)
1841 {
1842         MatrixObject *self;
1843         int x, row, col;
1844
1845         /*matrix objects can be any 2-4row x 2-4col matrix*/
1846         if(rowSize < 2 || rowSize > 4 || colSize < 2 || colSize > 4){
1847                 PyErr_SetString(PyExc_RuntimeError, "matrix(): row and column sizes must be between 2 and 4");
1848                 return NULL;
1849         }
1850
1851         if(base_type)   self = (MatrixObject *)base_type->tp_alloc(base_type, 0);
1852         else                    self = PyObject_NEW(MatrixObject, &matrix_Type);
1853
1854         self->rowSize = rowSize;
1855         self->colSize = colSize;
1856         
1857         /* init callbacks as NULL */
1858         self->cb_user= NULL;
1859         self->cb_type= self->cb_subtype= 0;
1860
1861         if(type == Py_WRAP){
1862                 self->contigPtr = mat;
1863                 /*pointer array points to contigous memory*/
1864                 for(x = 0; x < rowSize; x++) {
1865                         self->matrix[x] = self->contigPtr + (x * colSize);
1866                 }
1867                 self->wrapped = Py_WRAP;
1868         }else if (type == Py_NEW){
1869                 self->contigPtr = PyMem_Malloc(rowSize * colSize * sizeof(float));
1870                 if(self->contigPtr == NULL) { /*allocation failure*/
1871                         PyErr_SetString( PyExc_MemoryError, "matrix(): problem allocating pointer space\n");
1872                         return NULL;
1873                 }
1874                 /*pointer array points to contigous memory*/
1875                 for(x = 0; x < rowSize; x++) {
1876                         self->matrix[x] = self->contigPtr + (x * colSize);
1877                 }
1878                 /*parse*/
1879                 if(mat) {       /*if a float array passed*/
1880                         for(row = 0; row < rowSize; row++) {
1881                                 for(col = 0; col < colSize; col++) {
1882                                         self->matrix[row][col] = mat[(row * colSize) + col];
1883                                 }
1884                         }
1885                 } else if (rowSize == colSize ) { /*or if no arguments are passed return identity matrix for square matrices */
1886                         Matrix_Identity(self);
1887                         Py_DECREF(self);
1888                 }
1889                 self->wrapped = Py_NEW;
1890         }else{ /*bad type*/
1891                 return NULL;
1892         }
1893         return (PyObject *) self;
1894 }
1895
1896 PyObject *newMatrixObject_cb(PyObject *cb_user, int rowSize, int colSize, int cb_type, int cb_subtype)
1897 {
1898         MatrixObject *self= (MatrixObject *)newMatrixObject(NULL, rowSize, colSize, Py_NEW, NULL);
1899         if(self) {
1900                 Py_INCREF(cb_user);
1901                 self->cb_user=                  cb_user;
1902                 self->cb_type=                  (unsigned char)cb_type;
1903                 self->cb_subtype=               (unsigned char)cb_subtype;
1904         }
1905         return (PyObject *) self;
1906 }
1907
1908 //----------------column_vector_multiplication (internal)---------
1909 //COLUMN VECTOR Multiplication (Matrix X Vector)
1910 // [1][4][7]   [a]
1911 // [2][5][8] * [b]
1912 // [3][6][9]   [c]
1913 //vector/matrix multiplication IS NOT COMMUTATIVE!!!!
1914 static PyObject *column_vector_multiplication(MatrixObject * mat, VectorObject* vec)
1915 {
1916         float vecNew[4], vecCopy[4];
1917         double dot = 0.0f;
1918         int x, y, z = 0;
1919
1920         if(!BaseMath_ReadCallback(mat) || !BaseMath_ReadCallback(vec))
1921                 return NULL;
1922         
1923         if(mat->rowSize != vec->size){
1924                 if(mat->rowSize == 4 && vec->size != 3){
1925                         PyErr_SetString(PyExc_AttributeError, "matrix * vector: matrix row size and vector size must be the same");
1926                         return NULL;
1927                 }else{
1928                         vecCopy[3] = 1.0f;
1929                 }
1930         }
1931
1932         for(x = 0; x < vec->size; x++){
1933                 vecCopy[x] = vec->vec[x];
1934         }
1935         vecNew[3] = 1.0f;
1936
1937         for(x = 0; x < mat->colSize; x++) {
1938                 for(y = 0; y < mat->rowSize; y++) {
1939                         dot += mat->matrix[y][x] * vecCopy[y];
1940                 }
1941                 vecNew[z++] = (float)dot;
1942                 dot = 0.0f;
1943         }
1944         return newVectorObject(vecNew, vec->size, Py_NEW, NULL);
1945 }