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