| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637 |
- /*!
- * @pixi/text-bitmap - v6.5.10
- * Compiled Thu, 06 Jul 2023 15:25:11 UTC
- *
- * @pixi/text-bitmap is licensed under the MIT License.
- * http://www.opensource.org/licenses/mit-license
- */
- import { Rectangle, Point, ObservablePoint } from '@pixi/math';
- import { settings } from '@pixi/settings';
- import { MeshGeometry, MeshMaterial, Mesh } from '@pixi/mesh';
- import { hex2rgb, string2hex, getResolutionOfUrl, removeItems } from '@pixi/utils';
- import { BaseTexture, Texture, Program, ExtensionType } from '@pixi/core';
- import { TEXT_GRADIENT, TextStyle, TextMetrics } from '@pixi/text';
- import { ALPHA_MODES, MIPMAP_MODES, BLEND_MODES } from '@pixi/constants';
- import { Container } from '@pixi/display';
- import { LoaderResource } from '@pixi/loaders';
- /*! *****************************************************************************
- Copyright (c) Microsoft Corporation.
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted.
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- PERFORMANCE OF THIS SOFTWARE.
- ***************************************************************************** */
- /* global Reflect, Promise */
- var extendStatics = function(d, b) {
- extendStatics = Object.setPrototypeOf ||
- ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
- function (d, b) { for (var p in b) { if (b.hasOwnProperty(p)) { d[p] = b[p]; } } };
- return extendStatics(d, b);
- };
- function __extends(d, b) {
- extendStatics(d, b);
- function __() { this.constructor = d; }
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
- }
- /* eslint-disable max-len */
- /**
- * Normalized parsed data from .fnt files.
- * @memberof PIXI
- */
- var BitmapFontData = /** @class */ (function () {
- function BitmapFontData() {
- this.info = [];
- this.common = [];
- this.page = [];
- this.char = [];
- this.kerning = [];
- this.distanceField = [];
- }
- return BitmapFontData;
- }());
- /**
- * BitmapFont format that's Text-based.
- * @private
- */
- var TextFormat = /** @class */ (function () {
- function TextFormat() {
- }
- /**
- * Check if resource refers to txt font data.
- * @param data
- * @returns - True if resource could be treated as font data, false otherwise.
- */
- TextFormat.test = function (data) {
- return typeof data === 'string' && data.indexOf('info face=') === 0;
- };
- /**
- * Convert text font data to a javascript object.
- * @param txt - Raw string data to be converted
- * @returns - Parsed font data
- */
- TextFormat.parse = function (txt) {
- // Retrieve data item
- var items = txt.match(/^[a-z]+\s+.+$/gm);
- var rawData = {
- info: [],
- common: [],
- page: [],
- char: [],
- chars: [],
- kerning: [],
- kernings: [],
- distanceField: [],
- };
- for (var i in items) {
- // Extract item name
- var name = items[i].match(/^[a-z]+/gm)[0];
- // Extract item attribute list as string ex.: "width=10"
- var attributeList = items[i].match(/[a-zA-Z]+=([^\s"']+|"([^"]*)")/gm);
- // Convert attribute list into an object
- var itemData = {};
- for (var i_1 in attributeList) {
- // Split key-value pairs
- var split = attributeList[i_1].split('=');
- var key = split[0];
- // Remove eventual quotes from value
- var strValue = split[1].replace(/"/gm, '');
- // Try to convert value into float
- var floatValue = parseFloat(strValue);
- // Use string value case float value is NaN
- var value = isNaN(floatValue) ? strValue : floatValue;
- itemData[key] = value;
- }
- // Push current item to the resulting data
- rawData[name].push(itemData);
- }
- var font = new BitmapFontData();
- rawData.info.forEach(function (info) { return font.info.push({
- face: info.face,
- size: parseInt(info.size, 10),
- }); });
- rawData.common.forEach(function (common) { return font.common.push({
- lineHeight: parseInt(common.lineHeight, 10),
- }); });
- rawData.page.forEach(function (page) { return font.page.push({
- id: parseInt(page.id, 10),
- file: page.file,
- }); });
- rawData.char.forEach(function (char) { return font.char.push({
- id: parseInt(char.id, 10),
- page: parseInt(char.page, 10),
- x: parseInt(char.x, 10),
- y: parseInt(char.y, 10),
- width: parseInt(char.width, 10),
- height: parseInt(char.height, 10),
- xoffset: parseInt(char.xoffset, 10),
- yoffset: parseInt(char.yoffset, 10),
- xadvance: parseInt(char.xadvance, 10),
- }); });
- rawData.kerning.forEach(function (kerning) { return font.kerning.push({
- first: parseInt(kerning.first, 10),
- second: parseInt(kerning.second, 10),
- amount: parseInt(kerning.amount, 10),
- }); });
- rawData.distanceField.forEach(function (df) { return font.distanceField.push({
- distanceRange: parseInt(df.distanceRange, 10),
- fieldType: df.fieldType,
- }); });
- return font;
- };
- return TextFormat;
- }());
- /**
- * BitmapFont format that's XML-based.
- * @private
- */
- var XMLFormat = /** @class */ (function () {
- function XMLFormat() {
- }
- /**
- * Check if resource refers to xml font data.
- * @param data
- * @returns - True if resource could be treated as font data, false otherwise.
- */
- XMLFormat.test = function (data) {
- return data instanceof XMLDocument
- && data.getElementsByTagName('page').length
- && data.getElementsByTagName('info')[0].getAttribute('face') !== null;
- };
- /**
- * Convert the XML into BitmapFontData that we can use.
- * @param xml
- * @returns - Data to use for BitmapFont
- */
- XMLFormat.parse = function (xml) {
- var data = new BitmapFontData();
- var info = xml.getElementsByTagName('info');
- var common = xml.getElementsByTagName('common');
- var page = xml.getElementsByTagName('page');
- var char = xml.getElementsByTagName('char');
- var kerning = xml.getElementsByTagName('kerning');
- var distanceField = xml.getElementsByTagName('distanceField');
- for (var i = 0; i < info.length; i++) {
- data.info.push({
- face: info[i].getAttribute('face'),
- size: parseInt(info[i].getAttribute('size'), 10),
- });
- }
- for (var i = 0; i < common.length; i++) {
- data.common.push({
- lineHeight: parseInt(common[i].getAttribute('lineHeight'), 10),
- });
- }
- for (var i = 0; i < page.length; i++) {
- data.page.push({
- id: parseInt(page[i].getAttribute('id'), 10) || 0,
- file: page[i].getAttribute('file'),
- });
- }
- for (var i = 0; i < char.length; i++) {
- var letter = char[i];
- data.char.push({
- id: parseInt(letter.getAttribute('id'), 10),
- page: parseInt(letter.getAttribute('page'), 10) || 0,
- x: parseInt(letter.getAttribute('x'), 10),
- y: parseInt(letter.getAttribute('y'), 10),
- width: parseInt(letter.getAttribute('width'), 10),
- height: parseInt(letter.getAttribute('height'), 10),
- xoffset: parseInt(letter.getAttribute('xoffset'), 10),
- yoffset: parseInt(letter.getAttribute('yoffset'), 10),
- xadvance: parseInt(letter.getAttribute('xadvance'), 10),
- });
- }
- for (var i = 0; i < kerning.length; i++) {
- data.kerning.push({
- first: parseInt(kerning[i].getAttribute('first'), 10),
- second: parseInt(kerning[i].getAttribute('second'), 10),
- amount: parseInt(kerning[i].getAttribute('amount'), 10),
- });
- }
- for (var i = 0; i < distanceField.length; i++) {
- data.distanceField.push({
- fieldType: distanceField[i].getAttribute('fieldType'),
- distanceRange: parseInt(distanceField[i].getAttribute('distanceRange'), 10),
- });
- }
- return data;
- };
- return XMLFormat;
- }());
- /**
- * BitmapFont format that's XML-based.
- * @private
- */
- var XMLStringFormat = /** @class */ (function () {
- function XMLStringFormat() {
- }
- /**
- * Check if resource refers to text xml font data.
- * @param data
- * @returns - True if resource could be treated as font data, false otherwise.
- */
- XMLStringFormat.test = function (data) {
- if (typeof data === 'string' && data.indexOf('<font>') > -1) {
- var xml = new globalThis.DOMParser().parseFromString(data, 'text/xml');
- return XMLFormat.test(xml);
- }
- return false;
- };
- /**
- * Convert the text XML into BitmapFontData that we can use.
- * @param xmlTxt
- * @returns - Data to use for BitmapFont
- */
- XMLStringFormat.parse = function (xmlTxt) {
- var xml = new globalThis.DOMParser().parseFromString(xmlTxt, 'text/xml');
- return XMLFormat.parse(xml);
- };
- return XMLStringFormat;
- }());
- // Registered formats, maybe make this extensible in the future?
- var formats = [
- TextFormat,
- XMLFormat,
- XMLStringFormat ];
- /**
- * Auto-detect BitmapFont parsing format based on data.
- * @private
- * @param {any} data - Data to detect format
- * @returns {any} Format or null
- */
- function autoDetectFormat(data) {
- for (var i = 0; i < formats.length; i++) {
- if (formats[i].test(data)) {
- return formats[i];
- }
- }
- return null;
- }
- // TODO: Prevent code duplication b/w generateFillStyle & Text#generateFillStyle
- /**
- * Generates the fill style. Can automatically generate a gradient based on the fill style being an array
- * @private
- * @param canvas
- * @param context
- * @param {object} style - The style.
- * @param resolution
- * @param {string[]} lines - The lines of text.
- * @param metrics
- * @returns {string|number|CanvasGradient} The fill style
- */
- function generateFillStyle(canvas, context, style, resolution, lines, metrics) {
- // TODO: Can't have different types for getter and setter. The getter shouldn't have the number type as
- // the setter converts to string. See this thread for more details:
- // https://github.com/microsoft/TypeScript/issues/2521
- var fillStyle = style.fill;
- if (!Array.isArray(fillStyle)) {
- return fillStyle;
- }
- else if (fillStyle.length === 1) {
- return fillStyle[0];
- }
- // the gradient will be evenly spaced out according to how large the array is.
- // ['#FF0000', '#00FF00', '#0000FF'] would created stops at 0.25, 0.5 and 0.75
- var gradient;
- // a dropshadow will enlarge the canvas and result in the gradient being
- // generated with the incorrect dimensions
- var dropShadowCorrection = (style.dropShadow) ? style.dropShadowDistance : 0;
- // should also take padding into account, padding can offset the gradient
- var padding = style.padding || 0;
- var width = (canvas.width / resolution) - dropShadowCorrection - (padding * 2);
- var height = (canvas.height / resolution) - dropShadowCorrection - (padding * 2);
- // make a copy of the style settings, so we can manipulate them later
- var fill = fillStyle.slice();
- var fillGradientStops = style.fillGradientStops.slice();
- // wanting to evenly distribute the fills. So an array of 4 colours should give fills of 0.25, 0.5 and 0.75
- if (!fillGradientStops.length) {
- var lengthPlus1 = fill.length + 1;
- for (var i = 1; i < lengthPlus1; ++i) {
- fillGradientStops.push(i / lengthPlus1);
- }
- }
- // stop the bleeding of the last gradient on the line above to the top gradient of the this line
- // by hard defining the first gradient colour at point 0, and last gradient colour at point 1
- fill.unshift(fillStyle[0]);
- fillGradientStops.unshift(0);
- fill.push(fillStyle[fillStyle.length - 1]);
- fillGradientStops.push(1);
- if (style.fillGradientType === TEXT_GRADIENT.LINEAR_VERTICAL) {
- // start the gradient at the top center of the canvas, and end at the bottom middle of the canvas
- gradient = context.createLinearGradient(width / 2, padding, width / 2, height + padding);
- // we need to repeat the gradient so that each individual line of text has the same vertical gradient effect
- // ['#FF0000', '#00FF00', '#0000FF'] over 2 lines would create stops at 0.125, 0.25, 0.375, 0.625, 0.75, 0.875
- // There's potential for floating point precision issues at the seams between gradient repeats.
- // The loop below generates the stops in order, so track the last generated one to prevent
- // floating point precision from making us go the teeniest bit backwards, resulting in
- // the first and last colors getting swapped.
- var lastIterationStop = 0;
- // Actual height of the text itself, not counting spacing for lineHeight/leading/dropShadow etc
- var textHeight = metrics.fontProperties.fontSize + style.strokeThickness;
- // textHeight, but as a 0-1 size in global gradient stop space
- var gradStopLineHeight = textHeight / height;
- for (var i = 0; i < lines.length; i++) {
- var thisLineTop = metrics.lineHeight * i;
- for (var j = 0; j < fill.length; j++) {
- // 0-1 stop point for the current line, multiplied to global space afterwards
- var lineStop = 0;
- if (typeof fillGradientStops[j] === 'number') {
- lineStop = fillGradientStops[j];
- }
- else {
- lineStop = j / fill.length;
- }
- var globalStop = (thisLineTop / height) + (lineStop * gradStopLineHeight);
- // Prevent color stop generation going backwards from floating point imprecision
- var clampedStop = Math.max(lastIterationStop, globalStop);
- clampedStop = Math.min(clampedStop, 1); // Cap at 1 as well for safety's sake to avoid a possible throw.
- gradient.addColorStop(clampedStop, fill[j]);
- lastIterationStop = clampedStop;
- }
- }
- }
- else {
- // start the gradient at the center left of the canvas, and end at the center right of the canvas
- gradient = context.createLinearGradient(padding, height / 2, width + padding, height / 2);
- // can just evenly space out the gradients in this case, as multiple lines makes no difference
- // to an even left to right gradient
- var totalIterations = fill.length + 1;
- var currentIteration = 1;
- for (var i = 0; i < fill.length; i++) {
- var stop = void 0;
- if (typeof fillGradientStops[i] === 'number') {
- stop = fillGradientStops[i];
- }
- else {
- stop = currentIteration / totalIterations;
- }
- gradient.addColorStop(stop, fill[i]);
- currentIteration++;
- }
- }
- return gradient;
- }
- // TODO: Prevent code duplication b/w drawGlyph & Text#updateText
- /**
- * Draws the glyph `metrics.text` on the given canvas.
- *
- * Ignored because not directly exposed.
- * @ignore
- * @param {HTMLCanvasElement} canvas
- * @param {CanvasRenderingContext2D} context
- * @param {TextMetrics} metrics
- * @param {number} x
- * @param {number} y
- * @param {number} resolution
- * @param {TextStyle} style
- */
- function drawGlyph(canvas, context, metrics, x, y, resolution, style) {
- var char = metrics.text;
- var fontProperties = metrics.fontProperties;
- context.translate(x, y);
- context.scale(resolution, resolution);
- var tx = style.strokeThickness / 2;
- var ty = -(style.strokeThickness / 2);
- context.font = style.toFontString();
- context.lineWidth = style.strokeThickness;
- context.textBaseline = style.textBaseline;
- context.lineJoin = style.lineJoin;
- context.miterLimit = style.miterLimit;
- // set canvas text styles
- context.fillStyle = generateFillStyle(canvas, context, style, resolution, [char], metrics);
- context.strokeStyle = style.stroke;
- if (style.dropShadow) {
- var dropShadowColor = style.dropShadowColor;
- var rgb = hex2rgb(typeof dropShadowColor === 'number' ? dropShadowColor : string2hex(dropShadowColor));
- var dropShadowBlur = style.dropShadowBlur * resolution;
- var dropShadowDistance = style.dropShadowDistance * resolution;
- context.shadowColor = "rgba(" + rgb[0] * 255 + "," + rgb[1] * 255 + "," + rgb[2] * 255 + "," + style.dropShadowAlpha + ")";
- context.shadowBlur = dropShadowBlur;
- context.shadowOffsetX = Math.cos(style.dropShadowAngle) * dropShadowDistance;
- context.shadowOffsetY = Math.sin(style.dropShadowAngle) * dropShadowDistance;
- }
- else {
- context.shadowColor = 'black';
- context.shadowBlur = 0;
- context.shadowOffsetX = 0;
- context.shadowOffsetY = 0;
- }
- if (style.stroke && style.strokeThickness) {
- context.strokeText(char, tx, ty + metrics.lineHeight - fontProperties.descent);
- }
- if (style.fill) {
- context.fillText(char, tx, ty + metrics.lineHeight - fontProperties.descent);
- }
- context.setTransform(1, 0, 0, 1, 0, 0); // defaults needed for older browsers (e.g. Opera 29)
- context.fillStyle = 'rgba(0, 0, 0, 0)';
- }
- /**
- * Ponyfill for IE because it doesn't support `Array.from`
- * @param text
- * @private
- */
- function splitTextToCharacters(text) {
- return Array.from ? Array.from(text) : text.split('');
- }
- /**
- * Processes the passed character set data and returns a flattened array of all the characters.
- *
- * Ignored because not directly exposed.
- * @ignore
- * @param {string | string[] | string[][] } chars
- * @returns {string[]} the flattened array of characters
- */
- function resolveCharacters(chars) {
- // Split the chars string into individual characters
- if (typeof chars === 'string') {
- chars = [chars];
- }
- // Handle an array of characters+ranges
- var result = [];
- for (var i = 0, j = chars.length; i < j; i++) {
- var item = chars[i];
- // Handle range delimited by start/end chars
- if (Array.isArray(item)) {
- if (item.length !== 2) {
- throw new Error("[BitmapFont]: Invalid character range length, expecting 2 got " + item.length + ".");
- }
- var startCode = item[0].charCodeAt(0);
- var endCode = item[1].charCodeAt(0);
- if (endCode < startCode) {
- throw new Error('[BitmapFont]: Invalid character range.');
- }
- for (var i_1 = startCode, j_1 = endCode; i_1 <= j_1; i_1++) {
- result.push(String.fromCharCode(i_1));
- }
- }
- // Handle a character set string
- else {
- result.push.apply(result, splitTextToCharacters(item));
- }
- }
- if (result.length === 0) {
- throw new Error('[BitmapFont]: Empty set when resolving characters.');
- }
- return result;
- }
- /**
- * Ponyfill for IE because it doesn't support `codePointAt`
- * @param str
- * @private
- */
- function extractCharCode(str) {
- return str.codePointAt ? str.codePointAt(0) : str.charCodeAt(0);
- }
- /**
- * BitmapFont represents a typeface available for use with the BitmapText class. Use the `install`
- * method for adding a font to be used.
- * @memberof PIXI
- */
- var BitmapFont = /** @class */ (function () {
- /**
- * @param data
- * @param textures
- * @param ownsTextures - Setting to `true` will destroy page textures
- * when the font is uninstalled.
- */
- function BitmapFont(data, textures, ownsTextures) {
- var _a, _b;
- var info = data.info[0];
- var common = data.common[0];
- var page = data.page[0];
- var distanceField = data.distanceField[0];
- var res = getResolutionOfUrl(page.file);
- var pageTextures = {};
- this._ownsTextures = ownsTextures;
- this.font = info.face;
- this.size = info.size;
- this.lineHeight = common.lineHeight / res;
- this.chars = {};
- this.pageTextures = pageTextures;
- // Convert the input Texture, Textures or object
- // into a page Texture lookup by "id"
- for (var i = 0; i < data.page.length; i++) {
- var _c = data.page[i], id = _c.id, file = _c.file;
- pageTextures[id] = textures instanceof Array
- ? textures[i] : textures[file];
- // only MSDF and SDF fonts need no-premultiplied-alpha
- if ((distanceField === null || distanceField === void 0 ? void 0 : distanceField.fieldType) && distanceField.fieldType !== 'none') {
- pageTextures[id].baseTexture.alphaMode = ALPHA_MODES.NO_PREMULTIPLIED_ALPHA;
- pageTextures[id].baseTexture.mipmap = MIPMAP_MODES.OFF;
- }
- }
- // parse letters
- for (var i = 0; i < data.char.length; i++) {
- var _d = data.char[i], id = _d.id, page_1 = _d.page;
- var _e = data.char[i], x = _e.x, y = _e.y, width = _e.width, height = _e.height, xoffset = _e.xoffset, yoffset = _e.yoffset, xadvance = _e.xadvance;
- x /= res;
- y /= res;
- width /= res;
- height /= res;
- xoffset /= res;
- yoffset /= res;
- xadvance /= res;
- var rect = new Rectangle(x + (pageTextures[page_1].frame.x / res), y + (pageTextures[page_1].frame.y / res), width, height);
- this.chars[id] = {
- xOffset: xoffset,
- yOffset: yoffset,
- xAdvance: xadvance,
- kerning: {},
- texture: new Texture(pageTextures[page_1].baseTexture, rect),
- page: page_1,
- };
- }
- // parse kernings
- for (var i = 0; i < data.kerning.length; i++) {
- var _f = data.kerning[i], first = _f.first, second = _f.second, amount = _f.amount;
- first /= res;
- second /= res;
- amount /= res;
- if (this.chars[second]) {
- this.chars[second].kerning[first] = amount;
- }
- }
- // Store distance field information
- this.distanceFieldRange = distanceField === null || distanceField === void 0 ? void 0 : distanceField.distanceRange;
- this.distanceFieldType = (_b = (_a = distanceField === null || distanceField === void 0 ? void 0 : distanceField.fieldType) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== null && _b !== void 0 ? _b : 'none';
- }
- /** Remove references to created glyph textures. */
- BitmapFont.prototype.destroy = function () {
- for (var id in this.chars) {
- this.chars[id].texture.destroy();
- this.chars[id].texture = null;
- }
- for (var id in this.pageTextures) {
- if (this._ownsTextures) {
- this.pageTextures[id].destroy(true);
- }
- this.pageTextures[id] = null;
- }
- // Set readonly null.
- this.chars = null;
- this.pageTextures = null;
- };
- /**
- * Register a new bitmap font.
- * @param data - The
- * characters map that could be provided as xml or raw string.
- * @param textures - List of textures for each page.
- * @param ownsTextures - Set to `true` to destroy page textures
- * when the font is uninstalled. By default fonts created with
- * `BitmapFont.from` or from the `BitmapFontLoader` are `true`.
- * @returns {PIXI.BitmapFont} Result font object with font, size, lineHeight
- * and char fields.
- */
- BitmapFont.install = function (data, textures, ownsTextures) {
- var fontData;
- if (data instanceof BitmapFontData) {
- fontData = data;
- }
- else {
- var format = autoDetectFormat(data);
- if (!format) {
- throw new Error('Unrecognized data format for font.');
- }
- fontData = format.parse(data);
- }
- // Single texture, convert to list
- if (textures instanceof Texture) {
- textures = [textures];
- }
- var font = new BitmapFont(fontData, textures, ownsTextures);
- BitmapFont.available[font.font] = font;
- return font;
- };
- /**
- * Remove bitmap font by name.
- * @param name - Name of the font to uninstall.
- */
- BitmapFont.uninstall = function (name) {
- var font = BitmapFont.available[name];
- if (!font) {
- throw new Error("No font found named '" + name + "'");
- }
- font.destroy();
- delete BitmapFont.available[name];
- };
- /**
- * Generates a bitmap-font for the given style and character set. This does not support
- * kernings yet. With `style` properties, only the following non-layout properties are used:
- *
- * - {@link PIXI.TextStyle#dropShadow|dropShadow}
- * - {@link PIXI.TextStyle#dropShadowDistance|dropShadowDistance}
- * - {@link PIXI.TextStyle#dropShadowColor|dropShadowColor}
- * - {@link PIXI.TextStyle#dropShadowBlur|dropShadowBlur}
- * - {@link PIXI.TextStyle#dropShadowAngle|dropShadowAngle}
- * - {@link PIXI.TextStyle#fill|fill}
- * - {@link PIXI.TextStyle#fillGradientStops|fillGradientStops}
- * - {@link PIXI.TextStyle#fillGradientType|fillGradientType}
- * - {@link PIXI.TextStyle#fontFamily|fontFamily}
- * - {@link PIXI.TextStyle#fontSize|fontSize}
- * - {@link PIXI.TextStyle#fontVariant|fontVariant}
- * - {@link PIXI.TextStyle#fontWeight|fontWeight}
- * - {@link PIXI.TextStyle#lineJoin|lineJoin}
- * - {@link PIXI.TextStyle#miterLimit|miterLimit}
- * - {@link PIXI.TextStyle#stroke|stroke}
- * - {@link PIXI.TextStyle#strokeThickness|strokeThickness}
- * - {@link PIXI.TextStyle#textBaseline|textBaseline}
- * @param name - The name of the custom font to use with BitmapText.
- * @param textStyle - Style options to render with BitmapFont.
- * @param options - Setup options for font or name of the font.
- * @param {string|string[]|string[][]} [options.chars=PIXI.BitmapFont.ALPHANUMERIC] - characters included
- * in the font set. You can also use ranges. For example, `[['a', 'z'], ['A', 'Z'], "!@#$%^&*()~{}[] "]`.
- * Don't forget to include spaces ' ' in your character set!
- * @param {number} [options.resolution=1] - Render resolution for glyphs.
- * @param {number} [options.textureWidth=512] - Optional width of atlas, smaller values to reduce memory.
- * @param {number} [options.textureHeight=512] - Optional height of atlas, smaller values to reduce memory.
- * @param {number} [options.padding=4] - Padding between glyphs on texture atlas.
- * @returns Font generated by style options.
- * @example
- * PIXI.BitmapFont.from("TitleFont", {
- * fontFamily: "Arial",
- * fontSize: 12,
- * strokeThickness: 2,
- * fill: "purple"
- * });
- *
- * const title = new PIXI.BitmapText("This is the title", { fontName: "TitleFont" });
- */
- BitmapFont.from = function (name, textStyle, options) {
- if (!name) {
- throw new Error('[BitmapFont] Property `name` is required.');
- }
- var _a = Object.assign({}, BitmapFont.defaultOptions, options), chars = _a.chars, padding = _a.padding, resolution = _a.resolution, textureWidth = _a.textureWidth, textureHeight = _a.textureHeight;
- var charsList = resolveCharacters(chars);
- var style = textStyle instanceof TextStyle ? textStyle : new TextStyle(textStyle);
- var lineWidth = textureWidth;
- var fontData = new BitmapFontData();
- fontData.info[0] = {
- face: style.fontFamily,
- size: style.fontSize,
- };
- fontData.common[0] = {
- lineHeight: style.fontSize,
- };
- var positionX = 0;
- var positionY = 0;
- var canvas;
- var context;
- var baseTexture;
- var maxCharHeight = 0;
- var textures = [];
- for (var i = 0; i < charsList.length; i++) {
- if (!canvas) {
- canvas = settings.ADAPTER.createCanvas();
- canvas.width = textureWidth;
- canvas.height = textureHeight;
- context = canvas.getContext('2d');
- baseTexture = new BaseTexture(canvas, { resolution: resolution });
- textures.push(new Texture(baseTexture));
- fontData.page.push({
- id: textures.length - 1,
- file: '',
- });
- }
- // Measure glyph dimensions
- var character = charsList[i];
- var metrics = TextMetrics.measureText(character, style, false, canvas);
- var width = metrics.width;
- var height = Math.ceil(metrics.height);
- // This is ugly - but italics are given more space so they don't overlap
- var textureGlyphWidth = Math.ceil((style.fontStyle === 'italic' ? 2 : 1) * width);
- // Can't fit char anymore: next canvas please!
- if (positionY >= textureHeight - (height * resolution)) {
- if (positionY === 0) {
- // We don't want user debugging an infinite loop (or do we? :)
- throw new Error("[BitmapFont] textureHeight " + textureHeight + "px is too small "
- + ("(fontFamily: '" + style.fontFamily + "', fontSize: " + style.fontSize + "px, char: '" + character + "')"));
- }
- --i;
- // Create new atlas once current has filled up
- canvas = null;
- context = null;
- baseTexture = null;
- positionY = 0;
- positionX = 0;
- maxCharHeight = 0;
- continue;
- }
- maxCharHeight = Math.max(height + metrics.fontProperties.descent, maxCharHeight);
- // Wrap line once full row has been rendered
- if ((textureGlyphWidth * resolution) + positionX >= lineWidth) {
- if (positionX === 0) {
- // Avoid infinite loop (There can be some very wide char like '\uFDFD'!)
- throw new Error("[BitmapFont] textureWidth " + textureWidth + "px is too small "
- + ("(fontFamily: '" + style.fontFamily + "', fontSize: " + style.fontSize + "px, char: '" + character + "')"));
- }
- --i;
- positionY += maxCharHeight * resolution;
- positionY = Math.ceil(positionY);
- positionX = 0;
- maxCharHeight = 0;
- continue;
- }
- drawGlyph(canvas, context, metrics, positionX, positionY, resolution, style);
- // Unique (numeric) ID mapping to this glyph
- var id = extractCharCode(metrics.text);
- // Create a texture holding just the glyph
- fontData.char.push({
- id: id,
- page: textures.length - 1,
- x: positionX / resolution,
- y: positionY / resolution,
- width: textureGlyphWidth,
- height: height,
- xoffset: 0,
- yoffset: 0,
- xadvance: Math.ceil(width
- - (style.dropShadow ? style.dropShadowDistance : 0)
- - (style.stroke ? style.strokeThickness : 0)),
- });
- positionX += (textureGlyphWidth + (2 * padding)) * resolution;
- positionX = Math.ceil(positionX);
- }
- if (!(options === null || options === void 0 ? void 0 : options.skipKerning)) {
- // Brute-force kerning info, this can be expensive b/c it's an O(n²),
- // but we're using measureText which is native and fast.
- for (var i = 0, len = charsList.length; i < len; i++) {
- var first = charsList[i];
- for (var j = 0; j < len; j++) {
- var second = charsList[j];
- var c1 = context.measureText(first).width;
- var c2 = context.measureText(second).width;
- var total = context.measureText(first + second).width;
- var amount = total - (c1 + c2);
- if (amount) {
- fontData.kerning.push({
- first: extractCharCode(first),
- second: extractCharCode(second),
- amount: amount,
- });
- }
- }
- }
- }
- var font = new BitmapFont(fontData, textures, true);
- // Make it easier to replace a font
- if (BitmapFont.available[name] !== undefined) {
- BitmapFont.uninstall(name);
- }
- BitmapFont.available[name] = font;
- return font;
- };
- /**
- * This character set includes all the letters in the alphabet (both lower- and upper- case).
- * @type {string[][]}
- * @example
- * BitmapFont.from("ExampleFont", style, { chars: BitmapFont.ALPHA })
- */
- BitmapFont.ALPHA = [['a', 'z'], ['A', 'Z'], ' '];
- /**
- * This character set includes all decimal digits (from 0 to 9).
- * @type {string[][]}
- * @example
- * BitmapFont.from("ExampleFont", style, { chars: BitmapFont.NUMERIC })
- */
- BitmapFont.NUMERIC = [['0', '9']];
- /**
- * This character set is the union of `BitmapFont.ALPHA` and `BitmapFont.NUMERIC`.
- * @type {string[][]}
- */
- BitmapFont.ALPHANUMERIC = [['a', 'z'], ['A', 'Z'], ['0', '9'], ' '];
- /**
- * This character set consists of all the ASCII table.
- * @member {string[][]}
- * @see http://www.asciitable.com/
- */
- BitmapFont.ASCII = [[' ', '~']];
- /**
- * Collection of default options when using `BitmapFont.from`.
- * @property {number} [resolution=1] -
- * @property {number} [textureWidth=512] -
- * @property {number} [textureHeight=512] -
- * @property {number} [padding=4] -
- * @property {string|string[]|string[][]} chars = PIXI.BitmapFont.ALPHANUMERIC
- */
- BitmapFont.defaultOptions = {
- resolution: 1,
- textureWidth: 512,
- textureHeight: 512,
- padding: 4,
- chars: BitmapFont.ALPHANUMERIC,
- };
- /** Collection of available/installed fonts. */
- BitmapFont.available = {};
- return BitmapFont;
- }());
- var msdfFrag = "// Pixi texture info\r\nvarying vec2 vTextureCoord;\r\nuniform sampler2D uSampler;\r\n\r\n// Tint\r\nuniform vec4 uColor;\r\n\r\n// on 2D applications fwidth is screenScale / glyphAtlasScale * distanceFieldRange\r\nuniform float uFWidth;\r\n\r\nvoid main(void) {\r\n\r\n // To stack MSDF and SDF we need a non-pre-multiplied-alpha texture.\r\n vec4 texColor = texture2D(uSampler, vTextureCoord);\r\n\r\n // MSDF\r\n float median = texColor.r + texColor.g + texColor.b -\r\n min(texColor.r, min(texColor.g, texColor.b)) -\r\n max(texColor.r, max(texColor.g, texColor.b));\r\n // SDF\r\n median = min(median, texColor.a);\r\n\r\n float screenPxDistance = uFWidth * (median - 0.5);\r\n float alpha = clamp(screenPxDistance + 0.5, 0.0, 1.0);\r\n if (median < 0.01) {\r\n alpha = 0.0;\r\n } else if (median > 0.99) {\r\n alpha = 1.0;\r\n }\r\n\r\n // NPM Textures, NPM outputs\r\n gl_FragColor = vec4(uColor.rgb, uColor.a * alpha);\r\n\r\n}\r\n";
- var msdfVert = "// Mesh material default fragment\r\nattribute vec2 aVertexPosition;\r\nattribute vec2 aTextureCoord;\r\n\r\nuniform mat3 projectionMatrix;\r\nuniform mat3 translationMatrix;\r\nuniform mat3 uTextureMatrix;\r\n\r\nvarying vec2 vTextureCoord;\r\n\r\nvoid main(void)\r\n{\r\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\r\n\r\n vTextureCoord = (uTextureMatrix * vec3(aTextureCoord, 1.0)).xy;\r\n}\r\n";
- // If we ever need more than two pools, please make a Dict or something better.
- var pageMeshDataDefaultPageMeshData = [];
- var pageMeshDataMSDFPageMeshData = [];
- var charRenderDataPool = [];
- /**
- * A BitmapText object will create a line or multiple lines of text using bitmap font.
- *
- * The primary advantage of this class over Text is that all of your textures are pre-generated and loading,
- * meaning that rendering is fast, and changing text has no performance implications.
- *
- * Supporting character sets other than latin, such as CJK languages, may be impractical due to the number of characters.
- *
- * To split a line you can use '\n', '\r' or '\r\n' in your string.
- *
- * PixiJS can auto-generate fonts on-the-fly using BitmapFont or use fnt files provided by:
- * http://www.angelcode.com/products/bmfont/ for Windows or
- * http://www.bmglyph.com/ for Mac.
- *
- * You can also use SDF, MSDF and MTSDF BitmapFonts for vector-like scaling appearance provided by:
- * https://github.com/soimy/msdf-bmfont-xml for SDF and MSDF fnt files or
- * https://github.com/Chlumsky/msdf-atlas-gen for SDF, MSDF and MTSDF json files
- *
- * A BitmapText can only be created when the font is loaded.
- *
- * ```js
- * // in this case the font is in a file called 'desyrel.fnt'
- * let bitmapText = new PIXI.BitmapText("text using a fancy font!", {
- * fontName: "Desyrel",
- * fontSize: 35,
- * align: "right"
- * });
- * ```
- * @memberof PIXI
- */
- var BitmapText = /** @class */ (function (_super) {
- __extends(BitmapText, _super);
- /**
- * @param text - A string that you would like the text to display.
- * @param style - The style parameters.
- * @param {string} style.fontName - The installed BitmapFont name.
- * @param {number} [style.fontSize] - The size of the font in pixels, e.g. 24. If undefined,
- *. this will default to the BitmapFont size.
- * @param {string} [style.align='left'] - Alignment for multiline text ('left', 'center', 'right' or 'justify'),
- * does not affect single line text.
- * @param {number} [style.tint=0xFFFFFF] - The tint color.
- * @param {number} [style.letterSpacing=0] - The amount of spacing between letters.
- * @param {number} [style.maxWidth=0] - The max width of the text before line wrapping.
- */
- function BitmapText(text, style) {
- if (style === void 0) { style = {}; }
- var _this = _super.call(this) || this;
- /**
- * Private tracker for the current tint.
- * @private
- */
- _this._tint = 0xFFFFFF;
- // Apply the defaults
- var _a = Object.assign({}, BitmapText.styleDefaults, style), align = _a.align, tint = _a.tint, maxWidth = _a.maxWidth, letterSpacing = _a.letterSpacing, fontName = _a.fontName, fontSize = _a.fontSize;
- if (!BitmapFont.available[fontName]) {
- throw new Error("Missing BitmapFont \"" + fontName + "\"");
- }
- _this._activePagesMeshData = [];
- _this._textWidth = 0;
- _this._textHeight = 0;
- _this._align = align;
- _this._tint = tint;
- _this._font = undefined;
- _this._fontName = fontName;
- _this._fontSize = fontSize;
- _this.text = text;
- _this._maxWidth = maxWidth;
- _this._maxLineHeight = 0;
- _this._letterSpacing = letterSpacing;
- _this._anchor = new ObservablePoint(function () { _this.dirty = true; }, _this, 0, 0);
- _this._roundPixels = settings.ROUND_PIXELS;
- _this.dirty = true;
- _this._resolution = settings.RESOLUTION;
- _this._autoResolution = true;
- _this._textureCache = {};
- return _this;
- }
- /** Renders text and updates it when needed. This should only be called if the BitmapFont is regenerated. */
- BitmapText.prototype.updateText = function () {
- var _a;
- var data = BitmapFont.available[this._fontName];
- var fontSize = this.fontSize;
- var scale = fontSize / data.size;
- var pos = new Point();
- var chars = [];
- var lineWidths = [];
- var lineSpaces = [];
- var text = this._text.replace(/(?:\r\n|\r)/g, '\n') || ' ';
- var charsInput = splitTextToCharacters(text);
- var maxWidth = this._maxWidth * data.size / fontSize;
- var pageMeshDataPool = data.distanceFieldType === 'none'
- ? pageMeshDataDefaultPageMeshData : pageMeshDataMSDFPageMeshData;
- var prevCharCode = null;
- var lastLineWidth = 0;
- var maxLineWidth = 0;
- var line = 0;
- var lastBreakPos = -1;
- var lastBreakWidth = 0;
- var spacesRemoved = 0;
- var maxLineHeight = 0;
- var spaceCount = 0;
- for (var i = 0; i < charsInput.length; i++) {
- var char = charsInput[i];
- var charCode = extractCharCode(char);
- if ((/(?:\s)/).test(char)) {
- lastBreakPos = i;
- lastBreakWidth = lastLineWidth;
- spaceCount++;
- }
- if (char === '\r' || char === '\n') {
- lineWidths.push(lastLineWidth);
- lineSpaces.push(-1);
- maxLineWidth = Math.max(maxLineWidth, lastLineWidth);
- ++line;
- ++spacesRemoved;
- pos.x = 0;
- pos.y += data.lineHeight;
- prevCharCode = null;
- spaceCount = 0;
- continue;
- }
- var charData = data.chars[charCode];
- if (!charData) {
- continue;
- }
- if (prevCharCode && charData.kerning[prevCharCode]) {
- pos.x += charData.kerning[prevCharCode];
- }
- var charRenderData = charRenderDataPool.pop() || {
- texture: Texture.EMPTY,
- line: 0,
- charCode: 0,
- prevSpaces: 0,
- position: new Point(),
- };
- charRenderData.texture = charData.texture;
- charRenderData.line = line;
- charRenderData.charCode = charCode;
- charRenderData.position.x = pos.x + charData.xOffset + (this._letterSpacing / 2);
- charRenderData.position.y = pos.y + charData.yOffset;
- charRenderData.prevSpaces = spaceCount;
- chars.push(charRenderData);
- lastLineWidth = charRenderData.position.x
- + Math.max(charData.xAdvance - charData.xOffset, charData.texture.orig.width);
- pos.x += charData.xAdvance + this._letterSpacing;
- maxLineHeight = Math.max(maxLineHeight, (charData.yOffset + charData.texture.height));
- prevCharCode = charCode;
- if (lastBreakPos !== -1 && maxWidth > 0 && pos.x > maxWidth) {
- ++spacesRemoved;
- removeItems(chars, 1 + lastBreakPos - spacesRemoved, 1 + i - lastBreakPos);
- i = lastBreakPos;
- lastBreakPos = -1;
- lineWidths.push(lastBreakWidth);
- lineSpaces.push(chars.length > 0 ? chars[chars.length - 1].prevSpaces : 0);
- maxLineWidth = Math.max(maxLineWidth, lastBreakWidth);
- line++;
- pos.x = 0;
- pos.y += data.lineHeight;
- prevCharCode = null;
- spaceCount = 0;
- }
- }
- var lastChar = charsInput[charsInput.length - 1];
- if (lastChar !== '\r' && lastChar !== '\n') {
- if ((/(?:\s)/).test(lastChar)) {
- lastLineWidth = lastBreakWidth;
- }
- lineWidths.push(lastLineWidth);
- maxLineWidth = Math.max(maxLineWidth, lastLineWidth);
- lineSpaces.push(-1);
- }
- var lineAlignOffsets = [];
- for (var i = 0; i <= line; i++) {
- var alignOffset = 0;
- if (this._align === 'right') {
- alignOffset = maxLineWidth - lineWidths[i];
- }
- else if (this._align === 'center') {
- alignOffset = (maxLineWidth - lineWidths[i]) / 2;
- }
- else if (this._align === 'justify') {
- alignOffset = lineSpaces[i] < 0 ? 0 : (maxLineWidth - lineWidths[i]) / lineSpaces[i];
- }
- lineAlignOffsets.push(alignOffset);
- }
- var lenChars = chars.length;
- var pagesMeshData = {};
- var newPagesMeshData = [];
- var activePagesMeshData = this._activePagesMeshData;
- pageMeshDataPool.push.apply(pageMeshDataPool, activePagesMeshData);
- for (var i = 0; i < lenChars; i++) {
- var texture = chars[i].texture;
- var baseTextureUid = texture.baseTexture.uid;
- if (!pagesMeshData[baseTextureUid]) {
- var pageMeshData = pageMeshDataPool.pop();
- if (!pageMeshData) {
- var geometry = new MeshGeometry();
- var material = void 0;
- var meshBlendMode = void 0;
- if (data.distanceFieldType === 'none') {
- material = new MeshMaterial(Texture.EMPTY);
- meshBlendMode = BLEND_MODES.NORMAL;
- }
- else {
- material = new MeshMaterial(Texture.EMPTY, { program: Program.from(msdfVert, msdfFrag), uniforms: { uFWidth: 0 } });
- meshBlendMode = BLEND_MODES.NORMAL_NPM;
- }
- var mesh = new Mesh(geometry, material);
- mesh.blendMode = meshBlendMode;
- pageMeshData = {
- index: 0,
- indexCount: 0,
- vertexCount: 0,
- uvsCount: 0,
- total: 0,
- mesh: mesh,
- vertices: null,
- uvs: null,
- indices: null,
- };
- }
- // reset data..
- pageMeshData.index = 0;
- pageMeshData.indexCount = 0;
- pageMeshData.vertexCount = 0;
- pageMeshData.uvsCount = 0;
- pageMeshData.total = 0;
- // TODO need to get page texture here somehow..
- var _textureCache = this._textureCache;
- _textureCache[baseTextureUid] = _textureCache[baseTextureUid] || new Texture(texture.baseTexture);
- pageMeshData.mesh.texture = _textureCache[baseTextureUid];
- pageMeshData.mesh.tint = this._tint;
- newPagesMeshData.push(pageMeshData);
- pagesMeshData[baseTextureUid] = pageMeshData;
- }
- pagesMeshData[baseTextureUid].total++;
- }
- // lets find any previously active pageMeshDatas that are no longer required for
- // the updated text (if any), removed and return them to the pool.
- for (var i = 0; i < activePagesMeshData.length; i++) {
- if (newPagesMeshData.indexOf(activePagesMeshData[i]) === -1) {
- this.removeChild(activePagesMeshData[i].mesh);
- }
- }
- // next lets add any new meshes, that have not yet been added to this BitmapText
- // we only add if its not already a child of this BitmapObject
- for (var i = 0; i < newPagesMeshData.length; i++) {
- if (newPagesMeshData[i].mesh.parent !== this) {
- this.addChild(newPagesMeshData[i].mesh);
- }
- }
- // active page mesh datas are set to be the new pages added.
- this._activePagesMeshData = newPagesMeshData;
- for (var i in pagesMeshData) {
- var pageMeshData = pagesMeshData[i];
- var total = pageMeshData.total;
- // lets only allocate new buffers if we can fit the new text in the current ones..
- // unless that is, we will be batching. Currently batching dose not respect the size property of mesh
- if (!(((_a = pageMeshData.indices) === null || _a === void 0 ? void 0 : _a.length) > 6 * total) || pageMeshData.vertices.length < Mesh.BATCHABLE_SIZE * 2) {
- pageMeshData.vertices = new Float32Array(4 * 2 * total);
- pageMeshData.uvs = new Float32Array(4 * 2 * total);
- pageMeshData.indices = new Uint16Array(6 * total);
- }
- else {
- var total_1 = pageMeshData.total;
- var vertices = pageMeshData.vertices;
- // Clear the garbage at the end of the vertices buffer. This will prevent the bounds miscalculation.
- for (var i_1 = total_1 * 4 * 2; i_1 < vertices.length; i_1++) {
- vertices[i_1] = 0;
- }
- }
- // as a buffer maybe bigger than the current word, we set the size of the meshMaterial
- // to match the number of letters needed
- pageMeshData.mesh.size = 6 * total;
- }
- for (var i = 0; i < lenChars; i++) {
- var char = chars[i];
- var offset = char.position.x + (lineAlignOffsets[char.line] * (this._align === 'justify' ? char.prevSpaces : 1));
- if (this._roundPixels) {
- offset = Math.round(offset);
- }
- var xPos = offset * scale;
- var yPos = char.position.y * scale;
- var texture = char.texture;
- var pageMesh = pagesMeshData[texture.baseTexture.uid];
- var textureFrame = texture.frame;
- var textureUvs = texture._uvs;
- var index = pageMesh.index++;
- pageMesh.indices[(index * 6) + 0] = 0 + (index * 4);
- pageMesh.indices[(index * 6) + 1] = 1 + (index * 4);
- pageMesh.indices[(index * 6) + 2] = 2 + (index * 4);
- pageMesh.indices[(index * 6) + 3] = 0 + (index * 4);
- pageMesh.indices[(index * 6) + 4] = 2 + (index * 4);
- pageMesh.indices[(index * 6) + 5] = 3 + (index * 4);
- pageMesh.vertices[(index * 8) + 0] = xPos;
- pageMesh.vertices[(index * 8) + 1] = yPos;
- pageMesh.vertices[(index * 8) + 2] = xPos + (textureFrame.width * scale);
- pageMesh.vertices[(index * 8) + 3] = yPos;
- pageMesh.vertices[(index * 8) + 4] = xPos + (textureFrame.width * scale);
- pageMesh.vertices[(index * 8) + 5] = yPos + (textureFrame.height * scale);
- pageMesh.vertices[(index * 8) + 6] = xPos;
- pageMesh.vertices[(index * 8) + 7] = yPos + (textureFrame.height * scale);
- pageMesh.uvs[(index * 8) + 0] = textureUvs.x0;
- pageMesh.uvs[(index * 8) + 1] = textureUvs.y0;
- pageMesh.uvs[(index * 8) + 2] = textureUvs.x1;
- pageMesh.uvs[(index * 8) + 3] = textureUvs.y1;
- pageMesh.uvs[(index * 8) + 4] = textureUvs.x2;
- pageMesh.uvs[(index * 8) + 5] = textureUvs.y2;
- pageMesh.uvs[(index * 8) + 6] = textureUvs.x3;
- pageMesh.uvs[(index * 8) + 7] = textureUvs.y3;
- }
- this._textWidth = maxLineWidth * scale;
- this._textHeight = (pos.y + data.lineHeight) * scale;
- for (var i in pagesMeshData) {
- var pageMeshData = pagesMeshData[i];
- // apply anchor
- if (this.anchor.x !== 0 || this.anchor.y !== 0) {
- var vertexCount = 0;
- var anchorOffsetX = this._textWidth * this.anchor.x;
- var anchorOffsetY = this._textHeight * this.anchor.y;
- for (var i_2 = 0; i_2 < pageMeshData.total; i_2++) {
- pageMeshData.vertices[vertexCount++] -= anchorOffsetX;
- pageMeshData.vertices[vertexCount++] -= anchorOffsetY;
- pageMeshData.vertices[vertexCount++] -= anchorOffsetX;
- pageMeshData.vertices[vertexCount++] -= anchorOffsetY;
- pageMeshData.vertices[vertexCount++] -= anchorOffsetX;
- pageMeshData.vertices[vertexCount++] -= anchorOffsetY;
- pageMeshData.vertices[vertexCount++] -= anchorOffsetX;
- pageMeshData.vertices[vertexCount++] -= anchorOffsetY;
- }
- }
- this._maxLineHeight = maxLineHeight * scale;
- var vertexBuffer = pageMeshData.mesh.geometry.getBuffer('aVertexPosition');
- var textureBuffer = pageMeshData.mesh.geometry.getBuffer('aTextureCoord');
- var indexBuffer = pageMeshData.mesh.geometry.getIndex();
- vertexBuffer.data = pageMeshData.vertices;
- textureBuffer.data = pageMeshData.uvs;
- indexBuffer.data = pageMeshData.indices;
- vertexBuffer.update();
- textureBuffer.update();
- indexBuffer.update();
- }
- for (var i = 0; i < chars.length; i++) {
- charRenderDataPool.push(chars[i]);
- }
- this._font = data;
- this.dirty = false;
- };
- BitmapText.prototype.updateTransform = function () {
- this.validate();
- this.containerUpdateTransform();
- };
- BitmapText.prototype._render = function (renderer) {
- if (this._autoResolution && this._resolution !== renderer.resolution) {
- this._resolution = renderer.resolution;
- this.dirty = true;
- }
- // Update the uniform
- var _a = BitmapFont.available[this._fontName], distanceFieldRange = _a.distanceFieldRange, distanceFieldType = _a.distanceFieldType, size = _a.size;
- if (distanceFieldType !== 'none') {
- // Inject the shader code with the correct value
- var _b = this.worldTransform, a = _b.a, b = _b.b, c = _b.c, d = _b.d;
- var dx = Math.sqrt((a * a) + (b * b));
- var dy = Math.sqrt((c * c) + (d * d));
- var worldScale = (Math.abs(dx) + Math.abs(dy)) / 2;
- var fontScale = this.fontSize / size;
- for (var _i = 0, _c = this._activePagesMeshData; _i < _c.length; _i++) {
- var mesh = _c[_i];
- mesh.mesh.shader.uniforms.uFWidth = worldScale * distanceFieldRange * fontScale * this._resolution;
- }
- }
- _super.prototype._render.call(this, renderer);
- };
- /**
- * Validates text before calling parent's getLocalBounds
- * @returns - The rectangular bounding area
- */
- BitmapText.prototype.getLocalBounds = function () {
- this.validate();
- return _super.prototype.getLocalBounds.call(this);
- };
- /**
- * Updates text when needed
- * @private
- */
- BitmapText.prototype.validate = function () {
- var font = BitmapFont.available[this._fontName];
- if (!font) {
- throw new Error("Missing BitmapFont \"" + this._fontName + "\"");
- }
- if (this._font !== font) {
- this.dirty = true;
- }
- if (this.dirty) {
- this.updateText();
- }
- };
- Object.defineProperty(BitmapText.prototype, "tint", {
- /**
- * The tint of the BitmapText object.
- * @default 0xffffff
- */
- get: function () {
- return this._tint;
- },
- set: function (value) {
- if (this._tint === value)
- { return; }
- this._tint = value;
- for (var i = 0; i < this._activePagesMeshData.length; i++) {
- this._activePagesMeshData[i].mesh.tint = value;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(BitmapText.prototype, "align", {
- /**
- * The alignment of the BitmapText object.
- * @member {string}
- * @default 'left'
- */
- get: function () {
- return this._align;
- },
- set: function (value) {
- if (this._align !== value) {
- this._align = value;
- this.dirty = true;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(BitmapText.prototype, "fontName", {
- /** The name of the BitmapFont. */
- get: function () {
- return this._fontName;
- },
- set: function (value) {
- if (!BitmapFont.available[value]) {
- throw new Error("Missing BitmapFont \"" + value + "\"");
- }
- if (this._fontName !== value) {
- this._fontName = value;
- this.dirty = true;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(BitmapText.prototype, "fontSize", {
- /** The size of the font to display. */
- get: function () {
- var _a;
- return (_a = this._fontSize) !== null && _a !== void 0 ? _a : BitmapFont.available[this._fontName].size;
- },
- set: function (value) {
- if (this._fontSize !== value) {
- this._fontSize = value;
- this.dirty = true;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(BitmapText.prototype, "anchor", {
- /**
- * The anchor sets the origin point of the text.
- *
- * The default is `(0,0)`, this means the text's origin is the top left.
- *
- * Setting the anchor to `(0.5,0.5)` means the text's origin is centered.
- *
- * Setting the anchor to `(1,1)` would mean the text's origin point will be the bottom right corner.
- */
- get: function () {
- return this._anchor;
- },
- set: function (value) {
- if (typeof value === 'number') {
- this._anchor.set(value);
- }
- else {
- this._anchor.copyFrom(value);
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(BitmapText.prototype, "text", {
- /** The text of the BitmapText object. */
- get: function () {
- return this._text;
- },
- set: function (text) {
- text = String(text === null || text === undefined ? '' : text);
- if (this._text === text) {
- return;
- }
- this._text = text;
- this.dirty = true;
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(BitmapText.prototype, "maxWidth", {
- /**
- * The max width of this bitmap text in pixels. If the text provided is longer than the
- * value provided, line breaks will be automatically inserted in the last whitespace.
- * Disable by setting the value to 0.
- */
- get: function () {
- return this._maxWidth;
- },
- set: function (value) {
- if (this._maxWidth === value) {
- return;
- }
- this._maxWidth = value;
- this.dirty = true;
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(BitmapText.prototype, "maxLineHeight", {
- /**
- * The max line height. This is useful when trying to use the total height of the Text,
- * i.e. when trying to vertically align.
- * @readonly
- */
- get: function () {
- this.validate();
- return this._maxLineHeight;
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(BitmapText.prototype, "textWidth", {
- /**
- * The width of the overall text, different from fontSize,
- * which is defined in the style object.
- * @readonly
- */
- get: function () {
- this.validate();
- return this._textWidth;
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(BitmapText.prototype, "letterSpacing", {
- /** Additional space between characters. */
- get: function () {
- return this._letterSpacing;
- },
- set: function (value) {
- if (this._letterSpacing !== value) {
- this._letterSpacing = value;
- this.dirty = true;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(BitmapText.prototype, "roundPixels", {
- /**
- * If true PixiJS will Math.floor() x/y values when rendering, stopping pixel interpolation.
- * Advantages can include sharper image quality (like text) and faster rendering on canvas.
- * The main disadvantage is movement of objects may appear less smooth.
- * To set the global default, change {@link PIXI.settings.ROUND_PIXELS}
- * @default PIXI.settings.ROUND_PIXELS
- */
- get: function () {
- return this._roundPixels;
- },
- set: function (value) {
- if (value !== this._roundPixels) {
- this._roundPixels = value;
- this.dirty = true;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(BitmapText.prototype, "textHeight", {
- /**
- * The height of the overall text, different from fontSize,
- * which is defined in the style object.
- * @readonly
- */
- get: function () {
- this.validate();
- return this._textHeight;
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(BitmapText.prototype, "resolution", {
- /**
- * The resolution / device pixel ratio of the canvas.
- *
- * This is set to automatically match the renderer resolution by default, but can be overridden by setting manually.
- * @default 1
- */
- get: function () {
- return this._resolution;
- },
- set: function (value) {
- this._autoResolution = false;
- if (this._resolution === value) {
- return;
- }
- this._resolution = value;
- this.dirty = true;
- },
- enumerable: false,
- configurable: true
- });
- BitmapText.prototype.destroy = function (options) {
- var _textureCache = this._textureCache;
- var data = BitmapFont.available[this._fontName];
- var pageMeshDataPool = data.distanceFieldType === 'none'
- ? pageMeshDataDefaultPageMeshData : pageMeshDataMSDFPageMeshData;
- pageMeshDataPool.push.apply(pageMeshDataPool, this._activePagesMeshData);
- for (var _i = 0, _a = this._activePagesMeshData; _i < _a.length; _i++) {
- var pageMeshData = _a[_i];
- this.removeChild(pageMeshData.mesh);
- }
- this._activePagesMeshData = [];
- // Release references to any cached textures in page pool
- pageMeshDataPool
- .filter(function (page) { return _textureCache[page.mesh.texture.baseTexture.uid]; })
- .forEach(function (page) {
- page.mesh.texture = Texture.EMPTY;
- });
- for (var id in _textureCache) {
- var texture = _textureCache[id];
- texture.destroy();
- delete _textureCache[id];
- }
- this._font = null;
- this._textureCache = null;
- _super.prototype.destroy.call(this, options);
- };
- BitmapText.styleDefaults = {
- align: 'left',
- tint: 0xFFFFFF,
- maxWidth: 0,
- letterSpacing: 0,
- };
- return BitmapText;
- }(Container));
- /**
- * {@link PIXI.Loader Loader} middleware for loading
- * bitmap-based fonts suitable for using with {@link PIXI.BitmapText}.
- * @memberof PIXI
- */
- var BitmapFontLoader = /** @class */ (function () {
- function BitmapFontLoader() {
- }
- /**
- * Called when the plugin is installed.
- * @see PIXI.extensions.add
- */
- BitmapFontLoader.add = function () {
- LoaderResource.setExtensionXhrType('fnt', LoaderResource.XHR_RESPONSE_TYPE.TEXT);
- };
- /**
- * Called after a resource is loaded.
- * @see PIXI.Loader.loaderMiddleware
- * @param this
- * @param {PIXI.LoaderResource} resource
- * @param {Function} next
- */
- BitmapFontLoader.use = function (resource, next) {
- var format = autoDetectFormat(resource.data);
- // Resource was not recognised as any of the expected font data format
- if (!format) {
- next();
- return;
- }
- var baseUrl = BitmapFontLoader.getBaseUrl(this, resource);
- var data = format.parse(resource.data);
- var textures = {};
- // Handle completed, when the number of textures
- // load is the same number as references in the fnt file
- var completed = function (page) {
- textures[page.metadata.pageFile] = page.texture;
- if (Object.keys(textures).length === data.page.length) {
- resource.bitmapFont = BitmapFont.install(data, textures, true);
- next();
- }
- };
- for (var i = 0; i < data.page.length; ++i) {
- var pageFile = data.page[i].file;
- var url = baseUrl + pageFile;
- var exists = false;
- // incase the image is loaded outside
- // using the same loader, resource will be available
- for (var name in this.resources) {
- var bitmapResource = this.resources[name];
- if (bitmapResource.url === url) {
- bitmapResource.metadata.pageFile = pageFile;
- if (bitmapResource.texture) {
- completed(bitmapResource);
- }
- else {
- bitmapResource.onAfterMiddleware.add(completed);
- }
- exists = true;
- break;
- }
- }
- // texture is not loaded, we'll attempt to add
- // it to the load and add the texture to the list
- if (!exists) {
- // Standard loading options for images
- var options = {
- crossOrigin: resource.crossOrigin,
- loadType: LoaderResource.LOAD_TYPE.IMAGE,
- metadata: Object.assign({ pageFile: pageFile }, resource.metadata.imageMetadata),
- parentResource: resource,
- };
- this.add(url, options, completed);
- }
- }
- };
- /**
- * Get folder path from a resource.
- * @param loader
- * @param resource
- */
- BitmapFontLoader.getBaseUrl = function (loader, resource) {
- var resUrl = !resource.isDataUrl ? BitmapFontLoader.dirname(resource.url) : '';
- if (resource.isDataUrl) {
- if (resUrl === '.') {
- resUrl = '';
- }
- if (loader.baseUrl && resUrl) {
- // if baseurl has a trailing slash then add one to resUrl so the replace works below
- if (loader.baseUrl.charAt(loader.baseUrl.length - 1) === '/') {
- resUrl += '/';
- }
- }
- }
- // remove baseUrl from resUrl
- resUrl = resUrl.replace(loader.baseUrl, '');
- // if there is an resUrl now, it needs a trailing slash. Ensure that it does if the string isn't empty.
- if (resUrl && resUrl.charAt(resUrl.length - 1) !== '/') {
- resUrl += '/';
- }
- return resUrl;
- };
- /**
- * Replacement for NodeJS's path.dirname
- * @param {string} url - Path to get directory for
- */
- BitmapFontLoader.dirname = function (url) {
- var dir = url
- .replace(/\\/g, '/') // convert windows notation to UNIX notation, URL-safe because it's a forbidden character
- .replace(/\/$/, '') // replace trailing slash
- .replace(/\/[^\/]*$/, ''); // remove everything after the last
- // File request is relative, use current directory
- if (dir === url) {
- return '.';
- }
- // Started with a slash
- else if (dir === '') {
- return '/';
- }
- return dir;
- };
- /** @ignore */
- BitmapFontLoader.extension = ExtensionType.Loader;
- return BitmapFontLoader;
- }());
- export { BitmapFont, BitmapFontData, BitmapFontLoader, BitmapText, TextFormat, XMLFormat, XMLStringFormat, autoDetectFormat };
- //# sourceMappingURL=text-bitmap.mjs.map
|