UNPKG

playcanvas

Version:

Open-source WebGL/WebGPU 3D engine for the web

115 lines (114 loc) 3.3 kB
import { math } from "../../core/math/math.js"; import { Texture } from "../../platform/graphics/texture.js"; import { FILTER_NEAREST } from "../../platform/graphics/constants.js"; class WordAtlas { constructor(device, words) { const initContext = (context2) => { context2.font = '10px "Lucida Console", Monaco, monospace'; context2.textAlign = "left"; context2.textBaseline = "alphabetic"; }; const isNumber = (word) => { return word === "." || word.length === 1 && word.charCodeAt(0) >= 48 && word.charCodeAt(0) <= 57; }; const canvas = document.createElement("canvas"); const context = canvas.getContext("2d", { alpha: true }); initContext(context); const placements = /* @__PURE__ */ new Map(); const padding = 5; const width = 512; let x = padding; let y = padding; words.forEach((word) => { const measurement = context.measureText(word); const l = Math.ceil(-measurement.actualBoundingBoxLeft); const r = Math.ceil(measurement.actualBoundingBoxRight); const a = Math.ceil(measurement.actualBoundingBoxAscent); const d = Math.ceil(measurement.actualBoundingBoxDescent); const w = l + r; const h = a + d; if (x + w + padding >= width) { x = padding; y += 16; } placements.set(word, { l, r, a, d, w, h, x, y }); x += w + padding; }); canvas.width = 512; canvas.height = math.nextPowerOfTwo(y + 16 + padding); initContext(context); context.fillStyle = "rgb(0, 0, 0)"; context.fillRect(0, 0, canvas.width, canvas.height); placements.forEach((m, word) => { context.fillStyle = isNumber(word) ? "rgb(255, 240, 100)" : "rgb(150, 220, 230)"; context.fillText(word, m.x - m.l, m.y + m.a); }); this.placements = placements; const data = context.getImageData(0, 0, canvas.width, canvas.height).data; for (let i = 0; i < data.length; i += 4) { const maxChannel = Math.max(data[i + 0], data[i + 1], data[i + 2]); data[i + 3] = Math.min(maxChannel * 2, 255); } this.texture = new Texture(device, { name: "mini-stats-word-atlas", width: canvas.width, height: canvas.height, mipmaps: false, minFilter: FILTER_NEAREST, magFilter: FILTER_NEAREST, levels: [data] }); } destroy() { this.texture.destroy(); this.texture = null; } render(render2d, word, x, y) { const p = this.placements.get(word); if (p) { const padding = 1; render2d.quad( x + p.l - padding, y - p.d + padding, p.w + padding * 2, p.h + padding * 2, p.x - padding, this.texture.height - p.y - p.h - padding, void 0, void 0, this.texture, 1 ); return p.w; } let totalWidth = 0; for (let i = 0; i < word.length; i++) { const char = word[i]; if (char === " ") { totalWidth += 5; continue; } const charPlacement = this.placements.get(char); if (charPlacement) { const padding = 1; render2d.quad( x + totalWidth + charPlacement.l - padding, y - charPlacement.d + padding, charPlacement.w + padding * 2, charPlacement.h + padding * 2, charPlacement.x - padding, this.texture.height - charPlacement.y - charPlacement.h - padding, void 0, void 0, this.texture, 1 ); totalWidth += charPlacement.w; } } return totalWidth; } } export { WordAtlas };