{"version":3,"file":"SpineLoaderAbstract.mjs","sources":["../src/SpineLoaderAbstract.ts"],"sourcesContent":["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":["textureAtlas"],"mappings":"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"}