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