blob: 8be2c3111f4e436e9dd04fc9b38e7985ebb1983f [file] [log] [blame]
/*
* 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