From 420b60f203872d89e79be7f928733b35a5dee00d Mon Sep 17 00:00:00 2001
From: Simon Ser <contact@emersion.fr>
Date: Mon, 27 Jan 2025 17:54:55 +0100
Subject: [PATCH] util/matrix: add matrix_invert()

---
 include/util/matrix.h |  7 +++++++
 util/matrix.c         | 24 ++++++++++++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/include/util/matrix.h b/include/util/matrix.h
index 059a3bb1f..c45c99a06 100644
--- a/include/util/matrix.h
+++ b/include/util/matrix.h
@@ -39,4 +39,11 @@ void wlr_matrix_project_box(float mat[static 9], const struct wlr_box *box,
 void matrix_projection(float mat[static 9], int width, int height,
 	enum wl_output_transform transform);
 
+/**
+ * Compute the inverse of a matrix.
+ *
+ * The matrix needs to be inversible.
+ */
+void matrix_invert(float out[static 9], float m[static 9]);
+
 #endif
diff --git a/util/matrix.c b/util/matrix.c
index 86b434c64..640787c95 100644
--- a/util/matrix.c
+++ b/util/matrix.c
@@ -1,3 +1,4 @@
+#include <assert.h>
 #include <string.h>
 #include <wayland-server-protocol.h>
 #include <wlr/util/box.h>
@@ -139,3 +140,26 @@ void wlr_matrix_project_box(float mat[static 9], const struct wlr_box *box,
 
 	wlr_matrix_multiply(mat, projection, mat);
 }
+
+void matrix_invert(float out[static 9], float m[static 9]) {
+	float a = m[0], b = m[1], c = m[2], d = m[3], e = m[4], f = m[5], g = m[6], h = m[7], i = m[8];
+
+	// See: https://en.wikipedia.org/wiki/Determinant
+	float det = a*e*i + b*f*g + c*d*h - c*e*g - b*d*i - a*f*h;
+	assert(det != 0);
+	float inv_det = 1 / det;
+
+	// See: https://en.wikipedia.org/wiki/Invertible_matrix#Inversion_of_3_%C3%97_3_matrices
+	float result[] = {
+		inv_det * (e*i - f*h),
+		inv_det * -(b*i - c*h),
+		inv_det * (b*f - c*e),
+		inv_det * -(d*i - f*g),
+		inv_det * (a*i - c*g),
+		inv_det * -(a*f - c*d),
+		inv_det * (d*h - e*g),
+		inv_det * -(a*h - b*g),
+		inv_det * (a*e - b*d),
+	};
+	memcpy(out, result, sizeof(result));
+}