1 line
19 KiB
Plaintext
1 line
19 KiB
Plaintext
{"version":3,"file":"Spritesheet.mjs","sources":["../src/Spritesheet.ts"],"sourcesContent":["import { BaseTexture, Rectangle, Texture, utils } from '@pixi/core';\n\nimport type { ImageResource, IPointData, ITextureBorders } from '@pixi/core';\n\n/**\n * Represents the JSON data for a spritesheet atlas.\n * @memberof PIXI\n */\nexport interface ISpritesheetFrameData\n{\n frame: {\n h: number;\n w: number;\n x: number;\n y: number;\n };\n trimmed?: boolean;\n rotated?: boolean;\n sourceSize?: {\n h: number;\n w: number;\n };\n spriteSourceSize?: {\n h?: number;\n w?: number;\n x: number;\n y: number;\n };\n anchor?: IPointData;\n borders?: ITextureBorders;\n}\n\n/**\n * Atlas format.\n * @memberof PIXI\n */\nexport interface ISpritesheetData\n{\n animations?: utils.Dict<string[]>;\n frames: utils.Dict<ISpritesheetFrameData>;\n meta: {\n app?: string;\n format?: string;\n frameTags?: {\n from: number;\n name: string;\n to: number;\n direction: string;\n }[];\n image?: string;\n layers?: {\n blendMode: string;\n name: string;\n opacity: number;\n }[];\n scale: string | number;\n size?: {\n h: number;\n w: number;\n };\n slices?: {\n color: string;\n name: string;\n keys: {\n frame: number,\n bounds: {\n x: number;\n y: number;\n w: number;\n h: number;\n };\n }[];\n }[];\n // eslint-disable-next-line camelcase\n related_multi_packs?: string[];\n version?: string;\n };\n}\n\n/**\n * Options for loading a spritesheet from an atlas.\n * @memberof PIXI\n */\ninterface SpritesheetOptions<S extends ISpritesheetData = ISpritesheetData>\n{\n /** Reference to Texture */\n texture: BaseTexture | Texture;\n /** JSON data for the atlas. */\n data: S;\n /** The filename to consider when determining the resolution of the spritesheet. */\n resolutionFilename?: string;\n /**\n * Prefix to add to texture names when adding to global TextureCache,\n * using this option can be helpful if you have multiple texture atlases\n * that share texture names and you need to disambiguate them.\n */\n cachePrefix?: string;\n}\n\n/**\n * Utility class for maintaining reference to a collection\n * of Textures on a single Spritesheet.\n *\n * To access a sprite sheet from your code you may pass its JSON data file to Pixi's loader:\n *\n * ```js\n * import { Assets } from 'pixi.js';\n *\n * const sheet = await Assets.load('images/spritesheet.json');\n * ```\n *\n * Alternately, you may circumvent the loader by instantiating the Spritesheet directly:\n *\n * ```js\n * import { Spritesheet } from 'pixi.js';\n *\n * const sheet = new Spritesheet(texture, spritesheetData);\n * await sheet.parse();\n * console.log('Spritesheet ready to use!');\n * ```\n *\n * With the `sheet.textures` you can create Sprite objects, and `sheet.animations` can be used to create an AnimatedSprite.\n *\n * Here's an example of a sprite sheet JSON data file:\n * ```json\n * {\n * \"frames\": {\n * \"enemy1.png\":\n * {\n * \"frame\": {\"x\":103,\"y\":1,\"w\":32,\"h\":32},\n * \"spriteSourceSize\": {\"x\":0,\"y\":0,\"w\":32,\"h\":32},\n * \"sourceSize\": {\"w\":32,\"h\":32},\n * \"anchor\": {\"x\":16,\"y\":16}\n * },\n * \"enemy2.png\":\n * {\n * \"frame\": {\"x\":103,\"y\":35,\"w\":32,\"h\":32},\n * \"spriteSourceSize\": {\"x\":0,\"y\":0,\"w\":32,\"h\":32},\n * \"sourceSize\": {\"w\":32,\"h\":32},\n * \"anchor\": {\"x\":16,\"y\":16}\n * },\n * \"button.png\":\n * {\n * \"frame\": {\"x\":1,\"y\":1,\"w\":100,\"h\":100},\n * \"spriteSourceSize\": {\"x\":0,\"y\":0,\"w\":100,\"h\":100},\n * \"sourceSize\": {\"w\":100,\"h\":100},\n * \"anchor\": {\"x\":0,\"y\":0},\n * \"borders\": {\"left\":35,\"top\":35,\"right\":35,\"bottom\":35}\n * }\n * },\n *\n * \"animations\": {\n * \"enemy\": [\"enemy1.png\",\"enemy2.png\"]\n * },\n *\n * \"meta\": {\n * \"image\": \"sheet.png\",\n * \"format\": \"RGBA8888\",\n * \"size\": {\"w\":136,\"h\":102},\n * \"scale\": \"1\"\n * }\n * }\n * ```\n * Sprite sheets can be packed using tools like {@link https://codeandweb.com/texturepacker|TexturePacker},\n * {@link https://renderhjs.net/shoebox/|Shoebox} or {@link https://github.com/krzysztof-o/spritesheet.js|Spritesheet.js}.\n * Default anchor points (see {@link PIXI.Texture#defaultAnchor}), default 9-slice borders\n * (see {@link PIXI.Texture#defaultBorders}) and grouping of animation sprites are currently only\n * supported by TexturePacker.\n *\n * Alternative ways for loading spritesheet image if you need more control:\n *\n * ```js\n * import { Assets } from 'pixi.js';\n *\n * const sheetTexture = await Assets.load('images/spritesheet.png');\n * Assets.add({\n * alias: 'atlas',\n * src: 'images/spritesheet.json'\n * data: {texture: sheetTexture} // using of preloaded texture\n * });\n * const sheet = await Assets.load('atlas')\n * ```\n *\n * or:\n *\n * ```js\n * import { Assets } from 'pixi.js';\n *\n * Assets.add({\n * alias: 'atlas',\n * src: 'images/spritesheet.json'\n * data: {imageFilename: 'my-spritesheet.2x.avif'} // using of custom filename located in \"images/my-spritesheet.2x.avif\"\n * });\n * const sheet = await Assets.load('atlas')\n * ```\n * @memberof PIXI\n */\nexport class Spritesheet<S extends ISpritesheetData = ISpritesheetData>\n{\n /** The maximum number of Textures to build per process. */\n static readonly BATCH_SIZE = 1000;\n\n /** For multi-packed spritesheets, this contains a reference to all the other spritesheets it depends on. */\n public linkedSheets: Spritesheet<S>[] = [];\n\n /** Reference to ths source texture. */\n public baseTexture: BaseTexture;\n\n /**\n * A map containing all textures of the sprite sheet.\n * Can be used to create a {@link PIXI.Sprite|Sprite}:\n * @example\n * import { Sprite } from 'pixi.js';\n *\n * new Sprite(sheet.textures['image.png']);\n */\n public textures: Record<keyof S['frames'], Texture>;\n\n /**\n * A map containing the textures for each animation.\n * Can be used to create an {@link PIXI.AnimatedSprite|AnimatedSprite}:\n * @example\n * import { AnimatedSprite } from 'pixi.js';\n *\n * new AnimatedSprite(sheet.animations['anim_name']);\n */\n public animations: Record<keyof NonNullable<S['animations']>, Texture[]>;\n\n /**\n * Reference to the original JSON data.\n * @type {object}\n */\n public data: S;\n\n /** The resolution of the spritesheet. */\n public resolution: number;\n\n /**\n * Reference to original source image from the Loader. This reference is retained so we\n * can destroy the Texture later on. It is never used internally.\n */\n private _texture: Texture;\n\n /**\n * Map of spritesheet frames.\n * @type {object}\n */\n private _frames: S['frames'];\n\n /** Collection of frame names. */\n private _frameKeys: (keyof S['frames'])[];\n\n /** Current batch index being processed. */\n private _batchIndex: number;\n\n /**\n * Callback when parse is completed.\n * @type {Function}\n */\n private _callback: (textures: utils.Dict<Texture>) => void;\n\n /** Prefix string to add to global cache */\n public readonly cachePrefix: string;\n\n /**\n * @class\n * @param options - Options to use when constructing a new Spritesheet.\n */\n constructor(options: SpritesheetOptions<S>);\n\n /**\n * @class\n * @param texture - Reference to the source BaseTexture object.\n * @param {object} data - Spritesheet image data.\n * @param resolutionFilename - The filename to consider when determining\n * the resolution of the spritesheet. If not provided, the imageUrl will\n * be used on the BaseTexture.\n */\n constructor(texture: BaseTexture | Texture, data: S, resolutionFilename?: string);\n\n /** @ignore */\n constructor(optionsOrTexture: SpritesheetOptions<S> | BaseTexture | Texture, arg1?: S, arg2?: string)\n {\n if (optionsOrTexture instanceof BaseTexture || optionsOrTexture instanceof Texture)\n {\n optionsOrTexture = { texture: optionsOrTexture, data: arg1, resolutionFilename: arg2 };\n }\n const { texture, data, resolutionFilename = null, cachePrefix = '' } = optionsOrTexture;\n\n this.cachePrefix = cachePrefix;\n this._texture = texture instanceof Texture ? texture : null;\n this.baseTexture = texture instanceof BaseTexture ? texture : this._texture.baseTexture;\n this.textures = {} as Record<keyof S['frames'], Texture>;\n this.animations = {} as Record<keyof NonNullable<S['animations']>, Texture[]>;\n this.data = data;\n\n const resource = this.baseTexture.resource as ImageResource;\n\n this.resolution = this._updateResolution(resolutionFilename || (resource ? resource.url : null));\n this._frames = this.data.frames;\n this._frameKeys = Object.keys(this._frames);\n this._batchIndex = 0;\n this._callback = null;\n }\n\n /**\n * Generate the resolution from the filename or fallback\n * to the meta.scale field of the JSON data.\n * @param resolutionFilename - The filename to use for resolving\n * the default resolution.\n * @returns Resolution to use for spritesheet.\n */\n private _updateResolution(resolutionFilename: string = null): number\n {\n const { scale } = this.data.meta;\n\n // Use a defaultValue of `null` to check if a url-based resolution is set\n let resolution = utils.getResolutionOfUrl(resolutionFilename, null);\n\n // No resolution found via URL\n if (resolution === null)\n {\n // Use the scale value or default to 1\n resolution = typeof scale === 'number' ? scale : parseFloat(scale ?? '1');\n }\n\n // For non-1 resolutions, update baseTexture\n if (resolution !== 1)\n {\n this.baseTexture.setResolution(resolution);\n }\n\n return resolution;\n }\n\n /**\n * Parser spritesheet from loaded data. This is done asynchronously\n * to prevent creating too many Texture within a single process.\n * @method PIXI.Spritesheet#parse\n */\n public parse(): Promise<utils.Dict<Texture>>\n {\n return new Promise((resolve) =>\n {\n this._callback = resolve;\n this._batchIndex = 0;\n\n if (this._frameKeys.length <= Spritesheet.BATCH_SIZE)\n {\n this._processFrames(0);\n this._processAnimations();\n this._parseComplete();\n }\n else\n {\n this._nextBatch();\n }\n });\n }\n\n /**\n * Process a batch of frames\n * @param initialFrameIndex - The index of frame to start.\n */\n private _processFrames(initialFrameIndex: number): void\n {\n let frameIndex = initialFrameIndex;\n const maxFrames = Spritesheet.BATCH_SIZE;\n\n while (frameIndex - initialFrameIndex < maxFrames && frameIndex < this._frameKeys.length)\n {\n const i = this._frameKeys[frameIndex];\n const data = this._frames[i];\n const rect = data.frame;\n\n if (rect)\n {\n let frame = null;\n let trim = null;\n const sourceSize = data.trimmed !== false && data.sourceSize\n ? data.sourceSize : data.frame;\n\n const orig = new Rectangle(\n 0,\n 0,\n Math.floor(sourceSize.w) / this.resolution,\n Math.floor(sourceSize.h) / this.resolution\n );\n\n if (data.rotated)\n {\n frame = new Rectangle(\n Math.floor(rect.x) / this.resolution,\n Math.floor(rect.y) / this.resolution,\n Math.floor(rect.h) / this.resolution,\n Math.floor(rect.w) / this.resolution\n );\n }\n else\n {\n frame = new Rectangle(\n Math.floor(rect.x) / this.resolution,\n Math.floor(rect.y) / this.resolution,\n Math.floor(rect.w) / this.resolution,\n Math.floor(rect.h) / this.resolution\n );\n }\n\n // Check to see if the sprite is trimmed\n if (data.trimmed !== false && data.spriteSourceSize)\n {\n trim = new Rectangle(\n Math.floor(data.spriteSourceSize.x) / this.resolution,\n Math.floor(data.spriteSourceSize.y) / this.resolution,\n Math.floor(rect.w) / this.resolution,\n Math.floor(rect.h) / this.resolution\n );\n }\n\n this.textures[i] = new Texture(\n this.baseTexture,\n frame,\n orig,\n trim,\n data.rotated ? 2 : 0,\n data.anchor,\n data.borders\n );\n\n // lets also add the frame to pixi's global cache for 'from' and 'fromLoader' functions\n Texture.addToCache(this.textures[i], this.cachePrefix + i.toString());\n }\n\n frameIndex++;\n }\n }\n\n /** Parse animations config. */\n private _processAnimations(): void\n {\n const animations = this.data.animations || {};\n\n for (const animName in animations)\n {\n this.animations[animName as keyof S['animations']] = [];\n for (let i = 0; i < animations[animName].length; i++)\n {\n const frameName = animations[animName][i];\n\n this.animations[animName].push(this.textures[frameName]);\n }\n }\n }\n\n /** The parse has completed. */\n private _parseComplete(): void\n {\n const callback = this._callback;\n\n this._callback = null;\n this._batchIndex = 0;\n callback.call(this, this.textures);\n }\n\n /** Begin the next batch of textures. */\n private _nextBatch(): void\n {\n this._processFrames(this._batchIndex * Spritesheet.BATCH_SIZE);\n this._batchIndex++;\n setTimeout(() =>\n {\n if (this._batchIndex * Spritesheet.BATCH_SIZE < this._frameKeys.length)\n {\n this._nextBatch();\n }\n else\n {\n this._processAnimations();\n this._parseComplete();\n }\n }, 0);\n }\n\n /**\n * Destroy Spritesheet and don't use after this.\n * @param {boolean} [destroyBase=false] - Whether to destroy the base texture as well\n */\n public destroy(destroyBase = false): void\n {\n for (const i in this.textures)\n {\n this.textures[i].destroy();\n }\n this._frames = null;\n this._frameKeys = null;\n this.data = null;\n this.textures = null;\n if (destroyBase)\n {\n this._texture?.destroy();\n this.baseTexture.destroy();\n }\n this._texture = null;\n this.baseTexture = null;\n this.linkedSheets = [];\n }\n}\n"],"names":["_Spritesheet"],"mappings":";AAqMO,MAAM,eAAN,MAAMA,cACb;AAAA;AAAA,EAmFI,YAAY,kBAAiE,MAAU,MACvF;AA/EA,SAAO,eAAiC,KAgFhC,4BAA4B,eAAe,4BAA4B,aAEvE,mBAAmB,EAAE,SAAS,kBAAkB,MAAM,MAAM,oBAAoB,KAAK;AAEzF,UAAM,EAAE,SAAS,MAAM,qBAAqB,MAAM,cAAc,GAAO,IAAA;AAElE,SAAA,cAAc,aACnB,KAAK,WAAW,mBAAmB,UAAU,UAAU,MACvD,KAAK,cAAc,mBAAmB,cAAc,UAAU,KAAK,SAAS,aAC5E,KAAK,WAAW,CAAA,GAChB,KAAK,aAAa,CAClB,GAAA,KAAK,OAAO;AAEN,UAAA,WAAW,KAAK,YAAY;AAE7B,SAAA,aAAa,KAAK,kBAAkB,uBAAuB,WAAW,SAAS,MAAM,KAAK,GAC/F,KAAK,UAAU,KAAK,KAAK,QACzB,KAAK,aAAa,OAAO,KAAK,KAAK,OAAO,GAC1C,KAAK,cAAc,GACnB,KAAK,YAAY;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,kBAAkB,qBAA6B,MACvD;AACI,UAAM,EAAE,MAAU,IAAA,KAAK,KAAK;AAG5B,QAAI,aAAa,MAAM,mBAAmB,oBAAoB,IAAI;AAGlE,WAAI,eAAe,SAGf,aAAa,OAAO,SAAU,WAAW,QAAQ,WAAW,SAAS,GAAG,IAIxE,eAAe,KAEf,KAAK,YAAY,cAAc,UAAU,GAGtC;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,QACP;AACW,WAAA,IAAI,QAAQ,CAAC,YACpB;AACS,WAAA,YAAY,SACjB,KAAK,cAAc,GAEf,KAAK,WAAW,UAAUA,cAAY,cAEtC,KAAK,eAAe,CAAC,GACrB,KAAK,mBAAA,GACL,KAAK,eAIL,KAAA,KAAK;IAAW,CAEvB;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,eAAe,mBACvB;AACI,QAAI,aAAa;AACjB,UAAM,YAAYA,cAAY;AAE9B,WAAO,aAAa,oBAAoB,aAAa,aAAa,KAAK,WAAW,UAClF;AACU,YAAA,IAAI,KAAK,WAAW,UAAU,GAC9B,OAAO,KAAK,QAAQ,CAAC,GACrB,OAAO,KAAK;AAElB,UAAI,MACJ;AACQ,YAAA,QAAQ,MACR,OAAO;AACL,cAAA,aAAa,KAAK,YAAY,MAAS,KAAK,aAC5C,KAAK,aAAa,KAAK,OAEvB,OAAO,IAAI;AAAA,UACb;AAAA,UACA;AAAA,UACA,KAAK,MAAM,WAAW,CAAC,IAAI,KAAK;AAAA,UAChC,KAAK,MAAM,WAAW,CAAC,IAAI,KAAK;AAAA,QAAA;AAGhC,aAAK,UAEL,QAAQ,IAAI;AAAA,UACR,KAAK,MAAM,KAAK,CAAC,IAAI,KAAK;AAAA,UAC1B,KAAK,MAAM,KAAK,CAAC,IAAI,KAAK;AAAA,UAC1B,KAAK,MAAM,KAAK,CAAC,IAAI,KAAK;AAAA,UAC1B,KAAK,MAAM,KAAK,CAAC,IAAI,KAAK;AAAA,QAAA,IAK9B,QAAQ,IAAI;AAAA,UACR,KAAK,MAAM,KAAK,CAAC,IAAI,KAAK;AAAA,UAC1B,KAAK,MAAM,KAAK,CAAC,IAAI,KAAK;AAAA,UAC1B,KAAK,MAAM,KAAK,CAAC,IAAI,KAAK;AAAA,UAC1B,KAAK,MAAM,KAAK,CAAC,IAAI,KAAK;AAAA,QAAA,GAK9B,KAAK,YAAY,MAAS,KAAK,qBAE/B,OAAO,IAAI;AAAA,UACP,KAAK,MAAM,KAAK,iBAAiB,CAAC,IAAI,KAAK;AAAA,UAC3C,KAAK,MAAM,KAAK,iBAAiB,CAAC,IAAI,KAAK;AAAA,UAC3C,KAAK,MAAM,KAAK,CAAC,IAAI,KAAK;AAAA,UAC1B,KAAK,MAAM,KAAK,CAAC,IAAI,KAAK;AAAA,QAIlC,IAAA,KAAK,SAAS,CAAC,IAAI,IAAI;AAAA,UACnB,KAAK;AAAA,UACL;AAAA,UACA;AAAA,UACA;AAAA,UACA,KAAK,UAAU,IAAI;AAAA,UACnB,KAAK;AAAA,UACL,KAAK;AAAA,QACT,GAGA,QAAQ,WAAW,KAAK,SAAS,CAAC,GAAG,KAAK,cAAc,EAAE,SAAU,CAAA;AAAA,MACxE;AAEA;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA,EAGQ,qBACR;AACI,UAAM,aAAa,KAAK,KAAK,cAAc,CAAA;AAE3C,eAAW,YAAY,YACvB;AACS,WAAA,WAAW,QAAiC,IAAI;AACrD,eAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,EAAE,QAAQ,KACjD;AACI,cAAM,YAAY,WAAW,QAAQ,EAAE,CAAC;AAExC,aAAK,WAAW,QAAQ,EAAE,KAAK,KAAK,SAAS,SAAS,CAAC;AAAA,MAC3D;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA,EAGQ,iBACR;AACI,UAAM,WAAW,KAAK;AAEjB,SAAA,YAAY,MACjB,KAAK,cAAc,GACnB,SAAS,KAAK,MAAM,KAAK,QAAQ;AAAA,EACrC;AAAA;AAAA,EAGQ,aACR;AACS,SAAA,eAAe,KAAK,cAAcA,cAAY,UAAU,GAC7D,KAAK,eACL,WAAW,MACX;AACQ,WAAK,cAAcA,cAAY,aAAa,KAAK,WAAW,SAE5D,KAAK,WAAA,KAIL,KAAK,mBAAmB,GACxB,KAAK,eAAe;AAAA,OAEzB,CAAC;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,QAAQ,cAAc,IAC7B;AACI,eAAW,KAAK,KAAK;AAEZ,WAAA,SAAS,CAAC,EAAE,QAAQ;AAE7B,SAAK,UAAU,MACf,KAAK,aAAa,MAClB,KAAK,OAAO,MACZ,KAAK,WAAW,MACZ,gBAEA,KAAK,UAAU,QAAQ,GACvB,KAAK,YAAY,QAAQ,IAE7B,KAAK,WAAW,MAChB,KAAK,cAAc,MACnB,KAAK,eAAe,CAAA;AAAA,EACxB;AACJ;AArTa,aAGO,aAAa;AAH1B,IAAM,cAAN;"} |