Mirai's Miscellaneous Misadventures

M4 / main.js

let canvas = document.querySelector("canvas")
let context = canvas.getContext("2d")

let global = v =>
{
	if (typeof v === "number") return v
	return v.value
}

let main = async () =>
{
	let stamp = (data, x, y, image) =>
	{
		let view = getView()
		let width = view.getUint32(image, true)
		let height = view.getUint32(image + 4, true)
		context.rect(x - width / 2, y - height, width, height)
	}
	
	let imports = {env: {mirai_wasm_javascript_stamp: stamp}}
	let module
	try {module = await WebAssembly.instantiateStreaming(fetch("mimimi.wasm"), imports) }
	catch (e) { module = await WebAssembly.instantiate(await (await fetch("mimimi.wasm")).arrayBuffer(), imports) }
	
	let {instance: {exports}} = module
	
	let {memory, __heap_base: base, __indirect_function_table: table} = exports
	let {mirai_game_size, mirai_width, mirai_height} = exports
	let {mirai_start, mirai_step, mirai_assets} = exports
	let {mirai_wasm_stamp} = exports
	
	let getView = () => new DataView(memory.buffer)
	
	let view = getView()
	
	let offset = global(base)
	let size = view.getUint32(global(mirai_game_size), true)
	let width = view.getUint32(global(mirai_width), true)
	let height = view.getUint32(global(mirai_height), true)
	canvas.width = width
	canvas.height = height
	
	let alloc = size =>
	{
		let view = getView()
		let available = view.byteLength - offset
		
		if (available < size)
			memory.grow(Math.ceil((size - available) / 1024))
		
		let result = offset
		offset += size
		return result
	}
	
	let game = alloc(size)
	let engine = alloc(8)
	let keys = alloc(1)
	
	let f = table.grow(1)
	getView().setUint32(engine + 4, f, true)
	table.set(f, mirai_wasm_stamp)
	
	mirai_start(game, engine)
	
	let inputs = {ArrowLeft: 1, ArrowRight: 2}
	let down = 0
	
	addEventListener("keydown", ({code}) =>
	{
		let v = inputs[code]
		if (v) down = down | v
	})
	
	addEventListener("keyup", ({code}) =>
	{
		let v = inputs[code]
		if (v) down = down & ~v
		v %= 0x100
	})
	
	/*
	let image = new ImageData(width, height)
	let {data} = image
	for (let x = 0 ; x < width ; x++)
	for (let y = 0 ; y < height ; y++)
		data[(x + y * width) * 4 + 3] = 0xFF
	*/
	
	view = getView()
	let past = performance.now()
	let step = () =>
	{
		context.beginPath()
		context.rect(0, 0, width, height)
		context.fillStyle = "#EEE"
		context.fill()
		context.beginPath()
		view.setUint32(keys, down, true)
		mirai_step(game, keys)
		context.fillStyle = "#333"
		context.fill()
		
		let now = performance.now()
		setTimeout(step, (100/3) + past - now)
		past = now
	}
	step()
}

main()