<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="https://emojipedia-us.s3.amazonaws.com/source/skype/289/woman-cartwheeling_1f938-200d-2640-fe0f.png" type="image/x-icon">
<title>[acrylic demo]</title>
<style>
html, body {
display: flex;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
border: 0;
background-color: #050505;
overflow: hidden;
}
</style>
</head>
<body onload="onLoad();">
<canvas></canvas>
<script>
let canvas = document.querySelector('canvas');
let ctx = canvas.getContext('2d');
let wasm;
let app;
let imageData;
let w, h;
let addr, slice;
let pendingRequest = null;
let urlPrefix = null;
let timeout = null;
let previousFrame = performance.now();
const targetFPS = 10;
const targetFrameTime = parseInt(1000 / targetFPS);
let lastFrameTime;
function raw_log(s, l) {
let mem = wasm.exports.memory;
let slice = new Uint8Array(mem.buffer, s, l);
let str = String.fromCharCode.apply(null, slice);
console.log(str);
}
function raw_is_request_pending() {
return pendingRequest === null ? 0 : 1;
}
function onRequestLoad(event) {
clearTimeout(timeout);
let len = pendingRequest.response.byteLength;
let addr = wasm.exports.alloc_response_bytes(len);
let mem = wasm.exports.memory;
let dst = new Uint8Array(mem.buffer, addr, len);
let src = new Uint8Array(pendingRequest.response);
for (let i = 0; i < len; i++) dst[i] = src[i];
wasm.exports.process_response(app);
wasm.exports.drop_response_bytes();
pendingRequest = null;
needsSliceRefresh = true;
frame();
}
function raw_set_request_url_prefix(s, l) {
let mem = wasm.exports.memory;
let slice = new Uint8Array(mem.buffer, s, l);
urlPrefix = String.fromCharCode.apply(null, slice);
}
function raw_set_request_url(s, l) {
let mem = wasm.exports.memory;
let slice = new Uint8Array(mem.buffer, s, l);
let url = String.fromCharCode.apply(null, slice);
pendingRequest = new XMLHttpRequest();
pendingRequest.responseType = "arraybuffer";
pendingRequest.addEventListener("load", onRequestLoad);
pendingRequest.open("GET", urlPrefix + url);
pendingRequest.send();
}
function frame() {
if (w != window.innerWidth || h != window.innerHeight) {
w = window.innerWidth;
h = window.innerHeight;
addr = wasm.exports.set_output_size(app, w, h);
canvas.width = w;
canvas.height = h;
needsSliceRefresh = true;
}
if (needsSliceRefresh) {
let mem = wasm.exports.memory;
slice = new Uint8ClampedArray(mem.buffer, addr, w * h * 4);
needsSliceRefresh = false;
}
wasm.exports.frame(app);
ctx.putImageData(new ImageData(slice, w, h), 0, 0);
let now = performance.now();
lastFrameTime = now - previousFrame;
previousFrame = now;
let delay = (lastFrameTime > targetFrameTime) ? 0 : (targetFrameTime - lastFrameTime);
timeout = setTimeout(frame, delay);
}
const env = {
raw_log,
raw_is_request_pending,
raw_set_request_url_prefix,
raw_set_request_url,
};
function startWasm(file, debug) {
let path = 'target/wasm32-unknown-unknown/';
fetch( path + (debug ? 'debug/' : 'release/') + file + '.wasm').then(response => {
response.arrayBuffer().then(buffer => {
WebAssembly.compile(buffer).then(module => {
WebAssembly.instantiate(module, { env }).then(mod => {
wasm = mod;
app = wasm.exports.init();
frame();
});
});
});
});
}
function findWasm(debug) {
fetch('Cargo.toml').then(response => {
response.text().then(text => {
text.split('\n').map(line => {
let tokens = line.split('"');
if (tokens[0] == 'name = ') {
let file = tokens[1].replaceAll('-', '_');
startWasm(file, debug);
}
});
});
});
}
function onLoad() {
let hash = document.location.hash;
let debug;
if (hash == '#debug') {
debug = true;
} else if (hash == '#release') {
debug = false;
} else {
if (confirm('Use release build?')) {
document.location = '#release';
debug = false;
} else if (confirm('Use debug build?')) {
document.location = '#debug';
debug = true;
} else {
document.location = '';
}
}
findWasm(debug);
}
</script>
</body>
</html>