Mirai's Miscellaneous Misadventures
M22 / index.html
1<!-- copyright 2022 zamfofex -->
2<!-- license: AGPLv3 or later -->
3
4<!doctype html>
5<html lang="en">
6<meta charset="utf-8">
7
8<title>Mirai’s Miscellaneous Misadventures</title>
9
10<style>
11
12html, body
13{
14 width: 100%;
15 height: 100%;
16 display: flex;
17}
18
19body
20{
21 margin: 0;
22 background: #000;
23 touch-action: manipulation;
24}
25
26canvas
27{
28 width: 100%;
29 height: 100%;
30 image-rendering: crisp-edges;
31 image-rendering: pixelated;
32 object-fit: contain;
33}
34
35</style>
36
37<script type="module">
38
39let canvas = document.querySelector("canvas")
40let context = canvas.getContext("2d")
41
42let global = v =>
43{
44 if (typeof v === "number") return v
45 return v.value
46}
47
48let main = async () =>
49{
50 let stamp = (data, x, y, asset) =>
51 {
52 let image = toImage(asset)
53 if (!image) return
54 context.drawImage(image, x, y)
55 }
56
57 let memcpy = (a, b, n) =>
58 {
59 new Uint8Array(memory.buffer, a, n).set(new Uint8Array(memory.buffer, b, n))
60 return a
61 }
62
63 let memmove = (a, b, n) =>
64 {
65 new Uint8Array(memory.buffer, a, n).set(new Uint8Array(memory.buffer, b, n).slice())
66 return a
67 }
68
69 let memset = (a, b, n) =>
70 {
71 new Uint8Array(memory.buffer, a, n).set(Array(n).fill(b))
72 return a
73 }
74
75 let memcmp = (a, b, n) =>
76 {
77 a = new Uint8Array(memory.buffer, a, n)
78 b = new Uint8Array(memory.buffer, b, n)
79 for (let i = 0 ; i < n ; i++)
80 if (a[i] !== b[i]) return a[i] - b[i]
81 return 0
82 }
83
84 let imports = {env: {mimimi_wasm_javascript_stamp: stamp, memcpy, memmove, memset, memcmp}}
85 let module
86 try { module = await WebAssembly.instantiateStreaming(fetch("mimimi.wasm"), imports) }
87 catch (e) { module = await WebAssembly.instantiate(await (await fetch("mimimi.wasm")).arrayBuffer(), imports) }
88
89 let {instance: {exports}} = module
90
91 let {memory, __indirect_function_table: table} = exports
92 let {mimimi_wasm_allocator} = exports
93 let {mimimi_wasm_allocate} = exports
94 let {mimimi_wasm_stamp} = exports
95 let {mimimi_test} = exports
96
97 let getView = () => new DataView(memory.buffer)
98 let allocator = getView().getUint32(global(mimimi_wasm_allocator), true)
99
100 let chapter = mimimi_test(allocator)
101 let behavior = getView().getUint32(chapter, true)
102 let engine = getView().getUint32(chapter + 4, true)
103 let keys = chapter + 8
104
105 let size = mimimi_wasm_allocate(8)
106 getView().setUint32(size + 0, canvas.width, true)
107 getView().setUint32(size + 4, canvas.height, true)
108
109 let f = table.grow(1)
110 table.set(f, mimimi_wasm_stamp)
111
112 getView().setUint32(engine + 4, f, true)
113 getView().setUint32(engine + 8, size, true)
114
115 let inputs = {ArrowLeft: 1, ArrowRight: 2}
116 let down = 0
117
118 addEventListener("keydown", ({code}) =>
119 {
120 let v = inputs[code]
121 if (v) down = down | v
122 })
123
124 addEventListener("keyup", ({code}) =>
125 {
126 let v = inputs[code]
127 if (v) down = down & ~v
128 down %= 0x100
129 })
130
131 let tap = 0
132 addEventListener("pointerdown", ({x, y, button}) =>
133 {
134 if (button !== 0) return
135
136 if (x < innerWidth / 2)
137 tap = tap | 1
138 else
139 tap = tap | 2
140 })
141 addEventListener("pointerup", () => tap = 0)
142
143 let cache = new Map()
144
145 let rch = [0x11, 0x44, 0x77, 0x99, 0xCC, 0xFF]
146 let gch = [0x11, 0x33, 0x55, 0x77, 0x99, 0xBB, 0xDD, 0xFF]
147 let bch = [0x22, 0x55, 0x88, 0xBB, 0xEE]
148 let toImage = asset =>
149 {
150 let view = getView()
151
152 let cached = cache.get(asset)
153 if (cached !== undefined) return cached
154
155 let width = view.getUint32(asset, true)
156 let height = view.getUint32(asset + 4, true)
157 let colors = view.getUint32(asset + 8, true)
158
159 if (width === 0 || height === 0)
160 {
161 cache.set(asset, null)
162 return null
163 }
164
165 let image = new ImageData(width, height)
166 let {data} = image
167
168 for (let x = 0 ; x < width ; x++)
169 for (let y = 0 ; y < height ; y++)
170 {
171 let o = x + y * width
172 let color = view.getUint8(colors + o)
173
174 if (color === 0) continue
175
176 if (color < 0x10)
177 {
178 let ch = color * 0x11
179 data[o * 4 + 0] = ch
180 data[o * 4 + 1] = ch
181 data[o * 4 + 2] = ch
182 data[o * 4 + 3] = 0xFF
183 }
184 else
185 {
186 color -= 0x10
187 let r = rch[Math.floor(color / 40) % 6]
188 let g = gch[Math.floor(color / 5) % 8]
189 let b = bch[Math.floor(color / 1) % 5]
190
191 data[o * 4 + 0] = r
192 data[o * 4 + 1] = g
193 data[o * 4 + 2] = b
194 data[o * 4 + 3] = 0xFF
195 }
196 }
197
198 let canvas = document.createElement("canvas")
199 let ctx = canvas.getContext("2d")
200 canvas.width = image.width
201 canvas.height = image.height
202 ctx.putImageData(image, 0, 0)
203
204 cache.set(asset, canvas)
205 return canvas
206 }
207
208 let past = performance.now()
209 let step = () =>
210 {
211 let view = getView()
212
213 view.setUint8(keys, down|tap)
214 table.get(view.getUint32(behavior, true))(view.getUint32(behavior + 8, true))
215
216 let now = performance.now()
217 setTimeout(step, (100/3) + past - now)
218 past = now
219 }
220 step()
221}
222
223main()
224
225</script>
226
227<canvas width="512" height="256"></canvas>