fix for a bug in mathutils when a vector was accessing a matrix and the matrix size...
[blender.git] / source / blender / python / mathutils / mathutils_Matrix.c
1 /*
2  *
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  *
19  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20  * All rights reserved.
21  *
22  * Contributor(s): Michel Selten & Joseph Gilbert
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/python/mathutils/mathutils_Matrix.c
28  *  \ingroup pymathutils
29  */
30
31
32 #include <Python.h>
33
34 #include "mathutils.h"
35
36 #include "BLI_math.h"
37 #include "BLI_utildefines.h"
38 #include "BLI_string.h"
39 #include "BLI_dynstr.h"
40
41 typedef enum eMatrixAccess_t {
42         MAT_ACCESS_ROW,
43         MAT_ACCESS_COL
44 } eMatrixAccess_t;
45
46 static PyObject *Matrix_copy(MatrixObject *self);
47 static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value);
48 static PyObject *matrix__apply_to_copy(PyNoArgsFunction matrix_func, MatrixObject *self);
49 static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrixAccess_t type);
50
51 static int matrix_row_vector_check(MatrixObject *mat, VectorObject *vec, int row)
52 {
53         if ((vec->size != mat->num_col) || (row >= mat->num_row)) {
54                 PyErr_SetString(PyExc_AttributeError,
55                                 "Matrix(): "
56                                 "owner matrix has been resized since this row vector was created");
57                 return 0;
58         }
59         else {
60                 return 1;
61         }
62 }
63
64 static int matrix_col_vector_check(MatrixObject *mat, VectorObject *vec, int col)
65 {
66         if ((vec->size != mat->num_row) || (col >= mat->num_col)) {
67                 PyErr_SetString(PyExc_AttributeError,
68                                 "Matrix(): "
69                                 "owner matrix has been resized since this column vector was created");
70                 return 0;
71         }
72         else {
73                 return 1;
74         }
75 }
76
77 /* ----------------------------------------------------------------------------
78  * matrix row callbacks
79  * this is so you can do matrix[i][j] = val OR matrix.row[i][j] = val */
80
81 int mathutils_matrix_row_cb_index = -1;
82
83 static int mathutils_matrix_row_check(BaseMathObject *bmo)
84 {
85         MatrixObject *self = (MatrixObject *)bmo->cb_user;
86         return BaseMath_ReadCallback(self);
87 }
88
89 static int mathutils_matrix_row_get(BaseMathObject *bmo, int row)
90 {
91         MatrixObject *self = (MatrixObject *)bmo->cb_user;
92         int col;
93
94         if (BaseMath_ReadCallback(self) == -1)
95                 return -1;
96         if (!matrix_row_vector_check(self, (VectorObject *)bmo, row))
97                 return -1;
98
99         for (col = 0; col < self->num_col; col++) {
100                 bmo->data[col] = MATRIX_ITEM(self, row, col);
101         }
102
103         return 0;
104 }
105
106 static int mathutils_matrix_row_set(BaseMathObject *bmo, int row)
107 {
108         MatrixObject *self = (MatrixObject *)bmo->cb_user;
109         int col;
110
111         if (BaseMath_ReadCallback(self) == -1)
112                 return -1;
113         if (!matrix_row_vector_check(self, (VectorObject *)bmo, row))
114                 return -1;
115
116         for (col = 0; col < self->num_col; col++) {
117                 MATRIX_ITEM(self, row, col) = bmo->data[col];
118         }
119
120         (void)BaseMath_WriteCallback(self);
121         return 0;
122 }
123
124 static int mathutils_matrix_row_get_index(BaseMathObject *bmo, int row, int col)
125 {
126         MatrixObject *self = (MatrixObject *)bmo->cb_user;
127
128         if (BaseMath_ReadCallback(self) == -1)
129                 return -1;
130         if (!matrix_row_vector_check(self, (VectorObject *)bmo, row))
131                 return -1;
132
133         bmo->data[col] = MATRIX_ITEM(self, row, col);
134         return 0;
135 }
136
137 static int mathutils_matrix_row_set_index(BaseMathObject *bmo, int row, int col)
138 {
139         MatrixObject *self = (MatrixObject *)bmo->cb_user;
140
141         if (BaseMath_ReadCallback(self) == -1)
142                 return -1;
143         if (!matrix_row_vector_check(self, (VectorObject *)bmo, row))
144                 return -1;
145
146         MATRIX_ITEM(self, row, col) = bmo->data[col];
147
148         (void)BaseMath_WriteCallback(self);
149         return 0;
150 }
151
152 Mathutils_Callback mathutils_matrix_row_cb = {
153         mathutils_matrix_row_check,
154         mathutils_matrix_row_get,
155         mathutils_matrix_row_set,
156         mathutils_matrix_row_get_index,
157         mathutils_matrix_row_set_index
158 };
159
160
161 /* ----------------------------------------------------------------------------
162  * matrix row callbacks
163  * this is so you can do matrix.col[i][j] = val */
164
165 int mathutils_matrix_col_cb_index = -1;
166
167 static int mathutils_matrix_col_check(BaseMathObject *bmo)
168 {
169         MatrixObject *self = (MatrixObject *)bmo->cb_user;
170         return BaseMath_ReadCallback(self);
171 }
172
173 static int mathutils_matrix_col_get(BaseMathObject *bmo, int col)
174 {
175         MatrixObject *self = (MatrixObject *)bmo->cb_user;
176         int num_row;
177         int row;
178
179         if (BaseMath_ReadCallback(self) == -1)
180                 return -1;
181         if (!matrix_col_vector_check(self, (VectorObject *)bmo, col))
182                 return -1;
183
184         /* for 'translation' size will always be '3' even on 4x4 vec */
185         num_row = MIN2(self->num_row, ((VectorObject *)bmo)->size);
186
187         for (row = 0; row < num_row; row++) {
188                 bmo->data[row] = MATRIX_ITEM(self, row, col);
189         }
190
191         return 0;
192 }
193
194 static int mathutils_matrix_col_set(BaseMathObject *bmo, int col)
195 {
196         MatrixObject *self = (MatrixObject *)bmo->cb_user;
197         int num_row;
198         int row;
199
200         if (BaseMath_ReadCallback(self) == -1)
201                 return -1;
202         if (!matrix_col_vector_check(self, (VectorObject *)bmo, col))
203                 return -1;
204
205         /* for 'translation' size will always be '3' even on 4x4 vec */
206         num_row = MIN2(self->num_row, ((VectorObject *)bmo)->size);
207
208         for (row = 0; row < num_row; row++) {
209                 MATRIX_ITEM(self, row, col) = bmo->data[row];
210         }
211
212         (void)BaseMath_WriteCallback(self);
213         return 0;
214 }
215
216 static int mathutils_matrix_col_get_index(BaseMathObject *bmo, int col, int row)
217 {
218         MatrixObject *self = (MatrixObject *)bmo->cb_user;
219
220         if (BaseMath_ReadCallback(self) == -1)
221                 return -1;
222         if (!matrix_col_vector_check(self, (VectorObject *)bmo, col))
223                 return -1;
224
225         bmo->data[row] = MATRIX_ITEM(self, row, col);
226         return 0;
227 }
228
229 static int mathutils_matrix_col_set_index(BaseMathObject *bmo, int col, int row)
230 {
231         MatrixObject *self = (MatrixObject *)bmo->cb_user;
232
233         if (BaseMath_ReadCallback(self) == -1)
234                 return -1;
235         if (!matrix_col_vector_check(self, (VectorObject *)bmo, col))
236                 return -1;
237
238         MATRIX_ITEM(self, row, col) = bmo->data[row];
239
240         (void)BaseMath_WriteCallback(self);
241         return 0;
242 }
243
244 Mathutils_Callback mathutils_matrix_col_cb = {
245         mathutils_matrix_col_check,
246         mathutils_matrix_col_get,
247         mathutils_matrix_col_set,
248         mathutils_matrix_col_get_index,
249         mathutils_matrix_col_set_index
250 };
251
252
253 /* ----------------------------------------------------------------------------
254  * matrix row callbacks
255  * this is so you can do matrix.translation = val
256  * note, this is _exactly like matrix.col except the 4th component is always omitted */
257
258 int mathutils_matrix_translation_cb_index = -1;
259
260 static int mathutils_matrix_translation_check(BaseMathObject *bmo)
261 {
262         MatrixObject *self = (MatrixObject *)bmo->cb_user;
263         return BaseMath_ReadCallback(self);
264 }
265
266 static int mathutils_matrix_translation_get(BaseMathObject *bmo, int col)
267 {
268         MatrixObject *self = (MatrixObject *)bmo->cb_user;
269         int row;
270
271         if (BaseMath_ReadCallback(self) == -1)
272                 return -1;
273
274         for (row = 0; row < 3; row++) {
275                 bmo->data[row] = MATRIX_ITEM(self, row, col);
276         }
277
278         return 0;
279 }
280
281 static int mathutils_matrix_translation_set(BaseMathObject *bmo, int col)
282 {
283         MatrixObject *self = (MatrixObject *)bmo->cb_user;
284         int row;
285
286         if (BaseMath_ReadCallback(self) == -1)
287                 return -1;
288
289         for (row = 0; row < 3; row++) {
290                 MATRIX_ITEM(self, row, col) = bmo->data[row];
291         }
292
293         (void)BaseMath_WriteCallback(self);
294         return 0;
295 }
296
297 static int mathutils_matrix_translation_get_index(BaseMathObject *bmo, int col, int row)
298 {
299         MatrixObject *self = (MatrixObject *)bmo->cb_user;
300
301         if (BaseMath_ReadCallback(self) == -1)
302                 return -1;
303
304         bmo->data[row] = MATRIX_ITEM(self, row, col);
305         return 0;
306 }
307
308 static int mathutils_matrix_translation_set_index(BaseMathObject *bmo, int col, int row)
309 {
310         MatrixObject *self = (MatrixObject *)bmo->cb_user;
311
312         if (BaseMath_ReadCallback(self) == -1)
313                 return -1;
314
315         MATRIX_ITEM(self, row, col) = bmo->data[row];
316
317         (void)BaseMath_WriteCallback(self);
318         return 0;
319 }
320
321 Mathutils_Callback mathutils_matrix_translation_cb = {
322         mathutils_matrix_translation_check,
323         mathutils_matrix_translation_get,
324         mathutils_matrix_translation_set,
325         mathutils_matrix_translation_get_index,
326         mathutils_matrix_translation_set_index
327 };
328
329
330 /* matrix column callbacks, this is so you can do matrix.translation = Vector()  */
331
332 //----------------------------------mathutils.Matrix() -----------------
333 //mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc.
334 //create a new matrix type
335 static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
336 {
337         if (kwds && PyDict_Size(kwds)) {
338                 PyErr_SetString(PyExc_TypeError,
339                                 "Matrix(): "
340                                 "takes no keyword args");
341                 return NULL;
342         }
343
344         switch (PyTuple_GET_SIZE(args)) {
345                 case 0:
346                         return Matrix_CreatePyObject(NULL, 4, 4, Py_NEW, type);
347                 case 1:
348                 {
349                         PyObject *arg = PyTuple_GET_ITEM(args, 0);
350
351                         /* Input is now as a sequence of rows so length of sequence
352                          * is the number of rows */
353                         /* -1 is an error, size checks will accunt for this */
354                         const unsigned short num_row = PySequence_Size(arg);
355
356                         if (num_row >= 2 && num_row <= 4) {
357                                 PyObject *item = PySequence_GetItem(arg, 0);
358                                 /* Since each item is a row, number of items is the
359                                  * same as the number of columns */
360                                 const unsigned short num_col = PySequence_Size(item);
361                                 Py_XDECREF(item);
362
363                                 if (num_col >= 2 && num_col <= 4) {
364                                         /* sane row & col size, new matrix and assign as slice  */
365                                         PyObject *matrix = Matrix_CreatePyObject(NULL, num_col, num_row, Py_NEW, type);
366                                         if (Matrix_ass_slice((MatrixObject *)matrix, 0, INT_MAX, arg) == 0) {
367                                                 return matrix;
368                                         }
369                                         else { /* matrix ok, slice assignment not */
370                                                 Py_DECREF(matrix);
371                                         }
372                                 }
373                         }
374                 }
375         }
376
377         /* will overwrite error */
378         PyErr_SetString(PyExc_TypeError,
379                         "Matrix(): "
380                         "expects no args or 2-4 numeric sequences");
381         return NULL;
382 }
383
384 static PyObject *matrix__apply_to_copy(PyNoArgsFunction matrix_func, MatrixObject *self)
385 {
386         PyObject *ret = Matrix_copy(self);
387         PyObject *ret_dummy = matrix_func(ret);
388         if (ret_dummy) {
389                 Py_DECREF(ret_dummy);
390                 return (PyObject *)ret;
391         }
392         else { /* error */
393                 Py_DECREF(ret);
394                 return NULL;
395         }
396 }
397
398 /* when a matrix is 4x4 size but initialized as a 3x3, re-assign values for 4x4 */
399 static void matrix_3x3_as_4x4(float mat[16])
400 {
401         mat[10] = mat[8];
402         mat[9] = mat[7];
403         mat[8] = mat[6];
404         mat[7] = 0.0f;
405         mat[6] = mat[5];
406         mat[5] = mat[4];
407         mat[4] = mat[3];
408         mat[3] = 0.0f;
409 }
410
411 /*-----------------------CLASS-METHODS----------------------------*/
412
413 //mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc.
414 PyDoc_STRVAR(C_Matrix_Rotation_doc,
415 ".. classmethod:: Rotation(angle, size, axis)\n"
416 "\n"
417 "   Create a matrix representing a rotation.\n"
418 "\n"
419 "   :arg angle: The angle of rotation desired, in radians.\n"
420 "   :type angle: float\n"
421 "   :arg size: The size of the rotation matrix to construct [2, 4].\n"
422 "   :type size: int\n"
423 "   :arg axis: a string in ['X', 'Y', 'Z'] or a 3D Vector Object\n"
424 "      (optional when size is 2).\n"
425 "   :type axis: string or :class:`Vector`\n"
426 "   :return: A new rotation matrix.\n"
427 "   :rtype: :class:`Matrix`\n"
428 );
429 static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args)
430 {
431         PyObject *vec = NULL;
432         const char *axis = NULL;
433         int matSize;
434         double angle; /* use double because of precision problems at high values */
435         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
436                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
437
438         if (!PyArg_ParseTuple(args, "di|O", &angle, &matSize, &vec)) {
439                 PyErr_SetString(PyExc_TypeError,
440                                 "Matrix.Rotation(angle, size, axis): "
441                                 "expected float int and a string or vector");
442                 return NULL;
443         }
444
445         if (vec && PyUnicode_Check(vec)) {
446                 axis = _PyUnicode_AsString((PyObject *)vec);
447                 if (axis == NULL || axis[0] == '\0' || axis[1] != '\0' || axis[0] < 'X' || axis[0] > 'Z') {
448                         PyErr_SetString(PyExc_ValueError,
449                                         "Matrix.Rotation(): "
450                                         "3rd argument axis value must be a 3D vector "
451                                         "or a string in 'X', 'Y', 'Z'");
452                         return NULL;
453                 }
454                 else {
455                         /* use the string */
456                         vec = NULL;
457                 }
458         }
459
460         angle = angle_wrap_rad(angle);
461
462         if (matSize != 2 && matSize != 3 && matSize != 4) {
463                 PyErr_SetString(PyExc_ValueError,
464                                 "Matrix.Rotation(): "
465                                 "can only return a 2x2 3x3 or 4x4 matrix");
466                 return NULL;
467         }
468         if (matSize == 2 && (vec != NULL)) {
469                 PyErr_SetString(PyExc_ValueError,
470                                 "Matrix.Rotation(): "
471                                 "cannot create a 2x2 rotation matrix around arbitrary axis");
472                 return NULL;
473         }
474         if ((matSize == 3 || matSize == 4) && (axis == NULL) && (vec == NULL)) {
475                 PyErr_SetString(PyExc_ValueError,
476                                 "Matrix.Rotation(): "
477                                 "axis of rotation for 3d and 4d matrices is required");
478                 return NULL;
479         }
480
481         /* check for valid vector/axis above */
482         if (vec) {
483                 float tvec[3];
484
485                 if (mathutils_array_parse(tvec, 3, 3, vec, "Matrix.Rotation(angle, size, axis), invalid 'axis' arg") == -1)
486                         return NULL;
487
488                 axis_angle_to_mat3((float (*)[3])mat, tvec, angle);
489         }
490         else if (matSize == 2) {
491                 const float angle_cos = cosf(angle);
492                 const float angle_sin = sinf(angle);
493
494                 //2D rotation matrix
495                 mat[0] =  angle_cos;
496                 mat[1] =  angle_sin;
497                 mat[2] = -angle_sin;
498                 mat[3] =  angle_cos;
499         }
500         else {
501                 /* valid axis checked above */
502                 single_axis_angle_to_mat3((float (*)[3])mat, axis[0], angle);
503         }
504
505         if (matSize == 4) {
506                 matrix_3x3_as_4x4(mat);
507         }
508         //pass to matrix creation
509         return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
510 }
511
512
513 PyDoc_STRVAR(C_Matrix_Translation_doc,
514 ".. classmethod:: Translation(vector)\n"
515 "\n"
516 "   Create a matrix representing a translation.\n"
517 "\n"
518 "   :arg vector: The translation vector.\n"
519 "   :type vector: :class:`Vector`\n"
520 "   :return: An identity matrix with a translation.\n"
521 "   :rtype: :class:`Matrix`\n"
522 );
523 static PyObject *C_Matrix_Translation(PyObject *cls, PyObject *value)
524 {
525         float mat[4][4]= MAT4_UNITY;
526
527         if (mathutils_array_parse(mat[3], 3, 4, value, "mathutils.Matrix.Translation(vector), invalid vector arg") == -1)
528                 return NULL;
529
530         return Matrix_CreatePyObject(&mat[0][0], 4, 4, Py_NEW, (PyTypeObject *)cls);
531 }
532 //----------------------------------mathutils.Matrix.Scale() -------------
533 //mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc.
534 PyDoc_STRVAR(C_Matrix_Scale_doc,
535 ".. classmethod:: Scale(factor, size, axis)\n"
536 "\n"
537 "   Create a matrix representing a scaling.\n"
538 "\n"
539 "   :arg factor: The factor of scaling to apply.\n"
540 "   :type factor: float\n"
541 "   :arg size: The size of the scale matrix to construct [2, 4].\n"
542 "   :type size: int\n"
543 "   :arg axis: Direction to influence scale. (optional).\n"
544 "   :type axis: :class:`Vector`\n"
545 "   :return: A new scale matrix.\n"
546 "   :rtype: :class:`Matrix`\n"
547 );
548 static PyObject *C_Matrix_Scale(PyObject *cls, PyObject *args)
549 {
550         PyObject *vec = NULL;
551         int vec_size;
552         float tvec[3];
553         float factor;
554         int matSize;
555         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
556                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
557
558         if (!PyArg_ParseTuple(args, "fi|O:Matrix.Scale", &factor, &matSize, &vec)) {
559                 return NULL;
560         }
561         if (matSize != 2 && matSize != 3 && matSize != 4) {
562                 PyErr_SetString(PyExc_ValueError,
563                                 "Matrix.Scale(): "
564                                 "can only return a 2x2 3x3 or 4x4 matrix");
565                 return NULL;
566         }
567         if (vec) {
568                 vec_size = (matSize == 2 ? 2 : 3);
569                 if (mathutils_array_parse(tvec, vec_size, vec_size, vec, "Matrix.Scale(factor, size, axis), invalid 'axis' arg") == -1) {
570                         return NULL;
571                 }
572         }
573         if (vec == NULL) {      //scaling along axis
574                 if (matSize == 2) {
575                         mat[0] = factor;
576                         mat[3] = factor;
577                 }
578                 else {
579                         mat[0] = factor;
580                         mat[4] = factor;
581                         mat[8] = factor;
582                 }
583         }
584         else { //scaling in arbitrary direction
585                 //normalize arbitrary axis
586                 float norm = 0.0f;
587                 int x;
588                 for (x = 0; x < vec_size; x++) {
589                         norm += tvec[x] * tvec[x];
590                 }
591                 norm = (float) sqrt(norm);
592                 for (x = 0; x < vec_size; x++) {
593                         tvec[x] /= norm;
594                 }
595                 if (matSize == 2) {
596                         mat[0] = 1 + ((factor - 1) *(tvec[0] * tvec[0]));
597                         mat[1] =     ((factor - 1) *(tvec[0] * tvec[1]));
598                         mat[2] =     ((factor - 1) *(tvec[0] * tvec[1]));
599                         mat[3] = 1 + ((factor - 1) *(tvec[1] * tvec[1]));
600                 }
601                 else {
602                         mat[0] = 1 + ((factor - 1) *(tvec[0] * tvec[0]));
603                         mat[1] =     ((factor - 1) *(tvec[0] * tvec[1]));
604                         mat[2] =     ((factor - 1) *(tvec[0] * tvec[2]));
605                         mat[3] =     ((factor - 1) *(tvec[0] * tvec[1]));
606                         mat[4] = 1 + ((factor - 1) *(tvec[1] * tvec[1]));
607                         mat[5] =     ((factor - 1) *(tvec[1] * tvec[2]));
608                         mat[6] =     ((factor - 1) *(tvec[0] * tvec[2]));
609                         mat[7] =     ((factor - 1) *(tvec[1] * tvec[2]));
610                         mat[8] = 1 + ((factor - 1) *(tvec[2] * tvec[2]));
611                 }
612         }
613         if (matSize == 4) {
614                 matrix_3x3_as_4x4(mat);
615         }
616         //pass to matrix creation
617         return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
618 }
619 //----------------------------------mathutils.Matrix.OrthoProjection() ---
620 //mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc.
621 PyDoc_STRVAR(C_Matrix_OrthoProjection_doc,
622 ".. classmethod:: OrthoProjection(axis, size)\n"
623 "\n"
624 "   Create a matrix to represent an orthographic projection.\n"
625 "\n"
626 "   :arg axis: Can be any of the following: ['X', 'Y', 'XY', 'XZ', 'YZ'],\n"
627 "      where a single axis is for a 2D matrix.\n"
628 "      Or a vector for an arbitrary axis\n"
629 "   :type axis: string or :class:`Vector`\n"
630 "   :arg size: The size of the projection matrix to construct [2, 4].\n"
631 "   :type size: int\n"
632 "   :return: A new projection matrix.\n"
633 "   :rtype: :class:`Matrix`\n"
634 );
635 static PyObject *C_Matrix_OrthoProjection(PyObject *cls, PyObject *args)
636 {
637         PyObject *axis;
638
639         int matSize, x;
640         float norm = 0.0f;
641         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
642                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
643
644         if (!PyArg_ParseTuple(args, "Oi:Matrix.OrthoProjection", &axis, &matSize)) {
645                 return NULL;
646         }
647         if (matSize != 2 && matSize != 3 && matSize != 4) {
648                 PyErr_SetString(PyExc_ValueError,
649                                 "Matrix.OrthoProjection(): "
650                                 "can only return a 2x2 3x3 or 4x4 matrix");
651                 return NULL;
652         }
653
654         if (PyUnicode_Check(axis)) {    //ortho projection onto cardinal plane
655                 Py_ssize_t plane_len;
656                 const char *plane = _PyUnicode_AsStringAndSize(axis, &plane_len);
657                 if (matSize == 2) {
658                         if (plane_len == 1 && plane[0] == 'X') {
659                                 mat[0] = 1.0f;
660                         }
661                         else if (plane_len == 1 && plane[0] == 'Y') {
662                                 mat[3] = 1.0f;
663                         }
664                         else {
665                                 PyErr_Format(PyExc_ValueError,
666                                              "Matrix.OrthoProjection(): "
667                                              "unknown plane, expected: X, Y, not '%.200s'",
668                                              plane);
669                                 return NULL;
670                         }
671                 }
672                 else {
673                         if (plane_len == 2 && plane[0] == 'X' && plane[1] == 'Y') {
674                                 mat[0] = 1.0f;
675                                 mat[4] = 1.0f;
676                         }
677                         else if (plane_len == 2 && plane[0] == 'X' && plane[1] == 'Z') {
678                                 mat[0] = 1.0f;
679                                 mat[8] = 1.0f;
680                         }
681                         else if (plane_len == 2 && plane[0] == 'Y' && plane[1] == 'Z') {
682                                 mat[4] = 1.0f;
683                                 mat[8] = 1.0f;
684                         }
685                         else {
686                                 PyErr_Format(PyExc_ValueError,
687                                              "Matrix.OrthoProjection(): "
688                                              "unknown plane, expected: XY, XZ, YZ, not '%.200s'",
689                                              plane);
690                                 return NULL;
691                         }
692                 }
693         }
694         else {
695                 //arbitrary plane
696
697                 int vec_size = (matSize == 2 ? 2 : 3);
698                 float tvec[4];
699
700                 if (mathutils_array_parse(tvec, vec_size, vec_size, axis,
701                                           "Matrix.OrthoProjection(axis, size), invalid 'axis' arg") == -1)
702                 {
703                         return NULL;
704                 }
705
706                 //normalize arbitrary axis
707                 for (x = 0; x < vec_size; x++) {
708                         norm += tvec[x] * tvec[x];
709                 }
710                 norm = (float) sqrt(norm);
711                 for (x = 0; x < vec_size; x++) {
712                         tvec[x] /= norm;
713                 }
714                 if (matSize == 2) {
715                         mat[0] = 1 - (tvec[0] * tvec[0]);
716                         mat[1] =   - (tvec[0] * tvec[1]);
717                         mat[2] =   - (tvec[0] * tvec[1]);
718                         mat[3] = 1 - (tvec[1] * tvec[1]);
719                 }
720                 else if (matSize > 2) {
721                         mat[0] = 1 - (tvec[0] * tvec[0]);
722                         mat[1] =   - (tvec[0] * tvec[1]);
723                         mat[2] =   - (tvec[0] * tvec[2]);
724                         mat[3] =   - (tvec[0] * tvec[1]);
725                         mat[4] = 1 - (tvec[1] * tvec[1]);
726                         mat[5] =   - (tvec[1] * tvec[2]);
727                         mat[6] =   - (tvec[0] * tvec[2]);
728                         mat[7] =   - (tvec[1] * tvec[2]);
729                         mat[8] = 1 - (tvec[2] * tvec[2]);
730                 }
731         }
732         if (matSize == 4) {
733                 matrix_3x3_as_4x4(mat);
734         }
735         //pass to matrix creation
736         return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
737 }
738
739 PyDoc_STRVAR(C_Matrix_Shear_doc,
740 ".. classmethod:: Shear(plane, size, factor)\n"
741 "\n"
742 "   Create a matrix to represent an shear transformation.\n"
743 "\n"
744 "   :arg plane: Can be any of the following: ['X', 'Y', 'XY', 'XZ', 'YZ'],\n"
745 "      where a single axis is for a 2D matrix only.\n"
746 "   :type plane: string\n"
747 "   :arg size: The size of the shear matrix to construct [2, 4].\n"
748 "   :type size: int\n"
749 "   :arg factor: The factor of shear to apply. For a 3 or 4 *size* matrix\n"
750 "      pass a pair of floats corrasponding with the *plane* axis.\n"
751 "   :type factor: float or float pair\n"
752 "   :return: A new shear matrix.\n"
753 "   :rtype: :class:`Matrix`\n"
754 );
755 static PyObject *C_Matrix_Shear(PyObject *cls, PyObject *args)
756 {
757         int matSize;
758         const char *plane;
759         PyObject *fac;
760         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
761                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
762
763         if (!PyArg_ParseTuple(args, "siO:Matrix.Shear", &plane, &matSize, &fac)) {
764                 return NULL;
765         }
766         if (matSize != 2 && matSize != 3 && matSize != 4) {
767                 PyErr_SetString(PyExc_ValueError,
768                                 "Matrix.Shear(): "
769                                 "can only return a 2x2 3x3 or 4x4 matrix");
770                 return NULL;
771         }
772
773         if (matSize == 2) {
774                 float const factor = PyFloat_AsDouble(fac);
775
776                 if (factor == -1.0f && PyErr_Occurred()) {
777                         PyErr_SetString(PyExc_TypeError,
778                                         "Matrix.Shear(): "
779                                         "the factor to be a float");
780                         return NULL;
781                 }
782
783                 /* unit */
784                 mat[0] = 1.0f;
785                 mat[3] = 1.0f;
786
787                 if (strcmp(plane, "X") == 0) {
788                         mat[2] = factor;
789                 }
790                 else if (strcmp(plane, "Y") == 0) {
791                         mat[1] = factor;
792                 }
793                 else {
794                         PyErr_SetString(PyExc_ValueError,
795                                         "Matrix.Shear(): "
796                                         "expected: X, Y or wrong matrix size for shearing plane");
797                         return NULL;
798                 }
799         }
800         else {
801                 /* 3 or 4, apply as 3x3, resize later if needed */
802                 float factor[2];
803
804                 if (mathutils_array_parse(factor, 2, 2, fac, "Matrix.Shear()") < 0) {
805                         return NULL;
806                 }
807
808                 /* unit */
809                 mat[0] = 1.0f;
810                 mat[4] = 1.0f;
811                 mat[8] = 1.0f;
812
813                 if (strcmp(plane, "XY") == 0) {
814                         mat[6] = factor[0];
815                         mat[7] = factor[1];
816                 }
817                 else if (strcmp(plane, "XZ") == 0) {
818                         mat[3] = factor[0];
819                         mat[5] = factor[1];
820                 }
821                 else if (strcmp(plane, "YZ") == 0) {
822                         mat[1] = factor[0];
823                         mat[2] = factor[1];
824                 }
825                 else {
826                         PyErr_SetString(PyExc_ValueError,
827                                         "Matrix.Shear(): "
828                                         "expected: X, Y, XY, XZ, YZ");
829                         return NULL;
830                 }
831         }
832
833         if (matSize == 4) {
834                 matrix_3x3_as_4x4(mat);
835         }
836         //pass to matrix creation
837         return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
838 }
839
840 void matrix_as_3x3(float mat[3][3], MatrixObject *self)
841 {
842         copy_v3_v3(mat[0], MATRIX_COL_PTR(self, 0));
843         copy_v3_v3(mat[1], MATRIX_COL_PTR(self, 1));
844         copy_v3_v3(mat[2], MATRIX_COL_PTR(self, 2));
845 }
846
847 /* assumes rowsize == colsize is checked and the read callback has run */
848 static float matrix_determinant_internal(MatrixObject *self)
849 {
850         if (self->num_col == 2) {
851                 return determinant_m2(MATRIX_ITEM(self, 0, 0), MATRIX_ITEM(self, 0, 1),
852                                       MATRIX_ITEM(self, 1, 0), MATRIX_ITEM(self, 1, 1));
853         }
854         else if (self->num_col == 3) {
855                 return determinant_m3(MATRIX_ITEM(self, 0, 0), MATRIX_ITEM(self, 0, 1), MATRIX_ITEM(self, 0, 2),
856                                       MATRIX_ITEM(self, 1, 0), MATRIX_ITEM(self, 1, 1), MATRIX_ITEM(self, 1, 2),
857                                       MATRIX_ITEM(self, 2, 0), MATRIX_ITEM(self, 2, 1), MATRIX_ITEM(self, 2, 2));
858         }
859         else {
860                 return determinant_m4((float (*)[4])self->matrix);
861         }
862 }
863
864
865 /*-----------------------------METHODS----------------------------*/
866 PyDoc_STRVAR(Matrix_to_quaternion_doc,
867 ".. method:: to_quaternion()\n"
868 "\n"
869 "   Return a quaternion representation of the rotation matrix.\n"
870 "\n"
871 "   :return: Quaternion representation of the rotation matrix.\n"
872 "   :rtype: :class:`Quaternion`\n"
873 );
874 static PyObject *Matrix_to_quaternion(MatrixObject *self)
875 {
876         float quat[4];
877
878         if (BaseMath_ReadCallback(self) == -1)
879                 return NULL;
880
881         /* must be 3-4 cols, 3-4 rows, square matrix */
882         if ((self->num_row < 3) || (self->num_col < 3) || (self->num_row != self->num_col)) {
883                 PyErr_SetString(PyExc_ValueError,
884                                 "Matrix.to_quat(): "
885                                 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
886                 return NULL;
887         }
888         if (self->num_row == 3) {
889                 mat3_to_quat(quat, (float (*)[3])self->matrix);
890         }
891         else {
892                 mat4_to_quat(quat, (float (*)[4])self->matrix);
893         }
894
895         return Quaternion_CreatePyObject(quat, Py_NEW, NULL);
896 }
897
898 /*---------------------------matrix.toEuler() --------------------*/
899 PyDoc_STRVAR(Matrix_to_euler_doc,
900 ".. method:: to_euler(order, euler_compat)\n"
901 "\n"
902 "   Return an Euler representation of the rotation matrix\n"
903 "   (3x3 or 4x4 matrix only).\n"
904 "\n"
905 "   :arg order: Optional rotation order argument in\n"
906 "      ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX'].\n"
907 "   :type order: string\n"
908 "   :arg euler_compat: Optional euler argument the new euler will be made\n"
909 "      compatible with (no axis flipping between them).\n"
910 "      Useful for converting a series of matrices to animation curves.\n"
911 "   :type euler_compat: :class:`Euler`\n"
912 "   :return: Euler representation of the matrix.\n"
913 "   :rtype: :class:`Euler`\n"
914 );
915 static PyObject *Matrix_to_euler(MatrixObject *self, PyObject *args)
916 {
917         const char *order_str = NULL;
918         short order = EULER_ORDER_XYZ;
919         float eul[3], eul_compatf[3];
920         EulerObject *eul_compat = NULL;
921
922         float tmat[3][3];
923         float (*mat)[3];
924
925         if (BaseMath_ReadCallback(self) == -1)
926                 return NULL;
927
928         if (!PyArg_ParseTuple(args, "|sO!:to_euler", &order_str, &euler_Type, &eul_compat))
929                 return NULL;
930
931         if (eul_compat) {
932                 if (BaseMath_ReadCallback(eul_compat) == -1)
933                         return NULL;
934
935                 copy_v3_v3(eul_compatf, eul_compat->eul);
936         }
937
938         /*must be 3-4 cols, 3-4 rows, square matrix */
939         if (self->num_row ==3 && self->num_col ==3) {
940                 mat = (float (*)[3])self->matrix;
941         }
942         else if (self->num_row ==4 && self->num_col ==4) {
943                 copy_m3_m4(tmat, (float (*)[4])self->matrix);
944                 mat = tmat;
945         }
946         else {
947                 PyErr_SetString(PyExc_ValueError,
948                                 "Matrix.to_euler(): "
949                                 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
950                 return NULL;
951         }
952
953         if (order_str) {
954                 order = euler_order_from_string(order_str, "Matrix.to_euler()");
955
956                 if (order == -1)
957                         return NULL;
958         }
959
960         if (eul_compat) {
961                 if (order == 1) mat3_to_compatible_eul(eul, eul_compatf, mat);
962                 else                    mat3_to_compatible_eulO(eul, eul_compatf, order, mat);
963         }
964         else {
965                 if (order == 1) mat3_to_eul(eul, mat);
966                 else                    mat3_to_eulO(eul, order, mat);
967         }
968
969         return Euler_CreatePyObject(eul, order, Py_NEW, NULL);
970 }
971
972 PyDoc_STRVAR(Matrix_resize_4x4_doc,
973 ".. method:: resize_4x4()\n"
974 "\n"
975 "   Resize the matrix to 4x4.\n"
976 );
977 static PyObject *Matrix_resize_4x4(MatrixObject *self)
978 {
979         float mat[4][4] = MAT4_UNITY;
980         int col;
981
982         if (self->wrapped == Py_WRAP) {
983                 PyErr_SetString(PyExc_TypeError,
984                                 "Matrix.resize_4x4(): "
985                                 "cannot resize wrapped data - make a copy and resize that");
986                 return NULL;
987         }
988         if (self->cb_user) {
989                 PyErr_SetString(PyExc_TypeError,
990                                 "Matrix.resize_4x4(): "
991                                 "cannot resize owned data - make a copy and resize that");
992                 return NULL;
993         }
994
995         self->matrix = PyMem_Realloc(self->matrix, (sizeof(float) * 16));
996         if (self->matrix == NULL) {
997                 PyErr_SetString(PyExc_MemoryError,
998                                 "Matrix.resize_4x4(): "
999                                 "problem allocating pointer space");
1000                 return NULL;
1001         }
1002
1003         for (col = 0; col < self->num_col; col++) {
1004                 memcpy(mat[col], MATRIX_COL_PTR(self, col), self->num_row * sizeof(float));
1005         }
1006
1007         copy_m4_m4((float (*)[4])self->matrix, (float (*)[4])mat);
1008
1009         self->num_col = 4;
1010         self->num_row = 4;
1011
1012         Py_RETURN_NONE;
1013 }
1014
1015 PyDoc_STRVAR(Matrix_to_4x4_doc,
1016 ".. method:: to_4x4()\n"
1017 "\n"
1018 "   Return a 4x4 copy of this matrix.\n"
1019 "\n"
1020 "   :return: a new matrix.\n"
1021 "   :rtype: :class:`Matrix`\n"
1022 );
1023 static PyObject *Matrix_to_4x4(MatrixObject *self)
1024 {
1025         if (BaseMath_ReadCallback(self) == -1)
1026                 return NULL;
1027
1028         if (self->num_row == 4 && self->num_col == 4) {
1029                 return Matrix_CreatePyObject(self->matrix, 4, 4, Py_NEW, Py_TYPE(self));
1030         }
1031         else if (self->num_row == 3 && self->num_col == 3) {
1032                 float mat[4][4];
1033                 copy_m4_m3(mat, (float (*)[3])self->matrix);
1034                 return Matrix_CreatePyObject((float *)mat, 4, 4, Py_NEW, Py_TYPE(self));
1035         }
1036         /* TODO, 2x2 matrix */
1037
1038         PyErr_SetString(PyExc_TypeError,
1039                         "Matrix.to_4x4(): "
1040                         "inappropriate matrix size");
1041         return NULL;
1042 }
1043
1044 PyDoc_STRVAR(Matrix_to_3x3_doc,
1045 ".. method:: to_3x3()\n"
1046 "\n"
1047 "   Return a 3x3 copy of this matrix.\n"
1048 "\n"
1049 "   :return: a new matrix.\n"
1050 "   :rtype: :class:`Matrix`\n"
1051 );
1052 static PyObject *Matrix_to_3x3(MatrixObject *self)
1053 {
1054         float mat[3][3];
1055
1056         if (BaseMath_ReadCallback(self) == -1)
1057                 return NULL;
1058
1059         if ((self->num_row < 3) || (self->num_col < 3)) {
1060                 PyErr_SetString(PyExc_TypeError,
1061                                 "Matrix.to_3x3(): inappropriate matrix size");
1062                 return NULL;
1063         }
1064
1065         matrix_as_3x3(mat, self);
1066
1067         return Matrix_CreatePyObject((float *)mat, 3, 3, Py_NEW, Py_TYPE(self));
1068 }
1069
1070 PyDoc_STRVAR(Matrix_to_translation_doc,
1071 ".. method:: to_translation()\n"
1072 "\n"
1073 "   Return a the translation part of a 4 row matrix.\n"
1074 "\n"
1075 "   :return: Return a the translation of a matrix.\n"
1076 "   :rtype: :class:`Vector`\n"
1077 );
1078 static PyObject *Matrix_to_translation(MatrixObject *self)
1079 {
1080         if (BaseMath_ReadCallback(self) == -1)
1081                 return NULL;
1082
1083         if ((self->num_row < 3) || self->num_col < 4) {
1084                 PyErr_SetString(PyExc_TypeError,
1085                                 "Matrix.to_translation(): "
1086                                 "inappropriate matrix size");
1087                 return NULL;
1088         }
1089
1090         return Vector_CreatePyObject(MATRIX_COL_PTR(self, 3), 3, Py_NEW, NULL);
1091 }
1092
1093 PyDoc_STRVAR(Matrix_to_scale_doc,
1094 ".. method:: to_scale()\n"
1095 "\n"
1096 "   Return a the scale part of a 3x3 or 4x4 matrix.\n"
1097 "\n"
1098 "   :return: Return a the scale of a matrix.\n"
1099 "   :rtype: :class:`Vector`\n"
1100 "\n"
1101 "   .. 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"
1102 );
1103 static PyObject *Matrix_to_scale(MatrixObject *self)
1104 {
1105         float rot[3][3];
1106         float mat[3][3];
1107         float size[3];
1108
1109         if (BaseMath_ReadCallback(self) == -1)
1110                 return NULL;
1111
1112         /*must be 3-4 cols, 3-4 rows, square matrix */
1113         if ((self->num_row < 3) || (self->num_col < 3)) {
1114                 PyErr_SetString(PyExc_TypeError,
1115                                 "Matrix.to_scale(): "
1116                                 "inappropriate matrix size, 3x3 minimum size");
1117                 return NULL;
1118         }
1119
1120         matrix_as_3x3(mat, self);
1121
1122         /* compatible mat4_to_loc_rot_size */
1123         mat3_to_rot_size(rot, size, mat);
1124
1125         return Vector_CreatePyObject(size, 3, Py_NEW, NULL);
1126 }
1127
1128 /*---------------------------matrix.invert() ---------------------*/
1129 PyDoc_STRVAR(Matrix_invert_doc,
1130 ".. method:: invert()\n"
1131 "\n"
1132 "   Set the matrix to its inverse.\n"
1133 "\n"
1134 "   .. note:: :exc:`ValueError` exception is raised.\n"
1135 "\n"
1136 "   .. seealso:: <http://en.wikipedia.org/wiki/Inverse_matrix>\n"
1137 );
1138 static PyObject *Matrix_invert(MatrixObject *self)
1139 {
1140
1141         int x, y, z = 0;
1142         float det = 0.0f;
1143         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f,
1144                          0.0f, 0.0f, 0.0f, 0.0f,
1145                          0.0f, 0.0f, 0.0f, 0.0f,
1146                          0.0f, 0.0f, 0.0f, 1.0f};
1147
1148         if (BaseMath_ReadCallback(self) == -1)
1149                 return NULL;
1150
1151         if (self->num_col != self->num_row) {
1152                 PyErr_SetString(PyExc_TypeError,
1153                                 "Matrix.invert(ed): "
1154                                 "only square matrices are supported");
1155                 return NULL;
1156         }
1157
1158         /* calculate the determinant */
1159         det = matrix_determinant_internal(self);
1160
1161         if (det != 0) {
1162                 /* calculate the classical adjoint */
1163                 if (self->num_col == 2) {
1164                         mat[0] =  MATRIX_ITEM(self, 1, 1);
1165                         mat[1] = -MATRIX_ITEM(self, 0, 1);
1166                         mat[2] = -MATRIX_ITEM(self, 1, 0);
1167                         mat[3] =  MATRIX_ITEM(self, 0, 0);
1168                 }
1169                 else if (self->num_col == 3) {
1170                         adjoint_m3_m3((float (*)[3]) mat,(float (*)[3])self->matrix);
1171                 }
1172                 else if (self->num_col == 4) {
1173                         adjoint_m4_m4((float (*)[4]) mat, (float (*)[4])self->matrix);
1174                 }
1175                 /* divide by determinate */
1176                 for (x = 0; x < (self->num_col * self->num_row); x++) {
1177                         mat[x] /= det;
1178                 }
1179                 /* set values */
1180                 for (x = 0; x < self->num_col; x++) {
1181                         for (y = 0; y < self->num_row; y++) {
1182                                 MATRIX_ITEM(self, y, x) = mat[z];
1183                                 z++;
1184                         }
1185                 }
1186                 /*transpose
1187                 Matrix_transpose(self);*/
1188         }
1189         else {
1190                 PyErr_SetString(PyExc_ValueError,
1191                                 "Matrix.invert(ed): "
1192                                 "matrix does not have an inverse");
1193                 return NULL;
1194         }
1195
1196         (void)BaseMath_WriteCallback(self);
1197         Py_RETURN_NONE;
1198 }
1199
1200 PyDoc_STRVAR(Matrix_inverted_doc,
1201 ".. method:: inverted()\n"
1202 "\n"
1203 "   Return an inverted copy of the matrix.\n"
1204 "\n"
1205 "   :return: the  inverted matrix.\n"
1206 "   :rtype: :class:`Matrix`\n"
1207 "\n"
1208 "   .. note:: :exc:`ValueError` exception is raised.\n"
1209 );
1210 static PyObject *Matrix_inverted(MatrixObject *self)
1211 {
1212         return matrix__apply_to_copy((PyNoArgsFunction)Matrix_invert, self);
1213 }
1214
1215 PyDoc_STRVAR(Matrix_rotate_doc,
1216 ".. method:: rotate(other)\n"
1217 "\n"
1218 "   Rotates the matrix a by another mathutils value.\n"
1219 "\n"
1220 "   :arg other: rotation component of mathutils value\n"
1221 "   :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n"
1222 "\n"
1223 "   .. note:: If any of the columns are not unit length this may not have desired results.\n"
1224 );
1225 static PyObject *Matrix_rotate(MatrixObject *self, PyObject *value)
1226 {
1227         float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
1228
1229         if (BaseMath_ReadCallback(self) == -1)
1230                 return NULL;
1231
1232         if (mathutils_any_to_rotmat(other_rmat, value, "matrix.rotate(value)") == -1)
1233                 return NULL;
1234
1235         if (self->num_row != 3 || self->num_col != 3) {
1236                 PyErr_SetString(PyExc_TypeError,
1237                                 "Matrix.rotate(): "
1238                                 "must have 3x3 dimensions");
1239                 return NULL;
1240         }
1241
1242         matrix_as_3x3(self_rmat, self);
1243         mul_m3_m3m3(rmat, other_rmat, self_rmat);
1244
1245         copy_m3_m3((float (*)[3])(self->matrix), rmat);
1246
1247         (void)BaseMath_WriteCallback(self);
1248         Py_RETURN_NONE;
1249 }
1250
1251 /*---------------------------matrix.decompose() ---------------------*/
1252 PyDoc_STRVAR(Matrix_decompose_doc,
1253 ".. method:: decompose()\n"
1254 "\n"
1255 "   Return the location, rotaion and scale components of this matrix.\n"
1256 "\n"
1257 "   :return: loc, rot, scale triple.\n"
1258 "   :rtype: (:class:`Vector`, :class:`Quaternion`, :class:`Vector`)"
1259 );
1260 static PyObject *Matrix_decompose(MatrixObject *self)
1261 {
1262         PyObject *ret;
1263         float loc[3];
1264         float rot[3][3];
1265         float quat[4];
1266         float size[3];
1267
1268         if (self->num_row != 4 || self->num_col != 4) {
1269                 PyErr_SetString(PyExc_TypeError,
1270                                 "Matrix.decompose(): "
1271                                 "inappropriate matrix size - expects 4x4 matrix");
1272                 return NULL;
1273         }
1274
1275         if (BaseMath_ReadCallback(self) == -1)
1276                 return NULL;
1277
1278         mat4_to_loc_rot_size(loc, rot, size, (float (*)[4])self->matrix);
1279         mat3_to_quat(quat, rot);
1280
1281         ret = PyTuple_New(3);
1282         PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(loc, 3, Py_NEW, NULL));
1283         PyTuple_SET_ITEM(ret, 1, Quaternion_CreatePyObject(quat, Py_NEW, NULL));
1284         PyTuple_SET_ITEM(ret, 2, Vector_CreatePyObject(size, 3, Py_NEW, NULL));
1285
1286         return ret;
1287 }
1288
1289
1290
1291 PyDoc_STRVAR(Matrix_lerp_doc,
1292 ".. function:: lerp(other, factor)\n"
1293 "\n"
1294 "   Returns the interpolation of two matrices.\n"
1295 "\n"
1296 "   :arg other: value to interpolate with.\n"
1297 "   :type other: :class:`Matrix`\n"
1298 "   :arg factor: The interpolation value in [0.0, 1.0].\n"
1299 "   :type factor: float\n"
1300 "   :return: The interpolated rotation.\n"
1301 "   :rtype: :class:`Matrix`\n"
1302 );
1303 static PyObject *Matrix_lerp(MatrixObject *self, PyObject *args)
1304 {
1305         MatrixObject *mat2 = NULL;
1306         float fac, mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
1307
1308         if (!PyArg_ParseTuple(args, "O!f:lerp", &matrix_Type, &mat2, &fac))
1309                 return NULL;
1310
1311         if (self->num_col != mat2->num_col || self->num_row != mat2->num_row) {
1312                 PyErr_SetString(PyExc_ValueError,
1313                                 "Matrix.lerp(): "
1314                                 "expects both matrix objects of the same dimensions");
1315                 return NULL;
1316         }
1317
1318         if (BaseMath_ReadCallback(self) == -1 || BaseMath_ReadCallback(mat2) == -1)
1319                 return NULL;
1320
1321         /* TODO, different sized matrix */
1322         if (self->num_col == 4 && self->num_row == 4) {
1323                 blend_m4_m4m4((float (*)[4])mat, (float (*)[4])self->matrix, (float (*)[4])mat2->matrix, fac);
1324         }
1325         else if (self->num_col == 3 && self->num_row == 3) {
1326                 blend_m3_m3m3((float (*)[3])mat, (float (*)[3])self->matrix, (float (*)[3])mat2->matrix, fac);
1327         }
1328         else {
1329                 PyErr_SetString(PyExc_ValueError,
1330                                 "Matrix.lerp(): "
1331                                 "only 3x3 and 4x4 matrices supported");
1332                 return NULL;
1333         }
1334
1335         return Matrix_CreatePyObject(mat, self->num_col, self->num_row, Py_NEW, Py_TYPE(self));
1336 }
1337
1338 /*---------------------------matrix.determinant() ----------------*/
1339 PyDoc_STRVAR(Matrix_determinant_doc,
1340 ".. method:: determinant()\n"
1341 "\n"
1342 "   Return the determinant of a matrix.\n"
1343 "\n"
1344 "   :return: Return a the determinant of a matrix.\n"
1345 "   :rtype: float\n"
1346 "\n"
1347 "   .. seealso:: <http://en.wikipedia.org/wiki/Determinant>\n"
1348 );
1349 static PyObject *Matrix_determinant(MatrixObject *self)
1350 {
1351         if (BaseMath_ReadCallback(self) == -1)
1352                 return NULL;
1353
1354         if (self->num_col != self->num_row) {
1355                 PyErr_SetString(PyExc_TypeError,
1356                                 "Matrix.determinant(): "
1357                                 "only square matrices are supported");
1358                 return NULL;
1359         }
1360
1361         return PyFloat_FromDouble((double)matrix_determinant_internal(self));
1362 }
1363 /*---------------------------matrix.transpose() ------------------*/
1364 PyDoc_STRVAR(Matrix_transpose_doc,
1365 ".. method:: transpose()\n"
1366 "\n"
1367 "   Set the matrix to its transpose.\n"
1368 "\n"
1369 "   .. seealso:: <http://en.wikipedia.org/wiki/Transpose>\n"
1370 );
1371 static PyObject *Matrix_transpose(MatrixObject *self)
1372 {
1373         if (BaseMath_ReadCallback(self) == -1)
1374                 return NULL;
1375
1376         if (self->num_col != self->num_row) {
1377                 PyErr_SetString(PyExc_TypeError,
1378                                 "Matrix.transpose(d): "
1379                                 "only square matrices are supported");
1380                 return NULL;
1381         }
1382
1383         if (self->num_col == 2) {
1384                 const float t = MATRIX_ITEM(self, 1, 0);
1385                 MATRIX_ITEM(self, 1, 0) = MATRIX_ITEM(self, 0, 1);
1386                 MATRIX_ITEM(self, 0, 1) = t;
1387         }
1388         else if (self->num_col == 3) {
1389                 transpose_m3((float (*)[3])self->matrix);
1390         }
1391         else {
1392                 transpose_m4((float (*)[4])self->matrix);
1393         }
1394
1395         (void)BaseMath_WriteCallback(self);
1396         Py_RETURN_NONE;
1397 }
1398
1399 PyDoc_STRVAR(Matrix_transposed_doc,
1400 ".. method:: transposed()\n"
1401 "\n"
1402 "   Return a new, transposed matrix.\n"
1403 "\n"
1404 "   :return: a transposed matrix\n"
1405 "   :rtype: :class:`Matrix`\n"
1406 );
1407 static PyObject *Matrix_transposed(MatrixObject *self)
1408 {
1409         return matrix__apply_to_copy((PyNoArgsFunction)Matrix_transpose, self);
1410 }
1411
1412 /*---------------------------matrix.zero() -----------------------*/
1413 PyDoc_STRVAR(Matrix_zero_doc,
1414 ".. method:: zero()\n"
1415 "\n"
1416 "   Set all the matrix values to zero.\n"
1417 "\n"
1418 "   :return: an instance of itself\n"
1419 "   :rtype: :class:`Matrix`\n"
1420 );
1421 static PyObject *Matrix_zero(MatrixObject *self)
1422 {
1423         fill_vn_fl(self->matrix, self->num_col * self->num_row, 0.0f);
1424
1425         if (BaseMath_WriteCallback(self) == -1)
1426                 return NULL;
1427
1428         Py_RETURN_NONE;
1429 }
1430 /*---------------------------matrix.identity(() ------------------*/
1431 PyDoc_STRVAR(Matrix_identity_doc,
1432 ".. method:: identity()\n"
1433 "\n"
1434 "   Set the matrix to the identity matrix.\n"
1435 "\n"
1436 "   .. note:: An object with zero location and rotation, a scale of one,\n"
1437 "      will have an identity matrix.\n"
1438 "\n"
1439 "   .. seealso:: <http://en.wikipedia.org/wiki/Identity_matrix>\n"
1440 );
1441 static PyObject *Matrix_identity(MatrixObject *self)
1442 {
1443         if (BaseMath_ReadCallback(self) == -1)
1444                 return NULL;
1445
1446         if (self->num_col != self->num_row) {
1447                 PyErr_SetString(PyExc_TypeError,
1448                                 "Matrix.identity(): "
1449                                 "only square matrices are supported");
1450                 return NULL;
1451         }
1452
1453         if (self->num_col == 2) {
1454                 MATRIX_ITEM(self, 0, 0) = 1.0f;
1455                 MATRIX_ITEM(self, 0, 1) = 0.0f;
1456                 MATRIX_ITEM(self, 1, 0) = 0.0f;
1457                 MATRIX_ITEM(self, 1, 1) = 1.0f;
1458         }
1459         else if (self->num_col == 3) {
1460                 unit_m3((float (*)[3])self->matrix);
1461         }
1462         else {
1463                 unit_m4((float (*)[4])self->matrix);
1464         }
1465
1466         if (BaseMath_WriteCallback(self) == -1)
1467                 return NULL;
1468
1469         Py_RETURN_NONE;
1470 }
1471
1472 /*---------------------------Matrix.copy() ------------------*/
1473 PyDoc_STRVAR(Matrix_copy_doc,
1474 ".. method:: copy()\n"
1475 "\n"
1476 "   Returns a copy of this matrix.\n"
1477 "\n"
1478 "   :return: an instance of itself\n"
1479 "   :rtype: :class:`Matrix`\n"
1480 );
1481 static PyObject *Matrix_copy(MatrixObject *self)
1482 {
1483         if (BaseMath_ReadCallback(self) == -1)
1484                 return NULL;
1485
1486         return Matrix_CreatePyObject((float (*))self->matrix, self->num_col, self->num_row, Py_NEW, Py_TYPE(self));
1487 }
1488
1489 /*----------------------------print object (internal)-------------*/
1490 /* print the object to screen */
1491 static PyObject *Matrix_repr(MatrixObject *self)
1492 {
1493         int col, row;
1494         PyObject *rows[MATRIX_MAX_DIM] = {NULL};
1495
1496         if (BaseMath_ReadCallback(self) == -1)
1497                 return NULL;
1498
1499         for (row = 0; row < self->num_row; row++) {
1500                 rows[row] = PyTuple_New(self->num_col);
1501                 for (col = 0; col < self->num_col; col++) {
1502                         PyTuple_SET_ITEM(rows[row], col, PyFloat_FromDouble(MATRIX_ITEM(self, row, col)));
1503                 }
1504         }
1505         switch (self->num_row) {
1506         case 2: return PyUnicode_FromFormat("Matrix((%R,\n"
1507                                                                                 "        %R))", rows[0], rows[1]);
1508
1509         case 3: return PyUnicode_FromFormat("Matrix((%R,\n"
1510                                                                                 "        %R,\n"
1511                                                                                 "        %R))", rows[0], rows[1], rows[2]);
1512
1513         case 4: return PyUnicode_FromFormat("Matrix((%R,\n"
1514                                                                                 "        %R,\n"
1515                                                                                 "        %R,\n"
1516                                                                                 "        %R))", rows[0], rows[1], rows[2], rows[3]);
1517         }
1518
1519         Py_FatalError("Matrix(): invalid row size!");
1520         return NULL;
1521 }
1522
1523 static PyObject *Matrix_str(MatrixObject *self)
1524 {
1525         DynStr *ds;
1526
1527         int maxsize[MATRIX_MAX_DIM];
1528         int row, col;
1529
1530         char dummy_buf[1];
1531
1532         if (BaseMath_ReadCallback(self) == -1)
1533                 return NULL;
1534
1535         ds = BLI_dynstr_new();
1536
1537         /* First determine the maximum width for each column */
1538         for (col = 0; col < self->num_col; col++) {
1539                 maxsize[col] = 0;
1540                 for (row = 0; row < self->num_row; row++) {
1541                         int size = BLI_snprintf(dummy_buf, sizeof(dummy_buf), "%.4f", MATRIX_ITEM(self, row, col));
1542                         maxsize[col] = MAX2(maxsize[col], size);
1543                 }
1544         }
1545
1546         /* Now write the unicode string to be printed */
1547         BLI_dynstr_appendf(ds, "<Matrix %dx%d (", self->num_row, self->num_col);
1548         for (row = 0; row < self->num_row; row++) {
1549                 for (col = 0; col < self->num_col; col++) {
1550                         BLI_dynstr_appendf(ds, col ? ", %*.4f" : "%*.4f", maxsize[col], MATRIX_ITEM(self, row, col));
1551                 }
1552                 BLI_dynstr_append(ds, row + 1 != self->num_row ? ")\n             " : ")");
1553         }
1554         BLI_dynstr_append(ds, ">");
1555
1556         return mathutils_dynstr_to_py(ds); /* frees ds */
1557 }
1558
1559 static PyObject *Matrix_richcmpr(PyObject *a, PyObject *b, int op)
1560 {
1561         PyObject *res;
1562         int ok = -1; /* zero is true */
1563
1564         if (MatrixObject_Check(a) && MatrixObject_Check(b)) {
1565                 MatrixObject *matA = (MatrixObject *)a;
1566                 MatrixObject *matB = (MatrixObject *)b;
1567
1568                 if (BaseMath_ReadCallback(matA) == -1 || BaseMath_ReadCallback(matB) == -1)
1569                         return NULL;
1570
1571                 ok = (  (matA->num_row == matB->num_row) &&
1572                         (matA->num_col == matB->num_col) &&
1573                          EXPP_VectorsAreEqual(matA->matrix, matB->matrix, (matA->num_col * matA->num_row), 1)
1574                         ) ? 0 : -1;
1575         }
1576
1577         switch (op) {
1578         case Py_NE:
1579                 ok = !ok; /* pass through */
1580         case Py_EQ:
1581                 res = ok ? Py_False : Py_True;
1582                 break;
1583
1584         case Py_LT:
1585         case Py_LE:
1586         case Py_GT:
1587         case Py_GE:
1588                 res = Py_NotImplemented;
1589                 break;
1590         default:
1591                 PyErr_BadArgument();
1592                 return NULL;
1593         }
1594
1595         return Py_INCREF(res), res;
1596 }
1597
1598 /*---------------------SEQUENCE PROTOCOLS------------------------
1599   ----------------------------len(object)------------------------
1600   sequence length */
1601 static int Matrix_len(MatrixObject *self)
1602 {
1603         return (self->num_row);
1604 }
1605 /*----------------------------object[]---------------------------
1606   sequence accessor (get)
1607   the wrapped vector gives direct access to the matrix data */
1608 static PyObject *Matrix_item_row(MatrixObject *self, int row)
1609 {
1610         if (BaseMath_ReadCallback(self) == -1)
1611                 return NULL;
1612
1613         if (row < 0 || row >= self->num_row) {
1614                 PyErr_SetString(PyExc_IndexError,
1615                                 "matrix[attribute]: "
1616                                 "array index out of range");
1617                 return NULL;
1618         }
1619         return Vector_CreatePyObject_cb((PyObject *)self, self->num_col, mathutils_matrix_row_cb_index, row);
1620 }
1621 /* same but column access */
1622 static PyObject *Matrix_item_col(MatrixObject *self, int col)
1623 {
1624         if (BaseMath_ReadCallback(self) == -1)
1625                 return NULL;
1626
1627         if (col < 0 || col >= self->num_col) {
1628                 PyErr_SetString(PyExc_IndexError,
1629                                 "matrix[attribute]: "
1630                                 "array index out of range");
1631                 return NULL;
1632         }
1633         return Vector_CreatePyObject_cb((PyObject *)self, self->num_row, mathutils_matrix_col_cb_index, col);
1634 }
1635
1636 /*----------------------------object[]-------------------------
1637   sequence accessor (set) */
1638
1639 static int Matrix_ass_item_row(MatrixObject *self, int row, PyObject *value)
1640 {
1641         int col;
1642         float vec[4];
1643         if (BaseMath_ReadCallback(self) == -1)
1644                 return -1;
1645
1646         if (row >= self->num_row || row < 0) {
1647                 PyErr_SetString(PyExc_IndexError,
1648                                 "matrix[attribute] = x: bad row");
1649                 return -1;
1650         }
1651
1652         if (mathutils_array_parse(vec, self->num_col, self->num_col, value, "matrix[i] = value assignment") < 0) {
1653                 return -1;
1654         }
1655
1656         /* Since we are assigning a row we cannot memcpy */
1657         for (col = 0; col < self->num_col; col++) {
1658                 MATRIX_ITEM(self, row, col) = vec[col];
1659         }
1660
1661         (void)BaseMath_WriteCallback(self);
1662         return 0;
1663 }
1664 static int Matrix_ass_item_col(MatrixObject *self, int col, PyObject *value)
1665 {
1666         int row;
1667         float vec[4];
1668         if (BaseMath_ReadCallback(self) == -1)
1669                 return -1;
1670
1671         if (col >= self->num_col || col < 0) {
1672                 PyErr_SetString(PyExc_IndexError,
1673                                 "matrix[attribute] = x: bad col");
1674                 return -1;
1675         }
1676
1677         if (mathutils_array_parse(vec, self->num_row, self->num_row, value, "matrix[i] = value assignment") < 0) {
1678                 return -1;
1679         }
1680
1681         /* Since we are assigning a row we cannot memcpy */
1682         for (row = 0; row < self->num_row; row++) {
1683                 MATRIX_ITEM(self, row, col) = vec[row];
1684         }
1685
1686         (void)BaseMath_WriteCallback(self);
1687         return 0;
1688 }
1689
1690
1691 /*----------------------------object[z:y]------------------------
1692   sequence slice (get)*/
1693 static PyObject *Matrix_slice(MatrixObject *self, int begin, int end)
1694 {
1695
1696         PyObject *tuple;
1697         int count;
1698
1699         if (BaseMath_ReadCallback(self) == -1)
1700                 return NULL;
1701
1702         CLAMP(begin, 0, self->num_row);
1703         CLAMP(end, 0, self->num_row);
1704         begin = MIN2(begin, end);
1705
1706         tuple = PyTuple_New(end - begin);
1707         for (count = begin; count < end; count++) {
1708                 PyTuple_SET_ITEM(tuple, count - begin,
1709                                 Vector_CreatePyObject_cb((PyObject *)self, self->num_col, mathutils_matrix_row_cb_index, count));
1710
1711         }
1712
1713         return tuple;
1714 }
1715 /*----------------------------object[z:y]------------------------
1716   sequence slice (set)*/
1717 static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value)
1718 {
1719         PyObject *value_fast = NULL;
1720
1721         if (BaseMath_ReadCallback(self) == -1)
1722                 return -1;
1723
1724         CLAMP(begin, 0, self->num_row);
1725         CLAMP(end, 0, self->num_row);
1726         begin = MIN2(begin, end);
1727
1728         /* non list/tuple cases */
1729         if (!(value_fast = PySequence_Fast(value, "matrix[begin:end] = value"))) {
1730                 /* PySequence_Fast sets the error */
1731                 return -1;
1732         }
1733         else {
1734                 const int size = end - begin;
1735                 int row, col;
1736                 float mat[16];
1737                 float vec[4];
1738
1739                 if (PySequence_Fast_GET_SIZE(value_fast) != size) {
1740                         Py_DECREF(value_fast);
1741                         PyErr_SetString(PyExc_ValueError,
1742                                         "matrix[begin:end] = []: "
1743                                         "size mismatch in slice assignment");
1744                         return -1;
1745                 }
1746
1747                 memcpy(mat, self->matrix, self->num_col * self->num_row * sizeof(float));
1748
1749                 /* parse sub items */
1750                 for (row = begin; row < end; row++) {
1751                         /* parse each sub sequence */
1752                         PyObject *item = PySequence_Fast_GET_ITEM(value_fast, row - begin);
1753
1754                         if (mathutils_array_parse(vec, self->num_col, self->num_col, item, "matrix[begin:end] = value assignment") < 0)
1755                                 return -1;
1756
1757                         for (col = 0; col < self->num_col; col++) {
1758                                 mat[col * self->num_row + row] = vec[col];
1759                         }
1760                 }
1761
1762                 Py_DECREF(value_fast);
1763
1764                 /*parsed well - now set in matrix*/
1765                 memcpy(self->matrix, mat, self->num_col * self->num_row * sizeof(float));
1766
1767                 (void)BaseMath_WriteCallback(self);
1768                 return 0;
1769         }
1770 }
1771 /*------------------------NUMERIC PROTOCOLS----------------------
1772   ------------------------obj + obj------------------------------*/
1773 static PyObject *Matrix_add(PyObject *m1, PyObject *m2)
1774 {
1775         float mat[16];
1776         MatrixObject *mat1 = NULL, *mat2 = NULL;
1777
1778         mat1 = (MatrixObject *)m1;
1779         mat2 = (MatrixObject *)m2;
1780
1781         if (!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) {
1782                 PyErr_Format(PyExc_TypeError,
1783                              "Matrix addition: (%s + %s) "
1784                              "invalid type for this operation",
1785                              Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name);
1786                 return NULL;
1787         }
1788
1789         if (BaseMath_ReadCallback(mat1) == -1 || BaseMath_ReadCallback(mat2) == -1)
1790                 return NULL;
1791
1792         if (mat1->num_col != mat2->num_col || mat1->num_row != mat2->num_row) {
1793                 PyErr_SetString(PyExc_TypeError,
1794                                 "Matrix addition: "
1795                                 "matrices must have the same dimensions for this operation");
1796                 return NULL;
1797         }
1798
1799         add_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->num_col * mat1->num_row);
1800
1801         return Matrix_CreatePyObject(mat, mat1->num_col, mat1->num_row, Py_NEW, Py_TYPE(mat1));
1802 }
1803 /*------------------------obj - obj------------------------------
1804   subtraction*/
1805 static PyObject *Matrix_sub(PyObject *m1, PyObject *m2)
1806 {
1807         float mat[16];
1808         MatrixObject *mat1 = NULL, *mat2 = NULL;
1809
1810         mat1 = (MatrixObject *)m1;
1811         mat2 = (MatrixObject *)m2;
1812
1813         if (!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) {
1814                 PyErr_Format(PyExc_TypeError,
1815                              "Matrix subtraction: (%s - %s) "
1816                              "invalid type for this operation",
1817                              Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name
1818                              );
1819                 return NULL;
1820         }
1821
1822         if (BaseMath_ReadCallback(mat1) == -1 || BaseMath_ReadCallback(mat2) == -1)
1823                 return NULL;
1824
1825         if (mat1->num_col != mat2->num_col || mat1->num_row != mat2->num_row) {
1826                 PyErr_SetString(PyExc_TypeError,
1827                                 "Matrix addition: "
1828                                 "matrices must have the same dimensions for this operation");
1829                 return NULL;
1830         }
1831
1832         sub_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->num_col * mat1->num_row);
1833
1834         return Matrix_CreatePyObject(mat, mat1->num_col, mat1->num_row, Py_NEW, Py_TYPE(mat1));
1835 }
1836 /*------------------------obj * obj------------------------------
1837   mulplication*/
1838 static PyObject *matrix_mul_float(MatrixObject *mat, const float scalar)
1839 {
1840         float tmat[16];
1841         mul_vn_vn_fl(tmat, mat->matrix, mat->num_col * mat->num_row, scalar);
1842         return Matrix_CreatePyObject(tmat, mat->num_col, mat->num_row, Py_NEW, Py_TYPE(mat));
1843 }
1844
1845 static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
1846 {
1847         float scalar;
1848         int vec_size;
1849
1850         MatrixObject *mat1 = NULL, *mat2 = NULL;
1851
1852         if (MatrixObject_Check(m1)) {
1853                 mat1 = (MatrixObject *)m1;
1854                 if (BaseMath_ReadCallback(mat1) == -1)
1855                         return NULL;
1856         }
1857         if (MatrixObject_Check(m2)) {
1858                 mat2 = (MatrixObject *)m2;
1859                 if (BaseMath_ReadCallback(mat2) == -1)
1860                         return NULL;
1861         }
1862
1863         if (mat1 && mat2) {
1864                 /* MATRIX * MATRIX */
1865                 float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f,
1866                                  0.0f, 0.0f, 0.0f, 0.0f,
1867                                  0.0f, 0.0f, 0.0f, 0.0f,
1868                                  0.0f, 0.0f, 0.0f, 1.0f};
1869                 double dot = 0.0f;
1870                 int col, row, item;
1871
1872                 if (mat1->num_col != mat2->num_row) {
1873                         PyErr_SetString(PyExc_ValueError,
1874                                                         "matrix1 * matrix2: matrix1 number of columns "
1875                                                         "and the matrix2 number of rows must be the same");
1876                         return NULL;
1877                 }
1878
1879                 for (col = 0; col < mat2->num_col; col++) {
1880                         for (row = 0; row < mat1->num_row; row++) {
1881                                 for (item = 0; item < mat1->num_col; item++) {
1882                                         dot += MATRIX_ITEM(mat1, row, item) * MATRIX_ITEM(mat2, item, col);
1883                                 }
1884                                 mat[(col * mat1->num_row) + row] = (float)dot;
1885                                 dot = 0.0f;
1886                         }
1887                 }
1888
1889                 return Matrix_CreatePyObject(mat, mat2->num_col, mat1->num_row, Py_NEW, Py_TYPE(mat1));
1890         }
1891         else if (mat2) {
1892                 /*FLOAT/INT * MATRIX */
1893                 if (((scalar = PyFloat_AsDouble(m1)) == -1.0f && PyErr_Occurred()) == 0) {
1894                         return matrix_mul_float(mat2, scalar);
1895                 }
1896         }
1897         else if (mat1) {
1898                 /* MATRIX * VECTOR */
1899                 if (VectorObject_Check(m2)) {
1900                         VectorObject *vec2 = (VectorObject *)m2;
1901                         float tvec[4];
1902                         if (BaseMath_ReadCallback(vec2) == -1)
1903                                 return NULL;
1904                         if (column_vector_multiplication(tvec, vec2, mat1) == -1) {
1905                                 return NULL;
1906                         }
1907
1908                         if (mat1->num_col == 4 && vec2->size == 3) {
1909                                 vec_size = 3;
1910                         }
1911                         else {
1912                                 vec_size = mat1->num_row;
1913                         }
1914
1915                         return Vector_CreatePyObject(tvec, vec_size, Py_NEW, Py_TYPE(m2));
1916                 }
1917                 /*FLOAT/INT * MATRIX */
1918                 else if (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0) {
1919                         return matrix_mul_float(mat1, scalar);
1920                 }
1921         }
1922         else {
1923                 BLI_assert(!"internal error");
1924         }
1925
1926         PyErr_Format(PyExc_TypeError,
1927                      "Matrix multiplication: "
1928                      "not supported between '%.200s' and '%.200s' types",
1929                      Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name);
1930         return NULL;
1931 }
1932 static PyObject *Matrix_inv(MatrixObject *self)
1933 {
1934         if (BaseMath_ReadCallback(self) == -1)
1935                 return NULL;
1936
1937         return Matrix_invert(self);
1938 }
1939
1940 /*-----------------PROTOCOL DECLARATIONS--------------------------*/
1941 static PySequenceMethods Matrix_SeqMethods = {
1942         (lenfunc) Matrix_len,                                           /* sq_length */
1943         (binaryfunc) NULL,                                                      /* sq_concat */
1944         (ssizeargfunc) NULL,                                            /* sq_repeat */
1945         (ssizeargfunc) Matrix_item_row,                         /* sq_item */
1946         (ssizessizeargfunc) NULL,                                       /* sq_slice, deprecated */
1947         (ssizeobjargproc) Matrix_ass_item_row,          /* sq_ass_item */
1948         (ssizessizeobjargproc) NULL,                            /* sq_ass_slice, deprecated */
1949         (objobjproc) NULL,                                                      /* sq_contains */
1950         (binaryfunc) NULL,                                                      /* sq_inplace_concat */
1951         (ssizeargfunc) NULL,                                            /* sq_inplace_repeat */
1952 };
1953
1954
1955 static PyObject *Matrix_subscript(MatrixObject *self, PyObject *item)
1956 {
1957         if (PyIndex_Check(item)) {
1958                 Py_ssize_t i;
1959                 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
1960                 if (i == -1 && PyErr_Occurred())
1961                         return NULL;
1962                 if (i < 0)
1963                         i += self->num_row;
1964                 return Matrix_item_row(self, i);
1965         }
1966         else if (PySlice_Check(item)) {
1967                 Py_ssize_t start, stop, step, slicelength;
1968
1969                 if (PySlice_GetIndicesEx((void *)item, self->num_row, &start, &stop, &step, &slicelength) < 0)
1970                         return NULL;
1971
1972                 if (slicelength <= 0) {
1973                         return PyTuple_New(0);
1974                 }
1975                 else if (step == 1) {
1976                         return Matrix_slice(self, start, stop);
1977                 }
1978                 else {
1979                         PyErr_SetString(PyExc_IndexError,
1980                                         "slice steps not supported with matrices");
1981                         return NULL;
1982                 }
1983         }
1984         else {
1985                 PyErr_Format(PyExc_TypeError,
1986                              "matrix indices must be integers, not %.200s",
1987                              Py_TYPE(item)->tp_name);
1988                 return NULL;
1989         }
1990 }
1991
1992 static int Matrix_ass_subscript(MatrixObject *self, PyObject *item, PyObject *value)
1993 {
1994         if (PyIndex_Check(item)) {
1995                 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
1996                 if (i == -1 && PyErr_Occurred())
1997                         return -1;
1998                 if (i < 0)
1999                         i += self->num_row;
2000                 return Matrix_ass_item_row(self, i, value);
2001         }
2002         else if (PySlice_Check(item)) {
2003                 Py_ssize_t start, stop, step, slicelength;
2004
2005                 if (PySlice_GetIndicesEx((void *)item, self->num_row, &start, &stop, &step, &slicelength) < 0)
2006                         return -1;
2007
2008                 if (step == 1)
2009                         return Matrix_ass_slice(self, start, stop, value);
2010                 else {
2011                         PyErr_SetString(PyExc_IndexError,
2012                                         "slice steps not supported with matrices");
2013                         return -1;
2014                 }
2015         }
2016         else {
2017                 PyErr_Format(PyExc_TypeError,
2018                              "matrix indices must be integers, not %.200s",
2019                              Py_TYPE(item)->tp_name);
2020                 return -1;
2021         }
2022 }
2023
2024 static PyMappingMethods Matrix_AsMapping = {
2025         (lenfunc)Matrix_len,
2026         (binaryfunc)Matrix_subscript,
2027         (objobjargproc)Matrix_ass_subscript
2028 };
2029
2030
2031 static PyNumberMethods Matrix_NumMethods = {
2032                 (binaryfunc)    Matrix_add,     /*nb_add*/
2033                 (binaryfunc)    Matrix_sub,     /*nb_subtract*/
2034                 (binaryfunc)    Matrix_mul,     /*nb_multiply*/
2035                 NULL,                                                   /*nb_remainder*/
2036                 NULL,                                                   /*nb_divmod*/
2037                 NULL,                                                   /*nb_power*/
2038                 (unaryfunc)     0,      /*nb_negative*/
2039                 (unaryfunc)     0,      /*tp_positive*/
2040                 (unaryfunc)     0,      /*tp_absolute*/
2041                 (inquiry)       0,      /*tp_bool*/
2042                 (unaryfunc)     Matrix_inv,     /*nb_invert*/
2043                 NULL,                           /*nb_lshift*/
2044                 (binaryfunc)0,  /*nb_rshift*/
2045                 NULL,                           /*nb_and*/
2046                 NULL,                           /*nb_xor*/
2047                 NULL,                           /*nb_or*/
2048                 NULL,                           /*nb_int*/
2049                 NULL,                           /*nb_reserved*/
2050                 NULL,                           /*nb_float*/
2051                 NULL,                           /* nb_inplace_add */
2052                 NULL,                           /* nb_inplace_subtract */
2053                 NULL,                           /* nb_inplace_multiply */
2054                 NULL,                           /* nb_inplace_remainder */
2055                 NULL,                           /* nb_inplace_power */
2056                 NULL,                           /* nb_inplace_lshift */
2057                 NULL,                           /* nb_inplace_rshift */
2058                 NULL,                           /* nb_inplace_and */
2059                 NULL,                           /* nb_inplace_xor */
2060                 NULL,                           /* nb_inplace_or */
2061                 NULL,                           /* nb_floor_divide */
2062                 NULL,                           /* nb_true_divide */
2063                 NULL,                           /* nb_inplace_floor_divide */
2064                 NULL,                           /* nb_inplace_true_divide */
2065                 NULL,                           /* nb_index */
2066 };
2067
2068 PyDoc_STRVAR(Matrix_row_size_doc,
2069 "The row size of the matrix (readonly).\n\n:type: int"
2070 );
2071 static PyObject *Matrix_row_size_get(MatrixObject *self, void *UNUSED(closure))
2072 {
2073         return PyLong_FromLong((long) self->num_col);
2074 }
2075
2076 PyDoc_STRVAR(Matrix_col_size_doc,
2077 "The column size of the matrix (readonly).\n\n:type: int"
2078 );
2079 static PyObject *Matrix_col_size_get(MatrixObject *self, void *UNUSED(closure))
2080 {
2081         return PyLong_FromLong((long) self->num_row);
2082 }
2083
2084 PyDoc_STRVAR(Matrix_translation_doc,
2085 "The translation component of the matrix.\n\n:type: Vector"
2086 );
2087 static PyObject *Matrix_translation_get(MatrixObject *self, void *UNUSED(closure))
2088 {
2089         PyObject *ret;
2090
2091         if (BaseMath_ReadCallback(self) == -1)
2092                 return NULL;
2093
2094         /*must be 4x4 square matrix*/
2095         if (self->num_row != 4 || self->num_col != 4) {
2096                 PyErr_SetString(PyExc_AttributeError,
2097                                 "Matrix.translation: "
2098                                 "inappropriate matrix size, must be 4x4");
2099                 return NULL;
2100         }
2101
2102         ret = (PyObject *)Vector_CreatePyObject_cb((PyObject *)self, 3, mathutils_matrix_translation_cb_index, 3);
2103
2104         return ret;
2105 }
2106
2107 static int Matrix_translation_set(MatrixObject *self, PyObject *value, void *UNUSED(closure))
2108 {
2109         float tvec[3];
2110
2111         if (BaseMath_ReadCallback(self) == -1)
2112                 return -1;
2113
2114         /*must be 4x4 square matrix*/
2115         if (self->num_row != 4 || self->num_col != 4) {
2116                 PyErr_SetString(PyExc_AttributeError,
2117                                 "Matrix.translation: "
2118                                 "inappropriate matrix size, must be 4x4");
2119                 return -1;
2120         }
2121
2122         if ((mathutils_array_parse(tvec, 3, 3, value, "Matrix.translation")) == -1)
2123                 return -1;
2124
2125         copy_v3_v3(((float (*)[4])self->matrix)[3], tvec);
2126
2127         (void)BaseMath_WriteCallback(self);
2128
2129         return 0;
2130 }
2131
2132 PyDoc_STRVAR(Matrix_row_doc,
2133 "Access the matix by rows (default), (readonly).\n\n:type: Matrix Access"
2134 );
2135 static PyObject *Matrix_row_get(MatrixObject *self, void *UNUSED(closure))
2136 {
2137         return MatrixAccess_CreatePyObject(self, MAT_ACCESS_ROW);
2138 }
2139
2140 PyDoc_STRVAR(Matrix_col_doc,
2141 "Access the matix by colums, 3x3 and 4x4 only, (readonly).\n\n:type: Matrix Access"
2142 );
2143 static PyObject *Matrix_col_get(MatrixObject *self, void *UNUSED(closure))
2144 {
2145         return MatrixAccess_CreatePyObject(self, MAT_ACCESS_COL);
2146 }
2147
2148 PyDoc_STRVAR(Matrix_median_scale_doc,
2149 "The average scale applied to each axis (readonly).\n\n:type: float"
2150 );
2151 static PyObject *Matrix_median_scale_get(MatrixObject *self, void *UNUSED(closure))
2152 {
2153         float mat[3][3];
2154
2155         if (BaseMath_ReadCallback(self) == -1)
2156                 return NULL;
2157
2158         /*must be 3-4 cols, 3-4 rows, square matrix*/
2159         if ((self->num_row < 3) || (self->num_col < 3)) {
2160                 PyErr_SetString(PyExc_AttributeError,
2161                                 "Matrix.median_scale: "
2162                                 "inappropriate matrix size, 3x3 minimum");
2163                 return NULL;
2164         }
2165
2166         matrix_as_3x3(mat, self);
2167
2168         return PyFloat_FromDouble(mat3_to_scale(mat));
2169 }
2170
2171 PyDoc_STRVAR(Matrix_is_negative_doc,
2172 "True if this matrix results in a negative scale, 3x3 and 4x4 only, (readonly).\n\n:type: bool"
2173 );
2174 static PyObject *Matrix_is_negative_get(MatrixObject *self, void *UNUSED(closure))
2175 {
2176         if (BaseMath_ReadCallback(self) == -1)
2177                 return NULL;
2178
2179         /*must be 3-4 cols, 3-4 rows, square matrix*/
2180         if (self->num_row == 4 && self->num_col == 4)
2181                 return PyBool_FromLong(is_negative_m4((float (*)[4])self->matrix));
2182         else if (self->num_row == 3 && self->num_col == 3)
2183                 return PyBool_FromLong(is_negative_m3((float (*)[3])self->matrix));
2184         else {
2185                 PyErr_SetString(PyExc_AttributeError,
2186                                 "Matrix.is_negative: "
2187                                 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
2188                 return NULL;
2189         }
2190 }
2191
2192 PyDoc_STRVAR(Matrix_is_orthogonal_doc,
2193 "True if this matrix is orthogonal, 3x3 and 4x4 only, (readonly).\n\n:type: bool"
2194 );
2195 static PyObject *Matrix_is_orthogonal_get(MatrixObject *self, void *UNUSED(closure))
2196 {
2197         if (BaseMath_ReadCallback(self) == -1)
2198                 return NULL;
2199
2200         /*must be 3-4 cols, 3-4 rows, square matrix*/
2201         if (self->num_row == 4 && self->num_col == 4)
2202                 return PyBool_FromLong(is_orthogonal_m4((float (*)[4])self->matrix));
2203         else if (self->num_row == 3 && self->num_col == 3)
2204                 return PyBool_FromLong(is_orthogonal_m3((float (*)[3])self->matrix));
2205         else {
2206                 PyErr_SetString(PyExc_AttributeError,
2207                                 "Matrix.is_orthogonal: "
2208                                 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
2209                 return NULL;
2210         }
2211 }
2212
2213 /*****************************************************************************/
2214 /* Python attributes get/set structure:                                      */
2215 /*****************************************************************************/
2216 static PyGetSetDef Matrix_getseters[] = {
2217         {(char *)"row_size", (getter)Matrix_row_size_get, (setter)NULL, Matrix_row_size_doc, NULL},
2218         {(char *)"col_size", (getter)Matrix_col_size_get, (setter)NULL, Matrix_col_size_doc, NULL},
2219         {(char *)"median_scale", (getter)Matrix_median_scale_get, (setter)NULL, Matrix_median_scale_doc, NULL},
2220         {(char *)"translation", (getter)Matrix_translation_get, (setter)Matrix_translation_set, Matrix_translation_doc, NULL},
2221         {(char *)"row", (getter)Matrix_row_get, (setter)NULL, Matrix_row_doc, NULL},
2222         {(char *)"col", (getter)Matrix_col_get, (setter)NULL, Matrix_col_doc, NULL},
2223         {(char *)"is_negative", (getter)Matrix_is_negative_get, (setter)NULL, Matrix_is_negative_doc, NULL},
2224         {(char *)"is_orthogonal", (getter)Matrix_is_orthogonal_get, (setter)NULL, Matrix_is_orthogonal_doc, NULL},
2225         {(char *)"is_wrapped", (getter)BaseMathObject_is_wrapped_get, (setter)NULL, BaseMathObject_is_wrapped_doc, NULL},
2226         {(char *)"owner",(getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
2227         {NULL, NULL, NULL, NULL, NULL}  /* Sentinel */
2228 };
2229
2230 /*-----------------------METHOD DEFINITIONS ----------------------*/
2231 static struct PyMethodDef Matrix_methods[] = {
2232         /* derived values */
2233         {"determinant", (PyCFunction) Matrix_determinant, METH_NOARGS, Matrix_determinant_doc},
2234         {"decompose", (PyCFunction) Matrix_decompose, METH_NOARGS, Matrix_decompose_doc},
2235
2236         /* in place only */
2237         {"zero", (PyCFunction) Matrix_zero, METH_NOARGS, Matrix_zero_doc},
2238         {"identity", (PyCFunction) Matrix_identity, METH_NOARGS, Matrix_identity_doc},
2239
2240         /* operate on original or copy */
2241         {"transpose", (PyCFunction) Matrix_transpose, METH_NOARGS, Matrix_transpose_doc},
2242         {"transposed", (PyCFunction) Matrix_transposed, METH_NOARGS, Matrix_transposed_doc},
2243         {"invert", (PyCFunction) Matrix_invert, METH_NOARGS, Matrix_invert_doc},
2244         {"inverted", (PyCFunction) Matrix_inverted, METH_NOARGS, Matrix_inverted_doc},
2245         {"to_3x3", (PyCFunction) Matrix_to_3x3, METH_NOARGS, Matrix_to_3x3_doc},
2246         // TODO. {"resize_3x3", (PyCFunction) Matrix_resize3x3, METH_NOARGS, Matrix_resize3x3_doc},
2247         {"to_4x4", (PyCFunction) Matrix_to_4x4, METH_NOARGS, Matrix_to_4x4_doc},
2248         {"resize_4x4", (PyCFunction) Matrix_resize_4x4, METH_NOARGS, Matrix_resize_4x4_doc},
2249         {"rotate", (PyCFunction) Matrix_rotate, METH_O, Matrix_rotate_doc},
2250
2251         /* return converted representation */
2252         {"to_euler", (PyCFunction) Matrix_to_euler, METH_VARARGS, Matrix_to_euler_doc},
2253         {"to_quaternion", (PyCFunction) Matrix_to_quaternion, METH_NOARGS, Matrix_to_quaternion_doc},
2254         {"to_scale", (PyCFunction) Matrix_to_scale, METH_NOARGS, Matrix_to_scale_doc},
2255         {"to_translation", (PyCFunction) Matrix_to_translation, METH_NOARGS, Matrix_to_translation_doc},
2256
2257         /* operation between 2 or more types  */
2258         {"lerp", (PyCFunction) Matrix_lerp, METH_VARARGS, Matrix_lerp_doc},
2259         {"copy", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
2260         {"__copy__", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
2261
2262         /* class methods */
2263         {"Rotation", (PyCFunction) C_Matrix_Rotation, METH_VARARGS | METH_CLASS, C_Matrix_Rotation_doc},
2264         {"Scale", (PyCFunction) C_Matrix_Scale, METH_VARARGS | METH_CLASS, C_Matrix_Scale_doc},
2265         {"Shear", (PyCFunction) C_Matrix_Shear, METH_VARARGS | METH_CLASS, C_Matrix_Shear_doc},
2266         {"Translation", (PyCFunction) C_Matrix_Translation, METH_O | METH_CLASS, C_Matrix_Translation_doc},
2267         {"OrthoProjection", (PyCFunction) C_Matrix_OrthoProjection,  METH_VARARGS | METH_CLASS, C_Matrix_OrthoProjection_doc},
2268         {NULL, NULL, 0, NULL}
2269 };
2270
2271 /*------------------PY_OBECT DEFINITION--------------------------*/
2272 PyDoc_STRVAR(matrix_doc,
2273 "This object gives access to Matrices in Blender."
2274 );
2275 PyTypeObject matrix_Type = {
2276         PyVarObject_HEAD_INIT(NULL, 0)
2277         "mathutils.Matrix",                                     /*tp_name*/
2278         sizeof(MatrixObject),                           /*tp_basicsize*/
2279         0,                                                                      /*tp_itemsize*/
2280         (destructor)BaseMathObject_dealloc,     /*tp_dealloc*/
2281         NULL,                                                           /*tp_print*/
2282         NULL,                                                           /*tp_getattr*/
2283         NULL,                                                           /*tp_setattr*/
2284         NULL,                                                           /*tp_compare*/
2285         (reprfunc) Matrix_repr,                         /*tp_repr*/
2286         &Matrix_NumMethods,                                     /*tp_as_number*/
2287         &Matrix_SeqMethods,                                     /*tp_as_sequence*/
2288         &Matrix_AsMapping,                                      /*tp_as_mapping*/
2289         NULL,                                                           /*tp_hash*/
2290         NULL,                                                           /*tp_call*/
2291         (reprfunc) Matrix_str,                          /*tp_str*/
2292         NULL,                                                           /*tp_getattro*/
2293         NULL,                                                           /*tp_setattro*/
2294         NULL,                                                           /*tp_as_buffer*/
2295         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
2296         matrix_doc,                                                     /*tp_doc*/
2297         (traverseproc)BaseMathObject_traverse,  //tp_traverse
2298         (inquiry)BaseMathObject_clear,  //tp_clear
2299         (richcmpfunc)Matrix_richcmpr,           /*tp_richcompare*/
2300         0,                                                                      /*tp_weaklistoffset*/
2301         NULL,                                                           /*tp_iter*/
2302         NULL,                                                           /*tp_iternext*/
2303         Matrix_methods,                                         /*tp_methods*/
2304         NULL,                                                           /*tp_members*/
2305         Matrix_getseters,                                       /*tp_getset*/
2306         NULL,                                                           /*tp_base*/
2307         NULL,                                                           /*tp_dict*/
2308         NULL,                                                           /*tp_descr_get*/
2309         NULL,                                                           /*tp_descr_set*/
2310         0,                                                                      /*tp_dictoffset*/
2311         NULL,                                                           /*tp_init*/
2312         NULL,                                                           /*tp_alloc*/
2313         Matrix_new,                                                     /*tp_new*/
2314         NULL,                                                           /*tp_free*/
2315         NULL,                                                           /*tp_is_gc*/
2316         NULL,                                                           /*tp_bases*/
2317         NULL,                                                           /*tp_mro*/
2318         NULL,                                                           /*tp_cache*/
2319         NULL,                                                           /*tp_subclasses*/
2320         NULL,                                                           /*tp_weaklist*/
2321         NULL                                                            /*tp_del*/
2322 };
2323
2324 /* pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
2325  * (i.e. it was allocated elsewhere by MEM_mallocN())
2326  * pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
2327  * (i.e. it must be created here with PyMEM_malloc()) */
2328 PyObject *Matrix_CreatePyObject(float *mat,
2329                                 const unsigned short num_col, const unsigned short num_row,
2330                                 int type, PyTypeObject *base_type)
2331 {
2332         MatrixObject *self;
2333
2334         /* matrix objects can be any 2-4row x 2-4col matrix */
2335         if (num_col < 2 || num_col > 4 || num_row < 2 || num_row > 4) {
2336                 PyErr_SetString(PyExc_RuntimeError,
2337                                 "Matrix(): "
2338                                 "row and column sizes must be between 2 and 4");
2339                 return NULL;
2340         }
2341
2342         self = base_type ? (MatrixObject *)base_type->tp_alloc(base_type, 0) :
2343                            (MatrixObject *)PyObject_GC_New(MatrixObject, &matrix_Type);
2344
2345         if (self) {
2346                 self->num_col = num_col;
2347                 self->num_row = num_row;
2348
2349                 /* init callbacks as NULL */
2350                 self->cb_user = NULL;
2351                 self->cb_type = self->cb_subtype = 0;
2352
2353                 if (type == Py_WRAP) {
2354                         self->matrix = mat;
2355                         self->wrapped = Py_WRAP;
2356                 }
2357                 else if (type == Py_NEW) {
2358                         self->matrix = PyMem_Malloc(num_col * num_row * sizeof(float));
2359                         if (self->matrix == NULL) { /*allocation failure*/
2360                                 PyErr_SetString(PyExc_MemoryError,
2361                                                 "Matrix(): "
2362                                                 "problem allocating pointer space");
2363                                 return NULL;
2364                         }
2365
2366                         if (mat) {      /*if a float array passed*/
2367                                 memcpy(self->matrix, mat, num_col * num_row * sizeof(float));
2368                         }
2369                         else if (num_col == num_row) {
2370                                 /* or if no arguments are passed return identity matrix for square matrices */
2371                                 PyObject *ret_dummy = Matrix_identity(self);
2372                                 Py_DECREF(ret_dummy);
2373                         }
2374                         else {
2375                                 /* otherwise zero everything */
2376                                 memset(self->matrix, 0, num_col * num_row * sizeof(float));
2377                         }
2378                         self->wrapped = Py_NEW;
2379                 }
2380                 else {
2381                         Py_FatalError("Matrix(): invalid type!");
2382                         return NULL;
2383                 }
2384         }
2385         return (PyObject *) self;
2386 }
2387
2388 PyObject *Matrix_CreatePyObject_cb(PyObject *cb_user,
2389                                    const unsigned short num_col, const unsigned short num_row,
2390                                    int cb_type, int cb_subtype)
2391 {
2392         MatrixObject *self = (MatrixObject *)Matrix_CreatePyObject(NULL, num_col, num_row, Py_NEW, NULL);
2393         if (self) {
2394                 Py_INCREF(cb_user);
2395                 self->cb_user =                 cb_user;
2396                 self->cb_type =                 (unsigned char)cb_type;
2397                 self->cb_subtype =              (unsigned char)cb_subtype;
2398                 PyObject_GC_Track(self);
2399         }
2400         return (PyObject *) self;
2401 }
2402
2403
2404 /* ----------------------------------------------------------------------------
2405  * special type for alaternate access */
2406
2407 typedef struct {
2408         PyObject_HEAD /* required python macro   */
2409         MatrixObject *matrix_user;
2410         eMatrixAccess_t type;
2411 } MatrixAccessObject;
2412
2413 static int MatrixAccess_traverse(MatrixAccessObject *self, visitproc visit, void *arg)
2414 {
2415         Py_VISIT(self->matrix_user);
2416         return 0;
2417 }
2418
2419 int MatrixAccess_clear(MatrixAccessObject *self)
2420 {
2421         Py_CLEAR(self->matrix_user);
2422         return 0;
2423 }
2424
2425 void MatrixAccess_dealloc(MatrixAccessObject *self)
2426 {
2427         if (self->matrix_user) {
2428                 PyObject_GC_UnTrack(self);
2429                 MatrixAccess_clear(self);
2430         }
2431
2432         Py_TYPE(self)->tp_free(self);
2433 }
2434
2435 /* sequence access */
2436
2437 static int MatrixAccess_len(MatrixAccessObject *self)
2438 {
2439         return (self->type == MAT_ACCESS_ROW) ?
2440                     self->matrix_user->num_row :
2441                     self->matrix_user->num_col;
2442 }
2443
2444 static PyObject *MatrixAccess_subscript(MatrixAccessObject *self, PyObject *item)
2445 {
2446         MatrixObject *matrix_user = self->matrix_user;
2447
2448         if (PyIndex_Check(item)) {
2449                 Py_ssize_t i;
2450                 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
2451                 if (i == -1 && PyErr_Occurred())
2452                         return NULL;
2453                 if (self->type == MAT_ACCESS_ROW) {
2454                         if (i < 0)
2455                                 i += matrix_user->num_row;
2456                         return Matrix_item_row(matrix_user, i);
2457                 }
2458                 else { /* MAT_ACCESS_ROW */
2459                         if (i < 0)
2460                                 i += matrix_user->num_col;
2461                         return Matrix_item_col(matrix_user, i);
2462                 }
2463         }
2464         /* TODO, slice */
2465         else {
2466                 PyErr_Format(PyExc_TypeError,
2467                              "matrix indices must be integers, not %.200s",
2468                              Py_TYPE(item)->tp_name);
2469                 return NULL;
2470         }
2471 }
2472
2473 static int MatrixAccess_ass_subscript(MatrixAccessObject *self, PyObject *item, PyObject *value)
2474 {
2475         MatrixObject *matrix_user = self->matrix_user;
2476
2477         if (PyIndex_Check(item)) {
2478                 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
2479                 if (i == -1 && PyErr_Occurred())
2480                         return -1;
2481
2482                 if (self->type == MAT_ACCESS_ROW) {
2483                         if (i < 0)
2484                                 i += matrix_user->num_row;
2485                         return Matrix_ass_item_row(matrix_user, i, value);
2486                 }
2487                 else { /* MAT_ACCESS_ROW */
2488                         if (i < 0)
2489                                 i += matrix_user->num_col;
2490                         return Matrix_ass_item_col(matrix_user, i, value);
2491                 }
2492
2493         }
2494         /* TODO, slice */
2495         else {
2496                 PyErr_Format(PyExc_TypeError,
2497                              "matrix indices must be integers, not %.200s",
2498                              Py_TYPE(item)->tp_name);
2499                 return -1;
2500         }
2501 }
2502
2503
2504 static PyMappingMethods MatrixAccess_AsMapping = {
2505         (lenfunc)MatrixAccess_len,
2506         (binaryfunc)MatrixAccess_subscript,
2507         (objobjargproc) MatrixAccess_ass_subscript
2508 };
2509
2510 PyTypeObject matrix_access_Type = {
2511         PyVarObject_HEAD_INIT(NULL, 0)
2512         "MatrixAccess",                                         /*tp_name*/
2513         sizeof(MatrixAccessObject),                     /*tp_basicsize*/
2514         0,                                                                      /*tp_itemsize*/
2515         (destructor)MatrixAccess_dealloc,       /*tp_dealloc*/
2516         NULL,                                                           /*tp_print*/
2517         NULL,                                                           /*tp_getattr*/
2518         NULL,                                                           /*tp_setattr*/
2519         NULL,                                                           /*tp_compare*/
2520         NULL,                                                           /*tp_repr*/
2521         NULL,                                                           /*tp_as_number*/
2522         NULL /*&MatrixAccess_SeqMethods*/ /* TODO */,                   /*tp_as_sequence*/
2523         &MatrixAccess_AsMapping,                        /*tp_as_mapping*/
2524         NULL,                                                           /*tp_hash*/
2525         NULL,                                                           /*tp_call*/
2526         NULL,                                                           /*tp_str*/
2527         NULL,                                                           /*tp_getattro*/
2528         NULL,                                                           /*tp_setattro*/
2529         NULL,                                                           /*tp_as_buffer*/
2530         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
2531         NULL,                                                           /*tp_doc*/
2532         (traverseproc)MatrixAccess_traverse,    //tp_traverse
2533         (inquiry)MatrixAccess_clear,    //tp_clear
2534         NULL /* (richcmpfunc)MatrixAccess_richcmpr */ /* TODO*/, /*tp_richcompare*/
2535 };
2536
2537 static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrixAccess_t type)
2538 {
2539         MatrixAccessObject *matrix_access = (MatrixAccessObject *)PyObject_GC_New(MatrixObject, &matrix_access_Type);
2540
2541         matrix_access->matrix_user = matrix;
2542         Py_INCREF(matrix);
2543
2544         matrix_access->type = type;
2545
2546         return (PyObject *)matrix_access;
2547 }
2548
2549 /* end special access
2550  * -------------------------------------------------------------------------- */