function instantiate(compiledBuffer) {
const ctx = waltCanvas.getContext("2d");
const canvas = waltCanvas;
const imgData = ctx.createImageData(canvas.width, canvas.height);
const canvasWidth = canvas.width;
const canvasHeight = canvas.height;
const getCanvasWidth = () => canvasWidth;
const getCanvasHeight = () => canvasHeight;
const env = {
getCanvasWidth,
getCanvasHeight,
log: (val) => {
console.log(val);
}
};
window.addEventListener('resize', onresize, false);
return WebAssembly.instantiate(compiledBuffer, { env }).then(result => {
const exports = result.instance.exports;
const memory = exports.memory;
const { width, height } = canvas;
const wh = width * height;
const pages = 1 + ((20 * wh + 256) >> 16);
memory.grow(pages);
const heap = memory.buffer;
const HEAP_START = 65536;
const imageArray = new Uint8ClampedArray(heap, HEAP_START, 4 * wh);
const image32Array = new Uint32Array(heap, HEAP_START, wh);
const forceArray = new Int32Array(heap, HEAP_START + 4 * wh, wh);
const statusArray = new Int32Array(heap, HEAP_START + 8 * wh, wh);
const uArray = new Int32Array(heap, HEAP_START + 12 * wh, wh);
const velArray = new Int32Array(heap, HEAP_START + 16 * wh, wh);
const colorRampArray = new Uint32Array(heap, HEAP_START + 20 * wh, 256);
colorRampArray.set(colorRamp.RGBA32);
// we clamp to the range [0, width-1], so -1 is a
// way to indicate there was no previous mouse value
let lastMouseX = -1;
let lastMouseY = -1;
const applyBrush = exports.applyBrush;
canvas.onmousedown = (e) => {
e.preventDefault();
let bbox = canvas.getBoundingClientRect();
let mouseX = Math.round(e.clientX - bbox.left * (width / bbox.width));
let mouseY = Math.round(e.clientY - bbox.top * (height / bbox.height));
mouseX = Math.max(1, Math.min(canvasWidth-1, mouseX));
mouseY = Math.max(1, Math.min(canvasHeight-1, mouseY));
lastMouseX = mouseX;
lastMouseY = mouseY;
applyBrush(mouseX, mouseY, brushRadius);
};
canvas.onmousemove = (e) => {
e.preventDefault();
let bbox = canvas.getBoundingClientRect();
let mouseX = Math.round(e.clientX - bbox.left * (width / bbox.width));
let mouseY = Math.round(e.clientY - bbox.top * (height / bbox.height));
mouseX = Math.max(1, Math.min(canvasWidth-1, mouseX));
mouseY = Math.max(1, Math.min(canvasHeight-1, mouseY));
if (lastMouseX !== -1 && lastMouseY !== -1) {
const dx = mouseX - lastMouseX;
const dy = mouseY - lastMouseY;
const r = Math.sqrt(dx*dx + dy*dy);
for (let t = 0; t <= r; t += brushRadius+1 >> 1) {
const currX = lastMouseX + ((mouseX - lastMouseX) * (t / r)) | 0;
const currY = lastMouseY + ((mouseY - lastMouseY) * (t / r)) | 0;
applyBrush(currX, currY, brushRadius);
forceArray[currY * width + currX] = 0x3FFFFFFF;
}
applyBrush(mouseX, mouseY, brushRadius);
lastMouseX = mouseX;
lastMouseY = mouseY;
}
};
canvas.onmouseout = canvas.onmouseup = (e) => {
e.preventDefault();
lastMouseX = -1;
lastMouseY = -1;
};
// fake mouse events when triggering touch events
canvas.addEventListener("touchstart", function (e) {
e.preventDefault();
var touch = e.touches[0];
var mouseEvent = new MouseEvent("mousedown", {
clientX: touch.clientX,
clientY: touch.clientY
});
canvas.dispatchEvent(mouseEvent);
}, false);
canvas.addEventListener("touchend", function (e) {
e.preventDefault();
var touch = e.touches[0];
var mouseEvent = new MouseEvent("mouseup", {
clientX: touch.clientX,
clientY: touch.clientY
});
canvas.dispatchEvent(mouseEvent);
}, false);
canvas.addEventListener("touchmove", function (e) {
e.preventDefault();
var touch = e.touches[0];
var mouseEvent = new MouseEvent("mousemove", {
clientX: touch.clientX,
clientY: touch.clientY
});
canvas.dispatchEvent(mouseEvent);
}, false);
let raf;
let raindrop = 0x3FFFFFFF;
function run() {
if (rainNoise) {
const raindrop2 = raindrop^0xFFFFFFFF;
const j = width + (wh-(width*2)) * Math.random() | 0;
forceArray[j-width-1] = raindrop2;
forceArray[j-width] = raindrop2;
forceArray[j-width+1] = raindrop2;
forceArray[j-1] = raindrop2;
forceArray[j] = raindrop2;
forceArray[j+1] = raindrop;
forceArray[j+width-1] = raindrop2;
forceArray[j+width] = raindrop2;
forceArray[j+width+1] = raindrop2;
raindrop = raindrop2;
}
exports.step();
imgData.data.set(imageArray);
ctx.putImageData(imgData, 0, 0);
raf = requestAnimationFrame(run, 0);
}
function cancel() {
cancelAnimationFrame(raf);
}
exports.init(useColormap ? 1 : 0);
return { run, cancel, canvas };
});
}