You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
195 lines
5.2 KiB
195 lines
5.2 KiB
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]);
|
|
let fg = to_color(chars[index + 1]);
|
|
let bg = chars[index + 2] === 0 ? null : to_color(chars[index + 2]);
|
|
|
|
if (ch !== " ") {
|
|
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;
|
|
}
|
|
}
|
|
|
|
ctx.fillStyle = inside ? "#606060" : "#404040";
|
|
ctx.fillRect(
|
|
Math.round(x2 + tile_size / 2) - zoom_factor,
|
|
Math.round(y2 + tile_size / 2) - zoom_factor,
|
|
Math.max(zoom_factor, 2.0),
|
|
Math.max(zoom_factor, 2.0)
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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];
|
|
}
|