From 53c50f1667bae76b543196335ed77e1fb80b6b4d Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Tue, 10 Feb 2004 23:41:20 +0000 Subject: some useful matrix functions --- progs/util/matrix.c | 181 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 progs/util/matrix.c diff --git a/progs/util/matrix.c b/progs/util/matrix.c new file mode 100644 index 0000000000..8be2c3111f --- /dev/null +++ b/progs/util/matrix.c @@ -0,0 +1,181 @@ +/* + * matrix.c + * + * Some useful matrix functions. + * + * Brian Paul + * 10 Feb 2004 + */ + + + +#include +#include +#include + + +/** + * 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 -- cgit v1.2.3