Merged 15170:15635 from trunk (no conflicts or even merges)
[blender.git] / source / blender / python / api2_2x / matrix.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * Contributor(s): Michel Selten & Joseph Gilbert
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 #include "Mathutils.h"
29
30 #include "BKE_utildefines.h"
31 #include "BLI_arithb.h"
32 #include "BLI_blenlib.h"
33 #include "gen_utils.h"
34
35 /*-------------------------DOC STRINGS ---------------------------*/
36 char Matrix_Zero_doc[] = "() - set all values in the matrix to 0";
37 char Matrix_Identity_doc[] = "() - set the square matrix to it's identity matrix";
38 char Matrix_Transpose_doc[] = "() - set the matrix to it's transpose";
39 char Matrix_Determinant_doc[] = "() - return the determinant of the matrix";
40 char Matrix_Invert_doc[] =  "() - set the matrix to it's inverse if an inverse is possible";
41 char Matrix_TranslationPart_doc[] = "() - return a vector encompassing the translation of the matrix";
42 char Matrix_RotationPart_doc[] = "() - return a vector encompassing the rotation of the matrix";
43 char Matrix_scalePart_doc[] = "() - convert matrix to a 3D vector";
44 char Matrix_Resize4x4_doc[] = "() - resize the matrix to a 4x4 square matrix";
45 char Matrix_toEuler_doc[] = "() - convert matrix to a euler angle rotation";
46 char Matrix_toQuat_doc[] = "() - convert matrix to a quaternion rotation";
47 char Matrix_copy_doc[] = "() - return a copy of the matrix";
48 /*-----------------------METHOD DEFINITIONS ----------------------*/
49 struct PyMethodDef Matrix_methods[] = {
50         {"zero", (PyCFunction) Matrix_Zero, METH_NOARGS, Matrix_Zero_doc},
51         {"identity", (PyCFunction) Matrix_Identity, METH_NOARGS, Matrix_Identity_doc},
52         {"transpose", (PyCFunction) Matrix_Transpose, METH_NOARGS, Matrix_Transpose_doc},
53         {"determinant", (PyCFunction) Matrix_Determinant, METH_NOARGS, Matrix_Determinant_doc},
54         {"invert", (PyCFunction) Matrix_Invert, METH_NOARGS, Matrix_Invert_doc},
55         {"translationPart", (PyCFunction) Matrix_TranslationPart, METH_NOARGS, Matrix_TranslationPart_doc},
56         {"rotationPart", (PyCFunction) Matrix_RotationPart, METH_NOARGS, Matrix_RotationPart_doc},
57         {"scalePart", (PyCFunction) Matrix_scalePart, METH_NOARGS, Matrix_scalePart_doc},
58         {"resize4x4", (PyCFunction) Matrix_Resize4x4, METH_NOARGS, Matrix_Resize4x4_doc},
59         {"toEuler", (PyCFunction) Matrix_toEuler, METH_NOARGS, Matrix_toEuler_doc},
60         {"toQuat", (PyCFunction) Matrix_toQuat, METH_NOARGS, Matrix_toQuat_doc},
61         {"copy", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
62         {"__copy__", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
63         {NULL, NULL, 0, NULL}
64 };
65 /*-----------------------------METHODS----------------------------*/
66 /*---------------------------Matrix.toQuat() ---------------------*/
67 PyObject *Matrix_toQuat(MatrixObject * self)
68 {
69         float quat[4];
70
71         /*must be 3-4 cols, 3-4 rows, square matrix*/
72         if(self->colSize < 3 || self->rowSize < 3 || (self->colSize != self->rowSize)) {
73                 return EXPP_ReturnPyObjError(PyExc_AttributeError,
74                         "Matrix.toQuat(): inappropriate matrix size - expects 3x3 or 4x4 matrix\n");
75         } 
76         if(self->colSize == 3){
77         Mat3ToQuat((float (*)[3])*self->matrix, quat);
78         }else{
79                 Mat4ToQuat((float (*)[4])*self->matrix, quat);
80         }
81         
82         return newQuaternionObject(quat, Py_NEW);
83 }
84 /*---------------------------Matrix.toEuler() --------------------*/
85 PyObject *Matrix_toEuler(MatrixObject * self)
86 {
87         float eul[3];
88         
89         int x;
90
91         /*must be 3-4 cols, 3-4 rows, square matrix*/
92         if(self->colSize ==3 && self->rowSize ==3) {
93                 Mat3ToEul((float (*)[3])*self->matrix, eul);
94         }else if (self->colSize ==4 && self->rowSize ==4) {
95                 float tempmat3[3][3];
96                 Mat3CpyMat4(tempmat3, (float (*)[4])*self->matrix);
97                 Mat3ToEul(tempmat3, eul);
98         }else
99                 return EXPP_ReturnPyObjError(PyExc_AttributeError,
100                         "Matrix.toEuler(): inappropriate matrix size - expects 3x3 or 4x4 matrix\n");
101         
102         /*have to convert to degrees*/
103         for(x = 0; x < 3; x++) {
104                 eul[x] *= (float) (180 / Py_PI);
105         }
106         return newEulerObject(eul, Py_NEW);
107 }
108 /*---------------------------Matrix.resize4x4() ------------------*/
109 PyObject *Matrix_Resize4x4(MatrixObject * self)
110 {
111         int x, first_row_elem, curr_pos, new_pos, blank_columns, blank_rows, index;
112
113         if(self->data.blend_data){
114                 return EXPP_ReturnPyObjError(PyExc_TypeError,
115                         "cannot resize wrapped data - only python matrices\n");
116         }
117
118         self->data.py_data = PyMem_Realloc(self->data.py_data, (sizeof(float) * 16));
119         if(self->data.py_data == NULL) {
120                 return EXPP_ReturnPyObjError(PyExc_MemoryError,
121                         "matrix.resize4x4(): problem allocating pointer space\n\n");
122         }
123         self->contigPtr = self->data.py_data;  /*force*/
124         self->matrix = PyMem_Realloc(self->matrix, (sizeof(float *) * 4));
125         if(self->matrix == NULL) {
126                 return EXPP_ReturnPyObjError(PyExc_MemoryError,
127                         "matrix.resize4x4(): problem allocating pointer space\n\n");
128         }
129         /*set row pointers*/
130         for(x = 0; x < 4; x++) {
131                 self->matrix[x] = self->contigPtr + (x * 4);
132         }
133         /*move data to new spot in array + clean*/
134         for(blank_rows = (4 - self->rowSize); blank_rows > 0; blank_rows--){
135                 for(x = 0; x < 4; x++){
136                         index = (4 * (self->rowSize + (blank_rows - 1))) + x;
137                         if (index == 10 || index == 15){
138                                 self->contigPtr[index] = 1.0f;
139                         }else{
140                                 self->contigPtr[index] = 0.0f;
141                         }
142                 }
143         }
144         for(x = 1; x <= self->rowSize; x++){
145                 first_row_elem = (self->colSize * (self->rowSize - x));
146                 curr_pos = (first_row_elem + (self->colSize -1));
147                 new_pos = (4 * (self->rowSize - x )) + (curr_pos - first_row_elem);
148                 for(blank_columns = (4 - self->colSize); blank_columns > 0; blank_columns--){
149                         self->contigPtr[new_pos + blank_columns] = 0.0f;
150                 }
151                 for(curr_pos = curr_pos; curr_pos >= first_row_elem; curr_pos--){
152                         self->contigPtr[new_pos] = self->contigPtr[curr_pos];
153                         new_pos--;
154                 }
155         }
156         self->rowSize = 4;
157         self->colSize = 4;
158         return EXPP_incr_ret((PyObject*)self);
159 }
160 /*---------------------------Matrix.translationPart() ------------*/
161 PyObject *Matrix_TranslationPart(MatrixObject * self)
162 {
163         float vec[4];
164
165         if(self->colSize < 3 || self->rowSize < 4){
166                 return EXPP_ReturnPyObjError(PyExc_AttributeError,
167                         "Matrix.translationPart: inappropriate matrix size\n");
168         }
169
170         vec[0] = self->matrix[3][0];
171         vec[1] = self->matrix[3][1];
172         vec[2] = self->matrix[3][2];
173
174         return newVectorObject(vec, 3, Py_NEW);
175 }
176 /*---------------------------Matrix.rotationPart() ---------------*/
177 PyObject *Matrix_RotationPart(MatrixObject * self)
178 {
179         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
180                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
181
182         if(self->colSize < 3 || self->rowSize < 3){
183                 return EXPP_ReturnPyObjError(PyExc_AttributeError,
184                         "Matrix.rotationPart: inappropriate matrix size\n");
185         }
186
187         mat[0] = self->matrix[0][0];
188         mat[1] = self->matrix[0][1];
189         mat[2] = self->matrix[0][2];
190         mat[3] = self->matrix[1][0];
191         mat[4] = self->matrix[1][1];
192         mat[5] = self->matrix[1][2];
193         mat[6] = self->matrix[2][0];
194         mat[7] = self->matrix[2][1];
195         mat[8] = self->matrix[2][2];
196
197         return newMatrixObject(mat, 3, 3, Py_NEW);
198 }
199 /*---------------------------Matrix.scalePart() --------------------*/
200 PyObject *Matrix_scalePart(MatrixObject * self)
201 {
202         float scale[3], rot[3];
203         float mat[3][3], imat[3][3], tmat[3][3];
204
205         /*must be 3-4 cols, 3-4 rows, square matrix*/
206         if(self->colSize == 4 && self->rowSize == 4)
207                 Mat3CpyMat4(mat, (float (*)[4])*self->matrix);
208         else if(self->colSize == 3 && self->rowSize == 3)
209                 Mat3CpyMat3(mat, (float (*)[3])*self->matrix);
210         else
211                 return EXPP_ReturnPyObjError(PyExc_AttributeError,
212                         "Matrix.scalePart(): inappropriate matrix size - expects 3x3 or 4x4 matrix\n");
213         
214         /* functionality copied from editobject.c apply_obmat */
215         Mat3ToEul(mat, rot);
216         EulToMat3(rot, tmat);
217         Mat3Inv(imat, tmat);
218         Mat3MulMat3(tmat, imat, mat);
219         
220         scale[0]= tmat[0][0];
221         scale[1]= tmat[1][1];
222         scale[2]= tmat[2][2];
223         return newVectorObject(scale, 3, Py_NEW);
224 }
225 /*---------------------------Matrix.invert() ---------------------*/
226 PyObject *Matrix_Invert(MatrixObject * self)
227 {
228         
229         int x, y, z = 0;
230         float det = 0.0f;
231         PyObject *f = NULL;
232         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
233                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
234
235         if(self->rowSize != self->colSize){
236                 return EXPP_ReturnPyObjError(PyExc_AttributeError,
237                         "Matrix.invert(ed): only square matrices are supported\n");
238         }
239
240         /*calculate the determinant*/
241         f = Matrix_Determinant(self);
242         det = (float)PyFloat_AS_DOUBLE(f); /*Increfs, so we need to decref*/
243         Py_DECREF(f);
244
245         if(det != 0) {
246                 /*calculate the classical adjoint*/
247                 if(self->rowSize == 2) {
248                         mat[0] = self->matrix[1][1];
249                         mat[1] = -self->matrix[1][0];
250                         mat[2] = -self->matrix[0][1];
251                         mat[3] = self->matrix[0][0];
252                 } else if(self->rowSize == 3) {
253                         Mat3Adj((float (*)[3]) mat,(float (*)[3]) *self->matrix);
254                 } else if(self->rowSize == 4) {
255                         Mat4Adj((float (*)[4]) mat, (float (*)[4]) *self->matrix);
256                 }
257                 /*divide by determinate*/
258                 for(x = 0; x < (self->rowSize * self->colSize); x++) {
259                         mat[x] /= det;
260                 }
261                 /*set values*/
262                 for(x = 0; x < self->rowSize; x++) {
263                         for(y = 0; y < self->colSize; y++) {
264                                 self->matrix[x][y] = mat[z];
265                                 z++;
266                         }
267                 }
268                 /*transpose
269                 Matrix_Transpose(self);*/
270         } else {
271                 return EXPP_ReturnPyObjError(PyExc_ValueError,
272                                 "matrix does not have an inverse");
273         }
274         return EXPP_incr_ret((PyObject*)self);
275 }
276
277
278 /*---------------------------Matrix.determinant() ----------------*/
279 PyObject *Matrix_Determinant(MatrixObject * self)
280 {
281         float det = 0.0f;
282
283         if(self->rowSize != self->colSize){
284                 return EXPP_ReturnPyObjError(PyExc_AttributeError,
285                         "Matrix.determinant: only square matrices are supported\n");
286         }
287
288         if(self->rowSize == 2) {
289                 det = Det2x2(self->matrix[0][0], self->matrix[0][1],
290                                          self->matrix[1][0], self->matrix[1][1]);
291         } else if(self->rowSize == 3) {
292                 det = Det3x3(self->matrix[0][0], self->matrix[0][1],
293                                          self->matrix[0][2], self->matrix[1][0],
294                                          self->matrix[1][1], self->matrix[1][2],
295                                          self->matrix[2][0], self->matrix[2][1],
296                                          self->matrix[2][2]);
297         } else {
298                 det = Det4x4((float (*)[4]) *self->matrix);
299         }
300
301         return PyFloat_FromDouble( (double) det );
302 }
303 /*---------------------------Matrix.transpose() ------------------*/
304 PyObject *Matrix_Transpose(MatrixObject * self)
305 {
306         float t = 0.0f;
307
308         if(self->rowSize != self->colSize){
309                 return EXPP_ReturnPyObjError(PyExc_AttributeError,
310                         "Matrix.transpose(d): only square matrices are supported\n");
311         }
312
313         if(self->rowSize == 2) {
314                 t = self->matrix[1][0];
315                 self->matrix[1][0] = self->matrix[0][1];
316                 self->matrix[0][1] = t;
317         } else if(self->rowSize == 3) {
318                 Mat3Transp((float (*)[3])*self->matrix);
319         } else {
320                 Mat4Transp((float (*)[4])*self->matrix);
321         }
322
323         return EXPP_incr_ret((PyObject*)self);
324 }
325
326
327 /*---------------------------Matrix.zero() -----------------------*/
328 PyObject *Matrix_Zero(MatrixObject * self)
329 {
330         int row, col;
331
332         for(row = 0; row < self->rowSize; row++) {
333                 for(col = 0; col < self->colSize; col++) {
334                         self->matrix[row][col] = 0.0f;
335                 }
336         }
337         return EXPP_incr_ret((PyObject*)self);
338 }
339 /*---------------------------Matrix.identity(() ------------------*/
340 PyObject *Matrix_Identity(MatrixObject * self)
341 {
342         if(self->rowSize != self->colSize){
343                 return EXPP_ReturnPyObjError(PyExc_AttributeError,
344                         "Matrix.identity: only square matrices are supported\n");
345         }
346
347         if(self->rowSize == 2) {
348                 self->matrix[0][0] = 1.0f;
349                 self->matrix[0][1] = 0.0f;
350                 self->matrix[1][0] = 0.0f;
351                 self->matrix[1][1] = 1.0f;
352         } else if(self->rowSize == 3) {
353                 Mat3One((float (*)[3]) *self->matrix);
354         } else {
355                 Mat4One((float (*)[4]) *self->matrix);
356         }
357
358         return EXPP_incr_ret((PyObject*)self);
359 }
360
361 /*---------------------------Matrix.inverted() ------------------*/
362 PyObject *Matrix_copy(MatrixObject * self)
363 {
364         return (PyObject*)(MatrixObject*)newMatrixObject((float (*))*self->matrix, self->rowSize, self->colSize, Py_NEW);
365 }
366
367 /*----------------------------dealloc()(internal) ----------------*/
368 /*free the py_object*/
369 static void Matrix_dealloc(MatrixObject * self)
370 {
371         Py_XDECREF(self->coerced_object);
372         PyMem_Free(self->matrix);
373         /*only free py_data*/
374         if(self->data.py_data){
375                 PyMem_Free(self->data.py_data);
376         }
377         PyObject_DEL(self);
378 }
379 /*----------------------------getattr()(internal) ----------------*/
380 /*object.attribute access (get)*/
381 static PyObject *Matrix_getattr(MatrixObject * self, char *name)
382 {
383         if(STREQ(name, "rowSize")) {
384                 return PyInt_FromLong((long) self->rowSize);
385         } else if(STREQ(name, "colSize")) {
386                 return PyInt_FromLong((long) self->colSize);
387         }
388         if(STREQ(name, "wrapped")){
389                 if(self->wrapped == Py_WRAP)
390                         return EXPP_incr_ret((PyObject *)Py_True);
391                 else 
392                         return EXPP_incr_ret((PyObject *)Py_False);
393         }
394         return Py_FindMethod(Matrix_methods, (PyObject *) self, name);
395 }
396 /*----------------------------setattr()(internal) ----------------*/
397 /*object.attribute access (set)*/
398 static int Matrix_setattr(MatrixObject * self, char *name, PyObject * v)
399 {
400         /* This is not supported. */
401         return (-1);
402 }
403 /*----------------------------print object (internal)-------------*/
404 /*print the object to screen*/
405 static PyObject *Matrix_repr(MatrixObject * self)
406 {
407         int x, y;
408         char buffer[48], str[1024];
409
410         BLI_strncpy(str,"",1024);
411         for(x = 0; x < self->rowSize; x++){
412                 sprintf(buffer, "[");
413                 strcat(str,buffer);
414                 for(y = 0; y < (self->colSize - 1); y++) {
415                         sprintf(buffer, "%.6f, ", self->matrix[x][y]);
416                         strcat(str,buffer);
417                 }
418                 if(x < (self->rowSize-1)){
419                         sprintf(buffer, "%.6f](matrix [row %d])\n", self->matrix[x][y], x);
420                         strcat(str,buffer);
421                 }else{
422                         sprintf(buffer, "%.6f](matrix [row %d])", self->matrix[x][y], x);
423                         strcat(str,buffer);
424                 }
425         }
426
427         return PyString_FromString(str);
428 }
429 /*------------------------tp_richcmpr*/
430 /*returns -1 execption, 0 false, 1 true*/
431 static PyObject* Matrix_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
432 {
433         MatrixObject *matA = NULL, *matB = NULL;
434         int result = 0;
435
436         if (!MatrixObject_Check(objectA) || !MatrixObject_Check(objectB)){
437                 if (comparison_type == Py_NE){
438                         return EXPP_incr_ret(Py_True); 
439                 }else{
440                         return EXPP_incr_ret(Py_False);
441                 }
442         }
443         matA = (MatrixObject*)objectA;
444         matB = (MatrixObject*)objectB;
445
446         if (matA->colSize != matB->colSize || matA->rowSize != matB->rowSize){
447                 if (comparison_type == Py_NE){
448                         return EXPP_incr_ret(Py_True); 
449                 }else{
450                         return EXPP_incr_ret(Py_False);
451                 }
452         }
453
454         switch (comparison_type){
455                 case Py_EQ:
456                         /*contigPtr is basically a really long vector*/
457                         result = EXPP_VectorsAreEqual(matA->contigPtr, matB->contigPtr,
458                                 (matA->rowSize * matA->colSize), 1);
459                         break;
460                 case Py_NE:
461                         result = EXPP_VectorsAreEqual(matA->contigPtr, matB->contigPtr,
462                                 (matA->rowSize * matA->colSize), 1);
463                         if (result == 0){
464                                 result = 1;
465                         }else{
466                                 result = 0;
467                         }
468                         break;
469                 default:
470                         printf("The result of the comparison could not be evaluated");
471                         break;
472         }
473         if (result == 1){
474                 return EXPP_incr_ret(Py_True);
475         }else{
476                 return EXPP_incr_ret(Py_False);
477         }
478 }
479 /*------------------------tp_doc*/
480 static char MatrixObject_doc[] = "This is a wrapper for matrix objects.";
481 /*---------------------SEQUENCE PROTOCOLS------------------------
482   ----------------------------len(object)------------------------
483   sequence length*/
484 static int Matrix_len(MatrixObject * self)
485 {
486         return (self->rowSize);
487 }
488 /*----------------------------object[]---------------------------
489   sequence accessor (get)
490   the wrapped vector gives direct access to the matrix data*/
491 static PyObject *Matrix_item(MatrixObject * self, int i)
492 {
493         if(i < 0 || i >= self->rowSize)
494                 return EXPP_ReturnPyObjError(PyExc_IndexError,
495                 "matrix[attribute]: array index out of range\n");
496
497         return newVectorObject(self->matrix[i], self->colSize, Py_WRAP);
498 }
499 /*----------------------------object[]-------------------------
500   sequence accessor (set)*/
501 static int Matrix_ass_item(MatrixObject * self, int i, PyObject * ob)
502 {
503         int y, x, size = 0;
504         float vec[4];
505         PyObject *m, *f;
506
507         if(i >= self->rowSize || i < 0){
508                 return EXPP_ReturnIntError(PyExc_TypeError,
509                         "matrix[attribute] = x: bad row\n");
510         }
511
512         if(PySequence_Check(ob)){
513                 size = PySequence_Length(ob);
514                 if(size != self->colSize){
515                         return EXPP_ReturnIntError(PyExc_TypeError,
516                                 "matrix[attribute] = x: bad sequence size\n");
517                 }
518                 for (x = 0; x < size; x++) {
519                         m = PySequence_GetItem(ob, x);
520                         if (m == NULL) { /*Failed to read sequence*/
521                                 return EXPP_ReturnIntError(PyExc_RuntimeError, 
522                                         "matrix[attribute] = x: unable to read sequence\n");
523                         }
524
525                         f = PyNumber_Float(m);
526                         if(f == NULL) { /*parsed item not a number*/
527                                 Py_DECREF(m);
528                                 return EXPP_ReturnIntError(PyExc_TypeError, 
529                                         "matrix[attribute] = x: sequence argument not a number\n");
530                         }
531
532                         vec[x] = (float)PyFloat_AS_DOUBLE(f);
533                         EXPP_decr2(m, f);
534                 }
535                 /*parsed well - now set in matrix*/
536                 for(y = 0; y < size; y++){
537                         self->matrix[i][y] = vec[y];
538                 }
539                 return 0;
540         }else{
541                 return EXPP_ReturnIntError(PyExc_TypeError,
542                         "matrix[attribute] = x: expects a sequence of column size\n");
543         }
544 }
545 /*----------------------------object[z:y]------------------------
546   sequence slice (get)*/
547 static PyObject *Matrix_slice(MatrixObject * self, int begin, int end)
548 {
549
550         PyObject *list = NULL;
551         int count;
552
553         CLAMP(begin, 0, self->rowSize);
554         CLAMP(end, 0, self->rowSize);
555         begin = MIN2(begin,end);
556
557         list = PyList_New(end - begin);
558         for(count = begin; count < end; count++) {
559                 PyList_SetItem(list, count - begin,
560                                 newVectorObject(self->matrix[count], self->colSize, Py_WRAP));
561         }
562
563         return list;
564 }
565 /*----------------------------object[z:y]------------------------
566   sequence slice (set)*/
567 static int Matrix_ass_slice(MatrixObject * self, int begin, int end,
568                              PyObject * seq)
569 {
570         int i, x, y, size, sub_size = 0;
571         float mat[16];
572         PyObject *subseq;
573         PyObject *m, *f;
574
575         CLAMP(begin, 0, self->rowSize);
576         CLAMP(end, 0, self->rowSize);
577         begin = MIN2(begin,end);
578
579         if(PySequence_Check(seq)){
580                 size = PySequence_Length(seq);
581                 if(size != (end - begin)){
582                         return EXPP_ReturnIntError(PyExc_TypeError,
583                                 "matrix[begin:end] = []: size mismatch in slice assignment\n");
584                 }
585                 /*parse sub items*/
586                 for (i = 0; i < size; i++) {
587                         /*parse each sub sequence*/
588                         subseq = PySequence_GetItem(seq, i);
589                         if (subseq == NULL) { /*Failed to read sequence*/
590                                 return EXPP_ReturnIntError(PyExc_RuntimeError, 
591                                         "matrix[begin:end] = []: unable to read sequence\n");
592                         }
593
594                         if(PySequence_Check(subseq)){
595                                 /*subsequence is also a sequence*/
596                                 sub_size = PySequence_Length(subseq);
597                                 if(sub_size != self->colSize){
598                                         Py_DECREF(subseq);
599                                         return EXPP_ReturnIntError(PyExc_TypeError,
600                                                 "matrix[begin:end] = []: size mismatch in slice assignment\n");
601                                 }
602                                 for (y = 0; y < sub_size; y++) {
603                                         m = PySequence_GetItem(subseq, y);
604                                         if (m == NULL) { /*Failed to read sequence*/
605                                                 Py_DECREF(subseq);
606                                                 return EXPP_ReturnIntError(PyExc_RuntimeError, 
607                                                         "matrix[begin:end] = []: unable to read sequence\n");
608                                         }
609
610                                         f = PyNumber_Float(m);
611                                         if(f == NULL) { /*parsed item not a number*/
612                                                 EXPP_decr2(m, subseq);
613                                                 return EXPP_ReturnIntError(PyExc_TypeError, 
614                                                         "matrix[begin:end] = []: sequence argument not a number\n");
615                                         }
616
617                                         mat[(i * self->colSize) + y] = (float)PyFloat_AS_DOUBLE(f);
618                                         EXPP_decr2(f, m);
619                                 }
620                         }else{
621                                 Py_DECREF(subseq);
622                                 return EXPP_ReturnIntError(PyExc_TypeError,
623                                         "matrix[begin:end] = []: illegal argument type for built-in operation\n");
624                         }
625                         Py_DECREF(subseq);
626                 }
627                 /*parsed well - now set in matrix*/
628                 for(x = 0; x < (size * sub_size); x++){
629                         self->matrix[begin + (int)floor(x / self->colSize)][x % self->colSize] = mat[x];
630                 }
631                 return 0;
632         }else{
633                 return EXPP_ReturnIntError(PyExc_TypeError,
634                         "matrix[begin:end] = []: illegal argument type for built-in operation\n");
635         }
636 }
637 /*------------------------NUMERIC PROTOCOLS----------------------
638   ------------------------obj + obj------------------------------*/
639 static PyObject *Matrix_add(PyObject * m1, PyObject * m2)
640 {
641         int x, y;
642         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
643                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
644         MatrixObject *mat1 = NULL, *mat2 = NULL;
645
646         mat1 = (MatrixObject*)m1;
647         mat2 = (MatrixObject*)m2;
648
649         if(mat1->coerced_object || mat2->coerced_object){
650                 return EXPP_ReturnPyObjError(PyExc_AttributeError,
651                         "Matrix addition: arguments not valid for this operation....\n");
652         }
653         if(mat1->rowSize != mat2->rowSize || mat1->colSize != mat2->colSize){
654                 return EXPP_ReturnPyObjError(PyExc_AttributeError,
655                         "Matrix addition: matrices must have the same dimensions for this operation\n");
656         }
657
658         for(x = 0; x < mat1->rowSize; x++) {
659                 for(y = 0; y < mat1->colSize; y++) {
660                         mat[((x * mat1->colSize) + y)] = mat1->matrix[x][y] + mat2->matrix[x][y];
661                 }
662         }
663
664         return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW);
665 }
666 /*------------------------obj - obj------------------------------
667   subtraction*/
668 static PyObject *Matrix_sub(PyObject * m1, PyObject * m2)
669 {
670         int x, y;
671         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
672                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
673         MatrixObject *mat1 = NULL, *mat2 = NULL;
674
675         mat1 = (MatrixObject*)m1;
676         mat2 = (MatrixObject*)m2;
677
678         if(mat1->coerced_object || mat2->coerced_object){
679                 return EXPP_ReturnPyObjError(PyExc_AttributeError,
680                         "Matrix addition: arguments not valid for this operation....\n");
681         }
682         if(mat1->rowSize != mat2->rowSize || mat1->colSize != mat2->colSize){
683                 return EXPP_ReturnPyObjError(PyExc_AttributeError,
684                         "Matrix addition: matrices must have the same dimensions for this operation\n");
685         }
686
687         for(x = 0; x < mat1->rowSize; x++) {
688                 for(y = 0; y < mat1->colSize; y++) {
689                         mat[((x * mat1->colSize) + y)] = mat1->matrix[x][y] - mat2->matrix[x][y];
690                 }
691         }
692
693         return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW);
694 }
695 /*------------------------obj * obj------------------------------
696   mulplication*/
697 static PyObject *Matrix_mul(PyObject * m1, PyObject * m2)
698 {
699         int x, y, z;
700         float scalar;
701         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
702                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
703         double dot = 0.0f;
704         MatrixObject *mat1 = NULL, *mat2 = NULL;
705         PyObject *f = NULL;
706         PointObject *pt = NULL;
707
708         mat1 = (MatrixObject*)m1;
709         mat2 = (MatrixObject*)m2;
710
711         if(mat1->coerced_object){
712                 if (PyFloat_Check(mat1->coerced_object) || 
713                         PyInt_Check(mat1->coerced_object)){     /*FLOAT/INT * MATRIX*/
714                         f = PyNumber_Float(mat1->coerced_object);
715                         if(f == NULL) { /*parsed item not a number*/
716                                 return EXPP_ReturnPyObjError(PyExc_TypeError, 
717                                         "Matrix multiplication: arguments not acceptable for this operation\n");
718                         }
719
720                         scalar = (float)PyFloat_AS_DOUBLE(f);
721                         Py_DECREF(f);
722                         for(x = 0; x < mat2->rowSize; x++) {
723                                 for(y = 0; y < mat2->colSize; y++) {
724                                         mat[((x * mat2->colSize) + y)] = scalar * mat2->matrix[x][y];
725                                 }
726                         }
727                         return newMatrixObject(mat, mat2->rowSize, mat2->colSize, Py_NEW);
728                 }
729         }else{
730                 if(mat2->coerced_object){
731                         /* MATRIX * VECTOR   operation is now being done by vector */
732                         /*if(VectorObject_Check(mat2->coerced_object)){ 
733                                 vec = (VectorObject*)mat2->coerced_object;
734                                 return column_vector_multiplication(mat1, vec);
735                         }else */
736                         if(PointObject_Check(mat2->coerced_object)){ /*MATRIX * POINT*/
737                                 pt = (PointObject*)mat2->coerced_object;
738                                 return column_point_multiplication(mat1, pt);
739                         }else if (PyFloat_Check(mat2->coerced_object) || 
740                                 PyInt_Check(mat2->coerced_object)){     /*MATRIX * FLOAT/INT*/
741                                 f = PyNumber_Float(mat2->coerced_object);
742                                 if(f == NULL) { /*parsed item not a number*/
743                                         return EXPP_ReturnPyObjError(PyExc_TypeError, 
744                                                 "Matrix multiplication: arguments not acceptable for this operation\n");
745                                 }
746
747                                 scalar = (float)PyFloat_AS_DOUBLE(f);
748                                 Py_DECREF(f);
749                                 for(x = 0; x < mat1->rowSize; x++) {
750                                         for(y = 0; y < mat1->colSize; y++) {
751                                                 mat[((x * mat1->colSize) + y)] = scalar * mat1->matrix[x][y];
752                                         }
753                                 }
754                                 return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW);
755                         }
756                 }else{  /*MATRIX * MATRIX*/
757                         if(mat1->colSize != mat2->rowSize){
758                                 return EXPP_ReturnPyObjError(PyExc_AttributeError,
759                                         "Matrix multiplication: matrix A rowsize must equal matrix B colsize\n");
760                         }
761                         for(x = 0; x < mat1->rowSize; x++) {
762                                 for(y = 0; y < mat2->colSize; y++) {
763                                         for(z = 0; z < mat1->colSize; z++) {
764                                                 dot += (mat1->matrix[x][z] * mat2->matrix[z][y]);
765                                         }
766                                         mat[((x * mat1->rowSize) + y)] = (float)dot;
767                                         dot = 0.0f;
768                                 }
769                         }
770                         return newMatrixObject(mat, mat1->rowSize, mat2->colSize, Py_NEW);
771                 }
772         }
773
774         return EXPP_ReturnPyObjError(PyExc_TypeError, 
775                 "Matrix multiplication: arguments not acceptable for this operation\n");
776 }
777 PyObject* Matrix_inv(MatrixObject *self)
778 {
779         return Matrix_Invert(self);
780 }
781 /*------------------------coerce(obj, obj)-----------------------
782   coercion of unknown types to type MatrixObject for numeric protocols.
783
784   Coercion() is called whenever a math operation has 2 operands that
785  it doesn't understand how to evaluate. 2+Matrix for example. We want to 
786  evaluate some of these operations like: (vector * 2), however, for math
787  to proceed, the unknown operand must be cast to a type that python math will
788  understand. (e.g. in the case above case, 2 must be cast to a vector and 
789  then call vector.multiply(vector, scalar_cast_as_vector)*/
790 static int Matrix_coerce(PyObject ** m1, PyObject ** m2)
791 {
792         if(VectorObject_Check(*m2) || PyFloat_Check(*m2) || PyInt_Check(*m2) ||
793                         PointObject_Check(*m2)) {
794                 PyObject *coerced = EXPP_incr_ret(*m2);
795                 *m2 = newMatrixObject(NULL,3,3,Py_NEW);
796                 ((MatrixObject*)*m2)->coerced_object = coerced;
797                 Py_INCREF (*m1);
798                 return 0;
799         }
800
801         return EXPP_ReturnIntError(PyExc_TypeError, 
802                 "matrix.coerce(): unknown operand - can't coerce for numeric protocols");
803 }
804 /*-----------------PROTOCOL DECLARATIONS--------------------------*/
805 static PySequenceMethods Matrix_SeqMethods = {
806         (inquiry) Matrix_len,                                   /* sq_length */
807         (binaryfunc) 0,                                                 /* sq_concat */
808         (intargfunc) 0,                                                 /* sq_repeat */
809         (intargfunc) Matrix_item,                               /* sq_item */
810         (intintargfunc) Matrix_slice,                   /* sq_slice */
811         (intobjargproc) Matrix_ass_item,                /* sq_ass_item */
812         (intintobjargproc) Matrix_ass_slice,    /* sq_ass_slice */
813 };
814 static PyNumberMethods Matrix_NumMethods = {
815         (binaryfunc) Matrix_add,                                /* __add__ */
816         (binaryfunc) Matrix_sub,                                /* __sub__ */
817         (binaryfunc) Matrix_mul,                                /* __mul__ */
818         (binaryfunc) 0,                                                 /* __div__ */
819         (binaryfunc) 0,                                                 /* __mod__ */
820         (binaryfunc) 0,                                                 /* __divmod__ */
821         (ternaryfunc) 0,                                                /* __pow__ */
822         (unaryfunc) 0,                                                  /* __neg__ */
823         (unaryfunc) 0,                                                  /* __pos__ */
824         (unaryfunc) 0,                                                  /* __abs__ */
825         (inquiry) 0,                                                    /* __nonzero__ */
826         (unaryfunc) Matrix_inv,                                 /* __invert__ */
827         (binaryfunc) 0,                                                 /* __lshift__ */
828         (binaryfunc) 0,                                                 /* __rshift__ */
829         (binaryfunc) 0,                                                 /* __and__ */
830         (binaryfunc) 0,                                                 /* __xor__ */
831         (binaryfunc) 0,                                                 /* __or__ */
832         (coercion) Matrix_coerce,                               /* __coerce__ */
833         (unaryfunc) 0,                                                  /* __int__ */
834         (unaryfunc) 0,                                                  /* __long__ */
835         (unaryfunc) 0,                                                  /* __float__ */
836         (unaryfunc) 0,                                                  /* __oct__ */
837         (unaryfunc) 0,                                                  /* __hex__ */
838 };
839 /*------------------PY_OBECT DEFINITION--------------------------*/
840 PyTypeObject matrix_Type = {
841         PyObject_HEAD_INIT(NULL)                /*tp_head*/
842         0,                                                              /*tp_internal*/
843         "matrix",                                               /*tp_name*/
844         sizeof(MatrixObject),                   /*tp_basicsize*/
845         0,                                                              /*tp_itemsize*/
846         (destructor)Matrix_dealloc,             /*tp_dealloc*/
847         0,                                                              /*tp_print*/
848         (getattrfunc)Matrix_getattr,    /*tp_getattr*/
849         (setattrfunc) Matrix_setattr,   /*tp_setattr*/
850         0,                                                              /*tp_compare*/
851         (reprfunc) Matrix_repr,                 /*tp_repr*/
852         &Matrix_NumMethods,                             /*tp_as_number*/
853         &Matrix_SeqMethods,                             /*tp_as_sequence*/
854         0,                                                              /*tp_as_mapping*/
855         0,                                                              /*tp_hash*/
856         0,                                                              /*tp_call*/
857         0,                                                              /*tp_str*/
858         0,                                                              /*tp_getattro*/
859         0,                                                              /*tp_setattro*/
860         0,                                                              /*tp_as_buffer*/
861         Py_TPFLAGS_DEFAULT,                             /*tp_flags*/
862         MatrixObject_doc,                               /*tp_doc*/
863         0,                                                              /*tp_traverse*/
864         0,                                                              /*tp_clear*/
865         (richcmpfunc)Matrix_richcmpr,   /*tp_richcompare*/
866         0,                                                              /*tp_weaklistoffset*/
867         0,                                                              /*tp_iter*/
868         0,                                                              /*tp_iternext*/
869         0,                                                              /*tp_methods*/
870         0,                                                              /*tp_members*/
871         0,                                                              /*tp_getset*/
872         0,                                                              /*tp_base*/
873         0,                                                              /*tp_dict*/
874         0,                                                              /*tp_descr_get*/
875         0,                                                              /*tp_descr_set*/
876         0,                                                              /*tp_dictoffset*/
877         0,                                                              /*tp_init*/
878         0,                                                              /*tp_alloc*/
879         0,                                                              /*tp_new*/
880         0,                                                              /*tp_free*/
881         0,                                                              /*tp_is_gc*/
882         0,                                                              /*tp_bases*/
883         0,                                                              /*tp_mro*/
884         0,                                                              /*tp_cache*/
885         0,                                                              /*tp_subclasses*/
886         0,                                                              /*tp_weaklist*/
887         0                                                               /*tp_del*/
888 };
889
890 /*------------------------newMatrixObject (internal)-------------
891 creates a new matrix object
892 self->matrix     self->contiguous_ptr (reference to data.xxx)
893        [0]------------->[0]
894                         [1]
895                         [2]
896        [1]------------->[3]
897                         [4]
898                         [5]
899                      ....
900 self->matrix[1][1] = self->contiguous_ptr[4] = self->data.xxx_data[4]*/
901
902 /*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
903  (i.e. it was allocated elsewhere by MEM_mallocN())
904   pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
905  (i.e. it must be created here with PyMEM_malloc())*/
906 PyObject *newMatrixObject(float *mat, int rowSize, int colSize, int type)
907 {
908         MatrixObject *self;
909         int x, row, col;
910
911         /*matrix objects can be any 2-4row x 2-4col matrix*/
912         if(rowSize < 2 || rowSize > 4 || colSize < 2 || colSize > 4){
913                 return EXPP_ReturnPyObjError(PyExc_RuntimeError,
914                         "matrix(): row and column sizes must be between 2 and 4\n");
915         }
916
917         self = PyObject_NEW(MatrixObject, &matrix_Type);
918         self->data.blend_data = NULL;
919         self->data.py_data = NULL;
920         self->rowSize = rowSize;
921         self->colSize = colSize;
922         self->coerced_object = NULL;
923
924         if(type == Py_WRAP){
925                 self->data.blend_data = mat;
926                 self->contigPtr = self->data.blend_data;
927                 /*create pointer array*/
928                 self->matrix = PyMem_Malloc(rowSize * sizeof(float *));
929                 if(self->matrix == NULL) { /*allocation failure*/
930                         return EXPP_ReturnPyObjError( PyExc_MemoryError,
931                                 "matrix(): problem allocating pointer space\n");
932                 }
933                 /*pointer array points to contigous memory*/
934                 for(x = 0; x < rowSize; x++) {
935                         self->matrix[x] = self->contigPtr + (x * colSize);
936                 }
937                 self->wrapped = Py_WRAP;
938         }else if (type == Py_NEW){
939                 self->data.py_data = PyMem_Malloc(rowSize * colSize * sizeof(float));
940                 if(self->data.py_data == NULL) { /*allocation failure*/
941                         return EXPP_ReturnPyObjError( PyExc_MemoryError,
942                                 "matrix(): problem allocating pointer space\n");
943                 }
944                 self->contigPtr = self->data.py_data;
945                 /*create pointer array*/
946                 self->matrix = PyMem_Malloc(rowSize * sizeof(float *));
947                 if(self->matrix == NULL) { /*allocation failure*/
948                         PyMem_Free(self->data.py_data);
949                         return EXPP_ReturnPyObjError( PyExc_MemoryError,
950                                 "matrix(): problem allocating pointer space\n");
951                 }
952                 /*pointer array points to contigous memory*/
953                 for(x = 0; x < rowSize; x++) {
954                         self->matrix[x] = self->contigPtr + (x * colSize);
955                 }
956                 /*parse*/
957                 if(mat) {       /*if a float array passed*/
958                         for(row = 0; row < rowSize; row++) {
959                                 for(col = 0; col < colSize; col++) {
960                                         self->matrix[row][col] = mat[(row * colSize) + col];
961                                 }
962                         }
963                 } else if (rowSize == colSize ) { /*or if no arguments are passed return identity matrix for square matrices */
964                         Matrix_Identity(self);
965                         Py_DECREF(self);
966                 }
967                 self->wrapped = Py_NEW;
968         }else{ /*bad type*/
969                 return NULL;
970         }
971         return (PyObject *) self;
972 }