cogl/matrix: Multiply using graphene matrices

At this point, we are still only changing CoglMatrix APIs internally, and
it should still produce the same output as before.

To achieve this, using graphens matrix implementation, we need to exploit
some knowledge about conventions used in Cogl and graphene respectively.

In Cogl, transformation matrices are equivalent to those of affine
transformation matrices. The convention used by graphene, however, is to
operate on matrices that are transposed compared to their affine
counterparts.

So for example, let's say we want to multiply the affine matrices A and B,
to get C.

  A × B = C

The first step is to convert A and B to graphene matrices. We do this by
importing the floating point array, importing it directly using graphene.

Cogl exports its matrix to a column major floating point array. When we
import this in graphene, being row major, we end up with the same matrix,
only transposed.

Cogl       Graphene

  A   <===>   Aᵀ
  B   <===>   Bᵀ

We then multiply these imported matrices in reverse

  Bᵀ × Aᵀ

which in turn, due to ABᵀ = BᵀAᵀ, gives us

  Bᵀ × Aᵀ = (A × B)ᵀ

Our original goal was to find C, thus we know that

  A × B = C

That means we can shuffle things around a bit.

  A × B = C

  Bᵀ × Aᵀ = (A × B)ᵀ

  Bᵀ × Aᵀ = Cᵀ

With the same conversion as done when going from Cogl to graphene, only
the other way around, we still end up effectively transposing the matrix
during the conversion.

Graphene      Cogl

   Cᵀ  <===>   C

Thus when converting Cᵀ to Cogl, we in fact end up with C.

(Explanation authored by Jonas Ådahl)

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1439
This commit is contained in:
Georges Basile Stavracas Neto 2020-09-10 10:34:15 -03:00
parent 2b9ce99ff2
commit 02a30f2a22

View File

@ -326,32 +326,22 @@ matrix_multiply_array_with_flags (CoglMatrix *result,
matrix_multiply4x4 ((float *)result, (float *)result, array); matrix_multiply4x4 ((float *)result, (float *)result, array);
} }
/* Joins both flags and marks the type and inverse as dirty. Calls
* matrix_multiply3x4() if both matrices are 3D, or matrix_multiply4x4()
* otherwise.
*/
static void
_cogl_matrix_multiply (CoglMatrix *result,
const CoglMatrix *a,
const CoglMatrix *b)
{
result->flags = (a->flags |
b->flags |
MAT_DIRTY_TYPE |
MAT_DIRTY_INVERSE);
if (TEST_MAT_FLAGS(result, MAT_FLAGS_3D))
matrix_multiply3x4 ((float *)result, (float *)a, (float *)b);
else
matrix_multiply4x4 ((float *)result, (float *)a, (float *)b);
}
void void
cogl_matrix_multiply (CoglMatrix *result, cogl_matrix_multiply (CoglMatrix *result,
const CoglMatrix *a, const CoglMatrix *a,
const CoglMatrix *b) const CoglMatrix *b)
{ {
_cogl_matrix_multiply (result, a, b); graphene_matrix_t res;
graphene_matrix_t ma;
graphene_matrix_t mb;
cogl_matrix_to_graphene_matrix (a, &ma);
cogl_matrix_to_graphene_matrix (b, &mb);
graphene_matrix_multiply (&mb, &ma, &res);
graphene_matrix_to_cogl_matrix (&res, result);
result->flags = a->flags | b->flags | MAT_DIRTY_TYPE | MAT_DIRTY_INVERSE;
_COGL_MATRIX_DEBUG_PRINT (result); _COGL_MATRIX_DEBUG_PRINT (result);
} }