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