Files
wireless-docs/texture.js
2026-07-05 10:14:01 -04:00

79 lines
2.5 KiB
JavaScript

export class TextureHandler {
constructor(size) {
this.canvas = document.createElement('canvas');
this.canvas.width = size;
this.canvas.height = size;
this.ctx = this.canvas.getContext('2d', {willReadFrequently: true});
this.ctx.imageSmoothingEnabled = false;
this.uvmap = new Map();
this.pendingDraws = new Map();
this.cellSize = 16;
this.padding = 1;
this.x = 0;
this.y = 0;
this.rowHeight = 0;
}
prepare(cache, id, url) {
if (this.x + this.cellSize > this.canvas.width) {
this.x = 0;
this.y += this.rowHeight + this.padding;
this.rowHeight = 0;
}
const currentX = this.x;
const currentY = this.y;
this.x += this.cellSize + this.padding;
this.rowHeight = Math.max(this.rowHeight, this.cellSize);
const uvData = {
u: currentX / this.canvas.width,
v: currentY / this.canvas.height,
du: this.cellSize / this.canvas.width,
dv: this.cellSize / this.canvas.height,
};
this.uvmap.set(id, uvData);
this.pendingDraws.set(id, {x: currentX, y: currentY});
}
async process(cache, id, url) {
const pos = this.pendingDraws.get(id);
if (!pos) throw new Error(`Not prepared for ${id}.`);
this.pendingDraws.delete(id);
const drawMissing = () => {
const half = this.cellSize / 2;
this.ctx.fillStyle = '#ff00ff'; // Magenta
this.ctx.fillRect(pos.x, pos.y, half, half);
this.ctx.fillRect(pos.x + half, pos.y + half, half, half);
this.ctx.fillStyle = '#000000'; // Black
this.ctx.fillRect(pos.x + half, pos.y, half, half);
this.ctx.fillRect(pos.x, pos.y + half, half, half);
};
if (id === ':missing') {
drawMissing();
return this.uvmap.get(id);
}
try {
const img = await new Promise((resolve, reject) => {
const i = new Image();
i.crossOrigin = 'anonymous';
i.onload = () => resolve(i);
i.onerror = () => reject(new Error(`Image load failed`));
i.src = url + '.png';
});
this.ctx.drawImage(img, pos.x, pos.y, this.cellSize, this.cellSize);
} catch (e) {
console.warn(`Missing texture: ${id}`);
drawMissing();
}
return this.uvmap.get(id);
}
}