minor edits to exception formatting (remove ... or \n from suffix)
[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");
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");
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");
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");
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");
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");
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");
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'");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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
1047 static char Matrix_Lerp_doc[] =
1048 ".. function:: lerp(other, factor)\n"
1049 "\n"
1050 "   Returns the interpolation of two matricies.\n"
1051 "\n"
1052 "   :arg other: value to interpolate with.\n"
1053 "   :type other: :class:`Matrix`\n"
1054 "   :arg factor: The interpolation value in [0.0, 1.0].\n"
1055 "   :type factor: float\n"
1056 "   :return: The interpolated rotation.\n"
1057 "   :rtype: :class:`Matrix`\n";
1058
1059 static PyObject *Matrix_Lerp(MatrixObject *self, PyObject *args)
1060 {
1061         MatrixObject *mat2 = NULL;
1062         float fac, mat[MATRIX_MAX_DIM*MATRIX_MAX_DIM];
1063
1064         if(!PyArg_ParseTuple(args, "O!f:lerp", &matrix_Type, &mat2, &fac))
1065                 return NULL;
1066
1067         if(self->rowSize != mat2->rowSize || self->colSize != mat2->colSize) {
1068                 PyErr_SetString(PyExc_AttributeError, "matrix.lerp(): expects both matrix objects of the same dimensions");
1069                 return NULL;
1070         }
1071
1072         if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(mat2))
1073                 return NULL;
1074
1075         /* TODO, different sized matrix */
1076         if(self->rowSize==4 && self->colSize==4) {
1077                 blend_m4_m4m4((float (*)[4])mat, (float (*)[4])self->contigPtr, (float (*)[4])mat2->contigPtr, fac);
1078         }
1079         else if (self->rowSize==3 && self->colSize==3) {
1080                 blend_m3_m3m3((float (*)[3])mat, (float (*)[3])self->contigPtr, (float (*)[3])mat2->contigPtr, fac);
1081         }
1082         else {
1083                 PyErr_SetString(PyExc_AttributeError, "matrix.lerp(): only 3x3 and 4x4 matrices supported");
1084                 return NULL;
1085         }
1086
1087         return (PyObject*)newMatrixObject(mat, self->rowSize, self->colSize, Py_NEW, Py_TYPE(self));
1088 }
1089
1090 /*---------------------------Matrix.determinant() ----------------*/
1091 static char Matrix_Determinant_doc[] =
1092 ".. method:: determinant()\n"
1093 "\n"
1094 "   Return the determinant of a matrix.\n"
1095 "\n"
1096 "   :return: Return a the determinant of a matrix.\n"
1097 "   :rtype: float\n"
1098 "\n"
1099 "   .. seealso:: <http://en.wikipedia.org/wiki/Determinant>\n";
1100
1101 PyObject *Matrix_Determinant(MatrixObject * self)
1102 {
1103         if(!BaseMath_ReadCallback(self))
1104                 return NULL;
1105         
1106         if(self->rowSize != self->colSize){
1107                 PyErr_SetString(PyExc_AttributeError, "Matrix.determinant: only square matrices are supported");
1108                 return NULL;
1109         }
1110
1111         return PyFloat_FromDouble((double)matrix_determinant(self));
1112 }
1113 /*---------------------------Matrix.transpose() ------------------*/
1114 static char Matrix_Transpose_doc[] =
1115 ".. method:: transpose()\n"
1116 "\n"
1117 "   Set the matrix to its transpose.\n"
1118 "\n"
1119 "   :return: an instance of itself\n"
1120 "   :rtype: :class:`Matrix`\n"
1121 "\n"
1122 "   .. seealso:: <http://en.wikipedia.org/wiki/Transpose>\n";
1123
1124 PyObject *Matrix_Transpose(MatrixObject * self)
1125 {
1126         float t = 0.0f;
1127
1128         if(!BaseMath_ReadCallback(self))
1129                 return NULL;
1130         
1131         if(self->rowSize != self->colSize){
1132                 PyErr_SetString(PyExc_AttributeError, "Matrix.transpose(d): only square matrices are supported");
1133                 return NULL;
1134         }
1135
1136         if(self->rowSize == 2) {
1137                 t = self->matrix[1][0];
1138                 self->matrix[1][0] = self->matrix[0][1];
1139                 self->matrix[0][1] = t;
1140         } else if(self->rowSize == 3) {
1141                 transpose_m3((float (*)[3])self->contigPtr);
1142         } else {
1143                 transpose_m4((float (*)[4])self->contigPtr);
1144         }
1145
1146         (void)BaseMath_WriteCallback(self);
1147         Py_INCREF(self);
1148         return (PyObject *)self;
1149 }
1150
1151
1152 /*---------------------------Matrix.zero() -----------------------*/
1153 static char Matrix_Zero_doc[] =
1154 ".. method:: zero()\n"
1155 "\n"
1156 "   Set all the matrix values to zero.\n"
1157 "\n"
1158 "   :return: an instance of itself\n"
1159 "   :rtype: :class:`Matrix`\n";
1160
1161 PyObject *Matrix_Zero(MatrixObject * self)
1162 {
1163         int row, col;
1164         
1165         for(row = 0; row < self->rowSize; row++) {
1166                 for(col = 0; col < self->colSize; col++) {
1167                         self->matrix[row][col] = 0.0f;
1168                 }
1169         }
1170         
1171         if(!BaseMath_WriteCallback(self))
1172                 return NULL;
1173         
1174         Py_INCREF(self);
1175         return (PyObject *)self;
1176 }
1177 /*---------------------------Matrix.identity(() ------------------*/
1178 static char Matrix_Identity_doc[] =
1179 ".. method:: identity()\n"
1180 "\n"
1181 "   Set the matrix to the identity matrix.\n"
1182 "\n"
1183 "   :return: an instance of itself\n"
1184 "   :rtype: :class:`Matrix`\n"
1185 "\n"
1186 "   .. note:: An object with zero location and rotation, a scale of one, will have an identity matrix.\n"
1187 "\n"
1188 "   .. seealso:: <http://en.wikipedia.org/wiki/Identity_matrix>\n";
1189
1190 PyObject *Matrix_Identity(MatrixObject * self)
1191 {
1192         if(!BaseMath_ReadCallback(self))
1193                 return NULL;
1194         
1195         if(self->rowSize != self->colSize){
1196                 PyErr_SetString(PyExc_AttributeError, "Matrix.identity: only square matrices are supported");
1197                 return NULL;
1198         }
1199
1200         if(self->rowSize == 2) {
1201                 self->matrix[0][0] = 1.0f;
1202                 self->matrix[0][1] = 0.0f;
1203                 self->matrix[1][0] = 0.0f;
1204                 self->matrix[1][1] = 1.0f;
1205         } else if(self->rowSize == 3) {
1206                 unit_m3((float (*)[3])self->contigPtr);
1207         } else {
1208                 unit_m4((float (*)[4])self->contigPtr);
1209         }
1210
1211         if(!BaseMath_WriteCallback(self))
1212                 return NULL;
1213         
1214         Py_INCREF(self);
1215         return (PyObject *)self;
1216 }
1217
1218 /*---------------------------Matrix.copy() ------------------*/
1219 static char Matrix_copy_doc[] =
1220 ".. method:: copy()\n"
1221 "\n"
1222 "   Returns a copy of this matrix.\n"
1223 "\n"
1224 "   :return: an instance of itself\n"
1225 "   :rtype: :class:`Matrix`\n";
1226
1227 PyObject *Matrix_copy(MatrixObject *self)
1228 {
1229         if(!BaseMath_ReadCallback(self))
1230                 return NULL;
1231         
1232         return (PyObject*)newMatrixObject((float (*))self->contigPtr, self->rowSize, self->colSize, Py_NEW, Py_TYPE(self));
1233 }
1234
1235 /*----------------------------print object (internal)-------------*/
1236 /*print the object to screen*/
1237 static PyObject *Matrix_repr(MatrixObject * self)
1238 {
1239         int x, y;
1240         PyObject *rows[MATRIX_MAX_DIM]= {0};
1241
1242         if(!BaseMath_ReadCallback(self))
1243                 return NULL;
1244
1245         for(x = 0; x < self->rowSize; x++){
1246                 rows[x]= PyTuple_New(self->rowSize);
1247                 for(y = 0; y < self->colSize; y++) {
1248                         PyTuple_SET_ITEM(rows[x], y, PyFloat_FromDouble(self->matrix[x][y]));
1249                 }
1250         }
1251         switch(self->rowSize) {
1252         case 2: return PyUnicode_FromFormat("Matrix(%R,\n"
1253                                                                                 "       %R)", rows[0], rows[1]);
1254
1255         case 3: return PyUnicode_FromFormat("Matrix(%R,\n"
1256                                                                                 "       %R,\n"
1257                                                                                 "       %R)", rows[0], rows[1], rows[2]);
1258
1259         case 4: return PyUnicode_FromFormat("Matrix(%R,\n"
1260                                                                                 "       %R,\n"
1261                                                                                 "       %R,\n"
1262                                                                                 "       %R)", rows[0], rows[1], rows[2], rows[3]);
1263         }
1264
1265         PyErr_SetString(PyExc_RuntimeError, "invalid matrix size");
1266         return NULL;
1267 }
1268
1269 /*------------------------tp_richcmpr*/
1270 /*returns -1 execption, 0 false, 1 true*/
1271 static PyObject* Matrix_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
1272 {
1273         MatrixObject *matA = NULL, *matB = NULL;
1274         int result = 0;
1275
1276         if (!MatrixObject_Check(objectA) || !MatrixObject_Check(objectB)){
1277                 if (comparison_type == Py_NE){
1278                         Py_RETURN_TRUE;
1279                 }else{
1280                         Py_RETURN_FALSE;
1281                 }
1282         }
1283         matA = (MatrixObject*)objectA;
1284         matB = (MatrixObject*)objectB;
1285
1286         if(!BaseMath_ReadCallback(matA) || !BaseMath_ReadCallback(matB))
1287                 return NULL;
1288         
1289         if (matA->colSize != matB->colSize || matA->rowSize != matB->rowSize){
1290                 if (comparison_type == Py_NE){
1291                         Py_RETURN_TRUE;
1292                 }else{
1293                         Py_RETURN_FALSE;
1294                 }
1295         }
1296
1297         switch (comparison_type){
1298                 case Py_EQ:
1299                         /*contigPtr is basically a really long vector*/
1300                         result = EXPP_VectorsAreEqual(matA->contigPtr, matB->contigPtr,
1301                                 (matA->rowSize * matA->colSize), 1);
1302                         break;
1303                 case Py_NE:
1304                         result = EXPP_VectorsAreEqual(matA->contigPtr, matB->contigPtr,
1305                                 (matA->rowSize * matA->colSize), 1);
1306                         if (result == 0){
1307                                 result = 1;
1308                         }else{
1309                                 result = 0;
1310                         }
1311                         break;
1312                 default:
1313                         printf("The result of the comparison could not be evaluated");
1314                         break;
1315         }
1316         if (result == 1){
1317                 Py_RETURN_TRUE;
1318         }else{
1319                 Py_RETURN_FALSE;
1320         }
1321 }
1322
1323 /*---------------------SEQUENCE PROTOCOLS------------------------
1324   ----------------------------len(object)------------------------
1325   sequence length*/
1326 static int Matrix_len(MatrixObject * self)
1327 {
1328         return (self->rowSize);
1329 }
1330 /*----------------------------object[]---------------------------
1331   sequence accessor (get)
1332   the wrapped vector gives direct access to the matrix data*/
1333 static PyObject *Matrix_item(MatrixObject * self, int i)
1334 {
1335         if(!BaseMath_ReadCallback(self))
1336                 return NULL;
1337         
1338         if(i < 0 || i >= self->rowSize) {
1339                 PyErr_SetString(PyExc_IndexError, "matrix[attribute]: array index out of range");
1340                 return NULL;
1341         }
1342         return newVectorObject_cb((PyObject *)self, self->colSize, mathutils_matrix_vector_cb_index, i);
1343 }
1344 /*----------------------------object[]-------------------------
1345   sequence accessor (set)*/
1346 static int Matrix_ass_item(MatrixObject * self, int i, PyObject * ob)
1347 {
1348         int y, x, size = 0;
1349         float vec[4];
1350         PyObject *m, *f;
1351
1352         if(!BaseMath_ReadCallback(self))
1353                 return -1;
1354         
1355         if(i >= self->rowSize || i < 0){
1356                 PyErr_SetString(PyExc_TypeError, "matrix[attribute] = x: bad column");
1357                 return -1;
1358         }
1359
1360         if(PySequence_Check(ob)){
1361                 size = PySequence_Length(ob);
1362                 if(size != self->colSize){
1363                         PyErr_SetString(PyExc_TypeError, "matrix[attribute] = x: bad sequence size");
1364                         return -1;
1365                 }
1366                 for (x = 0; x < size; x++) {
1367                         m = PySequence_GetItem(ob, x);
1368                         if (m == NULL) { /*Failed to read sequence*/
1369                                 PyErr_SetString(PyExc_RuntimeError, "matrix[attribute] = x: unable to read sequence");
1370                                 return -1;
1371                         }
1372
1373                         f = PyNumber_Float(m);
1374                         if(f == NULL) { /*parsed item not a number*/
1375                                 Py_DECREF(m);
1376                                 PyErr_SetString(PyExc_TypeError, "matrix[attribute] = x: sequence argument not a number");
1377                                 return -1;
1378                         }
1379
1380                         vec[x] = (float)PyFloat_AS_DOUBLE(f);
1381                         Py_DECREF(m);
1382                         Py_DECREF(f);
1383                 }
1384                 /*parsed well - now set in matrix*/
1385                 for(y = 0; y < size; y++){
1386                         self->matrix[i][y] = vec[y];
1387                 }
1388                 
1389                 (void)BaseMath_WriteCallback(self);
1390                 return 0;
1391         }else{
1392                 PyErr_SetString(PyExc_TypeError, "matrix[attribute] = x: expects a sequence of column size");
1393                 return -1;
1394         }
1395 }
1396 /*----------------------------object[z:y]------------------------
1397   sequence slice (get)*/
1398 static PyObject *Matrix_slice(MatrixObject * self, int begin, int end)
1399 {
1400
1401         PyObject *list = NULL;
1402         int count;
1403         
1404         if(!BaseMath_ReadCallback(self))
1405                 return NULL;
1406
1407         CLAMP(begin, 0, self->rowSize);
1408         CLAMP(end, 0, self->rowSize);
1409         begin = MIN2(begin,end);
1410
1411         list = PyList_New(end - begin);
1412         for(count = begin; count < end; count++) {
1413                 PyList_SetItem(list, count - begin,
1414                                 newVectorObject_cb((PyObject *)self, self->colSize, mathutils_matrix_vector_cb_index, count));
1415
1416         }
1417
1418         return list;
1419 }
1420 /*----------------------------object[z:y]------------------------
1421   sequence slice (set)*/
1422 static int Matrix_ass_slice(MatrixObject * self, int begin, int end, PyObject * seq)
1423 {
1424         int i, x, y, size, sub_size = 0;
1425         float mat[16], f;
1426         PyObject *subseq;
1427         PyObject *m;
1428
1429         if(!BaseMath_ReadCallback(self))
1430                 return -1;
1431         
1432         CLAMP(begin, 0, self->rowSize);
1433         CLAMP(end, 0, self->rowSize);
1434         begin = MIN2(begin,end);
1435
1436         if(PySequence_Check(seq)){
1437                 size = PySequence_Length(seq);
1438                 if(size != (end - begin)){
1439                         PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: size mismatch in slice assignment");
1440                         return -1;
1441                 }
1442                 /*parse sub items*/
1443                 for (i = 0; i < size; i++) {
1444                         /*parse each sub sequence*/
1445                         subseq = PySequence_GetItem(seq, i);
1446                         if (subseq == NULL) { /*Failed to read sequence*/
1447                                 PyErr_SetString(PyExc_RuntimeError, "matrix[begin:end] = []: unable to read sequence");
1448                                 return -1;
1449                         }
1450
1451                         if(PySequence_Check(subseq)){
1452                                 /*subsequence is also a sequence*/
1453                                 sub_size = PySequence_Length(subseq);
1454                                 if(sub_size != self->colSize){
1455                                         Py_DECREF(subseq);
1456                                         PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: size mismatch in slice assignment");
1457                                         return -1;
1458                                 }
1459                                 for (y = 0; y < sub_size; y++) {
1460                                         m = PySequence_GetItem(subseq, y);
1461                                         if (m == NULL) { /*Failed to read sequence*/
1462                                                 Py_DECREF(subseq);
1463                                                 PyErr_SetString(PyExc_RuntimeError, "matrix[begin:end] = []: unable to read sequence");
1464                                                 return -1;
1465                                         }
1466                                         
1467                                         f = PyFloat_AsDouble(m); /* faster to assume a float and raise an error after */
1468                                         if(f == -1 && PyErr_Occurred()) { /*parsed item not a number*/
1469                                                 Py_DECREF(m);
1470                                                 Py_DECREF(subseq);
1471                                                 PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: sequence argument not a number");
1472                                                 return -1;
1473                                         }
1474
1475                                         mat[(i * self->colSize) + y] = f;
1476                                         Py_DECREF(m);
1477                                 }
1478                         }else{
1479                                 Py_DECREF(subseq);
1480                                 PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: illegal argument type for built-in operation");
1481                                 return -1;
1482                         }
1483                         Py_DECREF(subseq);
1484                 }
1485                 /*parsed well - now set in matrix*/
1486                 for(x = 0; x < (size * sub_size); x++){
1487                         self->matrix[begin + (int)floor(x / self->colSize)][x % self->colSize] = mat[x];
1488                 }
1489                 
1490                 (void)BaseMath_WriteCallback(self);
1491                 return 0;
1492         }else{
1493                 PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: illegal argument type for built-in operation");
1494                 return -1;
1495         }
1496 }
1497 /*------------------------NUMERIC PROTOCOLS----------------------
1498   ------------------------obj + obj------------------------------*/
1499 static PyObject *Matrix_add(PyObject * m1, PyObject * m2)
1500 {
1501         int x, y;
1502         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1503                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
1504         MatrixObject *mat1 = NULL, *mat2 = NULL;
1505
1506         mat1 = (MatrixObject*)m1;
1507         mat2 = (MatrixObject*)m2;
1508
1509         if(!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) {
1510                 PyErr_SetString(PyExc_AttributeError, "Matrix addition: arguments not valid for this operation");
1511                 return NULL;
1512         }
1513         
1514         if(!BaseMath_ReadCallback(mat1) || !BaseMath_ReadCallback(mat2))
1515                 return NULL;
1516         
1517         if(mat1->rowSize != mat2->rowSize || mat1->colSize != mat2->colSize){
1518                 PyErr_SetString(PyExc_AttributeError, "Matrix addition: matrices must have the same dimensions for this operation");
1519                 return NULL;
1520         }
1521
1522         for(x = 0; x < mat1->rowSize; x++) {
1523                 for(y = 0; y < mat1->colSize; y++) {
1524                         mat[((x * mat1->colSize) + y)] = mat1->matrix[x][y] + mat2->matrix[x][y];
1525                 }
1526         }
1527
1528         return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW, NULL);
1529 }
1530 /*------------------------obj - obj------------------------------
1531   subtraction*/
1532 static PyObject *Matrix_sub(PyObject * m1, PyObject * m2)
1533 {
1534         int x, y;
1535         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1536                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
1537         MatrixObject *mat1 = NULL, *mat2 = NULL;
1538
1539         mat1 = (MatrixObject*)m1;
1540         mat2 = (MatrixObject*)m2;
1541
1542         if(!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) {
1543                 PyErr_SetString(PyExc_AttributeError, "Matrix addition: arguments not valid for this operation");
1544                 return NULL;
1545         }
1546         
1547         if(!BaseMath_ReadCallback(mat1) || !BaseMath_ReadCallback(mat2))
1548                 return NULL;
1549         
1550         if(mat1->rowSize != mat2->rowSize || mat1->colSize != mat2->colSize){
1551                 PyErr_SetString(PyExc_AttributeError, "Matrix addition: matrices must have the same dimensions for this operation");
1552                 return NULL;
1553         }
1554
1555         for(x = 0; x < mat1->rowSize; x++) {
1556                 for(y = 0; y < mat1->colSize; y++) {
1557                         mat[((x * mat1->colSize) + y)] = mat1->matrix[x][y] - mat2->matrix[x][y];
1558                 }
1559         }
1560
1561         return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW, NULL);
1562 }
1563 /*------------------------obj * obj------------------------------
1564   mulplication*/
1565 static PyObject *Matrix_mul(PyObject * m1, PyObject * m2)
1566 {
1567         int x, y, z;
1568         float scalar;
1569         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1570                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
1571         double dot = 0.0f;
1572         MatrixObject *mat1 = NULL, *mat2 = NULL;
1573
1574         if(MatrixObject_Check(m1)) {
1575                 mat1 = (MatrixObject*)m1;
1576                 if(!BaseMath_ReadCallback(mat1))
1577                         return NULL;
1578         }
1579         if(MatrixObject_Check(m2)) {
1580                 mat2 = (MatrixObject*)m2;
1581                 if(!BaseMath_ReadCallback(mat2))
1582                         return NULL;
1583         }
1584
1585         if(mat1 && mat2) { /*MATRIX * MATRIX*/
1586                 if(mat1->rowSize != mat2->colSize){
1587                         PyErr_SetString(PyExc_AttributeError,"Matrix multiplication: matrix A rowsize must equal matrix B colsize");
1588                         return NULL;
1589                 }
1590                 for(x = 0; x < mat2->rowSize; x++) {
1591                         for(y = 0; y < mat1->colSize; y++) {
1592                                 for(z = 0; z < mat1->rowSize; z++) {
1593                                         dot += (mat1->matrix[z][y] * mat2->matrix[x][z]);
1594                                 }
1595                                 mat[((x * mat1->colSize) + y)] = (float)dot;
1596                                 dot = 0.0f;
1597                         }
1598                 }
1599                 
1600                 return newMatrixObject(mat, mat2->rowSize, mat1->colSize, Py_NEW, NULL);
1601         }
1602         
1603         if(mat1==NULL){
1604                 scalar=PyFloat_AsDouble(m1); // may not be a float
1605                 if ((scalar == -1.0 && PyErr_Occurred())==0) { /*FLOAT/INT * MATRIX, this line annoys theeth, lets see if he finds it */
1606                         for(x = 0; x < mat2->rowSize; x++) {
1607                                 for(y = 0; y < mat2->colSize; y++) {
1608                                         mat[((x * mat2->colSize) + y)] = scalar * mat2->matrix[x][y];
1609                                 }
1610                         }
1611                         return newMatrixObject(mat, mat2->rowSize, mat2->colSize, Py_NEW, NULL);
1612                 }
1613                 
1614                 PyErr_SetString(PyExc_TypeError, "Matrix multiplication: arguments not acceptable for this operation");
1615                 return NULL;
1616         }
1617         else /* if(mat1) { */ {
1618                 if(VectorObject_Check(m2)) { /* MATRIX*VECTOR */
1619                         PyErr_SetString(PyExc_TypeError, "Matrix multiplication: Only 'vec * matrix' is supported, not the reverse");
1620                         return NULL;
1621                 }
1622                 else {
1623                         scalar= PyFloat_AsDouble(m2);
1624                         if ((scalar == -1.0 && PyErr_Occurred())==0) { /* MATRIX*FLOAT/INT */
1625                                 for(x = 0; x < mat1->rowSize; x++) {
1626                                         for(y = 0; y < mat1->colSize; y++) {
1627                                                 mat[((x * mat1->colSize) + y)] = scalar * mat1->matrix[x][y];
1628                                         }
1629                                 }
1630                                 return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW, NULL);
1631                         }
1632                 }
1633                 PyErr_SetString(PyExc_TypeError, "Matrix multiplication: arguments not acceptable for this operation");
1634                 return NULL;
1635         }
1636
1637         PyErr_SetString(PyExc_TypeError, "Matrix multiplication: arguments not acceptable for this operation");
1638         return NULL;
1639 }
1640 static PyObject* Matrix_inv(MatrixObject *self)
1641 {
1642         if(!BaseMath_ReadCallback(self))
1643                 return NULL;
1644         
1645         return Matrix_Invert(self);
1646 }
1647
1648 /*-----------------PROTOCOL DECLARATIONS--------------------------*/
1649 static PySequenceMethods Matrix_SeqMethods = {
1650         (lenfunc) Matrix_len,                                           /* sq_length */
1651         (binaryfunc) NULL,                                                      /* sq_concat */
1652         (ssizeargfunc) NULL,                                            /* sq_repeat */
1653         (ssizeargfunc) Matrix_item,                                     /* sq_item */
1654         (ssizessizeargfunc) Matrix_slice,                       /* sq_slice, deprecated TODO, replace */
1655         (ssizeobjargproc) Matrix_ass_item,                      /* sq_ass_item */
1656         (ssizessizeobjargproc) Matrix_ass_slice,        /* sq_ass_slice, deprecated TODO, replace */
1657         (objobjproc) NULL,                                                      /* sq_contains */
1658         (binaryfunc) NULL,                                                      /* sq_inplace_concat */
1659         (ssizeargfunc) NULL,                                            /* sq_inplace_repeat */
1660 };
1661
1662
1663 static PyObject *Matrix_subscript(MatrixObject* self, PyObject* item)
1664 {
1665         if (PyIndex_Check(item)) {
1666                 Py_ssize_t i;
1667                 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
1668                 if (i == -1 && PyErr_Occurred())
1669                         return NULL;
1670                 if (i < 0)
1671                         i += self->rowSize;
1672                 return Matrix_item(self, i);
1673         } else if (PySlice_Check(item)) {
1674                 Py_ssize_t start, stop, step, slicelength;
1675
1676                 if (PySlice_GetIndicesEx((PySliceObject*)item, self->rowSize, &start, &stop, &step, &slicelength) < 0)
1677                         return NULL;
1678
1679                 if (slicelength <= 0) {
1680                         return PyList_New(0);
1681                 }
1682                 else if (step == 1) {
1683                         return Matrix_slice(self, start, stop);
1684                 }
1685                 else {
1686                         PyErr_SetString(PyExc_TypeError, "slice steps not supported with matricies");
1687                         return NULL;
1688                 }
1689         }
1690         else {
1691                 PyErr_Format(PyExc_TypeError,
1692                                  "vector indices must be integers, not %.200s",
1693                                  item->ob_type->tp_name);
1694                 return NULL;
1695         }
1696 }
1697
1698 static int Matrix_ass_subscript(MatrixObject* self, PyObject* item, PyObject* value)
1699 {
1700         if (PyIndex_Check(item)) {
1701                 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
1702                 if (i == -1 && PyErr_Occurred())
1703                         return -1;
1704                 if (i < 0)
1705                         i += self->rowSize;
1706                 return Matrix_ass_item(self, i, value);
1707         }
1708         else if (PySlice_Check(item)) {
1709                 Py_ssize_t start, stop, step, slicelength;
1710
1711                 if (PySlice_GetIndicesEx((PySliceObject*)item, self->rowSize, &start, &stop, &step, &slicelength) < 0)
1712                         return -1;
1713
1714                 if (step == 1)
1715                         return Matrix_ass_slice(self, start, stop, value);
1716                 else {
1717                         PyErr_SetString(PyExc_TypeError, "slice steps not supported with matricies");
1718                         return -1;
1719                 }
1720         }
1721         else {
1722                 PyErr_Format(PyExc_TypeError,
1723                                  "matrix indices must be integers, not %.200s",
1724                                  item->ob_type->tp_name);
1725                 return -1;
1726         }
1727 }
1728
1729 static PyMappingMethods Matrix_AsMapping = {
1730         (lenfunc)Matrix_len,
1731         (binaryfunc)Matrix_subscript,
1732         (objobjargproc)Matrix_ass_subscript
1733 };
1734
1735
1736 static PyNumberMethods Matrix_NumMethods = {
1737                 (binaryfunc)    Matrix_add,     /*nb_add*/
1738                 (binaryfunc)    Matrix_sub,     /*nb_subtract*/
1739                 (binaryfunc)    Matrix_mul,     /*nb_multiply*/
1740                 0,                                                      /*nb_remainder*/
1741                 0,                                                      /*nb_divmod*/
1742                 0,                                                      /*nb_power*/
1743                 (unaryfunc)     0,      /*nb_negative*/
1744                 (unaryfunc)     0,      /*tp_positive*/
1745                 (unaryfunc)     0,      /*tp_absolute*/
1746                 (inquiry)       0,      /*tp_bool*/
1747                 (unaryfunc)     Matrix_inv,     /*nb_invert*/
1748                 0,                              /*nb_lshift*/
1749                 (binaryfunc)0,  /*nb_rshift*/
1750                 0,                              /*nb_and*/
1751                 0,                              /*nb_xor*/
1752                 0,                              /*nb_or*/
1753                 0,                              /*nb_int*/
1754                 0,                              /*nb_reserved*/
1755                 0,                              /*nb_float*/
1756                 0,                              /* nb_inplace_add */
1757                 0,                              /* nb_inplace_subtract */
1758                 0,                              /* nb_inplace_multiply */
1759                 0,                              /* nb_inplace_remainder */
1760                 0,                              /* nb_inplace_power */
1761                 0,                              /* nb_inplace_lshift */
1762                 0,                              /* nb_inplace_rshift */
1763                 0,                              /* nb_inplace_and */
1764                 0,                              /* nb_inplace_xor */
1765                 0,                              /* nb_inplace_or */
1766                 0,                              /* nb_floor_divide */
1767                 0,                              /* nb_true_divide */
1768                 0,                              /* nb_inplace_floor_divide */
1769                 0,                              /* nb_inplace_true_divide */
1770                 0,                              /* nb_index */
1771 };
1772
1773 static PyObject *Matrix_getRowSize(MatrixObject *self, void *UNUSED(closure))
1774 {
1775         return PyLong_FromLong((long) self->rowSize);
1776 }
1777
1778 static PyObject *Matrix_getColSize(MatrixObject *self, void *UNUSED(closure))
1779 {
1780         return PyLong_FromLong((long) self->colSize);
1781 }
1782
1783 static PyObject *Matrix_getMedianScale(MatrixObject *self, void *UNUSED(closure))
1784 {
1785         float mat[3][3];
1786
1787         if(!BaseMath_ReadCallback(self))
1788                 return NULL;
1789
1790         /*must be 3-4 cols, 3-4 rows, square matrix*/
1791         if(self->colSize == 4 && self->rowSize == 4)
1792                 copy_m3_m4(mat, (float (*)[4])self->contigPtr);
1793         else if(self->colSize == 3 && self->rowSize == 3)
1794                 copy_m3_m3(mat, (float (*)[3])self->contigPtr);
1795         else {
1796                 PyErr_SetString(PyExc_AttributeError, "Matrix.median_scale: inappropriate matrix size - expects 3x3 or 4x4 matrix");
1797                 return NULL;
1798         }
1799     
1800         return PyFloat_FromDouble(mat3_to_scale(mat));
1801 }
1802
1803 static PyObject *Matrix_getIsNegative(MatrixObject *self, void *UNUSED(closure))
1804 {
1805         if(!BaseMath_ReadCallback(self))
1806                 return NULL;
1807
1808         /*must be 3-4 cols, 3-4 rows, square matrix*/
1809         if(self->colSize == 4 && self->rowSize == 4)
1810                 return PyBool_FromLong(is_negative_m4((float (*)[4])self->contigPtr));
1811         else if(self->colSize == 3 && self->rowSize == 3)
1812                 return PyBool_FromLong(is_negative_m3((float (*)[3])self->contigPtr));
1813         else {
1814                 PyErr_SetString(PyExc_AttributeError, "Matrix.is_negative: inappropriate matrix size - expects 3x3 or 4x4 matrix");
1815                 return NULL;
1816         }
1817 }
1818
1819
1820 /*****************************************************************************/
1821 /* Python attributes get/set structure:                                      */
1822 /*****************************************************************************/
1823 static PyGetSetDef Matrix_getseters[] = {
1824         {"row_size", (getter)Matrix_getRowSize, (setter)NULL, "The row size of the matrix (readonly).\n\n:type: int", NULL},
1825         {"col_size", (getter)Matrix_getColSize, (setter)NULL, "The column size of the matrix (readonly).\n\n:type: int", NULL},
1826         {"median_scale", (getter)Matrix_getMedianScale, (setter)NULL, "The average scale applied to each axis (readonly).\n\n:type: float", NULL},
1827         {"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},
1828         {"is_wrapped", (getter)BaseMathObject_getWrapped, (setter)NULL, BaseMathObject_Wrapped_doc, NULL},
1829         {"owner",(getter)BaseMathObject_getOwner, (setter)NULL, BaseMathObject_Owner_doc, NULL},
1830         {NULL,NULL,NULL,NULL,NULL}  /* Sentinel */
1831 };
1832
1833 /*-----------------------METHOD DEFINITIONS ----------------------*/
1834 static struct PyMethodDef Matrix_methods[] = {
1835         {"zero", (PyCFunction) Matrix_Zero, METH_NOARGS, Matrix_Zero_doc},
1836         {"identity", (PyCFunction) Matrix_Identity, METH_NOARGS, Matrix_Identity_doc},
1837         {"transpose", (PyCFunction) Matrix_Transpose, METH_NOARGS, Matrix_Transpose_doc},
1838         {"lerp", (PyCFunction) Matrix_Lerp, METH_VARARGS, Matrix_Lerp_doc},
1839         {"determinant", (PyCFunction) Matrix_Determinant, METH_NOARGS, Matrix_Determinant_doc},
1840         {"invert", (PyCFunction) Matrix_Invert, METH_NOARGS, Matrix_Invert_doc},
1841         {"translation_part", (PyCFunction) Matrix_TranslationPart, METH_NOARGS, Matrix_TranslationPart_doc},
1842         {"rotation_part", (PyCFunction) Matrix_RotationPart, METH_NOARGS, Matrix_RotationPart_doc},
1843         {"scale_part", (PyCFunction) Matrix_scalePart, METH_NOARGS, Matrix_scalePart_doc},
1844         {"decompose", (PyCFunction) Matrix_decompose, METH_NOARGS, Matrix_decompose_doc},
1845         {"resize4x4", (PyCFunction) Matrix_Resize4x4, METH_NOARGS, Matrix_Resize4x4_doc},
1846         {"to_4x4", (PyCFunction) Matrix_to_4x4, METH_NOARGS, Matrix_to_4x4_doc},
1847         {"to_3x3", (PyCFunction) Matrix_to_3x3, METH_NOARGS, Matrix_to_3x3_doc},
1848         {"to_euler", (PyCFunction) Matrix_toEuler, METH_VARARGS, Matrix_toEuler_doc},
1849         {"to_quat", (PyCFunction) Matrix_toQuat, METH_NOARGS, Matrix_toQuat_doc},
1850         {"copy", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
1851         {"__copy__", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
1852         
1853         /* class methods */
1854         {"Rotation", (PyCFunction) C_Matrix_Rotation, METH_VARARGS | METH_CLASS, C_Matrix_Rotation_doc},
1855         {"Scale", (PyCFunction) C_Matrix_Scale, METH_VARARGS | METH_CLASS, C_Matrix_Scale_doc},
1856         {"Shear", (PyCFunction) C_Matrix_Shear, METH_VARARGS | METH_CLASS, C_Matrix_Shear_doc},
1857         {"Translation", (PyCFunction) C_Matrix_Translation, METH_O | METH_CLASS, C_Matrix_Translation_doc},
1858         {"OrthoProjection", (PyCFunction) C_Matrix_OrthoProjection,  METH_VARARGS | METH_CLASS, C_Matrix_OrthoProjection_doc},
1859         {NULL, NULL, 0, NULL}
1860 };
1861
1862 /*------------------PY_OBECT DEFINITION--------------------------*/
1863 static char matrix_doc[] =
1864 "This object gives access to Matrices in Blender.";
1865
1866 PyTypeObject matrix_Type = {
1867         PyVarObject_HEAD_INIT(NULL, 0)
1868         "matrix",                                               /*tp_name*/
1869         sizeof(MatrixObject),                   /*tp_basicsize*/
1870         0,                                                              /*tp_itemsize*/
1871         (destructor)BaseMathObject_dealloc,             /*tp_dealloc*/
1872         0,                                                              /*tp_print*/
1873         0,                                                              /*tp_getattr*/
1874         0,                                                              /*tp_setattr*/
1875         0,                                                              /*tp_compare*/
1876         (reprfunc) Matrix_repr,                 /*tp_repr*/
1877         &Matrix_NumMethods,                             /*tp_as_number*/
1878         &Matrix_SeqMethods,                             /*tp_as_sequence*/
1879         &Matrix_AsMapping,                              /*tp_as_mapping*/
1880         0,                                                              /*tp_hash*/
1881         0,                                                              /*tp_call*/
1882         0,                                                              /*tp_str*/
1883         0,                                                              /*tp_getattro*/
1884         0,                                                              /*tp_setattro*/
1885         0,                                                              /*tp_as_buffer*/
1886         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1887         matrix_doc,                                             /*tp_doc*/
1888         0,                                                              /*tp_traverse*/
1889         0,                                                              /*tp_clear*/
1890         (richcmpfunc)Matrix_richcmpr,   /*tp_richcompare*/
1891         0,                                                              /*tp_weaklistoffset*/
1892         0,                                                              /*tp_iter*/
1893         0,                                                              /*tp_iternext*/
1894         Matrix_methods,                                 /*tp_methods*/
1895         0,                                                              /*tp_members*/
1896         Matrix_getseters,                               /*tp_getset*/
1897         0,                                                              /*tp_base*/
1898         0,                                                              /*tp_dict*/
1899         0,                                                              /*tp_descr_get*/
1900         0,                                                              /*tp_descr_set*/
1901         0,                                                              /*tp_dictoffset*/
1902         0,                                                              /*tp_init*/
1903         0,                                                              /*tp_alloc*/
1904         Matrix_new,                                             /*tp_new*/
1905         0,                                                              /*tp_free*/
1906         0,                                                              /*tp_is_gc*/
1907         0,                                                              /*tp_bases*/
1908         0,                                                              /*tp_mro*/
1909         0,                                                              /*tp_cache*/
1910         0,                                                              /*tp_subclasses*/
1911         0,                                                              /*tp_weaklist*/
1912         0                                                               /*tp_del*/
1913 };
1914
1915 /*------------------------newMatrixObject (internal)-------------
1916 creates a new matrix object
1917 self->matrix     self->contiguous_ptr (reference to data.xxx)
1918            [0]------------->[0]
1919                                                 [1]
1920                                                 [2]
1921            [1]------------->[3]
1922                                                 [4]
1923                                                 [5]
1924
1925 self->matrix[1][1] = self->contigPtr[4] */
1926
1927 /*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
1928  (i.e. it was allocated elsewhere by MEM_mallocN())
1929   pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
1930  (i.e. it must be created here with PyMEM_malloc())*/
1931 PyObject *newMatrixObject(float *mat, int rowSize, int colSize, int type, PyTypeObject *base_type)
1932 {
1933         MatrixObject *self;
1934         int x, row, col;
1935
1936         /*matrix objects can be any 2-4row x 2-4col matrix*/
1937         if(rowSize < 2 || rowSize > 4 || colSize < 2 || colSize > 4){
1938                 PyErr_SetString(PyExc_RuntimeError, "matrix(): row and column sizes must be between 2 and 4");
1939                 return NULL;
1940         }
1941
1942         if(base_type)   self = (MatrixObject *)base_type->tp_alloc(base_type, 0);
1943         else                    self = PyObject_NEW(MatrixObject, &matrix_Type);
1944
1945         self->rowSize = rowSize;
1946         self->colSize = colSize;
1947         
1948         /* init callbacks as NULL */
1949         self->cb_user= NULL;
1950         self->cb_type= self->cb_subtype= 0;
1951
1952         if(type == Py_WRAP){
1953                 self->contigPtr = mat;
1954                 /*pointer array points to contigous memory*/
1955                 for(x = 0; x < rowSize; x++) {
1956                         self->matrix[x] = self->contigPtr + (x * colSize);
1957                 }
1958                 self->wrapped = Py_WRAP;
1959         }else if (type == Py_NEW){
1960                 self->contigPtr = PyMem_Malloc(rowSize * colSize * sizeof(float));
1961                 if(self->contigPtr == NULL) { /*allocation failure*/
1962                         PyErr_SetString(PyExc_MemoryError, "matrix(): problem allocating pointer space");
1963                         return NULL;
1964                 }
1965                 /*pointer array points to contigous memory*/
1966                 for(x = 0; x < rowSize; x++) {
1967                         self->matrix[x] = self->contigPtr + (x * colSize);
1968                 }
1969                 /*parse*/
1970                 if(mat) {       /*if a float array passed*/
1971                         for(row = 0; row < rowSize; row++) {
1972                                 for(col = 0; col < colSize; col++) {
1973                                         self->matrix[row][col] = mat[(row * colSize) + col];
1974                                 }
1975                         }
1976                 } else if (rowSize == colSize ) { /*or if no arguments are passed return identity matrix for square matrices */
1977                         Matrix_Identity(self);
1978                         Py_DECREF(self);
1979                 }
1980                 self->wrapped = Py_NEW;
1981         }else{ /*bad type*/
1982                 return NULL;
1983         }
1984         return (PyObject *) self;
1985 }
1986
1987 PyObject *newMatrixObject_cb(PyObject *cb_user, int rowSize, int colSize, int cb_type, int cb_subtype)
1988 {
1989         MatrixObject *self= (MatrixObject *)newMatrixObject(NULL, rowSize, colSize, Py_NEW, NULL);
1990         if(self) {
1991                 Py_INCREF(cb_user);
1992                 self->cb_user=                  cb_user;
1993                 self->cb_type=                  (unsigned char)cb_type;
1994                 self->cb_subtype=               (unsigned char)cb_subtype;
1995         }
1996         return (PyObject *) self;
1997 }