UNPKG

playcanvas

Version:

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

106 lines (103 loc) 3.49 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 { 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, undefined, undefined, 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, undefined, undefined, this.texture, 1); totalWidth += charPlacement.w; } } return totalWidth; } constructor(device, words){ const initContext = (context)=>{ context.font = '10px "Lucida Console", Monaco, monospace'; context.textAlign = 'left'; context.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 = 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: x, y: 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 ] }); } } export { WordAtlas };