a whole load of work in progress

This commit is contained in:
りき萌 2024-08-10 23:13:20 +02:00
parent caec0b8ac9
commit 26ba098183
63 changed files with 3234 additions and 321 deletions

View file

@ -1,154 +1,74 @@
let panicImpl;
let logImpl;
import { Painter } from "./painter.js";
import { Wall } from "./wall.js";
import { Haku } from "./haku.js";
import { getUserId, newSession, waitForLogin } from "./session.js";
import { debounce } from "./framework.js";
function makeLogFunction(level) {
return (length, pMessage) => {
logImpl(level, length, pMessage);
};
}
let main = document.querySelector("main");
let canvasRenderer = main.querySelector("rkgk-canvas-renderer");
let reticleRenderer = main.querySelector("rkgk-reticle-renderer");
let brushEditor = main.querySelector("rkgk-brush-editor");
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 haku = new Haku();
let painter = new Painter(512);
let memory = hakuInstance.exports.memory;
let w = hakuInstance.exports;
reticleRenderer.connectViewport(canvasRenderer.viewport);
canvasRenderer.addEventListener(".viewportUpdate", () => reticleRenderer.updateTransform());
let textEncoder = new TextEncoder();
function allocString(string) {
let size = string.length * 3;
let align = 1;
let pString = w.haku_alloc(size, align);
// In the background, connect to the server.
(async () => {
await waitForLogin();
console.info("login ready! starting session");
let buffer = new Uint8Array(memory.buffer, pString, size);
let result = textEncoder.encodeInto(string, buffer);
let session = await newSession(getUserId(), localStorage.getItem("rkgk.mostRecentWallId"));
localStorage.setItem("rkgk.mostRecentWallId", session.wallId);
return {
ptr: pString,
length: result.written,
size,
align,
};
}
let wall = new Wall(session.wallInfo.chunkSize);
canvasRenderer.initialize(wall);
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++;
for (let onlineUser of session.wallInfo.online) {
wall.onlineUsers.addUser(onlineUser.sessionId, { nickname: onlineUser.nickname });
}
let size = pCursor - pCString;
return readString(size, pCString);
}
session.addEventListener("error", (event) => console.error(event));
session.addEventListener("action", (event) => {
if (event.kind.event == "cursor") {
let reticle = reticleRenderer.getOrAddReticle(wall.onlineUsers, event.sessionId);
let { x, y } = event.kind.position;
reticle.setCursor(x, y);
}
});
class Panic extends Error {
name = "Panic";
}
let compileBrush = () => haku.setBrush(brushEditor.code);
compileBrush();
brushEditor.addEventListener(".codeChanged", () => compileBrush());
panicImpl = (length, pMessage) => {
throw new Panic(readString(length, pMessage));
};
let reportCursor = debounce(1000 / 60, (x, y) => session.reportCursor(x, y));
canvasRenderer.addEventListener(".cursor", async (event) => {
reportCursor(event.x, event.y);
});
logImpl = (level, length, pMessage) => {
console[level](readString(length, pMessage));
};
canvasRenderer.addEventListener(".paint", async (event) => {
painter.renderBrush(haku);
let imageBitmap = await painter.createImageBitmap();
w.haku_init_logging();
let left = event.x - painter.paintArea / 2;
let top = event.y - painter.paintArea / 2;
/* ------ */
let leftChunk = Math.floor(left / wall.chunkSize);
let topChunk = Math.floor(top / wall.chunkSize);
let rightChunk = Math.ceil((left + painter.paintArea) / wall.chunkSize);
let bottomChunk = Math.ceil((top + painter.paintArea) / wall.chunkSize);
for (let chunkY = topChunk; chunkY < bottomChunk; ++chunkY) {
for (let chunkX = leftChunk; chunkX < rightChunk; ++chunkX) {
let chunk = wall.getOrCreateChunk(chunkX, chunkY);
let x = Math.floor(-chunkX * wall.chunkSize + left);
let y = Math.floor(-chunkY * wall.chunkSize + top);
chunk.ctx.drawImage(imageBitmap, x, y);
}
}
imageBitmap.close();
});
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);
session.eventLoop();
})();