+/*
+ * Get a column vector (can also access the vector array directly).
+ */
+INLINE_MAYBE
+vec_t mat_col(mat_t m, int i)
+{
+ return m.v[i];
+}
+
+/*
+ * Get a row vector.
+ */
+INLINE_MAYBE
+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);
+ }
+}
+
+
+/*
+ * Print the matrix to stdout.
+ */
+INLINE_MAYBE
+void mat_print(mat_t m)
+{
+ printf("|");
+ vec_print(mat_row(m, 0));
+ printf("|\n|");
+ vec_print(mat_row(m, 1));
+ printf("|\n|");
+ vec_print(mat_row(m, 2));
+ printf("|\n|");
+ vec_print(mat_row(m, 3));
+ printf("|");
+}
+
+
+/*
+ * Multiply two matrices together.
+ */
+INLINE_MAYBE
+mat_t mat_mult(mat_t a, mat_t b)
+{
+#define _DOT(I,J) vec_dot2(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.
+ */
+INLINE_MAYBE
+vec_t mat_apply(mat_t m, vec_t v)
+{
+ return vec_new2(vec_dot2(v,mat_row(m,0)),
+ vec_dot2(v,mat_row(m,1)),
+ vec_dot2(v,mat_row(m,2)),
+ vec_dot2(v,mat_row(m,3)));
+}
+
+