Mirai's Miscellaneous Misadventures

M4 / main.js

1let canvas = document.querySelector("canvas")
2let context = canvas.getContext("2d")
3
4let global = v =>
5{
6	if (typeof v === "number") return v
7	return v.value
8}
9
10let main = async () =>
11{
12	let stamp = (data, x, y, image) =>
13	{
14		let view = getView()
15		let width = view.getUint32(image, true)
16		let height = view.getUint32(image + 4, true)
17		context.rect(x - width / 2, y - height, width, height)
18	}
19	
20	let imports = {env: {mirai_wasm_javascript_stamp: stamp}}
21	let module
22	try {module = await WebAssembly.instantiateStreaming(fetch("mimimi.wasm"), imports) }
23	catch (e) { module = await WebAssembly.instantiate(await (await fetch("mimimi.wasm")).arrayBuffer(), imports) }
24	
25	let {instance: {exports}} = module
26	
27	let {memory, __heap_base: base, __indirect_function_table: table} = exports
28	let {mirai_game_size, mirai_width, mirai_height} = exports
29	let {mirai_start, mirai_step, mirai_assets} = exports
30	let {mirai_wasm_stamp} = exports
31	
32	let getView = () => new DataView(memory.buffer)
33	
34	let view = getView()
35	
36	let offset = global(base)
37	let size = view.getUint32(global(mirai_game_size), true)
38	let width = view.getUint32(global(mirai_width), true)
39	let height = view.getUint32(global(mirai_height), true)
40	canvas.width = width
41	canvas.height = height
42	
43	let alloc = size =>
44	{
45		let view = getView()
46		let available = view.byteLength - offset
47		
48		if (available < size)
49			memory.grow(Math.ceil((size - available) / 1024))
50		
51		let result = offset
52		offset += size
53		return result
54	}
55	
56	let game = alloc(size)
57	let engine = alloc(8)
58	let keys = alloc(1)
59	
60	let f = table.grow(1)
61	getView().setUint32(engine + 4, f, true)
62	table.set(f, mirai_wasm_stamp)
63	
64	mirai_start(game, engine)
65	
66	let inputs = {ArrowLeft: 1, ArrowRight: 2}
67	let down = 0
68	
69	addEventListener("keydown", ({code}) =>
70	{
71		let v = inputs[code]
72		if (v) down = down | v
73	})
74	
75	addEventListener("keyup", ({code}) =>
76	{
77		let v = inputs[code]
78		if (v) down = down & ~v
79		v %= 0x100
80	})
81	
82	/*
83	let image = new ImageData(width, height)
84	let {data} = image
85	for (let x = 0 ; x < width ; x++)
86	for (let y = 0 ; y < height ; y++)
87		data[(x + y * width) * 4 + 3] = 0xFF
88	*/
89	
90	view = getView()
91	let past = performance.now()
92	let step = () =>
93	{
94		context.beginPath()
95		context.rect(0, 0, width, height)
96		context.fillStyle = "#EEE"
97		context.fill()
98		context.beginPath()
99		view.setUint32(keys, down, true)
100		mirai_step(game, keys)
101		context.fillStyle = "#333"
102		context.fill()
103		
104		let now = performance.now()
105		setTimeout(step, (100/3) + past - now)
106		past = now
107	}
108	step()
109}
110
111main()