+
+/*
+ * CS5600 University of Utah
+ * Charles McGarvey
+ * mcgarvey@eng.utah.edu
+ */
+
+#ifndef __MAT_H__
+#define __MAT_H__
+
+#include "common.h"
+#include "vec.h"
+
+
+/*
+ * A simple matrix class with column-major storage and notation.
+ */
+struct mat
+{
+ vec_t v[4];
+};
+typedef struct mat mat_t;
+
+/*
+ * Initialize a matrix with individual components, row by row.
+ */
+__fast__
+void mat_init(mat_t* m, scal_t m11, scal_t m12, scal_t m13, scal_t m14,
+ scal_t m21, scal_t m22, scal_t m23, scal_t m24,
+ scal_t m31, scal_t m32, scal_t m33, scal_t m34,
+ scal_t m41, scal_t m42, scal_t m43, scal_t m44)
+{
+ m->v[0] = vec_new2(m11, m21, m31, m41);
+ m->v[1] = vec_new2(m12, m22, m32, m42);
+ m->v[2] = vec_new2(m13, m23, m33, m43);
+ m->v[3] = vec_new2(m14, m24, m34, m44);
+}
+
+
+/*
+ * Create a new matrix with individual components, row by row.
+ */
+__fast__
+mat_t mat_new(scal_t m11, scal_t m12, scal_t m13, scal_t m14,
+ scal_t m21, scal_t m22, scal_t m23, scal_t m24,
+ scal_t m31, scal_t m32, scal_t m33, scal_t m34,
+ scal_t m41, scal_t m42, scal_t m43, scal_t m44)
+{
+ mat_t m;
+ mat_init(&m, m11, m12, m13, m14,
+ m21, m22, m23, m24,
+ m31, m32, m33, m34,
+ m41, m42, m43, m44);
+ return m;
+}
+
+/*
+ * Create a new matrix with four column vectors.
+ */
+__fast__
+mat_t mat_new2(vec_t a, vec_t b, vec_t c, vec_t d)
+{
+ mat_t m;
+ m.v[0] = a;
+ m.v[1] = b;
+ m.v[2] = c;
+ m.v[3] = d;
+ return m;
+}
+
+#define MAT_IDENTITY mat_new(S(1.0), S(0.0), S(0.0), S(0.0), \
+ S(0.0), S(1.0), S(0.0), S(0.0), \
+ S(0.0), S(0.0), S(1.0), S(0.0), \
+ S(0.0), S(0.0), S(0.0), S(1.0))
+
+
+/*
+ * Create a new translate matrix.
+ */
+__fast__
+mat_t MAT_TRANSLATE(scal_t x, scal_t y, scal_t z)
+{
+ return mat_new(S(1.0), S(0.0), S(0.0), x,
+ S(0.0), S(1.0), S(0.0), y,
+ S(0.0), S(0.0), S(1.0), z,
+ S(0.0), S(0.0), S(0.0), S(1.0));
+}
+
+/*
+ * Create a new scale matrix.
+ */
+__fast__
+mat_t MAT_SCALE(scal_t x, scal_t y, scal_t z)
+{
+ return mat_new( x, S(0.0), S(0.0), S(0.0),
+ S(0.0), y, S(0.0), S(0.0),
+ S(0.0), S(0.0), z, S(0.0),
+ S(0.0), S(0.0), S(0.0), S(1.0));
+}
+
+/*
+ * Create a rotation matrix (around the Z axis).
+ */
+__fast__
+mat_t MAT_ROTATE_Z(scal_t a)
+{
+ scal_t sin_a = scal_sin(a);
+ scal_t cos_a = scal_cos(a);
+ return mat_new( cos_a, -sin_a, S(0.0), S(0.0),
+ sin_a, cos_a, S(0.0), S(0.0),
+ S(0.0), S(0.0), S(1.0), S(0.0),
+ S(0.0), S(0.0), S(0.0), S(1.0));
+}
+
+/*
+ * Create a 2D orthogonal projection matrix.
+ */
+__fast__
+mat_t MAT_ORTHO(scal_t left, scal_t right, scal_t bottom, scal_t top)
+{
+ scal_t rml = right - left;
+ scal_t rpl = right + left;
+ scal_t tmb = top - bottom;
+ scal_t tpb = top + bottom;
+ return mat_new(S(2.0) / rml, S(0.0), S(0.0), -rpl / rml,
+ S(0.0), S(2.0) / tmb, S(0.0), -tpb / tmb,
+ S(0.0), S(0.0), S(-1.0), S(0.0),
+ S(0.0), S(0.0), S(0.0), S(1.0));
+}
+
+/*
+ * Create a viewport matrix.
+ */
+__fast__
+mat_t MAT_VIEWPORT(int x, int y, unsigned w, unsigned h)
+{
+ scal_t xs = (scal_t)x;
+ scal_t ys = (scal_t)y;
+ scal_t ws = (scal_t)w / S(2.0);
+ scal_t hs = (scal_t)h / S(2.0);
+ return mat_new( ws, S(0.0), S(0.0), ws + xs,
+ S(0.0), hs, S(0.0), hs + ys,
+ S(0.0), S(0.0), S(1.0), S(0.0),
+ S(0.0), S(0.0), S(0.0), S(1.0));
+}
+
+
+/*
+ * Get a column vector (can also access the vector array directly).
+ */
+__fast__
+vec_t mat_col(mat_t m, int i)
+{
+ return m.v[i];
+}
+
+/*
+ * Get a row vector.
+ */
+__fast__
+vec_t mat_row(mat_t m, int i)
+{
+ switch (i) {
+ case 0:
+ return vec_new2(m.v[0].x, m.v[1].x, m.v[2].x, m.v[3].x);
+ case 1:
+ return vec_new2(m.v[0].y, m.v[1].y, m.v[2].y, m.v[3].y);
+ case 2:
+ return vec_new2(m.v[0].z, m.v[1].z, m.v[2].z, m.v[3].z);
+ case 3:
+ return vec_new2(m.v[0].w, m.v[1].w, m.v[2].w, m.v[3].w);
+ }
+}
+
+
+/*
+ * Multiply two matrices together.
+ */
+__fast__
+mat_t mat_mult(mat_t a, mat_t b)
+{
+#define _DOT(I,J) vec_dot(mat_row(a,I), mat_col(b,J))
+ return mat_new(_DOT(0,0), _DOT(0,1), _DOT(0,2), _DOT(0,3),
+ _DOT(1,0), _DOT(1,1), _DOT(1,2), _DOT(1,3),
+ _DOT(2,0), _DOT(2,1), _DOT(2,2), _DOT(2,3),
+ _DOT(3,0), _DOT(3,1), _DOT(3,2), _DOT(3,3));
+#undef _DOT
+}
+
+/*
+ * Transform a vector using a matrix.
+ */
+__fast__
+vec_t mat_apply(mat_t m, vec_t v)
+{
+ return vec_new2(vec_dot(v,mat_row(m,0)),
+ vec_dot(v,mat_row(m,1)),
+ vec_dot(v,mat_row(m,2)),
+ vec_dot(v,mat_row(m,3)));
+}
+
+
+#endif // __MAT_H__
+