@pixi-spine/loader-base
Version:
Pixi loader middleware base
1 lines • 17.6 kB
Source Map (JSON)
{"version":3,"file":"loader-base.mjs","sources":["../src/atlasLoader.ts","../src/SpineLoaderAbstract.ts"],"sourcesContent":["import { TextureAtlas, settings as spine_settings } from '@pixi-spine/base';\nimport { type AssetExtension, LoaderParserPriority, LoadAsset, Loader, checkExtension } from '@pixi/assets';\nimport { BaseTexture, extensions, ExtensionType, settings, Texture, utils } from '@pixi/core';\nimport type { ISpineMetadata } from './SpineLoaderAbstract';\n\ntype RawAtlas = string;\n\nconst spineTextureAtlasLoader: AssetExtension<RawAtlas | TextureAtlas, ISpineMetadata> = {\n extension: ExtensionType.Asset,\n\n // cache: {\n // test: (asset: RawAtlas | TextureAtlas) => asset instanceof TextureAtlas,\n // getCacheableAssets: (keys: string[], asset: RawAtlas | TextureAtlas) => getCacheableAssets(keys, asset),\n // },\n\n loader: {\n extension: {\n type: ExtensionType.LoadParser,\n priority: LoaderParserPriority.Normal,\n },\n\n test(url: string): boolean {\n return checkExtension(url, '.atlas');\n },\n\n async load(url: string): Promise<RawAtlas> {\n const response = await settings.ADAPTER.fetch(url);\n\n const txt = await response.text();\n\n return txt as RawAtlas;\n },\n\n testParse(asset: unknown, options: LoadAsset): Promise<boolean> {\n const isExtensionRight = checkExtension(options.src, '.atlas');\n const isString = typeof asset === 'string';\n\n return Promise.resolve(isExtensionRight && isString);\n },\n\n async parse(asset: RawAtlas, options: LoadAsset, loader: Loader): Promise<TextureAtlas> {\n const metadata: ISpineMetadata = options.data;\n let basePath = utils.path.dirname(options.src);\n\n if (basePath && basePath.lastIndexOf('/') !== basePath.length - 1) {\n basePath += '/';\n }\n\n let resolve = null;\n let reject = null;\n const retPromise = new Promise<TextureAtlas>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n\n // Retval is going to be a texture atlas. However we need to wait for it's callback to resolve this promise.\n let retval;\n const resolveCallback = (newAtlas: TextureAtlas): void => {\n if (!newAtlas) {\n reject('Something went terribly wrong loading a spine .atlas file\\nMost likely your texture failed to load.');\n }\n resolve(retval);\n };\n\n // if we have an already loaded pixi image in the image field, use that.\n if (metadata.image || metadata.images) {\n // merge the objects\n const pages = Object.assign(metadata.image ? { default: metadata.image } : {}, metadata.images);\n\n retval = new TextureAtlas(\n asset as RawAtlas,\n (line: any, callback: any) => {\n const page = pages[line] || (pages.default as any);\n\n if (page && page.baseTexture) callback(page.baseTexture);\n else callback(page);\n },\n resolveCallback\n );\n } else {\n // We don't have ready to use pixi textures, we need to load them now!\n retval = new TextureAtlas(asset as RawAtlas, makeSpineTextureAtlasLoaderFunctionFromPixiLoaderObject(loader, basePath, metadata.imageMetadata), resolveCallback);\n }\n\n return (await retPromise) as TextureAtlas;\n },\n\n unload(atlas: TextureAtlas) {\n atlas.dispose();\n },\n },\n} as AssetExtension<RawAtlas | TextureAtlas, ISpineMetadata>;\n\n/**\n * Ugly function to promisify the spine texture atlas loader function.\n * @public\n */\nexport const makeSpineTextureAtlasLoaderFunctionFromPixiLoaderObject = (loader: Loader, atlasBasePath: string, imageMetadata: any) => {\n return async (pageName: string, textureLoadedCallback: (tex: BaseTexture) => any): Promise<void> => {\n try {\n // const url = utils.path.join(...atlasBasePath.split(utils.path.sep), pageName); // Broken in upstream\n\n const url = utils.path.normalize([...atlasBasePath.split(utils.path.sep), pageName].join(utils.path.sep));\n\n const texture = await loader.load<Texture>({ src: url, data: imageMetadata });\n\n textureLoadedCallback(texture.baseTexture);\n } catch (e) {\n if (spine_settings.REPORT_TEXTURE_LOADER_ERROR) {\n console.error('Spine: error in texture loader', e);\n }\n textureLoadedCallback(null);\n }\n };\n};\n\nextensions.add(spineTextureAtlasLoader);\n","import { ISkeletonData, ISkeletonParser, TextureAtlas } from '@pixi-spine/base';\nimport { AssetExtension, checkExtension, LoadAsset, Loader, LoaderParserPriority } from '@pixi/assets';\nimport { BaseTexture, extensions, ExtensionType, settings, Texture, utils } from '@pixi/core';\nimport { makeSpineTextureAtlasLoaderFunctionFromPixiLoaderObject } from './atlasLoader';\n\ntype SPINEJSON = any;\ntype SPINEBINARY = ArrayBuffer;\n\nfunction isJson(resource: unknown): resource is SPINEJSON {\n return resource.hasOwnProperty('bones');\n}\n\nfunction isBuffer(resource: unknown): resource is SPINEBINARY {\n return resource instanceof ArrayBuffer;\n}\n\n/**\n * This abstract class is used to create a spine loader specifically for a needed version\n * @public\n */\nexport abstract class SpineLoaderAbstract<SKD extends ISkeletonData> {\n constructor() {}\n\n abstract createJsonParser(): ISkeletonParser;\n\n abstract createBinaryParser(): ISkeletonParser;\n\n abstract parseData(parser: ISkeletonParser, atlas: TextureAtlas, dataToParse: any): ISpineResource<SKD>;\n\n public installLoader(): any {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const spineAdapter = this;\n const spineLoaderExtension: AssetExtension<SPINEJSON | SPINEBINARY | ISpineResource<SKD>, ISpineMetadata> = {\n extension: ExtensionType.Asset,\n\n loader: {\n extension: {\n type: ExtensionType.LoadParser,\n priority: LoaderParserPriority.Normal,\n },\n\n // #region Downloading skel buffer data\n test(url) {\n return checkExtension(url, '.skel');\n },\n\n async load<SPINEBINARY>(url: string): Promise<SPINEBINARY> {\n const response = await settings.ADAPTER.fetch(url);\n\n const buffer = await response.arrayBuffer();\n\n return buffer as SPINEBINARY;\n },\n // #endregion\n\n // #region Parsing spine data\n testParse(asset: unknown, options: LoadAsset): Promise<boolean> {\n const isJsonSpineModel = checkExtension(options.src, '.json') && isJson(asset);\n const isBinarySpineModel = checkExtension(options.src, '.skel') && isBuffer(asset);\n\n // From 6.x loader. If the atlas is strictly false we bail\n const isMetadataAngry = options.data?.spineAtlas === false;\n\n return Promise.resolve((isJsonSpineModel && !isMetadataAngry) || isBinarySpineModel);\n },\n\n async parse(asset: SPINEJSON | SPINEBINARY, loadAsset, loader): Promise<ISpineResource<SKD>> {\n const fileExt = utils.path.extname(loadAsset.src).toLowerCase();\n const fileName = utils.path.basename(loadAsset.src, fileExt);\n let basePath = utils.path.dirname(loadAsset.src);\n\n if (basePath && basePath.lastIndexOf('/') !== basePath.length - 1) {\n basePath += '/';\n }\n\n const isJsonSpineModel = checkExtension(loadAsset.src, '.json') && isJson(asset);\n // const isBinarySpineModel = fileExt === 'slel' && isBuffer(asset);\n\n let parser: ISkeletonParser = null;\n let dataToParse = asset;\n\n if (isJsonSpineModel) {\n parser = spineAdapter.createJsonParser();\n } else {\n parser = spineAdapter.createBinaryParser();\n dataToParse = new Uint8Array(asset);\n }\n\n const metadata = (loadAsset.data || {}) as ISpineMetadata;\n const metadataSkeletonScale = metadata?.spineSkeletonScale ?? null;\n\n if (metadataSkeletonScale) {\n parser.scale = metadataSkeletonScale;\n }\n\n // if metadataAtlas is a TextureAtlas, use it directly\n const metadataAtlas: TextureAtlas = metadata.spineAtlas as TextureAtlas;\n\n if (metadataAtlas && metadataAtlas.pages) {\n return spineAdapter.parseData(parser, metadataAtlas, dataToParse);\n }\n\n // if for some odd reason, you dumped the text information of the atlas into the metadata...\n const textAtlas = metadata.atlasRawData;\n\n if (textAtlas) {\n let auxResolve = null;\n let auxReject = null;\n const atlasPromise = new Promise<TextureAtlas>((resolve, reject) => {\n auxResolve = resolve;\n auxReject = reject;\n });\n const atlas = new TextureAtlas(textAtlas, makeSpineTextureAtlasLoaderFunctionFromPixiLoaderObject(loader, basePath, metadata.imageMetadata), (newAtlas) => {\n if (!newAtlas) {\n auxReject('Something went terribly wrong loading a spine .atlas file\\nMost likely your texture failed to load.');\n }\n auxResolve(atlas);\n });\n const textureAtlas = await atlasPromise;\n\n return spineAdapter.parseData(parser, textureAtlas, dataToParse);\n }\n\n // Maybe you told us where to find the file? (I sure hope you remembered to add the .atlas extension)\n let atlasPath = metadata.spineAtlasFile;\n\n // Finally, if no information at all about the atlas, we guess the atlas file name\n if (!atlasPath) {\n atlasPath = `${basePath + fileName}.atlas`;\n }\n\n const textureAtlas = await loader.load<TextureAtlas>({ src: atlasPath, data: metadata, alias: metadata.spineAtlasAlias });\n\n return spineAdapter.parseData(parser, textureAtlas, dataToParse);\n },\n\n // #endregion\n\n // unload(asset: ISpineResource<SKD>, loadAsset, loader) {\n // \t???\n // },\n },\n } as AssetExtension<SPINEJSON | SPINEBINARY | ISpineResource<SKD>, ISpineMetadata>;\n\n extensions.add(spineLoaderExtension);\n\n return spineLoaderExtension;\n }\n}\n\n/**\n * The final spineData+spineAtlas object that can be used to create a Spine.\n * @public\n */\nexport interface ISpineResource<SKD extends ISkeletonData> {\n spineData: SKD;\n spineAtlas: TextureAtlas;\n}\n\n/**\n * Metadata for loading spine assets\n * @public\n */\nexport interface ISpineMetadata {\n // Passed directly to Spine's SkeletonJson/BinaryParser\n spineSkeletonScale?: number;\n // If you already have a TextureAtlas, you can pass it directly\n spineAtlas?: Partial<TextureAtlas>;\n // If you are going to download an .atlas file, you can specify an alias here for cache/future lookup\n spineAtlasAlias?: string[];\n // If you want to use a custom .atlas file, you can specify the path here. **It must be a .atlas file or you need your own parser!**\n spineAtlasFile?: string;\n // If for some reason, you have the raw text content of an .atlas file, and want to use it dump it here\n atlasRawData?: string;\n // If you are hardcore and can write your own loader function to load the textures for the atlas, you can pass it here\n imageLoader?: (loader: Loader, path: string) => (path: string, callback: (tex: BaseTexture) => any) => any;\n // If you are downloading an .atlas file, this metadata will go to the Texture loader\n imageMetadata?: any;\n // If you already have atlas pages loaded as pixi textures and want to use that to create the atlas, you can pass them here\n images?: Record<string, Texture | BaseTexture>;\n // If your spine only uses one atlas page and you have it as a pixi texture, you can pass it here\n image?: Texture | BaseTexture;\n}\n"],"names":["spineTextureAtlasLoader","ExtensionType","LoaderParserPriority","url","checkExtension","settings","asset","options","isExtensionRight","isString","loader","metadata","basePath","utils","resolve","reject","retPromise","res","rej","retval","resolveCallback","newAtlas","pages","TextureAtlas","line","callback","page","makeSpineTextureAtlasLoaderFunctionFromPixiLoaderObject","atlas","atlasBasePath","imageMetadata","pageName","textureLoadedCallback","texture","e","spine_settings","extensions","isJson","resource","isBuffer","SpineLoaderAbstract","spineAdapter","spineLoaderExtension","_a","isJsonSpineModel","isBinarySpineModel","isMetadataAngry","loadAsset","fileExt","fileName","parser","dataToParse","metadataSkeletonScale","metadataAtlas","textAtlas","auxResolve","auxReject","atlasPromise","textureAtlas","atlasPath"],"mappings":"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"}