r/Place
Closed this issue · 1 comments
dylanninin commented
dylanninin commented
Map the 4-bit colors to useable 32-bit colors
...
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
...
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;
},
};
...