dylanninin/dylanninin.com

r/Place

Closed this issue · 1 comments

Map the 4-bit colors to useable 32-bit colors

screen shot 2017-04-25 at 4 21 25 pm

    ...
    if (window.fetch) {
        // If the fetch API is available, use it so we can process the response
        // in chunks as it comes in.
        // TODO - should we render the board as it streams in?
        fetch(buildFullURL("/api/place/board-bitmap"), { credentials: 'include' })
          .then(function(res) {
            // Firefox implements the fetch API, but doesn't support the
            // ReadableStream portion that Chrome does. In that case we'll
            // use the arrayBuffer method, which reads the response to
            // completion and returns a Promise<ArrayBuffer>
            if (!(res.body && res.body.getReader)) {
              res.arrayBuffer().then(function(arrayBuffer) {
                handleChunk(new Uint8Array(arrayBuffer));
                dfd.resolve(timestamp, canvas);
              });
              return;
            }

            function next(reader) {
              reader.read().then(function(chunk) {
                if (chunk.done) {
                  dfd.resolve(timestamp, canvas);
                } else {
                  handleChunk(chunk.value);
                  next(reader);
                }
              });
            }
            next(res.body.getReader());
          });
      } else {
        // Fall back to using a normal XHR request.
        var oReq = new XMLHttpRequest();
        oReq.responseType = "arraybuffer";
        var resp = oReq.open("GET", buildFullURL("/api/place/board-bitmap"), true);

        oReq.onload = function (oEvent) {
          var arrayBuffer = oReq.response;
          if (!arrayBuffer) { dfd.resolve(); }
          var responseArray = new Uint8Array(arrayBuffer);
          handleChunk(responseArray);
          dfd.resolve(timestamp, canvas);
        };

        oReq.send(null);
      }
     ...
      ...
      function handleChunk(responseArray) {
        // If we haven't set the timestamp yet, slice it off of this chunk
        if (!timestamp) {
          timestamp = (new Uint32Array(responseArray.buffer, 0, 1))[0],
          responseArray = new Uint8Array(responseArray.buffer, 4);
        }
        // Each byte in the responseArray represents two values in the canvas
        for (var i = 0; i < responseArray.byteLength; i++) {
          canvas[offset + 2 * i] = responseArray[i] >> 4;
          canvas[offset + 2 * i + 1] = responseArray[i] & 15;
        }
        offset += responseArray.byteLength * 2;
      ...
  • Mapped to 32bit colors

    ...
    parseHexColor: function(hexColor) {
      var colorVal = parseInt(hexColor.slice(1), 16);
      return {
        red: colorVal >> 16 & 0xFF,
        green: colorVal >> 8 & 0xFF,
        blue: colorVal & 0xFF,
      };
    },
    ...
    ...
    this.paletteABGR = palette.map(function(colorString) {
        var color = parseHexColor(colorString);
        dataView.setUint8(1, color.blue);
        dataView.setUint8(2, color.green);
        dataView.setUint8(3, color.red);
        return dataView.getUint32(0);
      });
    ...
    ...
    DEFAULT_COLOR_PALETTE: [
      '#FFFFFF', // white
      '#E4E4E4', // light grey
      '#888888', // grey
      '#222222', // black
      '#FFA7D1', // pink
      '#E50000', // red
      '#E59500', // orange
      '#A06A42', // brown
      '#E5D900', // yellow
      '#94E044', // lime
      '#02BE01', // green
      '#00D3DD', // cyan
      '#0083C7', // blue
      '#0000EA', // dark blue
      '#CF6EE4', // magenta
      '#820080', // purple
    ],
    ...

ABGR: RGBA reverse-byte order

screen shot 2017-04-25 at 4 22 18 pm

    ...
    getPaletteColorABGR: function(colorIndex) {
      colorIndex = Math.min(MAX_COLOR_INDEX, Math.max(0, colorIndex|0));
      return this.paletteABGR[colorIndex % this.paletteABGR.length] || DEFAULT_COLOR_ABGR;
    },
   ...

Draw canvas

    ...
    setInitialState: function(state) {
      // Iterate over API response state.
      var canvas = [];

      // Safari TypedArray implementation doesn't support forEach :weary:
      var colorIndex, color;
      for (var i = 0; i < state.length; i++) {
        colorIndex = state[i];
        color = this.getPaletteColorABGR(colorIndex);
        Canvasse.setBufferState(i, color);
        // Assumes that all non-0 values in local state are *newer* than the
        // state we're loading. This might not be strictly true but eh
        if (colorIndex > 0) {
          this.state[i] = colorIndex;
        }
      }

      Canvasse.drawBufferToDisplay();
    },
    ...
    ...
    drawBufferToDisplay: function() {
      var imageData = new ImageData(this.readBuffer, this.width, this.height);
      this.ctx.putImageData(imageData, 0, 0);
      this.isBufferDirty = false;
    },
  };
  ...