UNPKG

@awayjs/scene

Version:
203 lines (202 loc) 8.05 kB
import { __extends } from "tslib"; import { FNTGeneratorBase } from './FNTGeneratrorBase'; import { BitmapImage2D } from '@awayjs/stage'; import { Rectangle } from '@awayjs/core'; import { GraphicsPathCommand } from '@awayjs/graphics'; var Bounds = /** @class */ (function () { function Bounds() { this.left = Number.MAX_VALUE; this.right = Number.MIN_VALUE; this.top = Number.MAX_VALUE; this.bottom = Number.MIN_VALUE; } Bounds.prototype.grown = function (x, y) { if (x < this.left) this.left = x; if (x > this.right) this.right = x; if (y < this.top) this.top = y; if (y > this.bottom) this.bottom = y; }; Bounds.prototype.toRect = function () { return new Rectangle(this.left, this.top, this.right - this.left, this.bottom - this.top); }; return Bounds; }()); var FNTGeneratorCanvas = /** @class */ (function (_super) { __extends(FNTGeneratorCanvas, _super); function FNTGeneratorCanvas(stage, debug) { if (debug === void 0) { debug = false; } var _this = _super.call(this, stage) || this; /** * Debug mode. * Prevent OffscreenCanvas and prevent canvas clear. * Store canvas */ _this.debug = false; _this.debug = debug; return _this; } FNTGeneratorCanvas.getCanvasContext = function (width, height, debug) { if (width === void 0) { width = 100; } if (height === void 0) { height = 100; } if (debug === void 0) { debug = false; } var canvas = ('OffscreenCanvas' in self && !debug) ? new self.OffscreenCanvas(width, height) : document.createElement('canvas'); canvas.width = width; canvas.height = height; return canvas.getContext('2d', { desynchronized: true, alpha: true }); }; FNTGeneratorCanvas.freeCanvasContext = function (ctx) { if (ctx.canvas instanceof self.OffscreenCanvas) { return; } // safari bug with canvas leaks ctx.canvas.width = 0; ctx.canvas.height = 0; }; FNTGeneratorCanvas.transformChar = function (char) { var fillData = char.fill_data_path; // empty command if (fillData.commands.length === 0) { return null; } var path = new Path2D(); var box = new Bounds(); var data = fillData.data; var commands = fillData.commands; var pointer = 0; for (var _i = 0, commands_1 = commands; _i < commands_1.length; _i++) { var command = commands_1[_i]; switch (command) { case GraphicsPathCommand.MOVE_TO: { // flash path in twips, transform it var px = data[pointer++] / 20; var py = data[pointer++] / 20; box.grown(px, py); path.moveTo(px, py); break; } case GraphicsPathCommand.LINE_TO: { var px = data[pointer++] / 20; var py = data[pointer++] / 20; box.grown(px, py); path.lineTo(px, py); break; } case GraphicsPathCommand.CURVE_TO: { var cx = data[pointer++] / 20; var cy = data[pointer++] / 20; var dx = data[pointer++] / 20; var dy = data[pointer++] / 20; box.grown(cx, cy); box.grown(dx, dy); path.quadraticCurveTo(cx, cy, dx, dy); } } } return { path: path, char: char, rect: box.toRect(), }; }; FNTGeneratorCanvas.sortPatches = function (a, b) { return a.rect.height - b.rect.height; }; FNTGeneratorCanvas.render = function (table, context, size, fontSize, padding) { if (fontSize === void 0) { fontSize = 0; } if (padding === void 0) { padding = 0; } var chars = table.get_font_chars(); var patches = []; var doublePad = padding * 2; var totalArea = 0; var scale = 1; for (var _i = 0, chars_1 = chars; _i < chars_1.length; _i++) { var char = chars_1[_i]; var path = FNTGeneratorCanvas.transformChar(char); if (!path) { continue; } totalArea += (doublePad + path.rect.width) * (doublePad + path.rect.height); patches.push(path); } patches.sort(FNTGeneratorCanvas.sortPatches); // TODO compute valid scale when fontSize is 0 if (fontSize) { table.initFontSize(fontSize); scale = /* 20 * table._size_multiply **/ size / table.get_font_em_size(); } /** * Render glyphs onto canvas * We will render glyphs as white and background as black transparent */ context.save(); context.clearRect(0, 0, size, size); context.fillStyle = '#fff'; var tx = padding; var ty = padding; var maxHeight = 0; // pack glyph based on size for (var _a = 0, patches_1 = patches; _a < patches_1.length; _a++) { var path = patches_1[_a]; if (!path.path) { continue; } // if overflow - jump next location if (tx + path.rect.width + doublePad >= size / scale) { tx = padding; ty += maxHeight + doublePad; maxHeight = 0; } /** * @todo Support multiple channel table data */ if (ty + path.rect.height > size / scale) { console.warn('[FNTGeneratorCanvas] Font image overflow, font will corrupted!'); } maxHeight = Math.max(path.rect.height, maxHeight); context.setTransform(scale, 0, 0, scale, (tx - path.rect.x) * scale, (ty - path.rect.y) * scale); context.fill(path.path); //context.strokeRect(path.rect.x,path.rect.y, path.rect.width, path.rect.height); path.char.fnt_rect = new Rectangle((path.rect.x) / path.char.char_width, (path.rect.y) / table.get_font_em_size(), path.rect.width / path.char.char_width, path.rect.height / table.get_font_em_size()); path.char.fnt_uv = new Rectangle(tx * scale / size, ty * scale / size, path.rect.width * scale / size, path.rect.height * scale / size); /* path.char.fnt_uv = new Rectangle( (tx - path.rect.x) * scale / size, 1 - (ty - path.rect.y) * scale / scale, path.rect.width * scale / size, path.rect.height * scale / size );*/ path.char.fnt_channel = 0; tx += path.rect.width + doublePad; } context.restore(); }; FNTGeneratorCanvas.prototype.generate = function (font, size, fontSize, padding) { var context = FNTGeneratorCanvas.getCanvasContext(size, size, this.debug); var bitmaps = []; for (var key in font.font_styles) { var table = font.font_styles[key]; // render table in context FNTGeneratorCanvas.render(table, context, size, fontSize, padding); var data = context.getImageData(0, 0, size, size); var image = new BitmapImage2D(size, size, true, 0, true, this._stage); image.setPixels(new Rectangle(0, 0, size, size), data.data); bitmaps.push(image); table.addFNTChannel(image); } if (!this.debug) { FNTGeneratorCanvas.freeCanvasContext(context); } else { this.canvas = context.canvas; } return bitmaps; }; return FNTGeneratorCanvas; }(FNTGeneratorBase)); export { FNTGeneratorCanvas };