initial commit
This commit is contained in:
commit
caec0b8ac9
27 changed files with 4786 additions and 0 deletions
18
static/index.html
Normal file
18
static/index.html
Normal file
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>canvane</title>
|
||||
<script src="static/index.js" type="module"></script>
|
||||
<script src="static/live-reload.js" type="module"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<main>
|
||||
<canvas id="render" width="256" height="256">Please enable JavaScript</canvas>
|
||||
<br>
|
||||
<textarea id="code" cols="80" rows="25">(stroke 1 (rgba 0 0 0 255) (vec 32 32))</textarea>
|
||||
<p id="output" style="white-space: pre-wrap;"></p>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
154
static/index.js
Normal file
154
static/index.js
Normal file
|
@ -0,0 +1,154 @@
|
|||
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);
|
16
static/live-reload.js
Normal file
16
static/live-reload.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
// NOTE: The server never fulfills this request, it stalls forever.
|
||||
// Once the connection is closed, we try to connect with the server until we establish a successful
|
||||
// connection. Then we reload the page.
|
||||
await fetch("/dev/live-reload/stall").catch(async () => {
|
||||
while (true) {
|
||||
try {
|
||||
let response = await fetch("/dev/live-reload/back-up");
|
||||
if (response.status == 200) {
|
||||
window.location.reload();
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
}
|
||||
}
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue