slideUntilHit works, apparently
authorBenjamin Smedberg <benjamin@smedbergs.us>
Fri, 12 Dec 2008 12:21:18 -0500
changeset 4 8be31ac9ef27
parent 3 c6cb8be67953
child 5 b45eafc86660
push id1
push userbsmedberg@mozilla.com
push date2008-12-12 21:25 +0000
slideUntilHit works, apparently I had to comment out the undefined checks in hitTest to get it to trace... I'm not sure whether that's an expected thing yet.
jswordle.js
--- a/jswordle.js
+++ b/jswordle.js
@@ -182,123 +182,148 @@ function getWords()
         continue;
       if (commonWordMap.hasOwnProperty(word.toLowerCase()))
         continue;
       yield word;
     }
   }
 }
 
-function hitTest(x, y, width, height, imgdata)
+function hitTest(fullimg, wordimg, x, y)
 {
-  let data = imgdata.data;
+  let wdata = wordimg.data;
+  let fdata = fullimg.data;
 
-  if (x < 0 || x >= imgdata.width ||
-      y < 0 || y >= imgdata.height ||
-      height <= 0 || (x + width > imgdata.width) ||
-      width <= 0 || (y + height > imgdata.height))
-    throw new Error("Bad args to hitTest: " + [x, y, width, height]);
+  if (x < 0 || y < 0 ||
+      x + wordimg.width > fullimg.width ||
+      y + wordimg.height > fullimg.height)
+    throw new Error("Bad args to hitTest");
+
+  for (let wy = wordimg.height - 1; wy >= 0; --wy) {
+    let widx = wy * wordimg.width * 4;
+    let widxend = widx + (wordimg.width * 4);
+
+    let fidx = ((y + wy) * fullimg.width + x) * 4;
+    for (; widx < widxend; widx += 4, fidx += 4) {
 
-  for (let iy = y; iy < y + height; ++iy) {
-    let idx = ((iy * imgdata.width) + x) * 4;
-    let end = idx + width * 4;
+      // + 3 is the opacity component
+      let wv = wdata[widx + 3];
+      let fv = fdata[fidx + 3];
+
+      /*
+      if (wv === undefined)
+	throw new Error("Word index out of bounds");
+      if (fv === undefined)
+	throw new Error("Full index out of bounds");
+       */
 
-    for (; idx < end; ++idx) {
-      let v = data[idx];
-      if (v === undefined)
-	throw new Error("Out of bounds?");
+      if (wv && fv)
+	return true;
+    }
+  }
+  return false;
+}
 
-      if (v != 0) {
-	setStatus("hitTest hit something at idx: " + idx);
-	return true;
-      }
+function slideUntilHit(fullimg, wordimg, x, y, dx, dy, backoff)
+{
+  if (kParanoid) {
+    if (hitTest(fullimg, wordimg, x, y)) {
+      throw new Error("slideUntilHit hitting at start!");
     }
   }
 
-  return false;
+  let ix, iy;
+  for (ix = x, iy = y;
+       true;
+       ix += dx, iy += dy) {
+    if (hitTest(fullimg, wordimg, ix, iy))
+      break;
+  }
+
+  // TODO: don't back off past the original starting point!
+  ix += backoff * -dx;
+  iy += backoff * -dy;
+
+  return [ix, iy];
 }
 
-function mergeImageData(fulldata, merge, x, y)
+function merge(fullimg, wordimg, x, y)
 {
-  for (let iy = 0; iy < merge.height; ++iy) {
-    let idx = iy * merge.width * 4;
-    let end = idx + (merge.width * 4);
+  let wdata = wordimg.data;
+  let fdata = fullimg.data;
+
+  if (x < 0 || y < 0 ||
+      x + wordimg.width > fullimg.width ||
+      y + wordimg.height > fullimg.height)
+    throw new Error("Bad args to hitTest");
 
-    let fullrow = y + iy;
-    let fullidx = (((iy + y) * fulldata.width) + x) * 4;
+  for (let wy = wordimg.height - 1; wy >= 0; --wy) {
+    let widx = wy * wordimg.width * 4;
+    let widxend = widx + (wordimg.width * 4);
 
-    for (; idx < end; ++idx, ++fullidx)
-      fulldata.data[fullidx] = merge.data[idx];
+    let fidx = ((y + wy) * fullimg.width + x) * 4;
+    for (; widx < widxend; widx += 4, fidx += 4) {
+      if (wdata[widx + 3]) {
+	// if the word bit has opacity
+	fdata[fidx] = wdata[widx];
+	fdata[fidx + 1] = wdata[widx + 1];
+	fdata[fidx + 2] = wdata[widx + 2];
+	fdata[fidx + 3] = wdata[widx + 3];
+      }
+    }
   }
 }
 
-function safeGetImageData(cx, x, y, width, height)
+function drawWord(cx, word, size, vertical)
 {
-  if (x < 0) {
-    width += x;
-    x = 0;
-  }
-  if (y < 0) {
-    height += y;
-    y = 0;
-  }
-  if (x + width > kWidth)
-    width = kWidth - x;
-  if (y + height > kHeight)
-    height = kHeight - y;
+  cx.font = size + 'px Baskerville';
+  let width = cx.measureText(word).width;
 
-  try {
-    return cx.getImageData(x, y, width, height);
-  }
-  catch (e) {
-    throw new Error("Bad bounds: " + [x, y, width, height]);
-  }
-}
-
-function compareArrays(a1, a2)
-{
-  if (a1.length != a2.length)
-    throw new Error("Arrays differ in length!");
-
-  for (let i = 0; i < a1.length; ++i)
-    if (a1[i] !== a2[i]) {
-      throw new Error("Arrays differ at index: " + i);
-    }
-}
-
-function drawWord(cx, word, x, y, vertical, size, width, data)
-{
-  setStatus("drawWord: " + [word, x, y, vertical, size, width]);
-
-  let update = {
-    x: x - size,
-    y: y - size
-  };
+  let geth, getw;
 
   if (vertical) {
+    geth = width + size * 2;
+    getw = size * 3;
+
+    if (geth > kHeight)
+      throw new Error("Word is just too long, vertically");
+
+    cx.clearRect(0, 0, getw, geth);
+
     cx.textAlign = 'right';
     cx.save();
-    cx.translate(x, y);
+    cx.translate(size, size);
     cx.rotate(270 * Math.PI / 180);
     cx.fillText(word, 0, 0);
     cx.restore();
 
-    update.w = size * 3;
-    update.h = width + size * 2;
   }
   else {
-    cx.textAlign = 'left';
-    cx.fillText(word, x, y);
+    geth = size * 3;
+    getw = width + size * 2;
 
-    update.w = width + size * 2;
-    update.h = size * 3;
+    cx.clearRect(0, 0, getw, geth);
+
+    cx.textAlign = 'left';
+    cx.fillText(word, size, size);
   }
 
-  let mdata = safeGetImageData(cx, update.x, update.y, update.w, update.h);
-  mergeImageData(data, mdata, Math.max(update.x, 0), Math.max(update.y, 0));
+  return cx.getImageData(0, 0, getw, geth);
+}
+
+function simpletest(cx, imgdata)
+{
+  let fontsize = 80;
+
+  let wdata = drawWord(cx, 'Happiness', 80, false);
+  merge(imgdata, wdata, 10, 10);
+
+  wdata = drawWord(cx, 'Sillyness', 60, true);
+  let [x,y] = slideUntilHit(imgdata, wdata, 600, 20, -1, 0, 20);
+  merge(imgdata, wdata, x, y);
 }
 
 function draw()
 {
   statusel.textContent = '';
 
   let words = getWordList();
 
@@ -308,37 +333,22 @@ function draw()
   cx.textBaseline = 'top';
   cx.fillStyle = "rgb(200, 0, 0, 0.8)";
 
   let first = true;
   let word, size;
 
   let imgdata = cx.getImageData(0, 0, kWidth, kHeight);
 
-  /* comment out testing code
-
-  let fontsize = 80;
-
-  cx.font = fontsize + 'px Zapfino';
-  let w = cx.measureText("jumping Jacks").width;
-  cx.fillStyle = 'rgba(200, 0, 0, 0.5)';
-  cx.fillRect(100, 100, w, fontsize);
-
-  cx.fillText("jumping Jacks", 100, 100);
+  /* comment out testing code */
 
-  let ir = {x: 100 - fontsize,
-	    y: 100 - fontsize,
-	    width: w + fontsize * 2,
-	    height: fontsize * 3};
+  simpletest(cx, imgdata);
 
-  cx.strokeRect(ir.x, ir.y, ir.width, ir.height);
-
-  let smalldata = safeGetImageData(cx, ir.x, ir.y, ir.width, ir.height);
-  mergeImageData(imgdata, smalldata, ir.x, ir.y);
-  */
+  cx.putImageData(imgdata, 0, 0);
+  return;
 
   let i = 0;
 
   /* Place the first five words randomly */
   for (; i < 5; ++i) {
     let [word, size] = words[i];
 
     cx.font = size + 'px Baskerville';