Raytracer: shadows and multi-sample anti-aliasing.
diff --git a/scripts/clang.sha b/scripts/clang.sha
index 2235828..9e16a30 100644
--- a/scripts/clang.sha
+++ b/scripts/clang.sha
@@ -1 +1 @@
-157d401f5d70ed850010a3c88902e03d1a9a3d2e
+1b26d93e5d7d6b9dbaed1900575923f7dc588399
diff --git a/scripts/llvm.sha b/scripts/llvm.sha
index 99171ff..dd5c87c 100644
--- a/scripts/llvm.sha
+++ b/scripts/llvm.sha
@@ -1 +1 @@
-d10549743ae65fcc4420a5b07606f97f5cac4bae
+832d1103af38a870d0baf9b59194e9a6f482647d
diff --git a/test/raytrace.cc b/test/raytrace.cc
index 88af016..efd1a4d 100644
--- a/test/raytrace.cc
+++ b/test/raytrace.cc
@@ -7,6 +7,7 @@
 
 unsigned int buffer[WIDTH * HEIGHT];
 
+const byte permute[256] = {104, 69, 63, 141, 115, 14, 55, 219, 91, 103, 143, 149, 53, 105, 116, 196, 107, 11, 226, 239, 188, 108, 100, 224, 253, 140, 158, 134, 38, 126, 216, 148, 137, 43, 200, 164, 194, 242, 251, 18, 28, 101, 106, 217, 57, 183, 179, 87, 198, 119, 175, 174, 202, 77, 62, 146, 117, 98, 150, 132, 182, 176, 78, 236, 59, 113, 17, 247, 191, 227, 49, 230, 167, 144, 252, 3, 228, 170, 215, 204, 45, 32, 21, 131, 68, 72, 128, 114, 250, 1, 88, 235, 58, 95, 0, 65, 205, 233, 111, 96, 110, 172, 40, 173, 186, 48, 220, 121, 83, 35, 244, 36, 34, 130, 127, 125, 142, 246, 147, 76, 39, 187, 189, 90, 237, 52, 24, 243, 192, 207, 255, 163, 248, 7, 5, 156, 211, 15, 160, 6, 109, 37, 92, 249, 94, 66, 60, 231, 177, 23, 152, 93, 12, 221, 197, 245, 112, 229, 254, 122, 74, 171, 44, 70, 165, 64, 8, 82, 133, 33, 184, 26, 206, 213, 4, 10, 73, 166, 209, 159, 138, 201, 169, 124, 151, 154, 71, 190, 56, 89, 139, 193, 27, 212, 234, 185, 25, 20, 155, 145, 54, 51, 208, 29, 210, 223, 61, 67, 31, 13, 99, 225, 199, 81, 85, 118, 2, 181, 97, 75, 180, 9, 86, 195, 120, 232, 161, 30, 129, 222, 47, 123, 218, 214, 80, 102, 16, 84, 240, 41, 136, 22, 238, 168, 157, 241, 203, 79, 42, 178, 153, 19, 50, 135, 46, 162};
 
 static unsigned int f2b(float value) {
   if (value < 0.0f) {
@@ -106,31 +107,43 @@
   Vec3(0.1f, 1.0f, 0.1f).blend(Vec3(0.1f, 0.1f, 1.0f), amt, out);
 }
 
+struct Sphere {
+  Vec3 center;
+  float radius;
+};
+
 class Intersection {
  public:
   Vec3 pos;
   Vec3 normal;
+  float distance;
 };
 
-static int intersect(const Vec3& pos, const Vec3& dir, Vec3* normal) {
-  // The sphere.
-  const float radius = 4.0f;
-  // TODO movement.
-  Vec3 center(0.0f, 0.0f, -6.0f);
+Intersection intersection;
 
+static int intersectSphere(const Vec3& pos, const Vec3& dir, const Sphere& sphere, Intersection* intersection) {
   Vec3 offset(pos);
-  offset.sub(center);
+  offset.sub(sphere.center);
 
   float dot = dir.dot(offset);
-  float partial = dot * dot + radius * radius - offset.dot(offset);
+  float partial = dot * dot + sphere.radius * sphere.radius - offset.dot(offset);
   if (partial >= 0.0f) {
     float d = -dot - sqrtF32(partial);
-    if (d >= 0.0f) {
-      Vec3 n(pos);
-      n.scaledAdd(dir, d);
-      n.sub(center);
-      n.normalize();
-      *normal = n;
+    if (d > 0.0f) {
+      if (intersection) {
+	// Intersection positon.
+	Vec3 p(pos);
+	p.scaledAdd(dir, d);
+
+	// Intersection normal.
+	Vec3 n(p);
+	n.sub(sphere.center);
+	n.normalize();
+
+	intersection->pos = p;
+	intersection->normal = n;
+	intersection->distance = d;
+      }
       return 1;
     }
   }
@@ -140,10 +153,123 @@
 Vec3 light;
 Vec3 normal;
 Vec3 pos;
-Vec3 dir;
+Vec3 eye;
+Vec3 env;
+
+class Material {
+public:
+  Vec3 diffuseColor;
+};
+
+const struct Material material[] = {
+  {
+    Vec3(0.7f, 0.7f, 0.7f)
+  },
+  {
+    Vec3(0.9f, 0.1f, 0.1f)
+  },
+  {
+    Vec3(0.9f, 0.1f, 0.9f)
+  }
+};
+
+const int num_objects = 3;
+
+struct Sphere scene[num_objects] = {
+  {Vec3(-2.0f, -1.0f, -6.0f), 3.0f},
+  {Vec3(2.0f, -1.0f, -6.0f), 3.0f},
+  {Vec3(0.0f, 2.0f, -6.0f), 3.0f},
+};
+
+static void shade(const Vec3& eye, const Vec3& light, const float lightVisibility, const Vec3& normal, const Material& material, Vec3* color) {
+  // Surface diffuse.
+  float ambientScale = 0.2f;
+
+  // Ambient color
+  sampleEnv(normal, &env);
+  env.scale(ambientScale);
+  color->scaledAdd(material.diffuseColor, env);
+
+  if (lightVisibility <= 0.0f) {
+    return;
+  }
+
+  // Diffuse color
+  float diffuse = normal.nlDot(light);
+  color->scaledAdd(material.diffuseColor, diffuse * lightVisibility);
+
+  // Specular color
+
+  // Compute the half vector;
+  Vec3 half(eye);
+  half.scale(-1.0f);
+  half.add(light);
+  half.normalize();
+
+  float specular = normal.nlDot(half);
+  // Take it to the 64th power, manually.
+  specular = specular * specular;
+  specular = specular * specular;
+  specular = specular * specular;
+  specular = specular * specular;
+  specular = specular * specular;
+  specular = specular * specular;
+
+  specular = specular * 0.6f;
+
+  color->scaledAdd(Vec3(1.0f, 1.0f, 1.0f), specular * lightVisibility);
+}
+
+Vec3 color;
+
+static void cast(const Vec3& pos, const Vec3& eye, const Vec3& light, Vec3* color) {
+  int closest = -1;
+  Intersection closestIntersection;
+  closestIntersection.distance = 1e9;
+
+  for (int o = 0; o < num_objects; o++) {
+    float distance;
+    if (intersectSphere(pos, eye, scene[o], &intersection)) {
+      if (intersection.distance < closestIntersection.distance) {
+	closest = o;
+	closestIntersection = intersection;
+      }
+    }
+  }
+
+  // Light accumulation
+  *color = Vec3(0.0f, 0.0f, 0.0f);
+  if (closest != -1) {
+
+    // Shadow ray.
+    float lightVisibility = 1.0f;
+    Vec3 towardsLight(light);
+    //towardsLight.scale(-1.0f);
+    for (int o = 0; o < num_objects; o++) {
+      if (intersectSphere(closestIntersection.pos, towardsLight, scene[o], 0)) {
+	lightVisibility = 0.0f;
+	break;
+      }
+    }
+
+    shade(eye, light, lightVisibility, closestIntersection.normal, material[closest], color);
+  } else {
+    sampleEnv(eye, &env);
+    color->add(env);
+  }
+}
+
+static byte rand2(int a, int b) {
+  return permute[(permute[a & 255] + b) & 255];
+}
+
+static byte rand3(int a, int b, int c) {
+  return permute[(rand2(a, b) + c) & 255];
+}
 
 static void emitImage(unsigned int* p, int width, int height) {
-  light = Vec3(20.0f, 20.0f, 15.0f);
+  //light = Vec3(20.0f, 20.0f, 15.0f);
+  light = Vec3(10.0f, 20.0f, 5.0f);
   light.normalize();
 
   for (int j = 0; j < height; j++) {
@@ -151,49 +277,30 @@
     for (int i = 0; i < width; i++) {
       const float x = i / (float)width - 0.5f;
 
-      pos = Vec3(x, y, 0.0f);
-      dir = Vec3(x, y, -0.5f);
-      dir.normalize();
+      Vec3 accumulate(0.0f, 0.0f, 0.0f);
 
-      // Compute the half vector;
-      Vec3 half(dir);
-      half.scale(-1.0f);
-      half.add(light);
-      half.normalize();
+      const int num_samples = 16;
 
-      // Light accumulation
-      Vec3 color(0.0f, 0.0f, 0.0f);
+      for (int s = 0; s < num_samples; s++) {
+	// The position from which the ray is being emitted.
+	// (A 1 x 1 square centered around the z axis.)
+	float xJitter = (signed char)rand3(s, i, j) / 128.0f / (float) width * 0.5f;
+	float yJitter = (signed char)rand3(s + 128, i, j) / 128.0f / (float) height * 0.5f;
+	pos = Vec3(x + xJitter, y + yJitter, 0.0f);
+	// The direction in which the ray is being emitted, assuming the focal
+	// point is 0.5 behind the image plane.
+	eye = pos;
+	eye.z -= 0.5f;
+	eye.normalize();
 
-      // Surface diffuse.
-      Vec3 diffuseColor(0.7f, 0.7f, 0.7f);
+	cast(pos, eye, light, &color);
 
-      Vec3 env;
-      if (intersect(pos, dir, &normal)) {
-        float ambientScale = 0.2f;
-        sampleEnv(normal, &env);
-	env.scale(ambientScale);
-	color.scaledAdd(diffuseColor, env);
-
-        float diffuse = normal.nlDot(light);
-	color.scaledAdd(diffuseColor, diffuse);
-
-        float specular = normal.nlDot(half);
-        // Take it to the 64th power, manually.
-        specular = specular * specular;
-        specular = specular * specular;
-        specular = specular * specular;
-        specular = specular * specular;
-        specular = specular * specular;
-        specular = specular * specular;
-
-        specular = specular * 0.6f;
-
-        color.scaledAdd(Vec3(1.0f, 1.0f, 1.0f), specular);
-      } else {
-        sampleEnv(dir, &env);
-        color.add(env);
+	accumulate.add(color);
       }
-      unsigned int pixel = packColor(color.x, color.y, color.z, 255);
+
+      accumulate.scale(1.0f / num_samples);
+
+      unsigned int pixel = packColor(accumulate.x, accumulate.y, accumulate.z, 255);
       *p++ = pixel;
     }
   }
diff --git a/third_party/wasm-experimental b/third_party/wasm-experimental
index 7b457e2..5add231 160000
--- a/third_party/wasm-experimental
+++ b/third_party/wasm-experimental
@@ -1 +1 @@
-Subproject commit 7b457e2c864c5f6c24a73e1f9041bf7ff587aca6
+Subproject commit 5add231ed9a089e1e77f4b2dd0bfb912349ba876