|
31 | 31 | const BIT_ROT = 10; |
32 | 32 |
|
33 | 33 | // Set up the canvas with a 2D rendering context |
34 | | -var cnv = document.getElementsByTagName("canvas")[0]; |
35 | | -var ctx = cnv.getContext("2d"); |
36 | | -var bcr = cnv.getBoundingClientRect(); |
| 34 | +var canvas = document.getElementsByTagName("canvas")[0]; |
| 35 | +var ctx = canvas.getContext("2d"); |
| 36 | +var bcr = canvas.getBoundingClientRect(); |
37 | 37 |
|
38 | 38 | // Compute the size of the universe (here: 2px per cell) |
39 | | -var width = bcr.width >>> 1; |
40 | | -var height = bcr.height >>> 1; |
41 | | -var size = width * height; |
42 | | -var byteSize = (size + size) << 2; // input & output (here: 4b per cell) |
| 39 | +var width = bcr.width >>> 1; |
| 40 | +var height = bcr.height >>> 1; |
| 41 | +var size = width * height; |
| 42 | +var byteSize = (2 * size) << 2; // input & output (here: 4b per cell) |
43 | 43 |
|
44 | | -cnv.width = width; |
45 | | -cnv.height = height; |
46 | | -cnv.style = ` |
| 44 | +canvas.width = width; |
| 45 | +canvas.height = height; |
| 46 | +canvas.style = ` |
47 | 47 | image-rendering: optimizeSpeed; |
48 | 48 | image-rendering: -moz-crisp-edges; |
49 | 49 | image-rendering: -webkit-optimize-contrast; |
|
56 | 56 | ctx.imageSmoothingEnabled = false; |
57 | 57 |
|
58 | 58 | // Compute the size of and instantiate the module's memory |
59 | | -var memory = new WebAssembly.Memory({ initial: ((byteSize + 0xffff) & ~0xffff) >>> 16 }); |
| 59 | +var memory = new WebAssembly.Memory({ |
| 60 | + initial: ((byteSize + 0xffff) & ~0xffff) >>> 16 |
| 61 | +}); |
60 | 62 |
|
61 | 63 | // Fetch and instantiate the module |
62 | | -fetch("build/optimized.wasm") |
| 64 | +fetch("build/release.wasm") |
63 | 65 | .then(response => response.arrayBuffer()) |
64 | 66 | .then(buffer => WebAssembly.instantiate(buffer, { |
65 | 67 | env: { |
66 | 68 | memory, |
67 | | - abort: function() {}, |
| 69 | + abort() {}, |
68 | 70 | "Math.random": Math.random |
69 | 71 | }, |
70 | 72 | config: { |
71 | | - BGR_ALIVE : rgb2bgr(RGB_ALIVE) | 1, // little endian, LSB must be set |
72 | | - BGR_DEAD : rgb2bgr(RGB_DEAD) & ~1, // little endian, LSB must not be set |
73 | | - BIT_ROT |
| 73 | + BIT_ROT, |
| 74 | + BGR_ALIVE: rgb2bgr(RGB_ALIVE) | 1, // little endian, LSB must be set |
| 75 | + BGR_DEAD: rgb2bgr(RGB_DEAD) & ~1, // little endian, LSB must not be set |
74 | 76 | }, |
75 | 77 | })) |
76 | 78 | .then(module => { |
|
84 | 86 | // Update about 30 times a second |
85 | 87 | (function update() { |
86 | 88 | setTimeout(update, 1000 / 30); |
87 | | - mem.copyWithin(0, size, size + size); // copy output to input |
88 | | - exports.step(); // perform the next step |
| 89 | + mem.copyWithin(0, size, 2 * size); // copy output to input |
| 90 | + exports.step(); // perform the next step |
89 | 91 | })(); |
90 | 92 |
|
91 | 93 | // Keep rendering the output at [size, 2*size] |
92 | 94 | var imageData = ctx.createImageData(width, height); |
93 | 95 | var argb = new Uint32Array(imageData.data.buffer); |
| 96 | + |
94 | 97 | (function render() { |
95 | 98 | requestAnimationFrame(render); |
96 | | - argb.set(mem.subarray(size, size + size)); // copy output to image buffer |
97 | | - ctx.putImageData(imageData, 0, 0); // apply image buffer |
| 99 | + argb.set(mem.subarray(size, 2 * size)); // copy output to image buffer |
| 100 | + ctx.putImageData(imageData, 0, 0); // apply image buffer |
98 | 101 | })(); |
99 | 102 |
|
100 | 103 | // When clicked or dragged, fill the current row and column with random live cells |
101 | | - var down = false; |
102 | | - [ [cnv, "mousedown"], |
103 | | - [cnv, "touchstart"] |
104 | | - ].forEach(eh => eh[0].addEventListener(eh[1], e => down = true)); |
105 | | - [ [document, "mouseup"], |
106 | | - [document, "touchend"] |
107 | | - ].forEach(eh => eh[0].addEventListener(eh[1], e => down = false)); |
108 | | - [ [cnv, "mousemove"], |
109 | | - [cnv, "touchmove"], |
110 | | - [cnv, "mousedown"] |
111 | | - ].forEach(eh => eh[0].addEventListener(eh[1], e => { |
112 | | - if (!down) return; |
113 | | - var loc; |
114 | | - if (e.touches) { |
115 | | - if (e.touches.length > 1) return; |
116 | | - loc = e.touches[0]; |
117 | | - } else { |
118 | | - loc = e; |
119 | | - } |
120 | | - var bcr = cnv.getBoundingClientRect(); |
121 | | - exports.fill((loc.clientX - bcr.left) >>> 1, (loc.clientY - bcr.top) >>> 1, 0.5); |
122 | | - })); |
| 104 | + let down = false; |
| 105 | + for (const ty of ["mousedown", "touchstart"]) { |
| 106 | + canvas.addEventListener(ty, e => down = true); |
| 107 | + } |
| 108 | + for (const ty of ["mouseup", "touchend"]) { |
| 109 | + document.addEventListener(ty, e => down = false); |
| 110 | + } |
| 111 | + for (const ty of ["mousemove", "touchmove", "mousedown"]) { |
| 112 | + canvas.addEventListener(ty, e => { |
| 113 | + if (!down) return; |
| 114 | + const touches = e.touches; |
| 115 | + let loc; |
| 116 | + if (touches) { |
| 117 | + if (touches.length > 1) return; |
| 118 | + loc = touches[0]; |
| 119 | + } else { |
| 120 | + loc = e; |
| 121 | + } |
| 122 | + const rect = canvas.getBoundingClientRect(); |
| 123 | + exports.fill( |
| 124 | + (loc.clientX - rect.left) >>> 1, |
| 125 | + (loc.clientY - rect.top) >>> 1, |
| 126 | + 0.5 |
| 127 | + ); |
| 128 | + }); |
| 129 | + } |
123 | 130 |
|
124 | 131 | // :-( |
125 | | - if (navigator.userAgent.indexOf(" Edge/") >= 0) document.getElementById("edge").style.display = "block"; |
| 132 | + if (navigator.userAgent.includes(" Edge/")) { |
| 133 | + document.getElementById("edge").style.display = "block"; |
| 134 | + } |
126 | 135 | }).catch(err => { |
127 | 136 | alert("Failed to load WASM: " + err.message + " (ad blocker, maybe?)"); |
128 | 137 | console.log(err.stack); |
|
0 commit comments