-include $(DEPS)
$(OBJS): Makefile
-.PHONY: all clean distclean run debug
+.PHONY: all clean distclean dist run debug
local size = {w = 640, h = 480}
-- Set the number of frames to be rendered for the animation.
-local frames = 512
+local frames = 360
-- Define the code to calculate where the camera is, in world coordinates.
local eye = function(frame)
t 2 0 -2
s 1 1 1
g dragon.raw
+M 0.3 0.3 0.3 5
c 0.7 0.3 0.2 0.8 0.2 0.1 0.9 0.2 0.2
t -2 -1 -2
s 2 2 2
t 2 -1.5 2
s 10 10 10
g bunny.raw
+M 0.2 0.2 0.2 1
c 0.9 0.8 0.9 0.8 0.7 0.9 0.9 0.8 0.7
t -2 -1 2
s 10 10 10
g teapot2.raw
+M 1 1 1 128
c 0 1 0 0 1 0 0 1 0
t 0 -1 0
s 0.6 0.6 0.6
#define IF_DEPTH_TEST(X)
#endif
+/*
+ * DOUBLE_FLOAT
+ * If enabled, scalars will be of type double. This provides and insane level
+ * of precision at a performance cost. The default behavior just uses floats.
+ */
+#if DOUBLE_FLOAT
+#define IF_DOUBLE_FLOAT(X) X
+#else
+#define IF_DOUBLE_FLOAT(X)
+#endif
+
/*
* EXPORT_BMP
* If enabled, each scene rasterization will be saved as a BMP image file.
* LIGHTING
* If enabled, local lighting will be used to increase realism of the scene.
* This option has a performance cost, but it can produce interesting visuals.
- * The behavior of this option also depends on the SMOOTH_COLOR option and
- * whether or not the model has unique vertex normals; if SMOOTH_COLOR is
- * disabled, each triangle will be shaded a flat color. If it is enabled,
- * Gouraud interpolation is used to smooth the lighting across the face of
- * each triangle. See the PRE_NORMALS and SMOOTH_COLOR options.
+ * The behavior of this option is effected by its precise value:
+ * 1 Phong lighting model with flat (per-face) interpolation.
+ * 2 Phong lighting model with Gouraud (per-vertex) interpolation.
+ * 3 Phong lighting model with Phong (per-pixel) interpolation.
*/
#if LIGHTING
#define IF_LIGHTING(X) X
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),
+ scal_t c = scal_cos(-theta);
+ scal_t s = scal_sin(-theta);
+ scal_t t = S(1.0) - c;
+ return mat_new(t * x * x + c, t * x * y + s * z, t * x * z - s * y, S(0.0),
+ t * x * y - s * z, t * y * y + c, t * y * z + s * x, S(0.0),
+ t * x * z + s * y, t * y * z - s * x, t * z * z + c, S(0.0),
S(0.0), S(0.0), S(0.0), S(1.0));
}
p->specular = COLOR_WHITE;
p->shininess = S(1.0);
#endif
- /*= light_new(COLOR_WHITE, vec_new(S(-2.0), S(4.0), S(0.0)));*/
+
p->zbuf = (scal_t*)mem_alloc(sizeof(scal_t) * size);
for (size_t i = 0; i < size; ++i) {
p->zbuf[i] = S(1.0);
* Determine what color is associated with the given vertex.
*/
INLINE_MAYBE
-color_t _get_vertex_color(raster_t* p, vert_t vert)
+color_t _do_phong_lighting(raster_t* p, vert_t vert)
{
#if LIGHTING
color_t color = COLOR_BLACK;
vec_t vpos = p->eye;
vec_t n = vert.n;
vec_t l = vec_normalize(vec_sub(lpos, mpos));
- vec_t r = vec_sub(vec_scale(n, S(2.0) * vec_dot(n, l)), l);
+ vec_t r = vec_normalize(vec_sub(vec_scale(n, S(2.0) * vec_dot(n, l)), l));
vec_t v = vec_normalize(vec_sub(vpos, mpos));
scal_t kd = scal_max(vec_dot(l, n), S(0.0));
return;
}
- tri_t temp = tri_transform(*triangle, p->model);
-#if LIGHTING && (!PRE_NORMALS || (!SMOOTH_COLOR && PRE_NORMALS >= 2))
- temp.a.n = temp.b.n = temp.c.n = vec_normalize(tri_normal(temp));
+#if LIGHTING >= 1
+ tri_t tl = tri_transform(*triangle, p->model);
+#if !PRE_NORMALS
+ tl.a.n = tl.b.n = tl.c.n = vec_normalize(tri_normal(tl));
#endif
-#if !SMOOTH_COLOR
- temp.a.c = tri_color(temp);
#endif
- color_t color1 = _get_vertex_color(p, temp.a);
-#if SMOOTH_COLOR
- color_t color2 = _get_vertex_color(p, temp.b);
- color_t color3 = _get_vertex_color(p, temp.c);
+
+#if LIGHTING == 1
+ vert_t tv = vert_new(tri_midpoint(tl));
+ tv.n = vec_normalize(tri_normal(tl));
+ tv.c = tri_color(tl);
+ color_t color = _do_phong_lighting(p, tv);
+#elif LIGHTING == 2 && SMOOTH_COLOR
+ color_t color1 = _do_phong_lighting(p, tl.a);
+ color_t color2 = _do_phong_lighting(p, tl.b);
+ color_t color3 = _do_phong_lighting(p, tl.c);
+#elif LIGHTING == 2 && !SMOOTH_COLOR
+ color_t c = tri_color(t);
+ tl.a.c = tl.b.c = tl.c.c = c;
+ color_t color1 = _do_phong_lighting(p, tl.a);
+ color_t color2 = _do_phong_lighting(p, tl.b);
+ color_t color3 = _do_phong_lighting(p, tl.c);
+#elif !LIGHTING && SMOOTH_COLOR
+ color_t color1 = t.a.c;
+ color_t color2 = t.b.c;
+ color_t color3 = t.c.c;
+#else
+ color_t color = tri_color(t);
#endif
for (int y = bottom; y < top; ++y) {
if (S(-1.0) < v.z && v.z < *n) {
#endif
color_t* c = p->pixels + y * p->w + x;
-#if SMOOTH_COLOR
+
+#if LIGHTING == 2 || (!LIGHTING && SMOOTH_COLOR)
*c = color_interp2(color1, color2, color3, b);
+#elif LIGHTING == 3 && SMOOTH_COLOR
+ *c = _do_phong_lighting(p, tri_interp(tl, b));
+#elif LIGHTING == 3 && !SMOOTH_COLOR
+ vert_t d = vert_new(tri_point(t, b));
+ d.c = tri_color(t);
+ d.n = tri_normal2(t, b);
+ *c = _do_phong_lighting(p, d);
#else
- *c = color1;
+ *c = color;
#endif
+
#if DEPTH_TEST
*n = v.z;
}
*/
static int _group_try_read_cache(const char* filename, list_t** l)
{
+ int count = 0;
char* cachename = mem_strcat(".", filename);
FILE* file = fopen(cachename, "rb");
if (file == NULL) {
goto fail;
}
- int count = 0;
_CHECK_IO(fread(&count, sizeof(count), 1, file));
float x1, y1, z1, x2, y2, z2, x3, y3, z3;
t.a.v = mat_apply(m, t.a.v);
t.b.v = mat_apply(m, t.b.v);
t.c.v = mat_apply(m, t.c.v);
+ t.a.n.w = t.b.n.w = t.c.n.w = S(0.0);
+ t.a.n = vec_normalize(mat_apply(m, t.a.n));
+ t.b.n = vec_normalize(mat_apply(m, t.b.n));
+ t.c.n = vec_normalize(mat_apply(m, t.c.n));
return t;
}
INLINE_MAYBE
vec_t tri_normal(tri_t t)
{
- return vec_cross(vec_sub(t.b.v, t.a.v), vec_sub(t.c.v, t.a.v));
+ vec_t n = vec_cross(vec_sub(t.b.v, t.a.v), vec_sub(t.c.v, t.a.v));
+ return n;
}
}
-/*
- * Get an interpolated z-value at the barycentric coordinates.
- */
-INLINE_MAYBE
-scal_t tri_z(tri_t t, scal_t b[3])
-{
- return t.a.v.z * b[0] + t.b.v.z * b[1] + t.c.v.z * b[2];
-}
-
/*
* Find the midpoint of the triangle.
*/
}
+/*
+ * Get an interpolated z-value at the barycentric coordinates.
+ */
+INLINE_MAYBE
+scal_t tri_z(tri_t t, scal_t b[3])
+{
+ return t.a.v.z * b[0] + t.b.v.z * b[1] + t.c.v.z * b[2];
+}
+
+/*
+ * Calculate an interpolated point.
+ */
+INLINE_MAYBE
+vec_t tri_point(tri_t t, scal_t b[3])
+{
+ return vec_interp(t.a.v, t.b.v, t.c.v, b);
+}
+
+/*
+ * Calculate an interpolated normal.
+ */
+INLINE_MAYBE
+vec_t tri_normal2(tri_t t, scal_t b[3])
+{
+ return vec_normalize(vec_interp(t.a.n, t.b.n, t.c.n, b));
+}
+
+/*
+ * Calculate an entirely new vertex within the triangle based on barycentric
+ * coordinates.
+ */
+INLINE_MAYBE
+vert_t tri_interp(tri_t t, scal_t b[3])
+{
+ vert_t v = vert_new(tri_point(t, b));
+ v.c = color_interp2(t.a.c, t.b.c, t.c.c, b);
+ v.n = tri_normal2(t, b);
+ return v;
+}
+
+
#endif // _TRI_H_
return vec_new2(x, y, z, S(1.0));
}
-#define VEC_ZERO vec_new(S(0.0), S(0.0), S(0.0))
-#define VEC_ORTHO_X vec_new(S(1.0), S(0.0), S(0.0))
-#define VEC_ORTHO_Y vec_new(S(0.0), S(1.0), S(0.0))
-#define VEC_ORTHO_Z vec_new(S(0.0), S(0.0), S(1.0))
+#define VEC_ZERO vec_new(S(0.0), S(0.0), S(0.0))
+#define VEC_ORTHO_X vec_new(S(1.0), S(0.0), S(0.0))
+#define VEC_ORTHO_Y vec_new(S(0.0), S(1.0), S(0.0))
+#define VEC_ORTHO_Z vec_new(S(0.0), S(0.0), S(1.0))
+#define VEC_ZERO_FREE vec_new2(S(0.0), S(0.0), S(0.0), S(0.0))
/*
return a;
}
+/*
+ * Add three vectors together.
+ */
+INLINE_MAYBE
+vec_t vec_add2(vec_t a, vec_t b, vec_t c)
+{
+ return vec_add(vec_add(a, b), c);
+}
+
/*
* Subtract a vector from another vector.
*/
}
+/*
+ * Interpolate smoothly between three vectors with barycentric coordinates.
+ */
+INLINE_MAYBE
+vec_t vec_interp(vec_t v1, vec_t v2, vec_t v3, scal_t b[3])
+{
+ return vec_new(v1.x * b[0] + v2.x * b[1] + v3.x * b[2],
+ v1.y * b[0] + v2.y * b[1] + v3.y * b[2],
+ v1.z * b[0] + v2.z * b[1] + v3.z * b[2]);
+}
+
+
+
#endif // _VEC_H_