add support for 3d scenes, depth testing, lighting
[chaz/rasterize] / mat.h
diff --git a/mat.h b/mat.h
index f6d4c1b119f8042e8370e8695f4fb34861f4a8cc..499d09261697a8c02261c7ac94844475ef507f07 100644 (file)
--- a/mat.h
+++ b/mat.h
@@ -5,8 +5,8 @@
  * mcgarvey@eng.utah.edu
  */
 
-#ifndef __MAT_H__
-#define __MAT_H__
+#ifndef _MAT_H_
+#define _MAT_H_
 
 #include "common.h"
 #include "vec.h"
@@ -24,7 +24,7 @@ typedef struct mat mat_t;
 /*
  * Initialize a matrix with individual components, row by row.
  */
-__fast__
+INLINE_MAYBE
 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,
@@ -40,7 +40,7 @@ void mat_init(mat_t* m, scal_t m11, scal_t m12, scal_t m13, scal_t m14,
 /*
  * Create a new matrix with individual components, row by row.
  */
-__fast__
+INLINE_MAYBE
 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,
@@ -57,7 +57,7 @@ mat_t mat_new(scal_t m11, scal_t m12, scal_t m13, scal_t m14,
 /*
  * Create a new matrix with four column vectors.
  */
-__fast__
+INLINE_MAYBE
 mat_t mat_new2(vec_t a, vec_t b, vec_t c, vec_t d)
 {
     mat_t m;
@@ -74,10 +74,83 @@ mat_t mat_new2(vec_t a, vec_t b, vec_t c, vec_t d)
                              S(0.0), S(0.0), S(0.0), S(1.0))
 
 
+/*
+ * 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)));
+}
+
+
 /*
  * Create a new translate matrix.
  */
-__fast__
+INLINE_MAYBE
 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,
@@ -86,119 +159,188 @@ mat_t MAT_TRANSLATE(scal_t x, scal_t y, scal_t z)
                    S(0.0), S(0.0), S(0.0), S(1.0));
 }
 
+/*
+ * Create a new translate matrix from a vector.
+ */
+INLINE_MAYBE
+mat_t MAT_TRANSLATE2(vec_t v)
+{
+    return MAT_TRANSLATE(v.x, v.y, v.z);
+}
+
 /*
  * Create a new scale matrix.
  */
-__fast__
+INLINE_MAYBE
 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));
+    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).
+ * Create a new scale matrix from a vector.
+ */
+INLINE_MAYBE
+mat_t MAT_SCALE2(vec_t v)
+{
+    return MAT_SCALE(v.x, v.y, v.z);
+}
+
+/*
+ * Create a rotation matrix (around the X axis).
  */
-__fast__
-mat_t MAT_ROTATE_Z(scal_t a)
+INLINE_MAYBE
+mat_t MAT_ROTATE_X(scal_t theta)
 {
-    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),
+    scal_t sin_a = scal_sin(theta);
+    scal_t cos_a = scal_cos(theta);
+    return mat_new(S(1.0), S(0.0), S(0.0), S(0.0),
+                   S(0.0),  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));
 }
 
 /*
- * Create a 2D orthogonal projection matrix.
+ * Create a rotation matrix (around the Y axis).
  */
-__fast__
-mat_t MAT_ORTHO(scal_t left, scal_t right, scal_t bottom, scal_t top)
+INLINE_MAYBE
+mat_t MAT_ROTATE_Y(scal_t theta)
 {
-    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));
+    scal_t sin_a = scal_sin(theta);
+    scal_t cos_a = scal_cos(theta);
+    return mat_new(cos_a, S(0.0),  sin_a, S(0.0),
+                  S(0.0), S(1.0), S(0.0), S(0.0),
+                  -sin_a, S(0.0),  cos_a, S(0.0),
+                  S(0.0), S(0.0), S(0.0), S(1.0));
 }
 
 /*
- * Create a viewport matrix.
+ * Create a rotation matrix (around the Z axis).
  */
-__fast__
-mat_t MAT_VIEWPORT(int x, int y, unsigned w, unsigned h)
+INLINE_MAYBE
+mat_t MAT_ROTATE_Z(scal_t theta)
 {
-    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));
+    scal_t sin_a = scal_sin(theta);
+    scal_t cos_a = scal_cos(theta);
+    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 rotation matrix (around an arbitrary axis).
+ */
+INLINE_MAYBE
+mat_t MAT_ROTATE(scal_t theta, scal_t x, scal_t y, scal_t z)
+{
+    /*
+     * This code is an implementation of an algorithm described by Glenn
+     * Murray at http://inside.mines.edu/~gmurray/ArbitraryAxisRotation/
+     */
+    vec_t v = vec_normalize(vec_new(x, y, z));
+    x = v.x;
+    y = v.y;
+    z = v.z;
+    scal_t sin_a = scal_sin(theta);
+    scal_t cos_a = scal_cos(theta);
+    scal_t x2 = x * x;
+    scal_t y2 = y * y;
+    scal_t z2 = z * z;
+    return mat_new(x2+(S(1.0)-x2)*cos_a, x*y*(S(1.0)-cos_a)-z*sin_a, x*z*(S(1.0)-cos_a)+y*sin_a, S(0.0),
+                   x*y*(S(1.0)-cos_a)+z*sin_a, y2+(S(1.0)-y2)*cos_a, y*z*(S(1.0)-cos_a)-y*sin_a, S(0.0),
+                   x*z*(S(1.0)-cos_a)-y*sin_a, y*z*(S(1.0)-cos_a)+x*sin_a, z2+(S(1.0)-z2)*cos_a, 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).
+ * Create a view matrix based on eye, spot, and an up vector.
  */
-__fast__
-vec_t mat_col(mat_t m, int i)
+INLINE_MAYBE
+mat_t MAT_LOOKAT(vec_t eye, vec_t spot, vec_t up)
 {
-    return m.v[i];
+    vec_t f = vec_normalize(vec_sub(spot, eye));
+    vec_t s = vec_normalize(vec_cross(f, up));
+    vec_t u = vec_cross(s, f);
+    return mat_mult(mat_new(s.x,    s.y,    s.z, S(0.0),
+                            u.x,    u.y,    u.z, S(0.0),
+                           -f.x,   -f.y,   -f.z, S(0.0),
+                         S(0.0), S(0.0), S(0.0), S(1.0)), MAT_TRANSLATE2(vec_neg(eye)));
 }
 
 /*
- * Get a row vector.
+ * Create a 3D orthogonal projection matrix.
  */
-__fast__
-vec_t mat_row(mat_t m, int i)
+INLINE_MAYBE
+mat_t MAT_ORTHO(scal_t left, scal_t right,
+                scal_t bottom, scal_t top,
+                scal_t near, scal_t far)
 {
-    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);
-    }
+    scal_t rml = right - left;
+    scal_t rpl = right + left;
+    scal_t tmb = top - bottom;
+    scal_t tpb = top + bottom;
+    scal_t fmn = far - near;
+    scal_t fpn = far + near;
+    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(-2.0)/fmn, -fpn / fmn,
+                       S(0.0),     S(0.0),      S(0.0),     S(1.0));
 }
 
+/*
+ * Create a frustum-based projection matrix.
+ */
+INLINE_MAYBE
+mat_t MAT_FRUSTUM(scal_t left, scal_t right,
+                  scal_t bottom, scal_t top,
+                  scal_t near, scal_t far)
+{
+    scal_t rml = right - left;
+    scal_t rpl = right + left;
+    scal_t tmb = top - bottom;
+    scal_t tpb = top + bottom;
+    scal_t fmn = far - near;
+    scal_t fpn = far + near;
+    scal_t n2  = near * S(2.0);
+    return mat_new(n2/rml, S(0.0),  rpl/rml,      S(0.0),
+                   S(0.0), n2/tmb,  tpb/tmb,      S(0.0),
+                   S(0.0), S(0.0), -fpn/fmn, -n2*far/fmn,
+                   S(0.0), S(0.0),  S(-1.0),      S(0.0));
+}
 
 /*
- * Multiply two matrices together.
+ * Create a perspective projection matrix.
  */
-__fast__
-mat_t mat_mult(mat_t a, mat_t b)
+INLINE_MAYBE
+mat_t MAT_PERSPECTIVE(scal_t fovy, scal_t aspect, scal_t near, scal_t far)
 {
-#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
+    scal_t top    = near * scal_tan(fovy * S(0.5));
+    scal_t bottom = -top;
+    scal_t left   = bottom * aspect;
+    scal_t right  = top * aspect;
+    return MAT_FRUSTUM(left, right, bottom, top, near, far);
 }
 
 /*
- * Transform a vector using a matrix.
+ * Create a viewport matrix.
  */
-__fast__
-vec_t mat_apply(mat_t m, vec_t v)
+INLINE_MAYBE
+mat_t MAT_VIEWPORT(int x, int y, int w, int h)
 {
-    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)));
+    scal_t xs = (scal_t)x;
+    scal_t ys = (scal_t)y;
+    scal_t ws = (scal_t)w * S(0.5);
+    scal_t hs = (scal_t)h * S(0.5);
+    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));
 }
 
 
-#endif // __MAT_H__
+#endif // _MAT_H_
 
This page took 0.033632 seconds and 4 git commands to generate.