From c33e2f731c2eab86bbad7b6a028f8a90ea40a00c Mon Sep 17 00:00:00 2001
From: Erik Faye-Lund <erik.faye-lund@collabora.com>
Date: Thu, 5 Jan 2023 13:59:24 +0100
Subject: [PATCH] egl,util: factor out matrix-code from es2gears to util

This factors out some commonly useful matrix-code from es2gears so it
can be reused elsewhere.
---
 src/egl/opengles2/es2gears.c  | 187 +++-------------------------------
 src/egl/opengles2/meson.build |   4 +-
 src/util/matrix.c             | 125 +++++++++++++++++++++++
 src/util/matrix.h             |  78 ++++++++++++++
 src/util/meson.build          |   3 +-
 5 files changed, 219 insertions(+), 178 deletions(-)
 create mode 100644 src/util/matrix.c
 create mode 100644 src/util/matrix.h

diff --git a/src/egl/opengles2/es2gears.c b/src/egl/opengles2/es2gears.c
index db67f3a9a..158c3e76b 100644
--- a/src/egl/opengles2/es2gears.c
+++ b/src/egl/opengles2/es2gears.c
@@ -51,6 +51,7 @@
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 #include "eglut.h"
+#include "matrix.h"
 
 #define STRIPS_PER_TOOTH 7
 #define VERTICES_PER_TOOTH 46
@@ -276,170 +277,6 @@ create_gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
    return gear;
 }
 
-/** 
- * Multiplies two 4x4 matrices.
- * 
- * The result is stored in matrix m.
- * 
- * @param m the first matrix to multiply
- * @param n the second matrix to multiply
- */
-static void
-multiply(GLfloat *m, const GLfloat *n)
-{
-   GLfloat tmp[16];
-   const GLfloat *row, *column;
-   div_t d;
-   int i, j;
-
-   for (i = 0; i < 16; i++) {
-      tmp[i] = 0;
-      d = div(i, 4);
-      row = n + d.quot * 4;
-      column = m + d.rem;
-      for (j = 0; j < 4; j++)
-         tmp[i] += row[j] * column[j * 4];
-   }
-   memcpy(m, &tmp, sizeof tmp);
-}
-
-/** 
- * Rotates a 4x4 matrix.
- * 
- * @param[in,out] m the matrix to rotate
- * @param angle the angle to rotate
- * @param x the x component of the direction to rotate to
- * @param y the y component of the direction to rotate to
- * @param z the z component of the direction to rotate to
- */
-static void
-rotate(GLfloat *m, GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
-{
-   double s, c;
-
-   sincos(angle, &s, &c);
-   GLfloat r[16] = {
-      x * x * (1 - c) + c,     y * x * (1 - c) + z * s, x * z * (1 - c) - y * s, 0,
-      x * y * (1 - c) - z * s, y * y * (1 - c) + c,     y * z * (1 - c) + x * s, 0, 
-      x * z * (1 - c) + y * s, y * z * (1 - c) - x * s, z * z * (1 - c) + c,     0,
-      0, 0, 0, 1
-   };
-
-   multiply(m, r);
-}
-
-
-/** 
- * Translates a 4x4 matrix.
- * 
- * @param[in,out] m the matrix to translate
- * @param x the x component of the direction to translate to
- * @param y the y component of the direction to translate to
- * @param z the z component of the direction to translate to
- */
-static void
-translate(GLfloat *m, GLfloat x, GLfloat y, GLfloat z)
-{
-   GLfloat t[16] = { 1, 0, 0, 0,  0, 1, 0, 0,  0, 0, 1, 0,  x, y, z, 1 };
-
-   multiply(m, t);
-}
-
-/** 
- * Creates an identity 4x4 matrix.
- * 
- * @param m the matrix make an identity matrix
- */
-static void
-identity(GLfloat *m)
-{
-   GLfloat t[16] = {
-      1.0, 0.0, 0.0, 0.0,
-      0.0, 1.0, 0.0, 0.0,
-      0.0, 0.0, 1.0, 0.0,
-      0.0, 0.0, 0.0, 1.0,
-   };
-
-   memcpy(m, t, sizeof(t));
-}
-
-/** 
- * Transposes a 4x4 matrix.
- *
- * @param m the matrix to transpose
- */
-static void 
-transpose(GLfloat *m)
-{
-   GLfloat t[16] = {
-      m[0], m[4], m[8],  m[12],
-      m[1], m[5], m[9],  m[13],
-      m[2], m[6], m[10], m[14],
-      m[3], m[7], m[11], m[15]};
-
-   memcpy(m, t, sizeof(t));
-}
-
-/**
- * Inverts a 4x4 matrix.
- *
- * This function can currently handle only pure translation-rotation matrices.
- * Read http://www.gamedev.net/community/forums/topic.asp?topic_id=425118
- * for an explanation.
- */
-static void
-invert(GLfloat *m)
-{
-   GLfloat t[16];
-   identity(t);
-
-   // Extract and invert the translation part 't'. The inverse of a
-   // translation matrix can be calculated by negating the translation
-   // coordinates.
-   t[12] = -m[12]; t[13] = -m[13]; t[14] = -m[14];
-
-   // Invert the rotation part 'r'. The inverse of a rotation matrix is
-   // equal to its transpose.
-   m[12] = m[13] = m[14] = 0;
-   transpose(m);
-
-   // inv(m) = inv(r) * inv(t)
-   multiply(m, t);
-}
-
-/** 
- * Calculate a frustum projection transformation.
- * 
- * @param m the matrix to save the transformation in
- * @param l the left plane distance
- * @param r the right plane distance
- * @param b the bottom plane distance
- * @param t the top plane distance
- * @param n the near plane distance
- * @param f the far plane distance
- */
-static void
-frustum(GLfloat *m, GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f)
-{
-   GLfloat tmp[16];
-   identity(tmp);
-
-   GLfloat deltaX = r - l;
-   GLfloat deltaY = t - b;
-   GLfloat deltaZ = f - n;
-
-   tmp[0] = (2 * n) / deltaX;
-   tmp[5] = (2 * n) / deltaY;
-   tmp[8] = (r + l) / deltaX;
-   tmp[9] = (t + b) / deltaY;
-   tmp[10] = -(f + n) / deltaZ;
-   tmp[11] = -1;
-   tmp[14] = -(2 * f * n) / deltaZ;
-   tmp[15] = 0;
-
-   memcpy(m, tmp, sizeof(tmp));
-}
-
 /**
  * Draws a gear.
  *
@@ -460,12 +297,12 @@ draw_gear(struct gear *gear, GLfloat *transform,
 
    /* Translate and rotate the gear */
    memcpy(model_view, transform, sizeof (model_view));
-   translate(model_view, x, y, 0);
-   rotate(model_view, 2 * M_PI * angle / 360.0, 0, 0, 1);
+   mat4_translate(model_view, x, y, 0);
+   mat4_rotate(model_view, 2 * M_PI * angle / 360.0, 0, 0, 1);
 
    /* Create and set the ModelViewProjectionMatrix */
    memcpy(model_view_projection, ProjectionMatrix, sizeof(model_view_projection));
-   multiply(model_view_projection, model_view);
+   mat4_multiply(model_view_projection, model_view);
 
    glUniformMatrix4fv(ModelViewProjectionMatrix_location, 1, GL_FALSE,
                       model_view_projection);
@@ -475,8 +312,8 @@ draw_gear(struct gear *gear, GLfloat *transform,
     * ModelView matrix.
     */
    memcpy(normal_matrix, model_view, sizeof (normal_matrix));
-   invert(normal_matrix);
-   transpose(normal_matrix);
+   mat4_invert(normal_matrix);
+   mat4_transpose(normal_matrix);
    glUniformMatrix4fv(NormalMatrix_location, 1, GL_FALSE, normal_matrix);
 
    /* Set the gear color */
@@ -513,16 +350,16 @@ gears_draw(void)
    const static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
    const static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
    GLfloat transform[16];
-   identity(transform);
+   mat4_identity(transform);
 
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
    /* Translate and rotate the view */
-   translate(transform, 0, 0, -40);
-   rotate(transform, 2 * M_PI * view_rot[0] / 360.0, 1, 0, 0);
-   rotate(transform, 2 * M_PI * view_rot[1] / 360.0, 0, 1, 0);
-   rotate(transform, 2 * M_PI * view_rot[2] / 360.0, 0, 0, 1);
+   mat4_translate(transform, 0, 0, -40);
+   mat4_rotate(transform, 2 * M_PI * view_rot[0] / 360.0, 1, 0, 0);
+   mat4_rotate(transform, 2 * M_PI * view_rot[1] / 360.0, 0, 1, 0);
+   mat4_rotate(transform, 2 * M_PI * view_rot[2] / 360.0, 0, 0, 1);
 
    /* Draw the gears */
    draw_gear(gear1, transform, -3.0, -2.0, angle, red);
@@ -541,7 +378,7 @@ gears_reshape(int width, int height)
 {
    /* Update the projection matrix */
    GLfloat h = (GLfloat)height / (GLfloat)width;
-   frustum(ProjectionMatrix, -1.0, 1.0, -h, h, 5.0, 60.0);
+   mat4_frustum(ProjectionMatrix, -1.0, 1.0, -h, h, 5.0, 60.0);
 
    /* Set the viewport */
    glViewport(0, 0, (GLint) width, (GLint) height);
diff --git a/src/egl/opengles2/meson.build b/src/egl/opengles2/meson.build
index 59f69ed72..9a4429885 100644
--- a/src/egl/opengles2/meson.build
+++ b/src/egl/opengles2/meson.build
@@ -6,7 +6,7 @@ executable(
 )
 executable(
   'es2gears_x11', files('es2gears.c'),
-  dependencies: [dep_gles2, idep_eglut_x11, dep_m],
+  dependencies: [dep_gles2, idep_eglut_x11, idep_util],
   install: true
 )
 executable(
@@ -16,6 +16,6 @@ executable(
 )
 executable(
   'es2gears_wayland', files('es2gears.c'),
-  dependencies: [dep_gles2, idep_eglut_wayland, dep_m],
+  dependencies: [dep_gles2, idep_eglut_wayland, idep_util],
   install: true
 )
diff --git a/src/util/matrix.c b/src/util/matrix.c
new file mode 100644
index 000000000..07ae149be
--- /dev/null
+++ b/src/util/matrix.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 1999-2001  Brian Paul
+ * Copyright (C) 2010  Kristian Høgsberg
+ * Copyright (C) 2010  Chia-I Wu
+ * Copyright (C) 2023  Collabora Ltd
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include "matrix.h"
+
+#define _GNU_SOURCE
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+
+void
+mat4_multiply(float *m, const float *n)
+{
+   float tmp[16];
+   const float *row, *column;
+   div_t d;
+   int i, j;
+
+   for (i = 0; i < 16; i++) {
+      tmp[i] = 0;
+      d = div(i, 4);
+      row = n + d.quot * 4;
+      column = m + d.rem;
+      for (j = 0; j < 4; j++)
+         tmp[i] += row[j] * column[j * 4];
+   }
+   memcpy(m, &tmp, sizeof tmp);
+}
+
+void
+mat4_rotate(float *m, float angle, float x, float y, float z)
+{
+   double s, c;
+
+   sincos(angle, &s, &c);
+   float r[16] = {
+      x * x * (1 - c) + c,     y * x * (1 - c) + z * s, x * z * (1 - c) - y * s, 0,
+      x * y * (1 - c) - z * s, y * y * (1 - c) + c,     y * z * (1 - c) + x * s, 0,
+      x * z * (1 - c) + y * s, y * z * (1 - c) - x * s, z * z * (1 - c) + c,     0,
+      0, 0, 0, 1
+   };
+
+   mat4_multiply(m, r);
+}
+
+void
+mat4_translate(float *m, float x, float y, float z)
+{
+   float t[16] = { 1, 0, 0, 0,  0, 1, 0, 0,  0, 0, 1, 0,  x, y, z, 1 };
+
+   mat4_multiply(m, t);
+}
+
+void
+mat4_identity(float *m)
+{
+   float t[16] = {
+      1.0, 0.0, 0.0, 0.0,
+      0.0, 1.0, 0.0, 0.0,
+      0.0, 0.0, 1.0, 0.0,
+      0.0, 0.0, 0.0, 1.0,
+   };
+
+   memcpy(m, t, sizeof(t));
+}
+
+void
+mat4_transpose(float *m)
+{
+   float t[16] = {
+      m[0], m[4], m[8],  m[12],
+      m[1], m[5], m[9],  m[13],
+      m[2], m[6], m[10], m[14],
+      m[3], m[7], m[11], m[15]};
+
+   memcpy(m, t, sizeof(t));
+}
+
+void
+mat4_invert(float *m)
+{
+   float t[16];
+   mat4_identity(t);
+
+   // Extract and invert the translation part 't'. The inverse of a
+   // translation matrix can be calculated by negating the translation
+   // coordinates.
+   t[12] = -m[12]; t[13] = -m[13]; t[14] = -m[14];
+
+   // Invert the rotation part 'r'. The inverse of a rotation matrix is
+   // equal to its transpose.
+   m[12] = m[13] = m[14] = 0;
+   mat4_transpose(m);
+
+   // inv(m) = inv(r) * inv(t)
+   mat4_multiply(m, t);
+}
+
+void
+mat4_frustum(float *m, float l, float r, float b, float t, float n, float f)
+{
+   float tmp[16];
+   mat4_identity(tmp);
+
+   float deltaX = r - l;
+   float deltaY = t - b;
+   float deltaZ = f - n;
+
+   tmp[0] = (2 * n) / deltaX;
+   tmp[5] = (2 * n) / deltaY;
+   tmp[8] = (r + l) / deltaX;
+   tmp[9] = (t + b) / deltaY;
+   tmp[10] = -(f + n) / deltaZ;
+   tmp[11] = -1;
+   tmp[14] = -(2 * f * n) / deltaZ;
+   tmp[15] = 0;
+
+   memcpy(m, tmp, sizeof(tmp));
+}
diff --git a/src/util/matrix.h b/src/util/matrix.h
new file mode 100644
index 000000000..278f502be
--- /dev/null
+++ b/src/util/matrix.h
@@ -0,0 +1,78 @@
+#ifndef MATRIX_H
+#define MATRIX_H
+
+/**
+ * Multiplies two 4x4 matrices.
+ *
+ * The result is stored in matrix m.
+ *
+ * @param m the first matrix to multiply
+ * @param n the second matrix to multiply
+ */
+void
+mat4_multiply(float *m, const float *n);
+
+/**
+ * Rotates a 4x4 matrix.
+ *
+ * @param[in,out] m the matrix to rotate
+ * @param angle the angle to rotate
+ * @param x the x component of the direction to rotate to
+ * @param y the y component of the direction to rotate to
+ * @param z the z component of the direction to rotate to
+ */
+void
+mat4_rotate(float *m, float angle, float x, float y, float z);
+
+/**
+ * Translates a 4x4 matrix.
+ *
+ * @param[in,out] m the matrix to translate
+ * @param x the x component of the direction to translate to
+ * @param y the y component of the direction to translate to
+ * @param z the z component of the direction to translate to
+ */
+void
+mat4_translate(float *m, float x, float y, float z);
+
+/**
+ * Creates an identity 4x4 matrix.
+ *
+ * @param m the matrix make an identity matrix
+ */
+void
+mat4_identity(float *m);
+
+/**
+ * Transposes a 4x4 matrix.
+ *
+ * @param m the matrix to transpose
+ */
+void
+mat4_transpose(float *m);
+
+/**
+ * Inverts a 4x4 matrix.
+ *
+ * This function can currently handle only pure translation-rotation matrices.
+ * Read http://www.gamedev.net/community/forums/topic.asp?topic_id=425118
+ * for an explanation.
+ */
+void
+mat4_invert(float *m);
+
+/**
+ * Calculate a frustum projection transformation.
+ *
+ * @param m the matrix to save the transformation in
+ * @param l the left plane distance
+ * @param r the right plane distance
+ * @param b the bottom plane distance
+ * @param t the top plane distance
+ * @param n the near plane distance
+ * @param f the far plane distance
+ */
+void
+mat4_frustum(float *m, float l, float r, float b, float t, float n, float f);
+
+#endif /* MATRIX_H */
diff --git a/src/util/meson.build b/src/util/meson.build
index 959e21702..ddcd48346 100644
--- a/src/util/meson.build
+++ b/src/util/meson.build
@@ -24,9 +24,10 @@ files_libutil = files(
   'readtex.c',
   'showbuffer.c',
   'trackball.c',
+  'matrix.c',
 )
 
-_deps = [dep_glu]
+_deps = [dep_glu, dep_m]
 if dep_glut.found()
   files_libutil += files('shaderutil.c')
   _deps += dep_glut
-- 
GitLab