rkgk/static/index.js
2024-08-10 23:10:22 +02:00

155 lines
4.3 KiB
JavaScript

let panicImpl;
let logImpl;
function makeLogFunction(level) {
return (length, pMessage) => {
logImpl(level, length, pMessage);
};
}
let { instance: hakuInstance, module: hakuModule } = await WebAssembly.instantiateStreaming(
fetch(import.meta.resolve("./wasm/haku.wasm")),
{
env: {
panic(length, pMessage) {
panicImpl(length, pMessage);
},
trace: makeLogFunction("trace"),
debug: makeLogFunction("debug"),
info: makeLogFunction("info"),
warn: makeLogFunction("warn"),
error: makeLogFunction("error"),
},
},
);
let memory = hakuInstance.exports.memory;
let w = hakuInstance.exports;
let textEncoder = new TextEncoder();
function allocString(string) {
let size = string.length * 3;
let align = 1;
let pString = w.haku_alloc(size, align);
let buffer = new Uint8Array(memory.buffer, pString, size);
let result = textEncoder.encodeInto(string, buffer);
return {
ptr: pString,
length: result.written,
size,
align,
};
}
function freeString(alloc) {
w.haku_free(alloc.ptr, alloc.size, alloc.align);
}
let textDecoder = new TextDecoder();
function readString(size, pString) {
let buffer = new Uint8Array(memory.buffer, pString, size);
return textDecoder.decode(buffer);
}
function readCString(pCString) {
let memoryBuffer = new Uint8Array(memory.buffer);
let pCursor = pCString;
while (memoryBuffer[pCursor] != 0 && memoryBuffer[pCursor] != null) {
pCursor++;
}
let size = pCursor - pCString;
return readString(size, pCString);
}
class Panic extends Error {
name = "Panic";
}
panicImpl = (length, pMessage) => {
throw new Panic(readString(length, pMessage));
};
logImpl = (level, length, pMessage) => {
console[level](readString(length, pMessage));
};
w.haku_init_logging();
/* ------ */
let renderCanvas = document.getElementById("render");
let codeTextArea = document.getElementById("code");
let outputP = document.getElementById("output");
let ctx = renderCanvas.getContext("2d");
function rerender() {
console.log("rerender");
let width = renderCanvas.width;
let height = renderCanvas.height;
let logs = [];
let pInstance = w.haku_instance_new();
let pBrush = w.haku_brush_new();
let pBitmap = w.haku_bitmap_new(width, height);
let code = allocString(codeTextArea.value);
let deallocEverything = () => {
freeString(code);
w.haku_bitmap_destroy(pBitmap);
w.haku_brush_destroy(pBrush);
w.haku_instance_destroy(pInstance);
outputP.textContent = logs.join("\n");
};
let compileStatusCode = w.haku_compile_brush(pInstance, pBrush, code.length, code.ptr);
let pCompileStatusString = w.haku_status_string(compileStatusCode);
logs.push(`compile: ${readCString(pCompileStatusString)}`);
for (let i = 0; i < w.haku_num_diagnostics(pBrush); ++i) {
let start = w.haku_diagnostic_start(pBrush, i);
let end = w.haku_diagnostic_end(pBrush, i);
let length = w.haku_diagnostic_message_len(pBrush, i);
let pMessage = w.haku_diagnostic_message(pBrush, i);
let message = readString(length, pMessage);
logs.push(`${start}..${end}: ${message}`);
}
if (w.haku_num_diagnostics(pBrush) > 0) {
deallocEverything();
return;
}
let renderStatusCode = w.haku_render_brush(pInstance, pBrush, pBitmap);
let pRenderStatusString = w.haku_status_string(renderStatusCode);
logs.push(`render: ${readCString(pRenderStatusString)}`);
if (w.haku_has_exception(pInstance)) {
let length = w.haku_exception_message_len(pInstance);
let pMessage = w.haku_exception_message(pInstance);
let message = readString(length, pMessage);
logs.push(`exception: ${message}`);
deallocEverything();
return;
}
let pBitmapData = w.haku_bitmap_data(pBitmap);
let bitmapDataBuffer = new Float32Array(memory.buffer, pBitmapData, width * height * 4);
let imageData = new ImageData(width, height);
for (let i = 0; i < bitmapDataBuffer.length; ++i) {
imageData.data[i] = bitmapDataBuffer[i] * 255;
}
ctx.putImageData(imageData, 0, 0);
deallocEverything();
}
rerender();
codeTextArea.addEventListener("input", rerender);