rkgk/static/wall.js

137 lines
3.5 KiB
JavaScript
Raw Normal View History

import { OnlineUsers } from "rkgk/online-users.js";
2024-08-10 23:13:20 +02:00
export class Chunk {
constructor(chunkAllocator) {
this.id = chunkAllocator.alloc();
2024-08-10 23:13:20 +02:00
}
2024-08-15 20:01:23 +02:00
destroy(chunkAllocator) {
chunkAllocator.dealloc(this.id);
2024-08-15 20:01:23 +02:00
}
upload(chunkAllocator, source) {
chunkAllocator.upload(this.id, source);
2024-09-03 22:16:28 +02:00
}
download(chunkAllocator) {
return chunkAllocator.download(this.id);
2024-08-15 20:01:23 +02:00
}
2024-08-10 23:13:20 +02:00
}
let layerIdCounter = 0;
2024-08-10 23:13:20 +02:00
export class Layer {
chunks = new Map();
id = layerIdCounter++;
constructor({ name, chunkSize, chunkLimit }) {
this.name = name;
this.chunkSize = chunkSize;
this.chunkLimit = chunkLimit;
console.info("created layer", this.id, this.name);
2024-08-10 23:13:20 +02:00
}
destroy() {
for (let { chunk } of this.chunks.values()) {
chunk.destroy();
}
2024-08-10 23:13:20 +02:00
}
getChunk(x, y) {
return this.chunks.get(chunkKey(x, y))?.chunk;
2024-08-10 23:13:20 +02:00
}
getOrCreateChunk(chunkAllocator, x, y) {
let key = chunkKey(x, y);
if (this.chunks.has(key)) {
return this.chunks.get(key)?.chunk;
2024-08-10 23:13:20 +02:00
} else {
if (this.chunkLimit != null && this.chunks.size >= this.chunkLimit) return null;
let chunk = new Chunk(chunkAllocator);
this.chunks.set(key, { x, y, chunk });
2024-08-10 23:13:20 +02:00
return chunk;
}
}
compositeAlpha(src) {
// TODO
// for (let { x, y, chunk: srcChunk } of src.chunks.values()) {
// srcChunk.syncFromPixmap();
// let dstChunk = this.getOrCreateChunk(x, y);
// if (dstChunk == null) continue;
// dstChunk.ctx.globalCompositeOperation = "source-over";
// dstChunk.ctx.drawImage(srcChunk.canvas, 0, 0);
// dstChunk.syncToPixmap();
// dstChunk.markModified();
// }
}
async toEdits() {
let edits = [];
// TODO
// let start = performance.now();
// for (let { x, y, chunk } of this.chunks.values()) {
// edits.push({
// chunk: { x, y },
// data: chunk.canvas.convertToBlob({ type: "image/png" }),
// });
// }
// for (let edit of edits) {
// edit.data = await edit.data;
// }
// let end = performance.now();
// console.debug("toEdits done", end - start);
return edits;
}
}
export function chunkKey(x, y) {
return `${x},${y}`;
}
export class Wall {
layers = []; // do not modify directly; only read
#layersById = new Map();
constructor(wallInfo) {
this.chunkSize = wallInfo.chunkSize;
this.paintArea = wallInfo.paintArea;
this.maxEditSize = wallInfo.maxEditSize;
this.onlineUsers = new OnlineUsers(wallInfo);
this.mainLayer = new Layer({ name: "main", chunkSize: this.chunkSize });
this.addLayer(this.mainLayer);
}
addLayer(layer) {
if (!this.#layersById.get(layer.id)) {
this.layers.push(layer);
this.#layersById.set(layer.id, layer);
} else {
console.warn("attempt to add layer more than once", layer);
}
return layer;
}
removeLayer(layer) {
if (this.#layersById.delete(layer.id)) {
let index = this.layers.findIndex((x) => x == layer);
this.layers.splice(index, 1);
} else {
console.warn("attempt to remove layer more than once", layer);
}
}
getLayerById(id) {
return this.#layersById.get(id);
}
2024-08-10 23:13:20 +02:00
}