Merge branch 'master' into blender2.8
[blender.git] / source / blender / python / mathutils / mathutils_Matrix.c
index d4f9e5e80e2dca18b50d9e69d6a4cc400c6047c9..c033a990901befda3512fbc738824df6472d5868 100644 (file)
@@ -2321,7 +2321,7 @@ static PyObject *Matrix_sub(PyObject *m1, PyObject *m2)
        return Matrix_CreatePyObject(mat, mat1->num_col, mat1->num_row, Py_TYPE(mat1));
 }
 /*------------------------obj * obj------------------------------
- * multiplication */
+ * element-wise multiplication */
 static PyObject *matrix_mul_float(MatrixObject *mat, const float scalar)
 {
        float tmat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
@@ -2332,7 +2332,6 @@ static PyObject *matrix_mul_float(MatrixObject *mat, const float scalar)
 static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
 {
        float scalar;
-       int vec_size;
 
        MatrixObject *mat1 = NULL, *mat2 = NULL;
 
@@ -2348,9 +2347,118 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
        }
 
        if (mat1 && mat2) {
+#ifdef USE_MATHUTILS_ELEM_MUL
                /* MATRIX * MATRIX */
                float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
 
+               if ((mat1->num_row != mat2->num_row) || (mat1->num_col != mat2->num_col)) {
+                       PyErr_SetString(PyExc_ValueError,
+                                       "matrix1 * matrix2: matrix1 number of rows/columns "
+                                       "and the matrix2 number of rows/columns must be the same");
+                       return NULL;
+               }
+
+               mul_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->num_col * mat1->num_row);
+
+               return Matrix_CreatePyObject(mat, mat2->num_col, mat1->num_row, Py_TYPE(mat1));
+#endif
+       }
+       else if (mat2) {
+               /*FLOAT/INT * MATRIX */
+               if (((scalar = PyFloat_AsDouble(m1)) == -1.0f && PyErr_Occurred()) == 0) {
+                       return matrix_mul_float(mat2, scalar);
+               }
+       }
+       else if (mat1) {
+               /* MATRIX * FLOAT/INT */
+               if (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0) {
+                       return matrix_mul_float(mat1, scalar);
+               }
+       }
+
+       PyErr_Format(PyExc_TypeError,
+                    "Element-wise multiplication: "
+                    "not supported between '%.200s' and '%.200s' types",
+                    Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name);
+       return NULL;
+}
+/*------------------------obj *= obj------------------------------
+ * Inplace element-wise multiplication */
+static PyObject *Matrix_imul(PyObject *m1, PyObject *m2)
+{
+       float scalar;
+
+       MatrixObject *mat1 = NULL, *mat2 = NULL;
+
+       if (MatrixObject_Check(m1)) {
+               mat1 = (MatrixObject *)m1;
+               if (BaseMath_ReadCallback(mat1) == -1)
+                       return NULL;
+       }
+       if (MatrixObject_Check(m2)) {
+               mat2 = (MatrixObject *)m2;
+               if (BaseMath_ReadCallback(mat2) == -1)
+                       return NULL;
+       }
+
+       if (mat1 && mat2) {
+#ifdef USE_MATHUTILS_ELEM_MUL
+               /* MATRIX *= MATRIX */
+               if ((mat1->num_row != mat2->num_row) || (mat1->num_col != mat2->num_col)) {
+                       PyErr_SetString(PyExc_ValueError,
+                                       "matrix1 *= matrix2: matrix1 number of rows/columns "
+                                       "and the matrix2 number of rows/columns must be the same");
+                       return NULL;
+               }
+
+               mul_vn_vn(mat1->matrix, mat2->matrix, mat1->num_col * mat1->num_row);
+#else
+               PyErr_Format(PyExc_TypeError,
+                            "Inplace element-wise multiplication: "
+                            "not supported between '%.200s' and '%.200s' types",
+                            Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name);
+               return NULL;
+#endif
+       }
+       else if (mat1 && (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0)) {
+               /* MATRIX *= FLOAT/INT */
+               mul_vn_fl(mat1->matrix, mat1->num_row * mat1->num_col, scalar);
+       }
+       else {
+               PyErr_Format(PyExc_TypeError,
+                            "Inplace element-wise multiplication: "
+                            "not supported between '%.200s' and '%.200s' types",
+                            Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name);
+               return NULL;
+       }
+
+       (void)BaseMath_WriteCallback(mat1);
+       Py_INCREF(m1);
+       return m1;
+}
+/*------------------------obj @ obj------------------------------
+ * matrix multiplication */
+static PyObject *Matrix_matmul(PyObject *m1, PyObject *m2)
+{
+       int vec_size;
+
+       MatrixObject *mat1 = NULL, *mat2 = NULL;
+
+       if (MatrixObject_Check(m1)) {
+               mat1 = (MatrixObject *)m1;
+               if (BaseMath_ReadCallback(mat1) == -1)
+                       return NULL;
+       }
+       if (MatrixObject_Check(m2)) {
+               mat2 = (MatrixObject *)m2;
+               if (BaseMath_ReadCallback(mat2) == -1)
+                       return NULL;
+       }
+
+       if (mat1 && mat2) {
+               /* MATRIX @ MATRIX */
+               float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
+
                int col, row, item;
 
                if (mat1->num_col != mat2->num_row) {
@@ -2372,14 +2480,8 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
 
                return Matrix_CreatePyObject(mat, mat2->num_col, mat1->num_row, Py_TYPE(mat1));
        }
-       else if (mat2) {
-               /*FLOAT/INT * MATRIX */
-               if (((scalar = PyFloat_AsDouble(m1)) == -1.0f && PyErr_Occurred()) == 0) {
-                       return matrix_mul_float(mat2, scalar);
-               }
-       }
        else if (mat1) {
-               /* MATRIX * VECTOR */
+               /* MATRIX @ VECTOR */
                if (VectorObject_Check(m2)) {
                        VectorObject *vec2 = (VectorObject *)m2;
                        float tvec[MATRIX_MAX_DIM];
@@ -2398,13 +2500,6 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
 
                        return Vector_CreatePyObject(tvec, vec_size, Py_TYPE(m2));
                }
-               /*FLOAT/INT * MATRIX */
-               else if (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0) {
-                       return matrix_mul_float(mat1, scalar);
-               }
-       }
-       else {
-               BLI_assert(!"internal error");
        }
 
        PyErr_Format(PyExc_TypeError,
@@ -2413,6 +2508,62 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
                     Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name);
        return NULL;
 }
+/*------------------------obj @= obj------------------------------
+ * inplace matrix multiplication */
+static PyObject *Matrix_imatmul(PyObject *m1, PyObject *m2)
+{
+       MatrixObject *mat1 = NULL, *mat2 = NULL;
+
+       if (MatrixObject_Check(m1)) {
+               mat1 = (MatrixObject *)m1;
+               if (BaseMath_ReadCallback(mat1) == -1)
+                       return NULL;
+       }
+       if (MatrixObject_Check(m2)) {
+               mat2 = (MatrixObject *)m2;
+               if (BaseMath_ReadCallback(mat2) == -1)
+                       return NULL;
+       }
+
+       if (mat1 && mat2) {
+               /* MATRIX @= MATRIX */
+               float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
+               int col, row, item;
+
+               if (mat1->num_col != mat2->num_row) {
+                       PyErr_SetString(PyExc_ValueError,
+                                       "matrix1 * matrix2: matrix1 number of columns "
+                                       "and the matrix2 number of rows must be the same");
+                       return NULL;
+               }
+
+               for (col = 0; col < mat2->num_col; col++) {
+                       for (row = 0; row < mat1->num_row; row++) {
+                               double dot = 0.0f;
+                               for (item = 0; item < mat1->num_col; item++) {
+                                       dot += (double)(MATRIX_ITEM(mat1, row, item) * MATRIX_ITEM(mat2, item, col));
+                               }
+                               /* store in new matrix as overwriting original at this point will cause
+                                * subsequent iterations to use incorrect values */
+                               mat[(col * mat1->num_row) + row] = (float)dot;
+                       }
+               }
+
+               /* copy matrix back */
+               memcpy(mat1->matrix, mat, (mat1->num_row * mat1->num_col) * sizeof(float));
+       }
+       else {
+               PyErr_Format(PyExc_TypeError,
+                            "Inplace matrix multiplication: "
+                            "not supported between '%.200s' and '%.200s' types",
+                            Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name);
+               return NULL;
+       }
+
+       (void)BaseMath_WriteCallback(mat1);
+       Py_INCREF(m1);
+       return m1;
+}
 
 /*-----------------PROTOCOL DECLARATIONS--------------------------*/
 static PySequenceMethods Matrix_SeqMethods = {
@@ -2527,7 +2678,7 @@ static PyNumberMethods Matrix_NumMethods = {
        NULL,                   /*nb_float*/
        NULL,                   /* nb_inplace_add */
        NULL,                   /* nb_inplace_subtract */
-       NULL,                   /* nb_inplace_multiply */
+       (binaryfunc) Matrix_imul,  /* nb_inplace_multiply */
        NULL,                   /* nb_inplace_remainder */
        NULL,                   /* nb_inplace_power */
        NULL,                   /* nb_inplace_lshift */
@@ -2540,6 +2691,8 @@ static PyNumberMethods Matrix_NumMethods = {
        NULL,                   /* nb_inplace_floor_divide */
        NULL,                   /* nb_inplace_true_divide */
        NULL,                   /* nb_index */
+       (binaryfunc) Matrix_matmul,  /* nb_matrix_multiply */
+       (binaryfunc) Matrix_imatmul, /* nb_inplace_matrix_multiply */
 };
 
 PyDoc_STRVAR(Matrix_translation_doc,