import init, { World, Pane, FullTile, Signal, available_tiles, } from "/stackline-wasm/pkg/stackline_wasm.js"; let promises = []; promises.push(init()); const canvas = document.getElementById("main-canvas"); const ctx = canvas.getContext("2d"); let font = new FontFace("Stackline Classic", "url(\"/font/StacklineClassic-Medium.otf\")"); promises.push(font.load()); await Promise.all(promises); font = await font.loaded; document.fonts.add(font); let world = World.new(); let cx = 0; let cy = 0; let zoom = 1; let pane = Pane.empty(5, 5); world.set_pane("main", pane); let available = available_tiles(); console.log(available); for (let n = 0; n < available.length; n++) { world.set( n % 5, ~~(n / 5), new FullTile(available[n]) ); } console.log(world.toString()); resize(); window.addEventListener("resize", resize); window.requestAnimationFrame(loop); function draw() { let zoom_factor = Math.ceil(Math.pow(2, zoom)); let tile_size = 10 * zoom_factor; ctx.fillStyle = "#202027"; ctx.fillRect(0, 0, canvas.width, canvas.height); let panes = []; for (let name of world.panes()) { let pane = world.get_pane(name); ctx.strokeStyle = "rgba(128, 128, 128, 0.5)"; ctx.lineWidth = zoom_factor; panes.push({ x: pane.x, y: pane.y, width: pane.width, height: pane.height }); ctx.strokeRect( Math.round(pane.x * tile_size + cx + canvas.width / 2) - zoom_factor * 1.5, Math.round(pane.y * tile_size + cy + canvas.height / 2) - zoom_factor * 1.5, Math.round(pane.width * tile_size) + zoom_factor * 3, Math.round(pane.height * tile_size) + zoom_factor * 3, ); pane.free(); } let from_y = Math.floor((-cy - canvas.height / 2) / tile_size); let to_y = Math.ceil((-cy + canvas.height / 2) / tile_size); let from_x = Math.floor((-cx - canvas.width / 2) / tile_size); let to_x = Math.ceil((-cx + canvas.width / 2) / tile_size); let width = to_x - from_x + 1; let height = to_y - from_y + 1; // TODO: memoize let chars = world.draw(-from_x, -from_y, width, height); ctx.textAlign = "left"; ctx.textBaseline = "top"; ctx.font = `${tile_size}px Stackline Classic`; for (let y = from_y; y <= to_y; y++) { for (let x = from_x; x <= to_x; x++) { let x2 = x * tile_size + cx + canvas.width / 2; let y2 = y * tile_size + cy + canvas.height / 2; let index = 3 * (width * (y - from_y) + x - from_x); let ch = String.fromCharCode(chars[index]); if (ch !== " ") { let fg = to_color(chars[index + 1]); let bg = chars[index + 2] === 0 ? null : to_color(chars[index + 2]); if (bg) { ctx.fillStyle = `rgba(${bg.join(",")})`; ctx.fillRect( Math.round(x2), Math.round(y2), Math.round(x2 + tile_size) - Math.round(x2), Math.round(y2 + tile_size) - Math.round(y2), ); } ctx.fillStyle = `rgba(${fg.join(",")})`; ctx.fillText( ch, Math.round(x2), Math.round(y2), ); } else { // Draw grid let inside = false; for (let pane of panes) { if (x >= pane.x && x < pane.x + pane.width && y >= pane.y && y < pane.y + pane.height) { inside = true; break; } } if (inside || width < 100 && height < 100) { ctx.fillStyle = inside ? "#505050" : "#303030"; ctx.fillRect( Math.round(x2 + tile_size / 2) - zoom_factor, Math.round(y2 + tile_size / 2) - zoom_factor, zoom_factor, zoom_factor ); } } } } } function resize() { canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; draw(); } function loop() { draw(); window.requestAnimationFrame(loop); } let mouse_x = 0, mouse_y = 0; let mouse_down = false; canvas.addEventListener("mousedown", (evt) => { mouse_x = evt.clientX; mouse_y = evt.clientY; mouse_down = true; }); canvas.addEventListener("mousemove", (evt) => { if (mouse_down) { // TODO: numerically stable solution cx += evt.clientX - mouse_x; cy += evt.clientY - mouse_y; mouse_x = evt.clientX; mouse_y = evt.clientY; } }); canvas.addEventListener("mouseup", (evt) => { mouse_down = false; }); canvas.addEventListener("mouseleave", (evt) => { mouse_down = false; }); canvas.addEventListener("wheel", (event) => { const ZOOM_STRENGTH = -0.005; zoom += event.deltaY * ZOOM_STRENGTH; zoom = Math.min(Math.max(zoom, 0.0), 4.0); }); function to_color(num) { let alpha = (num >> 24) & 0xff; let red = (num >> 16) & 0xff; let green = (num >> 8) & 0xff; let blue = num & 0xff; return [red, green, blue, alpha]; }