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