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}); this.ctx.fillStyle = '#00000066'; this.ctx.fillRect(currentX, currentY, this.cellSize, this.cellSize); } getFallback(id) { return this.uvmap.get(id); // UVs map to the black silhouette! } 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 = '#33333366'; // Gray this.ctx.fillRect(pos.x, pos.y, half, half); this.ctx.fillRect(pos.x + half, pos.y + half, half, half); this.ctx.fillStyle = '#00000066'; // Black this.ctx.fillRect(pos.x + half, pos.y, half, half); this.ctx.fillRect(pos.x, pos.y + half, half, half); }; drawMissing(); if (id !== ':missing') { 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'; }); // await new Promise(r => setTimeout(r, 2000)) this.ctx.clearRect(pos.x, pos.y, this.cellSize, this.cellSize); this.ctx.drawImage(img, pos.x, pos.y, this.cellSize, this.cellSize); } catch (e) { console.warn(`Missing texture: ${id}`); } } return this.uvmap.get(id); } }