svn merge -r 31145:31210 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 /* assumes rowsize == colsize is checked and the read callback has run */
185 static float matrix_determinant(MatrixObject * self)
186 {
187         if(self->rowSize == 2) {
188                 return determinant_m2(self->matrix[0][0], self->matrix[0][1],
189                                          self->matrix[1][0], self->matrix[1][1]);
190         } else if(self->rowSize == 3) {
191                 return determinant_m3(self->matrix[0][0], self->matrix[0][1],
192                                          self->matrix[0][2], self->matrix[1][0],
193                                          self->matrix[1][1], self->matrix[1][2],
194                                          self->matrix[2][0], self->matrix[2][1],
195                                          self->matrix[2][2]);
196         } else {
197                 return determinant_m4((float (*)[4])self->contigPtr);
198         }
199 }
200
201
202 /*-----------------------------METHODS----------------------------*/
203 static char Matrix_toQuat_doc[] =
204 ".. method:: to_quat()\n"
205 "\n"
206 "   Return a quaternion representation of the rotation matrix.\n"
207 "\n"
208 "   :return: Quaternion representation of the rotation matrix.\n"
209 "   :rtype: :class:`Quaternion`\n";
210
211 static PyObject *Matrix_toQuat(MatrixObject * self)
212 {
213         float quat[4];
214
215         if(!BaseMath_ReadCallback(self))
216                 return NULL;
217         
218         /*must be 3-4 cols, 3-4 rows, square matrix*/
219         if(self->colSize < 3 || self->rowSize < 3 || (self->colSize != self->rowSize)) {
220                 PyErr_SetString(PyExc_AttributeError, "Matrix.to_quat(): inappropriate matrix size - expects 3x3 or 4x4 matrix");
221                 return NULL;
222         } 
223         if(self->colSize == 3){
224                 mat3_to_quat( quat,(float (*)[3])self->contigPtr);
225         }else{
226                 mat4_to_quat( quat,(float (*)[4])self->contigPtr);
227         }
228         
229         return newQuaternionObject(quat, Py_NEW, NULL);
230 }
231
232 /*---------------------------Matrix.toEuler() --------------------*/
233 static char Matrix_toEuler_doc[] =
234 ".. method:: to_euler(order, euler_compat)\n"
235 "\n"
236 "   Return an Euler representation of the rotation matrix (3x3 or 4x4 matrix only).\n"
237 "\n"
238 "   :arg order: Optional rotation order argument in ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX'].\n"
239 "   :type order: string\n"
240 "   :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"
241 "   :type euler_compat: :class:`Euler`\n"
242 "   :return: Euler representation of the matrix.\n"
243 "   :rtype: :class:`Euler`\n";
244
245 PyObject *Matrix_toEuler(MatrixObject * self, PyObject *args)
246 {
247         char *order_str= NULL;
248         short order= EULER_ORDER_XYZ;
249         float eul[3], eul_compatf[3];
250         EulerObject *eul_compat = NULL;
251
252         float tmat[3][3];
253         float (*mat)[3];
254         
255         if(!BaseMath_ReadCallback(self))
256                 return NULL;
257         
258         if(!PyArg_ParseTuple(args, "|sO!:to_euler", &order_str, &euler_Type, &eul_compat))
259                 return NULL;
260         
261         if(eul_compat) {
262                 if(!BaseMath_ReadCallback(eul_compat))
263                         return NULL;
264
265                 copy_v3_v3(eul_compatf, eul_compat->eul);
266         }
267         
268         /*must be 3-4 cols, 3-4 rows, square matrix*/
269         if(self->colSize ==3 && self->rowSize ==3) {
270                 mat= (float (*)[3])self->contigPtr;
271         }else if (self->colSize ==4 && self->rowSize ==4) {
272                 copy_m3_m4(tmat, (float (*)[4])self->contigPtr);
273                 mat= tmat;
274         }else {
275                 PyErr_SetString(PyExc_AttributeError, "Matrix.to_euler(): inappropriate matrix size - expects 3x3 or 4x4 matrix\n");
276                 return NULL;
277         }
278
279         if(order_str) {
280                 order= euler_order_from_string(order_str, "Matrix.to_euler()");
281
282                 if(order == -1)
283                         return NULL;
284         }
285
286         if(eul_compat) {
287                 if(order == 1)  mat3_to_compatible_eul( eul, eul_compatf, mat);
288                 else                    mat3_to_compatible_eulO(eul, eul_compatf, order, mat);
289         }
290         else {
291                 if(order == 1)  mat3_to_eul(eul, mat);
292                 else                    mat3_to_eulO(eul, order, mat);
293         }
294
295         return newEulerObject(eul, order, Py_NEW, NULL);
296 }
297 /*---------------------------Matrix.resize4x4() ------------------*/
298 static char Matrix_Resize4x4_doc[] =
299 ".. method:: resize4x4()\n"
300 "\n"
301 "   Resize the matrix to 4x4.\n"
302 "\n"
303 "   :return: an instance of itself.\n"
304 "   :rtype: :class:`Matrix`\n";
305
306 PyObject *Matrix_Resize4x4(MatrixObject * self)
307 {
308         int x, first_row_elem, curr_pos, new_pos, blank_columns, blank_rows, index;
309
310         if(self->wrapped==Py_WRAP){
311                 PyErr_SetString(PyExc_TypeError, "cannot resize wrapped data - make a copy and resize that");
312                 return NULL;
313         }
314         if(self->cb_user){
315                 PyErr_SetString(PyExc_TypeError, "cannot resize owned data - make a copy and resize that");
316                 return NULL;
317         }
318         
319         self->contigPtr = PyMem_Realloc(self->contigPtr, (sizeof(float) * 16));
320         if(self->contigPtr == NULL) {
321                 PyErr_SetString(PyExc_MemoryError, "matrix.resize4x4(): problem allocating pointer space");
322                 return NULL;
323         }
324         /*set row pointers*/
325         for(x = 0; x < 4; x++) {
326                 self->matrix[x] = self->contigPtr + (x * 4);
327         }
328         /*move data to new spot in array + clean*/
329         for(blank_rows = (4 - self->rowSize); blank_rows > 0; blank_rows--){
330                 for(x = 0; x < 4; x++){
331                         index = (4 * (self->rowSize + (blank_rows - 1))) + x;
332                         if (index == 10 || index == 15){
333                                 self->contigPtr[index] = 1.0f;
334                         }else{
335                                 self->contigPtr[index] = 0.0f;
336                         }
337                 }
338         }
339         for(x = 1; x <= self->rowSize; x++){
340                 first_row_elem = (self->colSize * (self->rowSize - x));
341                 curr_pos = (first_row_elem + (self->colSize -1));
342                 new_pos = (4 * (self->rowSize - x )) + (curr_pos - first_row_elem);
343                 for(blank_columns = (4 - self->colSize); blank_columns > 0; blank_columns--){
344                         self->contigPtr[new_pos + blank_columns] = 0.0f;
345                 }
346                 for(curr_pos = curr_pos; curr_pos >= first_row_elem; curr_pos--){
347                         self->contigPtr[new_pos] = self->contigPtr[curr_pos];
348                         new_pos--;
349                 }
350         }
351         self->rowSize = 4;
352         self->colSize = 4;
353         
354         Py_INCREF(self);
355         return (PyObject *)self;
356 }
357
358 static char Matrix_to_4x4_doc[] =
359 ".. method:: to_4x4()\n"
360 "\n"
361 "   Return a 4x4 copy of this matrix.\n"
362 "\n"
363 "   :return: a new matrix.\n"
364 "   :rtype: :class:`Matrix`\n";
365 PyObject *Matrix_to_4x4(MatrixObject * self)
366 {
367         if(!BaseMath_ReadCallback(self))
368                 return NULL;
369
370         if(self->colSize==4 && self->rowSize==4) {
371                 return (PyObject *)newMatrixObject(self->contigPtr, 4, 4, Py_NEW, Py_TYPE(self));
372         }
373         else if(self->colSize==3 && self->rowSize==3) {
374                 float mat[4][4];
375                 copy_m4_m3(mat, (float (*)[3])self->contigPtr);
376                 return (PyObject *)newMatrixObject((float *)mat, 4, 4, Py_NEW, Py_TYPE(self));
377         }
378         /* TODO, 2x2 matrix */
379
380         PyErr_SetString(PyExc_TypeError, "Matrix.to_4x4(): inappropriate matrix size");
381         return NULL;
382 }
383
384 static char Matrix_to_3x3_doc[] =
385 ".. method:: to_3x3()\n"
386 "\n"
387 "   Return a 3x3 copy of this matrix.\n"
388 "\n"
389 "   :return: a new matrix.\n"
390 "   :rtype: :class:`Matrix`\n";
391 PyObject *Matrix_to_3x3(MatrixObject * self)
392 {
393         if(!BaseMath_ReadCallback(self))
394                 return NULL;
395
396         if(self->colSize==3 && self->rowSize==3) {
397                 return (PyObject *)newMatrixObject(self->contigPtr, 3, 3, Py_NEW, Py_TYPE(self));
398         }
399         else if(self->colSize==4 && self->rowSize==4) {
400                 float mat[3][3];
401                 copy_m3_m4(mat, (float (*)[4])self->contigPtr);
402                 return (PyObject *)newMatrixObject((float *)mat, 3, 3, Py_NEW, Py_TYPE(self));
403         }
404         /* TODO, 2x2 matrix */
405
406         PyErr_SetString(PyExc_TypeError, "Matrix.to_3x3(): inappropriate matrix size");
407         return NULL;
408 }
409
410 /*---------------------------Matrix.translationPart() ------------*/
411 static char Matrix_TranslationPart_doc[] =
412 ".. method:: translation_part()\n"
413 "\n"
414 "   Return a the translation part of a 4 row matrix.\n"
415 "\n"
416 "   :return: Return a the translation of a matrix.\n"
417 "   :rtype: :class:`Matrix`\n"
418 "\n"
419 "   .. note:: Note that the (4,4) element of a matrix can be used for uniform scaling too.\n";
420
421 PyObject *Matrix_TranslationPart(MatrixObject * self)
422 {
423         if(!BaseMath_ReadCallback(self))
424                 return NULL;
425         
426         if(self->colSize < 3 || self->rowSize < 4){
427                 PyErr_SetString(PyExc_AttributeError, "Matrix.translation_part(): inappropriate matrix size");
428                 return NULL;
429         }
430
431         return newVectorObject(self->matrix[3], 3, Py_NEW, NULL);
432 }
433 /*---------------------------Matrix.rotationPart() ---------------*/
434 static char Matrix_RotationPart_doc[] =
435 ".. method:: rotation_part()\n"
436 "\n"
437 "   Return the 3d submatrix corresponding to the linear term of the embedded affine transformation in 3d. This matrix represents rotation and scale.\n"
438 "\n"
439 "   :return: Return the 3d matrix for rotation and scale.\n"
440 "   :rtype: :class:`Matrix`\n"
441 "\n"
442 "   .. note:: Note that the (4,4) element of a matrix can be used for uniform scaling too.\n";
443
444 PyObject *Matrix_RotationPart(MatrixObject * self)
445 {
446         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
447                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
448
449         if(!BaseMath_ReadCallback(self))
450                 return NULL;
451
452         if(self->colSize < 3 || self->rowSize < 3){
453                 PyErr_SetString(PyExc_AttributeError, "Matrix.rotation_part(): inappropriate matrix size\n");
454                 return NULL;
455         }
456
457         mat[0] = self->matrix[0][0];
458         mat[1] = self->matrix[0][1];
459         mat[2] = self->matrix[0][2];
460         mat[3] = self->matrix[1][0];
461         mat[4] = self->matrix[1][1];
462         mat[5] = self->matrix[1][2];
463         mat[6] = self->matrix[2][0];
464         mat[7] = self->matrix[2][1];
465         mat[8] = self->matrix[2][2];
466
467         return newMatrixObject(mat, 3, 3, Py_NEW, Py_TYPE(self));
468 }
469 /*---------------------------Matrix.scalePart() --------------------*/
470 static char Matrix_scalePart_doc[] =
471 ".. method:: scale_part()\n"
472 "\n"
473 "   Return a the scale part of a 3x3 or 4x4 matrix.\n"
474 "\n"
475 "   :return: Return a the scale of a matrix.\n"
476 "   :rtype: :class:`Vector`\n"
477 "\n"
478 "   .. 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";
479
480 PyObject *Matrix_scalePart(MatrixObject * self)
481 {
482         float scale[3], rot[3];
483         float mat[3][3], imat[3][3], tmat[3][3];
484
485         if(!BaseMath_ReadCallback(self))
486                 return NULL;
487         
488         /*must be 3-4 cols, 3-4 rows, square matrix*/
489         if(self->colSize == 4 && self->rowSize == 4)
490                 copy_m3_m4(mat, (float (*)[4])self->contigPtr);
491         else if(self->colSize == 3 && self->rowSize == 3)
492                 copy_m3_m3(mat, (float (*)[3])self->contigPtr);
493         else {
494                 PyErr_SetString(PyExc_AttributeError, "Matrix.scale_part(): inappropriate matrix size - expects 3x3 or 4x4 matrix\n");
495                 return NULL;
496         }
497         /* functionality copied from editobject.c apply_obmat */
498         mat3_to_eul( rot,mat);
499         eul_to_mat3( tmat,rot);
500         invert_m3_m3(imat, tmat);
501         mul_m3_m3m3(tmat, imat, mat);
502         
503         scale[0]= tmat[0][0];
504         scale[1]= tmat[1][1];
505         scale[2]= tmat[2][2];
506         return newVectorObject(scale, 3, Py_NEW, NULL);
507 }
508 /*---------------------------Matrix.invert() ---------------------*/
509 static char Matrix_Invert_doc[] =
510 ".. method:: invert()\n"
511 "\n"
512 "   Set the matrix to its inverse.\n"
513 "\n"
514 "   :return: an instance of itself.\n"
515 "   :rtype: :class:`Matrix`\n"
516 "\n"
517 "   .. note:: :exc:`ValueError` exception is raised.\n"
518 "\n"
519 "   .. seealso:: <http://en.wikipedia.org/wiki/Inverse_matrix>\n";
520
521 PyObject *Matrix_Invert(MatrixObject * self)
522 {
523         
524         int x, y, z = 0;
525         float det = 0.0f;
526         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
527                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
528
529         if(!BaseMath_ReadCallback(self))
530                 return NULL;
531
532         if(self->rowSize != self->colSize){
533                 PyErr_SetString(PyExc_AttributeError, "Matrix.invert(ed): only square matrices are supported");
534                 return NULL;
535         }
536
537         /*calculate the determinant*/
538         det = matrix_determinant(self);
539
540         if(det != 0) {
541                 /*calculate the classical adjoint*/
542                 if(self->rowSize == 2) {
543                         mat[0] = self->matrix[1][1];
544                         mat[1] = -self->matrix[0][1];
545                         mat[2] = -self->matrix[1][0];
546                         mat[3] = self->matrix[0][0];
547                 } else if(self->rowSize == 3) {
548                         adjoint_m3_m3((float (*)[3]) mat,(float (*)[3])self->contigPtr);
549                 } else if(self->rowSize == 4) {
550                         adjoint_m4_m4((float (*)[4]) mat, (float (*)[4])self->contigPtr);
551                 }
552                 /*divide by determinate*/
553                 for(x = 0; x < (self->rowSize * self->colSize); x++) {
554                         mat[x] /= det;
555                 }
556                 /*set values*/
557                 for(x = 0; x < self->rowSize; x++) {
558                         for(y = 0; y < self->colSize; y++) {
559                                 self->matrix[x][y] = mat[z];
560                                 z++;
561                         }
562                 }
563                 /*transpose
564                 Matrix_Transpose(self);*/
565         } else {
566                 PyErr_SetString(PyExc_ValueError, "matrix does not have an inverse");
567                 return NULL;
568         }
569         
570         BaseMath_WriteCallback(self);
571         Py_INCREF(self);
572         return (PyObject *)self;
573 }
574
575
576 /*---------------------------Matrix.determinant() ----------------*/
577 static char Matrix_Determinant_doc[] =
578 ".. method:: determinant()\n"
579 "\n"
580 "   Return the determinant of a matrix.\n"
581 "\n"
582 "   :return: Return a the determinant of a matrix.\n"
583 "   :rtype: float\n"
584 "\n"
585 "   .. seealso:: <http://en.wikipedia.org/wiki/Determinant>\n";
586
587 PyObject *Matrix_Determinant(MatrixObject * self)
588 {
589         if(!BaseMath_ReadCallback(self))
590                 return NULL;
591         
592         if(self->rowSize != self->colSize){
593                 PyErr_SetString(PyExc_AttributeError, "Matrix.determinant: only square matrices are supported");
594                 return NULL;
595         }
596
597         return PyFloat_FromDouble((double)matrix_determinant(self));
598 }
599 /*---------------------------Matrix.transpose() ------------------*/
600 static char Matrix_Transpose_doc[] =
601 ".. method:: transpose()\n"
602 "\n"
603 "   Set the matrix to its transpose.\n"
604 "\n"
605 "   :return: an instance of itself\n"
606 "   :rtype: :class:`Matrix`\n"
607 "\n"
608 "   .. seealso:: <http://en.wikipedia.org/wiki/Transpose>\n";
609
610 PyObject *Matrix_Transpose(MatrixObject * self)
611 {
612         float t = 0.0f;
613
614         if(!BaseMath_ReadCallback(self))
615                 return NULL;
616         
617         if(self->rowSize != self->colSize){
618                 PyErr_SetString(PyExc_AttributeError, "Matrix.transpose(d): only square matrices are supported");
619                 return NULL;
620         }
621
622         if(self->rowSize == 2) {
623                 t = self->matrix[1][0];
624                 self->matrix[1][0] = self->matrix[0][1];
625                 self->matrix[0][1] = t;
626         } else if(self->rowSize == 3) {
627                 transpose_m3((float (*)[3])self->contigPtr);
628         } else {
629                 transpose_m4((float (*)[4])self->contigPtr);
630         }
631
632         BaseMath_WriteCallback(self);
633         Py_INCREF(self);
634         return (PyObject *)self;
635 }
636
637
638 /*---------------------------Matrix.zero() -----------------------*/
639 static char Matrix_Zero_doc[] =
640 ".. method:: zero()\n"
641 "\n"
642 "   Set all the matrix values to zero.\n"
643 "\n"
644 "   :return: an instance of itself\n"
645 "   :rtype: :class:`Matrix`\n";
646
647 PyObject *Matrix_Zero(MatrixObject * self)
648 {
649         int row, col;
650         
651         for(row = 0; row < self->rowSize; row++) {
652                 for(col = 0; col < self->colSize; col++) {
653                         self->matrix[row][col] = 0.0f;
654                 }
655         }
656         
657         if(!BaseMath_WriteCallback(self))
658                 return NULL;
659         
660         Py_INCREF(self);
661         return (PyObject *)self;
662 }
663 /*---------------------------Matrix.identity(() ------------------*/
664 static char Matrix_Identity_doc[] =
665 ".. method:: identity()\n"
666 "\n"
667 "   Set the matrix to the identity matrix.\n"
668 "\n"
669 "   :return: an instance of itself\n"
670 "   :rtype: :class:`Matrix`\n"
671 "\n"
672 "   .. note:: An object with zero location and rotation, a scale of one, will have an identity matrix.\n"
673 "\n"
674 "   .. seealso:: <http://en.wikipedia.org/wiki/Identity_matrix>\n";
675
676 PyObject *Matrix_Identity(MatrixObject * self)
677 {
678         if(!BaseMath_ReadCallback(self))
679                 return NULL;
680         
681         if(self->rowSize != self->colSize){
682                 PyErr_SetString(PyExc_AttributeError, "Matrix.identity: only square matrices are supported\n");
683                 return NULL;
684         }
685
686         if(self->rowSize == 2) {
687                 self->matrix[0][0] = 1.0f;
688                 self->matrix[0][1] = 0.0f;
689                 self->matrix[1][0] = 0.0f;
690                 self->matrix[1][1] = 1.0f;
691         } else if(self->rowSize == 3) {
692                 unit_m3((float (*)[3])self->contigPtr);
693         } else {
694                 unit_m4((float (*)[4])self->contigPtr);
695         }
696
697         if(!BaseMath_WriteCallback(self))
698                 return NULL;
699         
700         Py_INCREF(self);
701         return (PyObject *)self;
702 }
703
704 /*---------------------------Matrix.copy() ------------------*/
705 static char Matrix_copy_doc[] =
706 ".. method:: copy()\n"
707 "\n"
708 "   Returns a copy of this matrix.\n"
709 "\n"
710 "   :return: an instance of itself\n"
711 "   :rtype: :class:`Matrix`\n";
712
713 PyObject *Matrix_copy(MatrixObject * self)
714 {
715         if(!BaseMath_ReadCallback(self))
716                 return NULL;
717         
718         return (PyObject*)newMatrixObject((float (*))self->contigPtr, self->rowSize, self->colSize, Py_NEW, Py_TYPE(self));
719 }
720
721 /*----------------------------print object (internal)-------------*/
722 /*print the object to screen*/
723 static PyObject *Matrix_repr(MatrixObject * self)
724 {
725         int x, y;
726         char str[1024]="Matrix((", *str_p;
727
728         if(!BaseMath_ReadCallback(self))
729                 return NULL;
730
731         str_p= &str[8];
732
733         for(x = 0; x < self->colSize; x++){
734                 for(y = 0; y < (self->rowSize - 1); y++) {
735                         str_p += sprintf(str_p, "%f, ", self->matrix[y][x]);
736                 }
737                 if(x < (self->colSize-1)){
738                         str_p += sprintf(str_p, "%f), (", self->matrix[y][x]);
739                 }
740                 else{
741                         str_p += sprintf(str_p, "%f)", self->matrix[y][x]);
742                 }
743         }
744         strcat(str_p, ")");
745
746         return PyUnicode_FromString(str);
747 }
748 /*------------------------tp_richcmpr*/
749 /*returns -1 execption, 0 false, 1 true*/
750 static PyObject* Matrix_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
751 {
752         MatrixObject *matA = NULL, *matB = NULL;
753         int result = 0;
754
755         if (!MatrixObject_Check(objectA) || !MatrixObject_Check(objectB)){
756                 if (comparison_type == Py_NE){
757                         Py_RETURN_TRUE;
758                 }else{
759                         Py_RETURN_FALSE;
760                 }
761         }
762         matA = (MatrixObject*)objectA;
763         matB = (MatrixObject*)objectB;
764
765         if(!BaseMath_ReadCallback(matA) || !BaseMath_ReadCallback(matB))
766                 return NULL;
767         
768         if (matA->colSize != matB->colSize || matA->rowSize != matB->rowSize){
769                 if (comparison_type == Py_NE){
770                         Py_RETURN_TRUE;
771                 }else{
772                         Py_RETURN_FALSE;
773                 }
774         }
775
776         switch (comparison_type){
777                 case Py_EQ:
778                         /*contigPtr is basically a really long vector*/
779                         result = EXPP_VectorsAreEqual(matA->contigPtr, matB->contigPtr,
780                                 (matA->rowSize * matA->colSize), 1);
781                         break;
782                 case Py_NE:
783                         result = EXPP_VectorsAreEqual(matA->contigPtr, matB->contigPtr,
784                                 (matA->rowSize * matA->colSize), 1);
785                         if (result == 0){
786                                 result = 1;
787                         }else{
788                                 result = 0;
789                         }
790                         break;
791                 default:
792                         printf("The result of the comparison could not be evaluated");
793                         break;
794         }
795         if (result == 1){
796                 Py_RETURN_TRUE;
797         }else{
798                 Py_RETURN_FALSE;
799         }
800 }
801
802 /*---------------------SEQUENCE PROTOCOLS------------------------
803   ----------------------------len(object)------------------------
804   sequence length*/
805 static int Matrix_len(MatrixObject * self)
806 {
807         return (self->rowSize);
808 }
809 /*----------------------------object[]---------------------------
810   sequence accessor (get)
811   the wrapped vector gives direct access to the matrix data*/
812 static PyObject *Matrix_item(MatrixObject * self, int i)
813 {
814         if(!BaseMath_ReadCallback(self))
815                 return NULL;
816         
817         if(i < 0 || i >= self->rowSize) {
818                 PyErr_SetString(PyExc_IndexError, "matrix[attribute]: array index out of range");
819                 return NULL;
820         }
821         return newVectorObject_cb((PyObject *)self, self->colSize, mathutils_matrix_vector_cb_index, i);
822 }
823 /*----------------------------object[]-------------------------
824   sequence accessor (set)*/
825 static int Matrix_ass_item(MatrixObject * self, int i, PyObject * ob)
826 {
827         int y, x, size = 0;
828         float vec[4];
829         PyObject *m, *f;
830
831         if(!BaseMath_ReadCallback(self))
832                 return -1;
833         
834         if(i >= self->rowSize || i < 0){
835                 PyErr_SetString(PyExc_TypeError, "matrix[attribute] = x: bad column\n");
836                 return -1;
837         }
838
839         if(PySequence_Check(ob)){
840                 size = PySequence_Length(ob);
841                 if(size != self->colSize){
842                         PyErr_SetString(PyExc_TypeError, "matrix[attribute] = x: bad sequence size\n");
843                         return -1;
844                 }
845                 for (x = 0; x < size; x++) {
846                         m = PySequence_GetItem(ob, x);
847                         if (m == NULL) { /*Failed to read sequence*/
848                                 PyErr_SetString(PyExc_RuntimeError, "matrix[attribute] = x: unable to read sequence\n");
849                                 return -1;
850                         }
851
852                         f = PyNumber_Float(m);
853                         if(f == NULL) { /*parsed item not a number*/
854                                 Py_DECREF(m);
855                                 PyErr_SetString(PyExc_TypeError, "matrix[attribute] = x: sequence argument not a number\n");
856                                 return -1;
857                         }
858
859                         vec[x] = (float)PyFloat_AS_DOUBLE(f);
860                         Py_DECREF(m);
861                         Py_DECREF(f);
862                 }
863                 /*parsed well - now set in matrix*/
864                 for(y = 0; y < size; y++){
865                         self->matrix[i][y] = vec[y];
866                 }
867                 
868                 BaseMath_WriteCallback(self);
869                 return 0;
870         }else{
871                 PyErr_SetString(PyExc_TypeError, "matrix[attribute] = x: expects a sequence of column size\n");
872                 return -1;
873         }
874 }
875 /*----------------------------object[z:y]------------------------
876   sequence slice (get)*/
877 static PyObject *Matrix_slice(MatrixObject * self, int begin, int end)
878 {
879
880         PyObject *list = NULL;
881         int count;
882         
883         if(!BaseMath_ReadCallback(self))
884                 return NULL;
885
886         CLAMP(begin, 0, self->rowSize);
887         CLAMP(end, 0, self->rowSize);
888         begin = MIN2(begin,end);
889
890         list = PyList_New(end - begin);
891         for(count = begin; count < end; count++) {
892                 PyList_SetItem(list, count - begin,
893                                 newVectorObject_cb((PyObject *)self, self->colSize, mathutils_matrix_vector_cb_index, count));
894
895         }
896
897         return list;
898 }
899 /*----------------------------object[z:y]------------------------
900   sequence slice (set)*/
901 static int Matrix_ass_slice(MatrixObject * self, int begin, int end, PyObject * seq)
902 {
903         int i, x, y, size, sub_size = 0;
904         float mat[16], f;
905         PyObject *subseq;
906         PyObject *m;
907
908         if(!BaseMath_ReadCallback(self))
909                 return -1;
910         
911         CLAMP(begin, 0, self->rowSize);
912         CLAMP(end, 0, self->rowSize);
913         begin = MIN2(begin,end);
914
915         if(PySequence_Check(seq)){
916                 size = PySequence_Length(seq);
917                 if(size != (end - begin)){
918                         PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: size mismatch in slice assignment\n");
919                         return -1;
920                 }
921                 /*parse sub items*/
922                 for (i = 0; i < size; i++) {
923                         /*parse each sub sequence*/
924                         subseq = PySequence_GetItem(seq, i);
925                         if (subseq == NULL) { /*Failed to read sequence*/
926                                 PyErr_SetString(PyExc_RuntimeError, "matrix[begin:end] = []: unable to read sequence");
927                                 return -1;
928                         }
929
930                         if(PySequence_Check(subseq)){
931                                 /*subsequence is also a sequence*/
932                                 sub_size = PySequence_Length(subseq);
933                                 if(sub_size != self->colSize){
934                                         Py_DECREF(subseq);
935                                         PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: size mismatch in slice assignment\n");
936                                         return -1;
937                                 }
938                                 for (y = 0; y < sub_size; y++) {
939                                         m = PySequence_GetItem(subseq, y);
940                                         if (m == NULL) { /*Failed to read sequence*/
941                                                 Py_DECREF(subseq);
942                                                 PyErr_SetString(PyExc_RuntimeError, "matrix[begin:end] = []: unable to read sequence\n");
943                                                 return -1;
944                                         }
945                                         
946                                         f = PyFloat_AsDouble(m); /* faster to assume a float and raise an error after */
947                                         if(f == -1 && PyErr_Occurred()) { /*parsed item not a number*/
948                                                 Py_DECREF(m);
949                                                 Py_DECREF(subseq);
950                                                 PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: sequence argument not a number\n");
951                                                 return -1;
952                                         }
953
954                                         mat[(i * self->colSize) + y] = f;
955                                         Py_DECREF(m);
956                                 }
957                         }else{
958                                 Py_DECREF(subseq);
959                                 PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: illegal argument type for built-in operation\n");
960                                 return -1;
961                         }
962                         Py_DECREF(subseq);
963                 }
964                 /*parsed well - now set in matrix*/
965                 for(x = 0; x < (size * sub_size); x++){
966                         self->matrix[begin + (int)floor(x / self->colSize)][x % self->colSize] = mat[x];
967                 }
968                 
969                 BaseMath_WriteCallback(self);
970                 return 0;
971         }else{
972                 PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: illegal argument type for built-in operation\n");
973                 return -1;
974         }
975 }
976 /*------------------------NUMERIC PROTOCOLS----------------------
977   ------------------------obj + obj------------------------------*/
978 static PyObject *Matrix_add(PyObject * m1, PyObject * m2)
979 {
980         int x, y;
981         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
982                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
983         MatrixObject *mat1 = NULL, *mat2 = NULL;
984
985         mat1 = (MatrixObject*)m1;
986         mat2 = (MatrixObject*)m2;
987
988         if(!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) {
989                 PyErr_SetString(PyExc_AttributeError, "Matrix addition: arguments not valid for this operation....");
990                 return NULL;
991         }
992         
993         if(!BaseMath_ReadCallback(mat1) || !BaseMath_ReadCallback(mat2))
994                 return NULL;
995         
996         if(mat1->rowSize != mat2->rowSize || mat1->colSize != mat2->colSize){
997                 PyErr_SetString(PyExc_AttributeError, "Matrix addition: matrices must have the same dimensions for this operation");
998                 return NULL;
999         }
1000
1001         for(x = 0; x < mat1->rowSize; x++) {
1002                 for(y = 0; y < mat1->colSize; y++) {
1003                         mat[((x * mat1->colSize) + y)] = mat1->matrix[x][y] + mat2->matrix[x][y];
1004                 }
1005         }
1006
1007         return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW, NULL);
1008 }
1009 /*------------------------obj - obj------------------------------
1010   subtraction*/
1011 static PyObject *Matrix_sub(PyObject * m1, PyObject * m2)
1012 {
1013         int x, y;
1014         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1015                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
1016         MatrixObject *mat1 = NULL, *mat2 = NULL;
1017
1018         mat1 = (MatrixObject*)m1;
1019         mat2 = (MatrixObject*)m2;
1020
1021         if(!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) {
1022                 PyErr_SetString(PyExc_AttributeError, "Matrix addition: arguments not valid for this operation....");
1023                 return NULL;
1024         }
1025         
1026         if(!BaseMath_ReadCallback(mat1) || !BaseMath_ReadCallback(mat2))
1027                 return NULL;
1028         
1029         if(mat1->rowSize != mat2->rowSize || mat1->colSize != mat2->colSize){
1030                 PyErr_SetString(PyExc_AttributeError, "Matrix addition: matrices must have the same dimensions for this operation");
1031                 return NULL;
1032         }
1033
1034         for(x = 0; x < mat1->rowSize; x++) {
1035                 for(y = 0; y < mat1->colSize; y++) {
1036                         mat[((x * mat1->colSize) + y)] = mat1->matrix[x][y] - mat2->matrix[x][y];
1037                 }
1038         }
1039
1040         return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW, NULL);
1041 }
1042 /*------------------------obj * obj------------------------------
1043   mulplication*/
1044 static PyObject *Matrix_mul(PyObject * m1, PyObject * m2)
1045 {
1046         int x, y, z;
1047         float scalar;
1048         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1049                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
1050         double dot = 0.0f;
1051         MatrixObject *mat1 = NULL, *mat2 = NULL;
1052
1053         if(MatrixObject_Check(m1)) {
1054                 mat1 = (MatrixObject*)m1;
1055                 if(!BaseMath_ReadCallback(mat1))
1056                         return NULL;
1057         }
1058         if(MatrixObject_Check(m2)) {
1059                 mat2 = (MatrixObject*)m2;
1060                 if(!BaseMath_ReadCallback(mat2))
1061                         return NULL;
1062         }
1063
1064         if(mat1 && mat2) { /*MATRIX * MATRIX*/
1065                 if(mat1->rowSize != mat2->colSize){
1066                         PyErr_SetString(PyExc_AttributeError,"Matrix multiplication: matrix A rowsize must equal matrix B colsize");
1067                         return NULL;
1068                 }
1069                 for(x = 0; x < mat2->rowSize; x++) {
1070                         for(y = 0; y < mat1->colSize; y++) {
1071                                 for(z = 0; z < mat1->rowSize; z++) {
1072                                         dot += (mat1->matrix[z][y] * mat2->matrix[x][z]);
1073                                 }
1074                                 mat[((x * mat1->colSize) + y)] = (float)dot;
1075                                 dot = 0.0f;
1076                         }
1077                 }
1078                 
1079                 return newMatrixObject(mat, mat2->rowSize, mat1->colSize, Py_NEW, NULL);
1080         }
1081         
1082         if(mat1==NULL){
1083                 scalar=PyFloat_AsDouble(m1); // may not be a float...
1084                 if ((scalar == -1.0 && PyErr_Occurred())==0) { /*FLOAT/INT * MATRIX, this line annoys theeth, lets see if he finds it */
1085                         for(x = 0; x < mat2->rowSize; x++) {
1086                                 for(y = 0; y < mat2->colSize; y++) {
1087                                         mat[((x * mat2->colSize) + y)] = scalar * mat2->matrix[x][y];
1088                                 }
1089                         }
1090                         return newMatrixObject(mat, mat2->rowSize, mat2->colSize, Py_NEW, NULL);
1091                 }
1092                 
1093                 PyErr_SetString(PyExc_TypeError, "Matrix multiplication: arguments not acceptable for this operation");
1094                 return NULL;
1095         }
1096         else /* if(mat1) { */ {
1097                 
1098                 if(VectorObject_Check(m2)) { /* MATRIX*VECTOR */
1099                         return column_vector_multiplication(mat1, (VectorObject *)m2); /* vector update done inside the function */
1100                 }
1101                 else {
1102                         scalar= PyFloat_AsDouble(m2);
1103                         if ((scalar == -1.0 && PyErr_Occurred())==0) { /* MATRIX*FLOAT/INT */
1104                                 for(x = 0; x < mat1->rowSize; x++) {
1105                                         for(y = 0; y < mat1->colSize; y++) {
1106                                                 mat[((x * mat1->colSize) + y)] = scalar * mat1->matrix[x][y];
1107                                         }
1108                                 }
1109                                 return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW, NULL);
1110                         }
1111                 }
1112                 PyErr_SetString(PyExc_TypeError, "Matrix multiplication: arguments not acceptable for this operation");
1113                 return NULL;
1114         }
1115
1116         PyErr_SetString(PyExc_TypeError, "Matrix multiplication: arguments not acceptable for this operation\n");
1117         return NULL;
1118 }
1119 static PyObject* Matrix_inv(MatrixObject *self)
1120 {
1121         if(!BaseMath_ReadCallback(self))
1122                 return NULL;
1123         
1124         return Matrix_Invert(self);
1125 }
1126
1127 /*-----------------PROTOCOL DECLARATIONS--------------------------*/
1128 static PySequenceMethods Matrix_SeqMethods = {
1129         (lenfunc) Matrix_len,                                           /* sq_length */
1130         (binaryfunc) NULL,                                                      /* sq_concat */
1131         (ssizeargfunc) NULL,                                            /* sq_repeat */
1132         (ssizeargfunc) Matrix_item,                                     /* sq_item */
1133         (ssizessizeargfunc) Matrix_slice,                       /* sq_slice, deprecated TODO, replace */
1134         (ssizeobjargproc) Matrix_ass_item,                      /* sq_ass_item */
1135         (ssizessizeobjargproc) Matrix_ass_slice,        /* sq_ass_slice, deprecated TODO, replace */
1136         (objobjproc) NULL,                                                      /* sq_contains */
1137         (binaryfunc) NULL,                                                      /* sq_inplace_concat */
1138         (ssizeargfunc) NULL,                                            /* sq_inplace_repeat */
1139 };
1140
1141
1142 static PyObject *Matrix_subscript(MatrixObject* self, PyObject* item)
1143 {
1144         if (PyIndex_Check(item)) {
1145                 Py_ssize_t i;
1146                 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
1147                 if (i == -1 && PyErr_Occurred())
1148                         return NULL;
1149                 if (i < 0)
1150                         i += self->rowSize;
1151                 return Matrix_item(self, i);
1152         } else if (PySlice_Check(item)) {
1153                 Py_ssize_t start, stop, step, slicelength;
1154
1155                 if (PySlice_GetIndicesEx((PySliceObject*)item, self->rowSize, &start, &stop, &step, &slicelength) < 0)
1156                         return NULL;
1157
1158                 if (slicelength <= 0) {
1159                         return PyList_New(0);
1160                 }
1161                 else if (step == 1) {
1162                         return Matrix_slice(self, start, stop);
1163                 }
1164                 else {
1165                         PyErr_SetString(PyExc_TypeError, "slice steps not supported with matricies");
1166                         return NULL;
1167                 }
1168         }
1169         else {
1170                 PyErr_Format(PyExc_TypeError,
1171                                  "vector indices must be integers, not %.200s",
1172                                  item->ob_type->tp_name);
1173                 return NULL;
1174         }
1175 }
1176
1177 static int Matrix_ass_subscript(MatrixObject* self, PyObject* item, PyObject* value)
1178 {
1179         if (PyIndex_Check(item)) {
1180                 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
1181                 if (i == -1 && PyErr_Occurred())
1182                         return -1;
1183                 if (i < 0)
1184                         i += self->rowSize;
1185                 return Matrix_ass_item(self, i, value);
1186         }
1187         else if (PySlice_Check(item)) {
1188                 Py_ssize_t start, stop, step, slicelength;
1189
1190                 if (PySlice_GetIndicesEx((PySliceObject*)item, self->rowSize, &start, &stop, &step, &slicelength) < 0)
1191                         return -1;
1192
1193                 if (step == 1)
1194                         return Matrix_ass_slice(self, start, stop, value);
1195                 else {
1196                         PyErr_SetString(PyExc_TypeError, "slice steps not supported with matricies");
1197                         return -1;
1198                 }
1199         }
1200         else {
1201                 PyErr_Format(PyExc_TypeError,
1202                                  "matrix indices must be integers, not %.200s",
1203                                  item->ob_type->tp_name);
1204                 return -1;
1205         }
1206 }
1207
1208 static PyMappingMethods Matrix_AsMapping = {
1209         (lenfunc)Matrix_len,
1210         (binaryfunc)Matrix_subscript,
1211         (objobjargproc)Matrix_ass_subscript
1212 };
1213
1214
1215 static PyNumberMethods Matrix_NumMethods = {
1216                 (binaryfunc)    Matrix_add,     /*nb_add*/
1217                 (binaryfunc)    Matrix_sub,     /*nb_subtract*/
1218                 (binaryfunc)    Matrix_mul,     /*nb_multiply*/
1219                 0,                                                      /*nb_remainder*/
1220                 0,                                                      /*nb_divmod*/
1221                 0,                                                      /*nb_power*/
1222                 (unaryfunc)     0,      /*nb_negative*/
1223                 (unaryfunc)     0,      /*tp_positive*/
1224                 (unaryfunc)     0,      /*tp_absolute*/
1225                 (inquiry)       0,      /*tp_bool*/
1226                 (unaryfunc)     Matrix_inv,     /*nb_invert*/
1227                 0,                              /*nb_lshift*/
1228                 (binaryfunc)0,  /*nb_rshift*/
1229                 0,                              /*nb_and*/
1230                 0,                              /*nb_xor*/
1231                 0,                              /*nb_or*/
1232                 0,                              /*nb_int*/
1233                 0,                              /*nb_reserved*/
1234                 0,                              /*nb_float*/
1235                 0,                              /* nb_inplace_add */
1236                 0,                              /* nb_inplace_subtract */
1237                 0,                              /* nb_inplace_multiply */
1238                 0,                              /* nb_inplace_remainder */
1239                 0,                              /* nb_inplace_power */
1240                 0,                              /* nb_inplace_lshift */
1241                 0,                              /* nb_inplace_rshift */
1242                 0,                              /* nb_inplace_and */
1243                 0,                              /* nb_inplace_xor */
1244                 0,                              /* nb_inplace_or */
1245                 0,                              /* nb_floor_divide */
1246                 0,                              /* nb_true_divide */
1247                 0,                              /* nb_inplace_floor_divide */
1248                 0,                              /* nb_inplace_true_divide */
1249                 0,                              /* nb_index */
1250 };
1251
1252 static PyObject *Matrix_getRowSize( MatrixObject * self, void *type )
1253 {
1254         return PyLong_FromLong((long) self->rowSize);
1255 }
1256
1257 static PyObject *Matrix_getColSize( MatrixObject * self, void *type )
1258 {
1259         return PyLong_FromLong((long) self->colSize);
1260 }
1261
1262 static PyObject *Matrix_getMedianScale( MatrixObject * self, void *type )
1263 {
1264         float mat[3][3];
1265
1266         if(!BaseMath_ReadCallback(self))
1267                 return NULL;
1268
1269         /*must be 3-4 cols, 3-4 rows, square matrix*/
1270         if(self->colSize == 4 && self->rowSize == 4)
1271                 copy_m3_m4(mat, (float (*)[4])self->contigPtr);
1272         else if(self->colSize == 3 && self->rowSize == 3)
1273                 copy_m3_m3(mat, (float (*)[3])self->contigPtr);
1274         else {
1275                 PyErr_SetString(PyExc_AttributeError, "Matrix.median_scale: inappropriate matrix size - expects 3x3 or 4x4 matrix\n");
1276                 return NULL;
1277         }
1278     
1279         return PyFloat_FromDouble(mat3_to_scale(mat));
1280 }
1281
1282 static PyObject *Matrix_getIsNegative( MatrixObject * self, void *type )
1283 {
1284         if(!BaseMath_ReadCallback(self))
1285                 return NULL;
1286
1287         /*must be 3-4 cols, 3-4 rows, square matrix*/
1288         if(self->colSize == 4 && self->rowSize == 4)
1289                 return PyBool_FromLong(is_negative_m4((float (*)[4])self->contigPtr));
1290         else if(self->colSize == 3 && self->rowSize == 3)
1291                 return PyBool_FromLong(is_negative_m3((float (*)[3])self->contigPtr));
1292         else {
1293                 PyErr_SetString(PyExc_AttributeError, "Matrix.is_negative: inappropriate matrix size - expects 3x3 or 4x4 matrix\n");
1294                 return NULL;
1295         }
1296 }
1297
1298
1299 /*****************************************************************************/
1300 /* Python attributes get/set structure:                                      */
1301 /*****************************************************************************/
1302 static PyGetSetDef Matrix_getseters[] = {
1303         {"row_size", (getter)Matrix_getRowSize, (setter)NULL, "The row size of the matrix (readonly).\n\n:type: int", NULL},
1304         {"col_size", (getter)Matrix_getColSize, (setter)NULL, "The column size of the matrix (readonly).\n\n:type: int", NULL},
1305         {"median_scale", (getter)Matrix_getMedianScale, (setter)NULL, "The average scale applied to each axis (readonly).\n\n:type: float", NULL},
1306         {"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},
1307         {"is_wrapped", (getter)BaseMathObject_getWrapped, (setter)NULL, BaseMathObject_Wrapped_doc, NULL},
1308         {"owner",(getter)BaseMathObject_getOwner, (setter)NULL, BaseMathObject_Owner_doc, NULL},
1309         {NULL,NULL,NULL,NULL,NULL}  /* Sentinel */
1310 };
1311
1312 /*-----------------------METHOD DEFINITIONS ----------------------*/
1313 static struct PyMethodDef Matrix_methods[] = {
1314         {"zero", (PyCFunction) Matrix_Zero, METH_NOARGS, Matrix_Zero_doc},
1315         {"identity", (PyCFunction) Matrix_Identity, METH_NOARGS, Matrix_Identity_doc},
1316         {"transpose", (PyCFunction) Matrix_Transpose, METH_NOARGS, Matrix_Transpose_doc},
1317         {"determinant", (PyCFunction) Matrix_Determinant, METH_NOARGS, Matrix_Determinant_doc},
1318         {"invert", (PyCFunction) Matrix_Invert, METH_NOARGS, Matrix_Invert_doc},
1319         {"translation_part", (PyCFunction) Matrix_TranslationPart, METH_NOARGS, Matrix_TranslationPart_doc},
1320         {"rotation_part", (PyCFunction) Matrix_RotationPart, METH_NOARGS, Matrix_RotationPart_doc},
1321         {"scale_part", (PyCFunction) Matrix_scalePart, METH_NOARGS, Matrix_scalePart_doc},
1322         {"resize4x4", (PyCFunction) Matrix_Resize4x4, METH_NOARGS, Matrix_Resize4x4_doc},
1323         {"to_4x4", (PyCFunction) Matrix_to_4x4, METH_NOARGS, Matrix_to_4x4_doc},
1324         {"to_3x3", (PyCFunction) Matrix_to_3x3, METH_NOARGS, Matrix_to_3x3_doc},
1325         {"to_euler", (PyCFunction) Matrix_toEuler, METH_VARARGS, Matrix_toEuler_doc},
1326         {"to_quat", (PyCFunction) Matrix_toQuat, METH_NOARGS, Matrix_toQuat_doc},
1327         {"copy", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
1328         {"__copy__", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
1329         {NULL, NULL, 0, NULL}
1330 };
1331
1332 /*------------------PY_OBECT DEFINITION--------------------------*/
1333 static char matrix_doc[] =
1334 "This object gives access to Matrices in Blender.";
1335
1336 PyTypeObject matrix_Type = {
1337         PyVarObject_HEAD_INIT(NULL, 0)
1338         "matrix",                                               /*tp_name*/
1339         sizeof(MatrixObject),                   /*tp_basicsize*/
1340         0,                                                              /*tp_itemsize*/
1341         (destructor)BaseMathObject_dealloc,             /*tp_dealloc*/
1342         0,                                                              /*tp_print*/
1343         0,                                                              /*tp_getattr*/
1344         0,                                                              /*tp_setattr*/
1345         0,                                                              /*tp_compare*/
1346         (reprfunc) Matrix_repr,                 /*tp_repr*/
1347         &Matrix_NumMethods,                             /*tp_as_number*/
1348         &Matrix_SeqMethods,                             /*tp_as_sequence*/
1349         &Matrix_AsMapping,                              /*tp_as_mapping*/
1350         0,                                                              /*tp_hash*/
1351         0,                                                              /*tp_call*/
1352         0,                                                              /*tp_str*/
1353         0,                                                              /*tp_getattro*/
1354         0,                                                              /*tp_setattro*/
1355         0,                                                              /*tp_as_buffer*/
1356         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1357         matrix_doc,                                             /*tp_doc*/
1358         0,                                                              /*tp_traverse*/
1359         0,                                                              /*tp_clear*/
1360         (richcmpfunc)Matrix_richcmpr,   /*tp_richcompare*/
1361         0,                                                              /*tp_weaklistoffset*/
1362         0,                                                              /*tp_iter*/
1363         0,                                                              /*tp_iternext*/
1364         Matrix_methods,                                 /*tp_methods*/
1365         0,                                                              /*tp_members*/
1366         Matrix_getseters,                               /*tp_getset*/
1367         0,                                                              /*tp_base*/
1368         0,                                                              /*tp_dict*/
1369         0,                                                              /*tp_descr_get*/
1370         0,                                                              /*tp_descr_set*/
1371         0,                                                              /*tp_dictoffset*/
1372         0,                                                              /*tp_init*/
1373         0,                                                              /*tp_alloc*/
1374         Matrix_new,                                             /*tp_new*/
1375         0,                                                              /*tp_free*/
1376         0,                                                              /*tp_is_gc*/
1377         0,                                                              /*tp_bases*/
1378         0,                                                              /*tp_mro*/
1379         0,                                                              /*tp_cache*/
1380         0,                                                              /*tp_subclasses*/
1381         0,                                                              /*tp_weaklist*/
1382         0                                                               /*tp_del*/
1383 };
1384
1385 /*------------------------newMatrixObject (internal)-------------
1386 creates a new matrix object
1387 self->matrix     self->contiguous_ptr (reference to data.xxx)
1388            [0]------------->[0]
1389                                                 [1]
1390                                                 [2]
1391            [1]------------->[3]
1392                                                 [4]
1393                                                 [5]
1394                                  ....
1395 self->matrix[1][1] = self->contigPtr[4] */
1396
1397 /*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
1398  (i.e. it was allocated elsewhere by MEM_mallocN())
1399   pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
1400  (i.e. it must be created here with PyMEM_malloc())*/
1401 PyObject *newMatrixObject(float *mat, int rowSize, int colSize, int type, PyTypeObject *base_type)
1402 {
1403         MatrixObject *self;
1404         int x, row, col;
1405
1406         /*matrix objects can be any 2-4row x 2-4col matrix*/
1407         if(rowSize < 2 || rowSize > 4 || colSize < 2 || colSize > 4){
1408                 PyErr_SetString(PyExc_RuntimeError, "matrix(): row and column sizes must be between 2 and 4");
1409                 return NULL;
1410         }
1411
1412         if(base_type)   self = (MatrixObject *)base_type->tp_alloc(base_type, 0);
1413         else                    self = PyObject_NEW(MatrixObject, &matrix_Type);
1414
1415         self->rowSize = rowSize;
1416         self->colSize = colSize;
1417         
1418         /* init callbacks as NULL */
1419         self->cb_user= NULL;
1420         self->cb_type= self->cb_subtype= 0;
1421
1422         if(type == Py_WRAP){
1423                 self->contigPtr = mat;
1424                 /*pointer array points to contigous memory*/
1425                 for(x = 0; x < rowSize; x++) {
1426                         self->matrix[x] = self->contigPtr + (x * colSize);
1427                 }
1428                 self->wrapped = Py_WRAP;
1429         }else if (type == Py_NEW){
1430                 self->contigPtr = PyMem_Malloc(rowSize * colSize * sizeof(float));
1431                 if(self->contigPtr == NULL) { /*allocation failure*/
1432                         PyErr_SetString( PyExc_MemoryError, "matrix(): problem allocating pointer space\n");
1433                         return NULL;
1434                 }
1435                 /*pointer array points to contigous memory*/
1436                 for(x = 0; x < rowSize; x++) {
1437                         self->matrix[x] = self->contigPtr + (x * colSize);
1438                 }
1439                 /*parse*/
1440                 if(mat) {       /*if a float array passed*/
1441                         for(row = 0; row < rowSize; row++) {
1442                                 for(col = 0; col < colSize; col++) {
1443                                         self->matrix[row][col] = mat[(row * colSize) + col];
1444                                 }
1445                         }
1446                 } else if (rowSize == colSize ) { /*or if no arguments are passed return identity matrix for square matrices */
1447                         Matrix_Identity(self);
1448                         Py_DECREF(self);
1449                 }
1450                 self->wrapped = Py_NEW;
1451         }else{ /*bad type*/
1452                 return NULL;
1453         }
1454         return (PyObject *) self;
1455 }
1456
1457 PyObject *newMatrixObject_cb(PyObject *cb_user, int rowSize, int colSize, int cb_type, int cb_subtype)
1458 {
1459         MatrixObject *self= (MatrixObject *)newMatrixObject(NULL, rowSize, colSize, Py_NEW, NULL);
1460         if(self) {
1461                 Py_INCREF(cb_user);
1462                 self->cb_user=                  cb_user;
1463                 self->cb_type=                  (unsigned char)cb_type;
1464                 self->cb_subtype=               (unsigned char)cb_subtype;
1465         }
1466         return (PyObject *) self;
1467 }
1468
1469 //----------------column_vector_multiplication (internal)---------
1470 //COLUMN VECTOR Multiplication (Matrix X Vector)
1471 // [1][4][7]   [a]
1472 // [2][5][8] * [b]
1473 // [3][6][9]   [c]
1474 //vector/matrix multiplication IS NOT COMMUTATIVE!!!!
1475 static PyObject *column_vector_multiplication(MatrixObject * mat, VectorObject* vec)
1476 {
1477         float vecNew[4], vecCopy[4];
1478         double dot = 0.0f;
1479         int x, y, z = 0;
1480
1481         if(!BaseMath_ReadCallback(mat) || !BaseMath_ReadCallback(vec))
1482                 return NULL;
1483         
1484         if(mat->rowSize != vec->size){
1485                 if(mat->rowSize == 4 && vec->size != 3){
1486                         PyErr_SetString(PyExc_AttributeError, "matrix * vector: matrix row size and vector size must be the same");
1487                         return NULL;
1488                 }else{
1489                         vecCopy[3] = 1.0f;
1490                 }
1491         }
1492
1493         for(x = 0; x < vec->size; x++){
1494                 vecCopy[x] = vec->vec[x];
1495         }
1496         vecNew[3] = 1.0f;
1497
1498         for(x = 0; x < mat->colSize; x++) {
1499                 for(y = 0; y < mat->rowSize; y++) {
1500                         dot += mat->matrix[y][x] * vecCopy[y];
1501                 }
1502                 vecNew[z++] = (float)dot;
1503                 dot = 0.0f;
1504         }
1505         return newVectorObject(vecNew, vec->size, Py_NEW, NULL);
1506 }