diff --git a/packages/text-bitmap/src/BitmapFontLoader.js b/packages/text-bitmap/src/BitmapFontLoader.js index 650564a..4368ee5 100644 --- a/packages/text-bitmap/src/BitmapFontLoader.js +++ b/packages/text-bitmap/src/BitmapFontLoader.js @@ -112,29 +112,53 @@ xmlUrl += '/'; } - const textureUrl = xmlUrl + resource.data.getElementsByTagName('page')[0].getAttribute('file'); + const pages = resource.data.getElementsByTagName('page'); + const textures = []; + const loadOptions = { + crossOrigin: resource.crossOrigin, + loadType: LoaderResource.LOAD_TYPE.IMAGE, + metadata: resource.metadata.imageMetadata, + parentResource: resource, + }; - if (TextureCache[textureUrl]) + for (let x = 0; x < pages.length; ++x) { - // reuse existing texture - BitmapFontLoader.parse(resource, TextureCache[textureUrl]); - next(); - } - else - { - const loadOptions = { - crossOrigin: resource.crossOrigin, - loadType: LoaderResource.LOAD_TYPE.IMAGE, - metadata: resource.metadata.imageMetadata, - parentResource: resource, - }; + const textureUrl = xmlUrl + pages[x].getAttribute('file'); - // load the texture for the font - this.add(`${resource.name}_image`, textureUrl, loadOptions, (res) => + if (TextureCache[textureUrl]) { - BitmapFontLoader.parse(resource, res.texture); - next(); - }); + textures.push(TextureCache[textureUrl]); + } + else + { + // load the texture for the font + this.add(`${resource.name}_image${x}`, textureUrl, loadOptions, () => + { + const nextTextures = []; + + for (let x = 0; x < pages.length; ++x) + { + const nextTextureUrl = xmlUrl + pages[x].getAttribute('file'); + + if (TextureCache[nextTextureUrl]) + { + nextTextures.push(TextureCache[nextTextureUrl]); + } + else + { + return; + } + } + BitmapFontLoader.parse(resource, nextTextures); + next(); + }); + } + } + + if (textures.length === pages.length) + { + BitmapFontLoader.parse(resource, textures); + next(); } } } diff --git a/packages/text-bitmap/src/BitmapFontLoader.js b/packages/text-bitmap/src/BitmapFontLoader.js index 650564a..4368ee5 100644 --- a/packages/text-bitmap/src/BitmapFontLoader.js +++ b/packages/text-bitmap/src/BitmapFontLoader.js @@ -112,29 +112,53 @@ xmlUrl += '/'; } - const textureUrl = xmlUrl + resource.data.getElementsByTagName('page')[0].getAttribute('file'); + const pages = resource.data.getElementsByTagName('page'); + const textures = []; + const loadOptions = { + crossOrigin: resource.crossOrigin, + loadType: LoaderResource.LOAD_TYPE.IMAGE, + metadata: resource.metadata.imageMetadata, + parentResource: resource, + }; - if (TextureCache[textureUrl]) + for (let x = 0; x < pages.length; ++x) { - // reuse existing texture - BitmapFontLoader.parse(resource, TextureCache[textureUrl]); - next(); - } - else - { - const loadOptions = { - crossOrigin: resource.crossOrigin, - loadType: LoaderResource.LOAD_TYPE.IMAGE, - metadata: resource.metadata.imageMetadata, - parentResource: resource, - }; + const textureUrl = xmlUrl + pages[x].getAttribute('file'); - // load the texture for the font - this.add(`${resource.name}_image`, textureUrl, loadOptions, (res) => + if (TextureCache[textureUrl]) { - BitmapFontLoader.parse(resource, res.texture); - next(); - }); + textures.push(TextureCache[textureUrl]); + } + else + { + // load the texture for the font + this.add(`${resource.name}_image${x}`, textureUrl, loadOptions, () => + { + const nextTextures = []; + + for (let x = 0; x < pages.length; ++x) + { + const nextTextureUrl = xmlUrl + pages[x].getAttribute('file'); + + if (TextureCache[nextTextureUrl]) + { + nextTextures.push(TextureCache[nextTextureUrl]); + } + else + { + return; + } + } + BitmapFontLoader.parse(resource, nextTextures); + next(); + }); + } + } + + if (textures.length === pages.length) + { + BitmapFontLoader.parse(resource, textures); + next(); } } } diff --git a/packages/text-bitmap/src/BitmapText.js b/packages/text-bitmap/src/BitmapText.js index fa30f2e..b9b535a 100644 --- a/packages/text-bitmap/src/BitmapText.js +++ b/packages/text-bitmap/src/BitmapText.js @@ -509,10 +509,10 @@ * * @static * @param {XMLDocument} xml - The XML document data. - * @param {PIXI.Texture} texture - Texture with all symbols. + * @param {PIXI.Texture|PIXI.Texture[]} textures - List of textures for each page. * @return {Object} Result font object with font, size, lineHeight and char fields. */ - static registerFont(xml, texture) + static registerFont(xml, textures) { const data = {}; const info = xml.getElementsByTagName('info')[0]; @@ -524,29 +524,44 @@ data.size = parseInt(info.getAttribute('size'), 10); data.lineHeight = parseInt(common.getAttribute('lineHeight'), 10) / res; data.chars = {}; + if (!(textures instanceof Array)) + { + textures = [textures]; + } // parse letters const letters = xml.getElementsByTagName('char'); + let page; for (let i = 0; i < letters.length; i++) { const letter = letters[i]; const charCode = parseInt(letter.getAttribute('id'), 10); + let textureRect; - const textureRect = new Rectangle( - (parseInt(letter.getAttribute('x'), 10) / res) + (texture.frame.x / res), - (parseInt(letter.getAttribute('y'), 10) / res) + (texture.frame.y / res), - parseInt(letter.getAttribute('width'), 10) / res, - parseInt(letter.getAttribute('height'), 10) / res - ); + page = parseInt(letter.getAttribute('page'), 10); + if (isNaN(page)) + { + textureRect = new Rectangle(0, 0, 0, 0); + page = 0; + } + else + { + textureRect = new Rectangle( + (parseInt(letter.getAttribute('x'), 10) / res) + (textures[page].frame.x / res), + (parseInt(letter.getAttribute('y'), 10) / res) + (textures[page].frame.y / res), + parseInt(letter.getAttribute('width'), 10) / res, + parseInt(letter.getAttribute('height'), 10) / res + ); + } data.chars[charCode] = { xOffset: parseInt(letter.getAttribute('xoffset'), 10) / res, yOffset: parseInt(letter.getAttribute('yoffset'), 10) / res, xAdvance: parseInt(letter.getAttribute('xadvance'), 10) / res, kerning: {}, - texture: new Texture(texture.baseTexture, textureRect), - + texture: new Texture(textures[page].baseTexture, textureRect), + page, }; } diff --git a/packages/text-bitmap/src/BitmapFontLoader.js b/packages/text-bitmap/src/BitmapFontLoader.js index 650564a..4368ee5 100644 --- a/packages/text-bitmap/src/BitmapFontLoader.js +++ b/packages/text-bitmap/src/BitmapFontLoader.js @@ -112,29 +112,53 @@ xmlUrl += '/'; } - const textureUrl = xmlUrl + resource.data.getElementsByTagName('page')[0].getAttribute('file'); + const pages = resource.data.getElementsByTagName('page'); + const textures = []; + const loadOptions = { + crossOrigin: resource.crossOrigin, + loadType: LoaderResource.LOAD_TYPE.IMAGE, + metadata: resource.metadata.imageMetadata, + parentResource: resource, + }; - if (TextureCache[textureUrl]) + for (let x = 0; x < pages.length; ++x) { - // reuse existing texture - BitmapFontLoader.parse(resource, TextureCache[textureUrl]); - next(); - } - else - { - const loadOptions = { - crossOrigin: resource.crossOrigin, - loadType: LoaderResource.LOAD_TYPE.IMAGE, - metadata: resource.metadata.imageMetadata, - parentResource: resource, - }; + const textureUrl = xmlUrl + pages[x].getAttribute('file'); - // load the texture for the font - this.add(`${resource.name}_image`, textureUrl, loadOptions, (res) => + if (TextureCache[textureUrl]) { - BitmapFontLoader.parse(resource, res.texture); - next(); - }); + textures.push(TextureCache[textureUrl]); + } + else + { + // load the texture for the font + this.add(`${resource.name}_image${x}`, textureUrl, loadOptions, () => + { + const nextTextures = []; + + for (let x = 0; x < pages.length; ++x) + { + const nextTextureUrl = xmlUrl + pages[x].getAttribute('file'); + + if (TextureCache[nextTextureUrl]) + { + nextTextures.push(TextureCache[nextTextureUrl]); + } + else + { + return; + } + } + BitmapFontLoader.parse(resource, nextTextures); + next(); + }); + } + } + + if (textures.length === pages.length) + { + BitmapFontLoader.parse(resource, textures); + next(); } } } diff --git a/packages/text-bitmap/src/BitmapText.js b/packages/text-bitmap/src/BitmapText.js index fa30f2e..b9b535a 100644 --- a/packages/text-bitmap/src/BitmapText.js +++ b/packages/text-bitmap/src/BitmapText.js @@ -509,10 +509,10 @@ * * @static * @param {XMLDocument} xml - The XML document data. - * @param {PIXI.Texture} texture - Texture with all symbols. + * @param {PIXI.Texture|PIXI.Texture[]} textures - List of textures for each page. * @return {Object} Result font object with font, size, lineHeight and char fields. */ - static registerFont(xml, texture) + static registerFont(xml, textures) { const data = {}; const info = xml.getElementsByTagName('info')[0]; @@ -524,29 +524,44 @@ data.size = parseInt(info.getAttribute('size'), 10); data.lineHeight = parseInt(common.getAttribute('lineHeight'), 10) / res; data.chars = {}; + if (!(textures instanceof Array)) + { + textures = [textures]; + } // parse letters const letters = xml.getElementsByTagName('char'); + let page; for (let i = 0; i < letters.length; i++) { const letter = letters[i]; const charCode = parseInt(letter.getAttribute('id'), 10); + let textureRect; - const textureRect = new Rectangle( - (parseInt(letter.getAttribute('x'), 10) / res) + (texture.frame.x / res), - (parseInt(letter.getAttribute('y'), 10) / res) + (texture.frame.y / res), - parseInt(letter.getAttribute('width'), 10) / res, - parseInt(letter.getAttribute('height'), 10) / res - ); + page = parseInt(letter.getAttribute('page'), 10); + if (isNaN(page)) + { + textureRect = new Rectangle(0, 0, 0, 0); + page = 0; + } + else + { + textureRect = new Rectangle( + (parseInt(letter.getAttribute('x'), 10) / res) + (textures[page].frame.x / res), + (parseInt(letter.getAttribute('y'), 10) / res) + (textures[page].frame.y / res), + parseInt(letter.getAttribute('width'), 10) / res, + parseInt(letter.getAttribute('height'), 10) / res + ); + } data.chars[charCode] = { xOffset: parseInt(letter.getAttribute('xoffset'), 10) / res, yOffset: parseInt(letter.getAttribute('yoffset'), 10) / res, xAdvance: parseInt(letter.getAttribute('xadvance'), 10) / res, kerning: {}, - texture: new Texture(texture.baseTexture, textureRect), - + texture: new Texture(textures[page].baseTexture, textureRect), + page, }; } diff --git a/packages/text-bitmap/test/BitmapFontLoader.js b/packages/text-bitmap/test/BitmapFontLoader.js index 1f3d385..8afdcd0 100644 --- a/packages/text-bitmap/test/BitmapFontLoader.js +++ b/packages/text-bitmap/test/BitmapFontLoader.js @@ -1,5 +1,6 @@ const path = require('path'); const fs = require('fs'); +const { Loader } = require('@pixi/loaders'); const { BaseTextureCache, TextureCache } = require('@pixi/utils'); const { Texture, BaseTexture } = require('@pixi/core'); const { Spritesheet } = require('@pixi/spritesheet'); @@ -327,6 +328,71 @@ }); }); + it('should properly register bitmap font having more than one texture', function (done) + { + Loader.registerPlugin(BitmapFontLoader); + + const loader = new Loader(); + + loader.add(`${__dirname}/resources/split_font.fnt`); + loader.load(() => + { + const font = BitmapText.fonts.split_font; + + expect(font).to.be.an.object; + expect(BitmapText.fonts.split_font).to.equal(font); + expect(font).to.have.property('chars'); + const charA = font.chars['A'.charCodeAt(0) || 65]; + + expect(charA).to.exist; + let src = charA.texture.baseTexture.resource.url; + + src = src.substring(src.length - 17); + expect(src).to.equal('split_font_ab.png'); + expect(charA.texture.frame.x).to.equal(2); + expect(charA.texture.frame.y).to.equal(2); + expect(charA.texture.frame.width).to.equal(19); + expect(charA.texture.frame.height).to.equal(20); + const charB = font.chars['B'.charCodeAt(0) || 66]; + + expect(charB).to.exist; + src = charB.texture.baseTexture.resource.url; + + src = src.substring(src.length - 17); + expect(src).to.equal('split_font_ab.png'); + expect(charB.texture.frame.x).to.equal(2); + expect(charB.texture.frame.y).to.equal(24); + expect(charB.texture.frame.width).to.equal(15); + expect(charB.texture.frame.height).to.equal(20); + const charC = font.chars['C'.charCodeAt(0) || 67]; + + expect(charC).to.exist; + src = charC.texture.baseTexture.resource.url; + + src = src.substring(src.length - 17); + expect(src).to.equal('split_font_cd.png'); + expect(charC.texture.frame.x).to.equal(2); + expect(charC.texture.frame.y).to.equal(2); + expect(charC.texture.frame.width).to.equal(18); + expect(charC.texture.frame.height).to.equal(20); + const charD = font.chars['D'.charCodeAt(0) || 68]; + + expect(charD).to.exist; + src = charD.texture.baseTexture.resource.url; + + src = src.substring(src.length - 17); + expect(src).to.equal('split_font_cd.png'); + expect(charD.texture.frame.x).to.equal(2); + expect(charD.texture.frame.y).to.equal(24); + expect(charD.texture.frame.width).to.equal(17); + expect(charD.texture.frame.height).to.equal(20); + const charE = font.chars['E'.charCodeAt(0) || 69]; + + expect(charE).to.be.undefined; + done(); + }); + }); + it('should parse exist', function () { expect(BitmapFontLoader.parse).to.be.a('function'); diff --git a/packages/text-bitmap/src/BitmapFontLoader.js b/packages/text-bitmap/src/BitmapFontLoader.js index 650564a..4368ee5 100644 --- a/packages/text-bitmap/src/BitmapFontLoader.js +++ b/packages/text-bitmap/src/BitmapFontLoader.js @@ -112,29 +112,53 @@ xmlUrl += '/'; } - const textureUrl = xmlUrl + resource.data.getElementsByTagName('page')[0].getAttribute('file'); + const pages = resource.data.getElementsByTagName('page'); + const textures = []; + const loadOptions = { + crossOrigin: resource.crossOrigin, + loadType: LoaderResource.LOAD_TYPE.IMAGE, + metadata: resource.metadata.imageMetadata, + parentResource: resource, + }; - if (TextureCache[textureUrl]) + for (let x = 0; x < pages.length; ++x) { - // reuse existing texture - BitmapFontLoader.parse(resource, TextureCache[textureUrl]); - next(); - } - else - { - const loadOptions = { - crossOrigin: resource.crossOrigin, - loadType: LoaderResource.LOAD_TYPE.IMAGE, - metadata: resource.metadata.imageMetadata, - parentResource: resource, - }; + const textureUrl = xmlUrl + pages[x].getAttribute('file'); - // load the texture for the font - this.add(`${resource.name}_image`, textureUrl, loadOptions, (res) => + if (TextureCache[textureUrl]) { - BitmapFontLoader.parse(resource, res.texture); - next(); - }); + textures.push(TextureCache[textureUrl]); + } + else + { + // load the texture for the font + this.add(`${resource.name}_image${x}`, textureUrl, loadOptions, () => + { + const nextTextures = []; + + for (let x = 0; x < pages.length; ++x) + { + const nextTextureUrl = xmlUrl + pages[x].getAttribute('file'); + + if (TextureCache[nextTextureUrl]) + { + nextTextures.push(TextureCache[nextTextureUrl]); + } + else + { + return; + } + } + BitmapFontLoader.parse(resource, nextTextures); + next(); + }); + } + } + + if (textures.length === pages.length) + { + BitmapFontLoader.parse(resource, textures); + next(); } } } diff --git a/packages/text-bitmap/src/BitmapText.js b/packages/text-bitmap/src/BitmapText.js index fa30f2e..b9b535a 100644 --- a/packages/text-bitmap/src/BitmapText.js +++ b/packages/text-bitmap/src/BitmapText.js @@ -509,10 +509,10 @@ * * @static * @param {XMLDocument} xml - The XML document data. - * @param {PIXI.Texture} texture - Texture with all symbols. + * @param {PIXI.Texture|PIXI.Texture[]} textures - List of textures for each page. * @return {Object} Result font object with font, size, lineHeight and char fields. */ - static registerFont(xml, texture) + static registerFont(xml, textures) { const data = {}; const info = xml.getElementsByTagName('info')[0]; @@ -524,29 +524,44 @@ data.size = parseInt(info.getAttribute('size'), 10); data.lineHeight = parseInt(common.getAttribute('lineHeight'), 10) / res; data.chars = {}; + if (!(textures instanceof Array)) + { + textures = [textures]; + } // parse letters const letters = xml.getElementsByTagName('char'); + let page; for (let i = 0; i < letters.length; i++) { const letter = letters[i]; const charCode = parseInt(letter.getAttribute('id'), 10); + let textureRect; - const textureRect = new Rectangle( - (parseInt(letter.getAttribute('x'), 10) / res) + (texture.frame.x / res), - (parseInt(letter.getAttribute('y'), 10) / res) + (texture.frame.y / res), - parseInt(letter.getAttribute('width'), 10) / res, - parseInt(letter.getAttribute('height'), 10) / res - ); + page = parseInt(letter.getAttribute('page'), 10); + if (isNaN(page)) + { + textureRect = new Rectangle(0, 0, 0, 0); + page = 0; + } + else + { + textureRect = new Rectangle( + (parseInt(letter.getAttribute('x'), 10) / res) + (textures[page].frame.x / res), + (parseInt(letter.getAttribute('y'), 10) / res) + (textures[page].frame.y / res), + parseInt(letter.getAttribute('width'), 10) / res, + parseInt(letter.getAttribute('height'), 10) / res + ); + } data.chars[charCode] = { xOffset: parseInt(letter.getAttribute('xoffset'), 10) / res, yOffset: parseInt(letter.getAttribute('yoffset'), 10) / res, xAdvance: parseInt(letter.getAttribute('xadvance'), 10) / res, kerning: {}, - texture: new Texture(texture.baseTexture, textureRect), - + texture: new Texture(textures[page].baseTexture, textureRect), + page, }; } diff --git a/packages/text-bitmap/test/BitmapFontLoader.js b/packages/text-bitmap/test/BitmapFontLoader.js index 1f3d385..8afdcd0 100644 --- a/packages/text-bitmap/test/BitmapFontLoader.js +++ b/packages/text-bitmap/test/BitmapFontLoader.js @@ -1,5 +1,6 @@ const path = require('path'); const fs = require('fs'); +const { Loader } = require('@pixi/loaders'); const { BaseTextureCache, TextureCache } = require('@pixi/utils'); const { Texture, BaseTexture } = require('@pixi/core'); const { Spritesheet } = require('@pixi/spritesheet'); @@ -327,6 +328,71 @@ }); }); + it('should properly register bitmap font having more than one texture', function (done) + { + Loader.registerPlugin(BitmapFontLoader); + + const loader = new Loader(); + + loader.add(`${__dirname}/resources/split_font.fnt`); + loader.load(() => + { + const font = BitmapText.fonts.split_font; + + expect(font).to.be.an.object; + expect(BitmapText.fonts.split_font).to.equal(font); + expect(font).to.have.property('chars'); + const charA = font.chars['A'.charCodeAt(0) || 65]; + + expect(charA).to.exist; + let src = charA.texture.baseTexture.resource.url; + + src = src.substring(src.length - 17); + expect(src).to.equal('split_font_ab.png'); + expect(charA.texture.frame.x).to.equal(2); + expect(charA.texture.frame.y).to.equal(2); + expect(charA.texture.frame.width).to.equal(19); + expect(charA.texture.frame.height).to.equal(20); + const charB = font.chars['B'.charCodeAt(0) || 66]; + + expect(charB).to.exist; + src = charB.texture.baseTexture.resource.url; + + src = src.substring(src.length - 17); + expect(src).to.equal('split_font_ab.png'); + expect(charB.texture.frame.x).to.equal(2); + expect(charB.texture.frame.y).to.equal(24); + expect(charB.texture.frame.width).to.equal(15); + expect(charB.texture.frame.height).to.equal(20); + const charC = font.chars['C'.charCodeAt(0) || 67]; + + expect(charC).to.exist; + src = charC.texture.baseTexture.resource.url; + + src = src.substring(src.length - 17); + expect(src).to.equal('split_font_cd.png'); + expect(charC.texture.frame.x).to.equal(2); + expect(charC.texture.frame.y).to.equal(2); + expect(charC.texture.frame.width).to.equal(18); + expect(charC.texture.frame.height).to.equal(20); + const charD = font.chars['D'.charCodeAt(0) || 68]; + + expect(charD).to.exist; + src = charD.texture.baseTexture.resource.url; + + src = src.substring(src.length - 17); + expect(src).to.equal('split_font_cd.png'); + expect(charD.texture.frame.x).to.equal(2); + expect(charD.texture.frame.y).to.equal(24); + expect(charD.texture.frame.width).to.equal(17); + expect(charD.texture.frame.height).to.equal(20); + const charE = font.chars['E'.charCodeAt(0) || 69]; + + expect(charE).to.be.undefined; + done(); + }); + }); + it('should parse exist', function () { expect(BitmapFontLoader.parse).to.be.a('function'); diff --git a/packages/text-bitmap/test/resources/split_font.fnt b/packages/text-bitmap/test/resources/split_font.fnt new file mode 100644 index 0000000..35cbf49 --- /dev/null +++ b/packages/text-bitmap/test/resources/split_font.fnt @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/text-bitmap/src/BitmapFontLoader.js b/packages/text-bitmap/src/BitmapFontLoader.js index 650564a..4368ee5 100644 --- a/packages/text-bitmap/src/BitmapFontLoader.js +++ b/packages/text-bitmap/src/BitmapFontLoader.js @@ -112,29 +112,53 @@ xmlUrl += '/'; } - const textureUrl = xmlUrl + resource.data.getElementsByTagName('page')[0].getAttribute('file'); + const pages = resource.data.getElementsByTagName('page'); + const textures = []; + const loadOptions = { + crossOrigin: resource.crossOrigin, + loadType: LoaderResource.LOAD_TYPE.IMAGE, + metadata: resource.metadata.imageMetadata, + parentResource: resource, + }; - if (TextureCache[textureUrl]) + for (let x = 0; x < pages.length; ++x) { - // reuse existing texture - BitmapFontLoader.parse(resource, TextureCache[textureUrl]); - next(); - } - else - { - const loadOptions = { - crossOrigin: resource.crossOrigin, - loadType: LoaderResource.LOAD_TYPE.IMAGE, - metadata: resource.metadata.imageMetadata, - parentResource: resource, - }; + const textureUrl = xmlUrl + pages[x].getAttribute('file'); - // load the texture for the font - this.add(`${resource.name}_image`, textureUrl, loadOptions, (res) => + if (TextureCache[textureUrl]) { - BitmapFontLoader.parse(resource, res.texture); - next(); - }); + textures.push(TextureCache[textureUrl]); + } + else + { + // load the texture for the font + this.add(`${resource.name}_image${x}`, textureUrl, loadOptions, () => + { + const nextTextures = []; + + for (let x = 0; x < pages.length; ++x) + { + const nextTextureUrl = xmlUrl + pages[x].getAttribute('file'); + + if (TextureCache[nextTextureUrl]) + { + nextTextures.push(TextureCache[nextTextureUrl]); + } + else + { + return; + } + } + BitmapFontLoader.parse(resource, nextTextures); + next(); + }); + } + } + + if (textures.length === pages.length) + { + BitmapFontLoader.parse(resource, textures); + next(); } } } diff --git a/packages/text-bitmap/src/BitmapText.js b/packages/text-bitmap/src/BitmapText.js index fa30f2e..b9b535a 100644 --- a/packages/text-bitmap/src/BitmapText.js +++ b/packages/text-bitmap/src/BitmapText.js @@ -509,10 +509,10 @@ * * @static * @param {XMLDocument} xml - The XML document data. - * @param {PIXI.Texture} texture - Texture with all symbols. + * @param {PIXI.Texture|PIXI.Texture[]} textures - List of textures for each page. * @return {Object} Result font object with font, size, lineHeight and char fields. */ - static registerFont(xml, texture) + static registerFont(xml, textures) { const data = {}; const info = xml.getElementsByTagName('info')[0]; @@ -524,29 +524,44 @@ data.size = parseInt(info.getAttribute('size'), 10); data.lineHeight = parseInt(common.getAttribute('lineHeight'), 10) / res; data.chars = {}; + if (!(textures instanceof Array)) + { + textures = [textures]; + } // parse letters const letters = xml.getElementsByTagName('char'); + let page; for (let i = 0; i < letters.length; i++) { const letter = letters[i]; const charCode = parseInt(letter.getAttribute('id'), 10); + let textureRect; - const textureRect = new Rectangle( - (parseInt(letter.getAttribute('x'), 10) / res) + (texture.frame.x / res), - (parseInt(letter.getAttribute('y'), 10) / res) + (texture.frame.y / res), - parseInt(letter.getAttribute('width'), 10) / res, - parseInt(letter.getAttribute('height'), 10) / res - ); + page = parseInt(letter.getAttribute('page'), 10); + if (isNaN(page)) + { + textureRect = new Rectangle(0, 0, 0, 0); + page = 0; + } + else + { + textureRect = new Rectangle( + (parseInt(letter.getAttribute('x'), 10) / res) + (textures[page].frame.x / res), + (parseInt(letter.getAttribute('y'), 10) / res) + (textures[page].frame.y / res), + parseInt(letter.getAttribute('width'), 10) / res, + parseInt(letter.getAttribute('height'), 10) / res + ); + } data.chars[charCode] = { xOffset: parseInt(letter.getAttribute('xoffset'), 10) / res, yOffset: parseInt(letter.getAttribute('yoffset'), 10) / res, xAdvance: parseInt(letter.getAttribute('xadvance'), 10) / res, kerning: {}, - texture: new Texture(texture.baseTexture, textureRect), - + texture: new Texture(textures[page].baseTexture, textureRect), + page, }; } diff --git a/packages/text-bitmap/test/BitmapFontLoader.js b/packages/text-bitmap/test/BitmapFontLoader.js index 1f3d385..8afdcd0 100644 --- a/packages/text-bitmap/test/BitmapFontLoader.js +++ b/packages/text-bitmap/test/BitmapFontLoader.js @@ -1,5 +1,6 @@ const path = require('path'); const fs = require('fs'); +const { Loader } = require('@pixi/loaders'); const { BaseTextureCache, TextureCache } = require('@pixi/utils'); const { Texture, BaseTexture } = require('@pixi/core'); const { Spritesheet } = require('@pixi/spritesheet'); @@ -327,6 +328,71 @@ }); }); + it('should properly register bitmap font having more than one texture', function (done) + { + Loader.registerPlugin(BitmapFontLoader); + + const loader = new Loader(); + + loader.add(`${__dirname}/resources/split_font.fnt`); + loader.load(() => + { + const font = BitmapText.fonts.split_font; + + expect(font).to.be.an.object; + expect(BitmapText.fonts.split_font).to.equal(font); + expect(font).to.have.property('chars'); + const charA = font.chars['A'.charCodeAt(0) || 65]; + + expect(charA).to.exist; + let src = charA.texture.baseTexture.resource.url; + + src = src.substring(src.length - 17); + expect(src).to.equal('split_font_ab.png'); + expect(charA.texture.frame.x).to.equal(2); + expect(charA.texture.frame.y).to.equal(2); + expect(charA.texture.frame.width).to.equal(19); + expect(charA.texture.frame.height).to.equal(20); + const charB = font.chars['B'.charCodeAt(0) || 66]; + + expect(charB).to.exist; + src = charB.texture.baseTexture.resource.url; + + src = src.substring(src.length - 17); + expect(src).to.equal('split_font_ab.png'); + expect(charB.texture.frame.x).to.equal(2); + expect(charB.texture.frame.y).to.equal(24); + expect(charB.texture.frame.width).to.equal(15); + expect(charB.texture.frame.height).to.equal(20); + const charC = font.chars['C'.charCodeAt(0) || 67]; + + expect(charC).to.exist; + src = charC.texture.baseTexture.resource.url; + + src = src.substring(src.length - 17); + expect(src).to.equal('split_font_cd.png'); + expect(charC.texture.frame.x).to.equal(2); + expect(charC.texture.frame.y).to.equal(2); + expect(charC.texture.frame.width).to.equal(18); + expect(charC.texture.frame.height).to.equal(20); + const charD = font.chars['D'.charCodeAt(0) || 68]; + + expect(charD).to.exist; + src = charD.texture.baseTexture.resource.url; + + src = src.substring(src.length - 17); + expect(src).to.equal('split_font_cd.png'); + expect(charD.texture.frame.x).to.equal(2); + expect(charD.texture.frame.y).to.equal(24); + expect(charD.texture.frame.width).to.equal(17); + expect(charD.texture.frame.height).to.equal(20); + const charE = font.chars['E'.charCodeAt(0) || 69]; + + expect(charE).to.be.undefined; + done(); + }); + }); + it('should parse exist', function () { expect(BitmapFontLoader.parse).to.be.a('function'); diff --git a/packages/text-bitmap/test/resources/split_font.fnt b/packages/text-bitmap/test/resources/split_font.fnt new file mode 100644 index 0000000..35cbf49 --- /dev/null +++ b/packages/text-bitmap/test/resources/split_font.fnt @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/text-bitmap/test/resources/split_font_ab.png b/packages/text-bitmap/test/resources/split_font_ab.png new file mode 100644 index 0000000..dca6137 --- /dev/null +++ b/packages/text-bitmap/test/resources/split_font_ab.png Binary files differ diff --git a/packages/text-bitmap/src/BitmapFontLoader.js b/packages/text-bitmap/src/BitmapFontLoader.js index 650564a..4368ee5 100644 --- a/packages/text-bitmap/src/BitmapFontLoader.js +++ b/packages/text-bitmap/src/BitmapFontLoader.js @@ -112,29 +112,53 @@ xmlUrl += '/'; } - const textureUrl = xmlUrl + resource.data.getElementsByTagName('page')[0].getAttribute('file'); + const pages = resource.data.getElementsByTagName('page'); + const textures = []; + const loadOptions = { + crossOrigin: resource.crossOrigin, + loadType: LoaderResource.LOAD_TYPE.IMAGE, + metadata: resource.metadata.imageMetadata, + parentResource: resource, + }; - if (TextureCache[textureUrl]) + for (let x = 0; x < pages.length; ++x) { - // reuse existing texture - BitmapFontLoader.parse(resource, TextureCache[textureUrl]); - next(); - } - else - { - const loadOptions = { - crossOrigin: resource.crossOrigin, - loadType: LoaderResource.LOAD_TYPE.IMAGE, - metadata: resource.metadata.imageMetadata, - parentResource: resource, - }; + const textureUrl = xmlUrl + pages[x].getAttribute('file'); - // load the texture for the font - this.add(`${resource.name}_image`, textureUrl, loadOptions, (res) => + if (TextureCache[textureUrl]) { - BitmapFontLoader.parse(resource, res.texture); - next(); - }); + textures.push(TextureCache[textureUrl]); + } + else + { + // load the texture for the font + this.add(`${resource.name}_image${x}`, textureUrl, loadOptions, () => + { + const nextTextures = []; + + for (let x = 0; x < pages.length; ++x) + { + const nextTextureUrl = xmlUrl + pages[x].getAttribute('file'); + + if (TextureCache[nextTextureUrl]) + { + nextTextures.push(TextureCache[nextTextureUrl]); + } + else + { + return; + } + } + BitmapFontLoader.parse(resource, nextTextures); + next(); + }); + } + } + + if (textures.length === pages.length) + { + BitmapFontLoader.parse(resource, textures); + next(); } } } diff --git a/packages/text-bitmap/src/BitmapText.js b/packages/text-bitmap/src/BitmapText.js index fa30f2e..b9b535a 100644 --- a/packages/text-bitmap/src/BitmapText.js +++ b/packages/text-bitmap/src/BitmapText.js @@ -509,10 +509,10 @@ * * @static * @param {XMLDocument} xml - The XML document data. - * @param {PIXI.Texture} texture - Texture with all symbols. + * @param {PIXI.Texture|PIXI.Texture[]} textures - List of textures for each page. * @return {Object} Result font object with font, size, lineHeight and char fields. */ - static registerFont(xml, texture) + static registerFont(xml, textures) { const data = {}; const info = xml.getElementsByTagName('info')[0]; @@ -524,29 +524,44 @@ data.size = parseInt(info.getAttribute('size'), 10); data.lineHeight = parseInt(common.getAttribute('lineHeight'), 10) / res; data.chars = {}; + if (!(textures instanceof Array)) + { + textures = [textures]; + } // parse letters const letters = xml.getElementsByTagName('char'); + let page; for (let i = 0; i < letters.length; i++) { const letter = letters[i]; const charCode = parseInt(letter.getAttribute('id'), 10); + let textureRect; - const textureRect = new Rectangle( - (parseInt(letter.getAttribute('x'), 10) / res) + (texture.frame.x / res), - (parseInt(letter.getAttribute('y'), 10) / res) + (texture.frame.y / res), - parseInt(letter.getAttribute('width'), 10) / res, - parseInt(letter.getAttribute('height'), 10) / res - ); + page = parseInt(letter.getAttribute('page'), 10); + if (isNaN(page)) + { + textureRect = new Rectangle(0, 0, 0, 0); + page = 0; + } + else + { + textureRect = new Rectangle( + (parseInt(letter.getAttribute('x'), 10) / res) + (textures[page].frame.x / res), + (parseInt(letter.getAttribute('y'), 10) / res) + (textures[page].frame.y / res), + parseInt(letter.getAttribute('width'), 10) / res, + parseInt(letter.getAttribute('height'), 10) / res + ); + } data.chars[charCode] = { xOffset: parseInt(letter.getAttribute('xoffset'), 10) / res, yOffset: parseInt(letter.getAttribute('yoffset'), 10) / res, xAdvance: parseInt(letter.getAttribute('xadvance'), 10) / res, kerning: {}, - texture: new Texture(texture.baseTexture, textureRect), - + texture: new Texture(textures[page].baseTexture, textureRect), + page, }; } diff --git a/packages/text-bitmap/test/BitmapFontLoader.js b/packages/text-bitmap/test/BitmapFontLoader.js index 1f3d385..8afdcd0 100644 --- a/packages/text-bitmap/test/BitmapFontLoader.js +++ b/packages/text-bitmap/test/BitmapFontLoader.js @@ -1,5 +1,6 @@ const path = require('path'); const fs = require('fs'); +const { Loader } = require('@pixi/loaders'); const { BaseTextureCache, TextureCache } = require('@pixi/utils'); const { Texture, BaseTexture } = require('@pixi/core'); const { Spritesheet } = require('@pixi/spritesheet'); @@ -327,6 +328,71 @@ }); }); + it('should properly register bitmap font having more than one texture', function (done) + { + Loader.registerPlugin(BitmapFontLoader); + + const loader = new Loader(); + + loader.add(`${__dirname}/resources/split_font.fnt`); + loader.load(() => + { + const font = BitmapText.fonts.split_font; + + expect(font).to.be.an.object; + expect(BitmapText.fonts.split_font).to.equal(font); + expect(font).to.have.property('chars'); + const charA = font.chars['A'.charCodeAt(0) || 65]; + + expect(charA).to.exist; + let src = charA.texture.baseTexture.resource.url; + + src = src.substring(src.length - 17); + expect(src).to.equal('split_font_ab.png'); + expect(charA.texture.frame.x).to.equal(2); + expect(charA.texture.frame.y).to.equal(2); + expect(charA.texture.frame.width).to.equal(19); + expect(charA.texture.frame.height).to.equal(20); + const charB = font.chars['B'.charCodeAt(0) || 66]; + + expect(charB).to.exist; + src = charB.texture.baseTexture.resource.url; + + src = src.substring(src.length - 17); + expect(src).to.equal('split_font_ab.png'); + expect(charB.texture.frame.x).to.equal(2); + expect(charB.texture.frame.y).to.equal(24); + expect(charB.texture.frame.width).to.equal(15); + expect(charB.texture.frame.height).to.equal(20); + const charC = font.chars['C'.charCodeAt(0) || 67]; + + expect(charC).to.exist; + src = charC.texture.baseTexture.resource.url; + + src = src.substring(src.length - 17); + expect(src).to.equal('split_font_cd.png'); + expect(charC.texture.frame.x).to.equal(2); + expect(charC.texture.frame.y).to.equal(2); + expect(charC.texture.frame.width).to.equal(18); + expect(charC.texture.frame.height).to.equal(20); + const charD = font.chars['D'.charCodeAt(0) || 68]; + + expect(charD).to.exist; + src = charD.texture.baseTexture.resource.url; + + src = src.substring(src.length - 17); + expect(src).to.equal('split_font_cd.png'); + expect(charD.texture.frame.x).to.equal(2); + expect(charD.texture.frame.y).to.equal(24); + expect(charD.texture.frame.width).to.equal(17); + expect(charD.texture.frame.height).to.equal(20); + const charE = font.chars['E'.charCodeAt(0) || 69]; + + expect(charE).to.be.undefined; + done(); + }); + }); + it('should parse exist', function () { expect(BitmapFontLoader.parse).to.be.a('function'); diff --git a/packages/text-bitmap/test/resources/split_font.fnt b/packages/text-bitmap/test/resources/split_font.fnt new file mode 100644 index 0000000..35cbf49 --- /dev/null +++ b/packages/text-bitmap/test/resources/split_font.fnt @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/text-bitmap/test/resources/split_font_ab.png b/packages/text-bitmap/test/resources/split_font_ab.png new file mode 100644 index 0000000..dca6137 --- /dev/null +++ b/packages/text-bitmap/test/resources/split_font_ab.png Binary files differ diff --git a/packages/text-bitmap/test/resources/split_font_cd.png b/packages/text-bitmap/test/resources/split_font_cd.png new file mode 100644 index 0000000..8f3c77e --- /dev/null +++ b/packages/text-bitmap/test/resources/split_font_cd.png Binary files differ