some useful matrix functions
authorBrian Paul <brian.paul@tungstengraphics.com>
Tue, 10 Feb 2004 23:41:20 +0000 (23:41 +0000)
committerBrian Paul <brian.paul@tungstengraphics.com>
Tue, 10 Feb 2004 23:41:20 +0000 (23:41 +0000)
progs/util/matrix.c [new file with mode: 0644]

diff --git a/progs/util/matrix.c b/progs/util/matrix.c
new file mode 100644 (file)
index 0000000..8be2c31
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * matrix.c
+ *
+ * Some useful matrix functions.
+ *
+ * Brian Paul
+ * 10 Feb 2004
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+
+/**
+ * Pretty-print the given matrix.
+ */
+void
+PrintMatrix(const float p[16])
+{
+   printf("[ %6.3f %6.3f %6.3f %6.3f ]\n", p[0], p[4], p[8], p[12]);
+   printf("[ %6.3f %6.3f %6.3f %6.3f ]\n", p[1], p[5], p[9], p[13]);
+   printf("[ %6.3f %6.3f %6.3f %6.3f ]\n", p[2], p[6], p[10], p[14]);
+   printf("[ %6.3f %6.3f %6.3f %6.3f ]\n", p[3], p[7], p[11], p[15]);
+}
+
+
+/**
+ * Build a glFrustum matrix.
+ */
+void
+Frustum(float left, float right, float bottom, float top, float nearZ, float farZ, float *m)
+{
+   float x = (2.0F*nearZ) / (right-left);
+   float y = (2.0F*nearZ) / (top-bottom);
+   float a = (right+left) / (right-left);
+   float b = (top+bottom) / (top-bottom);
+   float c = -(farZ+nearZ) / ( farZ-nearZ);
+   float d = -(2.0F*farZ*nearZ) / (farZ-nearZ);
+
+#define M(row,col)  m[col*4+row]
+   M(0,0) = x;     M(0,1) = 0.0F;  M(0,2) = a;      M(0,3) = 0.0F;
+   M(1,0) = 0.0F;  M(1,1) = y;     M(1,2) = b;      M(1,3) = 0.0F;
+   M(2,0) = 0.0F;  M(2,1) = 0.0F;  M(2,2) = c;      M(2,3) = d;
+   M(3,0) = 0.0F;  M(3,1) = 0.0F;  M(3,2) = -1.0F;  M(3,3) = 0.0F;
+#undef M
+}
+
+
+/**
+ * Build a glOrtho marix.
+ */
+void
+Ortho(float left, float right, float bottom, float top, float nearZ, float farZ, float *m)
+{
+#define M(row,col)  m[col*4+row]
+   M(0,0) = 2.0F / (right-left);
+   M(0,1) = 0.0F;
+   M(0,2) = 0.0F;
+   M(0,3) = -(right+left) / (right-left);
+
+   M(1,0) = 0.0F;
+   M(1,1) = 2.0F / (top-bottom);
+   M(1,2) = 0.0F;
+   M(1,3) = -(top+bottom) / (top-bottom);
+
+   M(2,0) = 0.0F;
+   M(2,1) = 0.0F;
+   M(2,2) = -2.0F / (farZ-nearZ);
+   M(2,3) = -(farZ+nearZ) / (farZ-nearZ);
+
+   M(3,0) = 0.0F;
+   M(3,1) = 0.0F;
+   M(3,2) = 0.0F;
+   M(3,3) = 1.0F;
+#undef M
+}
+
+
+/**
+ * Decompose a projection matrix to determine original glFrustum or
+ * glOrtho parameters.
+ */
+void
+DecomposeProjection( const float *m,
+                     int *isPerspective,
+                     float *leftOut, float *rightOut,
+                     float *botOut, float *topOut,
+                     float *nearOut, float *farOut)
+{
+   if (m[15] == 0.0) {
+      /* perspective */
+      float p[16];
+      const float x = m[0];  /* 2N / (R-L) */
+      const float y = m[5];  /* 2N / (T-B) */
+      const float a = m[8];  /* (R+L) / (R-L) */
+      const float b = m[9];  /* (T+B) / (T-B) */
+      const float c = m[10]; /* -(F+N) / (F-N) */
+      const float d = m[14]; /* -2FN / (F-N) */
+
+      /* These equations found with simple algebra, knowing the arithmetic
+       * use to set up a typical perspective projection matrix in OpenGL.
+       */
+      const float nearZ = -d / (1.0 - c);
+      const float farZ = (c - 1.0) * nearZ / (c + 1.0);
+      const float left = nearZ * (a - 1.0) / x;
+      const float right = 2.0 * nearZ / x + left;
+      const float bottom = nearZ * (b - 1.0) / y;
+      const float top = 2.0 * nearZ / y + bottom;
+
+      *isPerspective = 1;
+      *leftOut = left;
+      *rightOut = right;
+      *botOut = bottom;
+      *topOut = top;
+      *nearOut = nearZ;
+      *farOut = farZ;
+   }
+   else {
+      /* orthographic */
+      const float x = m[0];  /*  2 / (R-L) */
+      const float y = m[5];  /*  2 / (T-B) */
+      const float z = m[10]; /* -2 / (F-N) */
+      const float a = m[12]; /* -(R+L) / (R-L) */
+      const float b = m[13]; /* -(T+B) / (T-B) */
+      const float c = m[14]; /* -(F+N) / (F-N) */
+      /* again, simple algebra */
+      const float right  = -(a - 1.0) / x;
+      const float left   = right - 2.0 / x;
+      const float top    = -(b - 1.0) / y;
+      const float bottom = top - 2.0 / y;
+      const float farZ   = (c - 1.0) / z;
+      const float nearZ  = farZ + 2.0 / z;
+
+      *isPerspective = 0;
+      *leftOut = left;
+      *rightOut = right;
+      *botOut = bottom;
+      *topOut = top;
+      *nearOut = nearZ;
+      *farOut = farZ;
+   }
+}
+
+
+#if 0
+/* test harness */
+int
+main(int argc, char *argv[])
+{
+   float m[16], p[16];
+   float l, r, b, t, n, f;
+   int persp;
+   int i;
+
+#if 0
+   l = -.9;
+   r = 1.2;
+   b = -0.5;
+   t = 1.4;
+   n = 30;
+   f = 84;
+   printf("  Frustum(%f, %f, %f, %f, %f, %f\n",l+1, r+1.2, b+.5, t+.3, n, f);
+   Frustum(l+1, r+1.2, b+.5, t+.3, n, f, p);
+   DecomposeProjection(p, &persp, &l, &r, &b, &t, &n, &f);
+   printf("glFrustum(%f, %f, %f, %f, %f, %f)\n",
+          l, r, b, t, n, f);
+   PrintMatrix(p);
+#else
+   printf("Ortho(-1, 1, -1, 1, 10, 84)\n");
+   Ortho(-1, 1, -1, 1, 10, 84, m);
+   PrintMatrix(m);
+   DecomposeProjection(m, &persp, &l, &r, &b, &t, &n, &f);
+   printf("Ortho(%f, %f, %f, %f, %f, %f) %d\n", l, r, b, t, n, f, persp);
+#endif
+
+   return 0;
+}
+#endif