diff --git a/spine-cpp/spine-cpp/src/spine/SkeletonBinary.cpp b/spine-cpp/spine-cpp/src/spine/SkeletonBinary.cpp index e931e786e..8613b8a18 100644 --- a/spine-cpp/spine-cpp/src/spine/SkeletonBinary.cpp +++ b/spine-cpp/spine-cpp/src/spine/SkeletonBinary.cpp @@ -1256,6 +1256,7 @@ Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, S switch (timelineType) { case ATTACHMENT_DEFORM: { + VertexAttachment *attachment = static_cast(baseAttachment); bool weighted = attachment->_bones.size() > 0; Vector &vertices = attachment->_vertices; int deformLength = weighted ? (int) vertices.size() / 3 * 2 : (int) vertices.size(); diff --git a/spine-sfml/cpp/example/testbed.cpp b/spine-sfml/cpp/example/testbed.cpp index e3faf832a..3bf47baaf 100644 --- a/spine-sfml/cpp/example/testbed.cpp +++ b/spine-sfml/cpp/example/testbed.cpp @@ -34,42 +34,42 @@ using namespace spine; int main(void) { - String atlasFile("data/spineboy-pma.atlas"); - String skeletonFile("data/spineboy-pro.skel"); - float scale = 0.6f; - SFMLTextureLoader textureLoader; - Atlas *atlas = new Atlas(atlasFile, &textureLoader); - SkeletonData *skeletonData = nullptr; - if (strncmp(skeletonFile.buffer(), ".skel", skeletonFile.length()) > 0) { - SkeletonBinary binary(atlas); - binary.setScale(scale); - skeletonData = binary.readSkeletonDataFile(skeletonFile); - } else { - SkeletonJson json(atlas); - json.setScale(scale); - skeletonData = json.readSkeletonDataFile(skeletonFile); - } + String atlasFile("data/spineboy-pma.atlas"); + String skeletonFile("data/spineboy-pro.skel"); + float scale = 0.6f; + SFMLTextureLoader textureLoader; + Atlas *atlas = new Atlas(atlasFile, &textureLoader); + SkeletonData *skeletonData = nullptr; + if (strncmp(skeletonFile.buffer(), ".skel", skeletonFile.length()) > 0) { + SkeletonBinary binary(atlas); + binary.setScale(scale); + skeletonData = binary.readSkeletonDataFile(skeletonFile); + } else { + SkeletonJson json(atlas); + json.setScale(scale); + skeletonData = json.readSkeletonDataFile(skeletonFile); + } - AnimationStateData stateData(skeletonData); - SkeletonDrawable drawable(skeletonData, &stateData); - drawable.skeleton->setPosition(320, 590); - drawable.state->setAnimation(0, "walk", true); + AnimationStateData stateData(skeletonData); + SkeletonDrawable drawable(skeletonData, &stateData); + drawable.skeleton->setPosition(320, 590); + drawable.state->setAnimation(0, "walk", true); - sf::RenderWindow window(sf::VideoMode(640, 640), "Spine SFML - testbed"); - window.setFramerateLimit(60); - sf::Event event; - sf::Clock deltaClock; - while (window.isOpen()) { - while (window.pollEvent(event)) - if (event.type == sf::Event::Closed) window.close(); + sf::RenderWindow window(sf::VideoMode(640, 640), "Spine SFML - testbed"); + window.setFramerateLimit(60); + sf::Event event; + sf::Clock deltaClock; + while (window.isOpen()) { + while (window.pollEvent(event)) + if (event.type == sf::Event::Closed) window.close(); - float delta = deltaClock.getElapsedTime().asSeconds(); - deltaClock.restart(); - drawable.update(delta); - window.clear(); - window.draw(drawable); - window.display(); - } + float delta = deltaClock.getElapsedTime().asSeconds(); + deltaClock.restart(); + drawable.update(delta); + window.clear(); + window.draw(drawable); + window.display(); + } - return 0; + return 0; } \ No newline at end of file diff --git a/spine-ts/package-lock.json b/spine-ts/package-lock.json index c61880364..4f087f2ff 100644 --- a/spine-ts/package-lock.json +++ b/spine-ts/package-lock.json @@ -8419,7 +8419,9 @@ "version": "4.2.10", "license": "LicenseRef-LICENSE", "dependencies": { + "@esotericsoftware/spine-canvas": "^4.2.10", "@esotericsoftware/spine-core": "^4.2.10", + "@esotericsoftware/spine-webgl": "^4.2.10", "phaser": "^3.55.2" } }, diff --git a/spine-ts/spine-phaser/example/index.js b/spine-ts/spine-phaser/example/index.js index 4b467bc62..2def9e013 100644 --- a/spine-ts/spine-phaser/example/index.js +++ b/spine-ts/spine-phaser/example/index.js @@ -8,7 +8,7 @@ var config = { type: Phaser.AUTO, width: 800, height: 600, - // type: Phaser.CANVAS, + type: Phaser.CANVAS, scene: { preload: preload, create: create, @@ -23,11 +23,12 @@ var config = { var game = new Phaser.Game(config); function preload () { - this.load.spine("raptor", "assets/raptor-pro.json", "assets/raptor.atlas", true); + this.load.spineJson("raptor-data", "assets/raptor-pro.json"); + this.load.spineAtlas("raptor-atlas", "assets/raptor.atlas"); } function create () { let plugin = this.spine; - var boy = this.add.spine(400, 600, 'raptor'); + var boy = this.add.spine(400, 600, 'raptor-data', "raptor-atlas"); this.add.text(10, 10, "Spine", { font: '16px Courier', fill: '#00ff00' }); } \ No newline at end of file diff --git a/spine-ts/spine-phaser/package.json b/spine-ts/spine-phaser/package.json index 43c74ca5c..936d0bab0 100644 --- a/spine-ts/spine-phaser/package.json +++ b/spine-ts/spine-phaser/package.json @@ -31,6 +31,8 @@ "homepage": "https://github.com/esotericsoftware/spine-runtimes#readme", "dependencies": { "@esotericsoftware/spine-core": "^4.2.10", + "@esotericsoftware/spine-webgl": "^4.2.10", + "@esotericsoftware/spine-canvas": "^4.2.10", "phaser": "^3.55.2" } } diff --git a/spine-ts/spine-phaser/src/SpineFile.ts b/spine-ts/spine-phaser/src/SpineFile.ts deleted file mode 100644 index 4fbaabd5f..000000000 --- a/spine-ts/spine-phaser/src/SpineFile.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { SPINE_ATLAS_CACHE_KEY, SPINE_FILE_TYPE, SPINE_LOADER_TYPE } from "./keys"; - -export class SpineFile extends Phaser.Loader.MultiFile { - constructor(loader: Phaser.Loader.LoaderPlugin, key: string, jsonURL: string, atlasURL: string, premultipliedAlpha: boolean = false, jsonXhrSettings: Phaser.Types.Loader.XHRSettingsObject, atlasXhrSettings: Phaser.Types.Loader.XHRSettingsObject) { - let json = new Phaser.Loader.FileTypes.JSONFile(loader, key, jsonURL, jsonXhrSettings); - let atlas = new Phaser.Loader.FileTypes.TextFile(loader, key, atlasURL, atlasXhrSettings); - atlas.cache = loader.cacheManager.custom[SPINE_ATLAS_CACHE_KEY]; - super(loader, SPINE_FILE_TYPE, key, [json, atlas]); - } - - addToCache() { - } -} \ No newline at end of file diff --git a/spine-ts/spine-phaser/src/SpineGameObject.ts b/spine-ts/spine-phaser/src/SpineGameObject.ts index 22a224c78..af19a3536 100644 --- a/spine-ts/spine-phaser/src/SpineGameObject.ts +++ b/spine-ts/spine-phaser/src/SpineGameObject.ts @@ -1,11 +1,12 @@ import { SPINE_GAME_OBJECT_TYPE } from "./keys"; import { SpinePlugin } from "./SpinePlugin"; import { ComputedSizeMixin, DepthMixin, FlipMixin, ScrollFactorMixin, TransformMixin, VisibleMixin } from "./mixins"; +import { AnimationState, AnimationStateData, Skeleton } from "@esotericsoftware/spine-core"; class BaseSpineGameObject extends Phaser.GameObjects.GameObject { - constructor(scene: Phaser.Scene, type: string) { - super(scene, type); - } + constructor (scene: Phaser.Scene, type: string) { + super(scene, type); + } } interface SpineContainer { @@ -13,21 +14,32 @@ interface SpineContainer { } export class SpineGameObject extends ComputedSizeMixin(DepthMixin(FlipMixin(ScrollFactorMixin(TransformMixin(VisibleMixin(BaseSpineGameObject)))))) { - blendMode = -1; + blendMode = -1; + skeleton: Skeleton | null = null; + animationState: AnimationState | null = null; - constructor(scene: Phaser.Scene, plugin: SpinePlugin, x: number, y: number, key: string) { - super(scene, SPINE_GAME_OBJECT_TYPE); - this.setPosition(x, y); - } + constructor (scene: Phaser.Scene, private plugin: SpinePlugin, x: number, y: number, dataKey: string, atlasKey: string) { + super(scene, SPINE_GAME_OBJECT_TYPE); + this.setPosition(x, y); + } - preUpdate(time: number, delta: number) { - } + setSkeleton (dataKey: string, atlasKey: string) { + if (dataKey && atlasKey) { + this.skeleton = this.plugin.createSkeleton(dataKey, atlasKey); + this.animationState = new AnimationState(new AnimationStateData(this.skeleton.data)); + } else { + this.skeleton = null; + } + } - renderWebGL(renderer: Phaser.Renderer.WebGL.WebGLRenderer, src: SpineGameObject, camera: Phaser.Cameras.Scene2D.Camera, parentMatrix: Phaser.GameObjects.Components.TransformMatrix, container: SpineContainer) { + preUpdate (time: number, delta: number) { + } - } + renderWebGL (renderer: Phaser.Renderer.WebGL.WebGLRenderer, src: SpineGameObject, camera: Phaser.Cameras.Scene2D.Camera, parentMatrix: Phaser.GameObjects.Components.TransformMatrix, container: SpineContainer) { - renderCanvas(renderer: Phaser.Renderer.Canvas.CanvasRenderer, src: SpineGameObject, camera: Phaser.Cameras.Scene2D.Camera, parentMatrix: Phaser.GameObjects.Components.TransformMatrix) { + } - } + renderCanvas (renderer: Phaser.Renderer.Canvas.CanvasRenderer, src: SpineGameObject, camera: Phaser.Cameras.Scene2D.Camera, parentMatrix: Phaser.GameObjects.Components.TransformMatrix) { + + } } \ No newline at end of file diff --git a/spine-ts/spine-phaser/src/SpinePlugin.ts b/spine-ts/spine-phaser/src/SpinePlugin.ts index d9f8e8ef1..f0a81879a 100644 --- a/spine-ts/spine-phaser/src/SpinePlugin.ts +++ b/spine-ts/spine-phaser/src/SpinePlugin.ts @@ -28,135 +28,286 @@ *****************************************************************************/ import Phaser from "phaser"; -import { SPINE_ATLAS_CACHE_KEY, SPINE_CONTAINER_TYPE, SPINE_FILE_TYPE, SPINE_GAME_OBJECT_TYPE, SPINE_TEXTURE_CACHE_KEY } from "./keys"; -import { SceneRenderer, SkeletonDebugRenderer, SkeletonRenderer } from "@esotericsoftware/spine-webgl" -import { SpineFile } from "./SpineFile"; +import { SPINE_ATLAS_CACHE_KEY, SPINE_CONTAINER_TYPE, SPINE_GAME_OBJECT_TYPE, SPINE_ATLAS_TEXTURE_CACHE_KEY, SPINE_SKELETON_DATA_FILE_TYPE, SPINE_ATLAS_FILE_TYPE, SPINE_SKELETON_FILE_CACHE_KEY as SPINE_SKELETON_DATA_CACHE_KEY } from "./keys"; +import { AtlasAttachmentLoader, GLTexture, SceneRenderer, Skeleton, SkeletonData, SkeletonDebugRenderer, SkeletonJson, SkeletonRenderer, TextureAtlas } from "@esotericsoftware/spine-webgl" import { SpineGameObject } from "./SpineGameObject"; +import { CanvasTexture } from "@esotericsoftware/spine-canvas"; export class SpinePlugin extends Phaser.Plugins.ScenePlugin { - game: Phaser.Game; - isWebGL: boolean; - atlasCache: Phaser.Cache.BaseCache; - spineTextureCache: Phaser.Cache.BaseCache; - jsonCache: Phaser.Cache.BaseCache; - textures: Phaser.Textures.TextureManager; - gl: WebGLRenderingContext | null; - phaserRenderer: Phaser.Renderer.Canvas.CanvasRenderer | Phaser.Renderer.WebGL.WebGLRenderer | null; - sceneRenderer: SceneRenderer | null; + game: Phaser.Game; + isWebGL: boolean; + gl: WebGLRenderingContext | null; + textureManager: Phaser.Textures.TextureManager; + phaserRenderer: Phaser.Renderer.Canvas.CanvasRenderer | Phaser.Renderer.WebGL.WebGLRenderer | null; + sceneRenderer: SceneRenderer | null; + skeletonDataCache: Phaser.Cache.BaseCache; + atlasCache: Phaser.Cache.BaseCache; - constructor(scene: Phaser.Scene, pluginManager: Phaser.Plugins.PluginManager, pluginKey: string) { - super(scene, pluginManager, pluginKey); - var game = this.game = pluginManager.game; - this.isWebGL = this.game.config.renderType === 2; - this.atlasCache = this.game.cache.addCustom(SPINE_ATLAS_CACHE_KEY); - this.spineTextureCache = this.game.cache.addCustom(SPINE_TEXTURE_CACHE_KEY); - this.jsonCache = this.game.cache.json; - this.textures = this.game.textures; - this.gl = this.isWebGL ? (this.game.renderer as Phaser.Renderer.WebGL.WebGLRenderer).gl : null; - this.phaserRenderer = this.game.renderer; - this.sceneRenderer = null; + constructor (scene: Phaser.Scene, pluginManager: Phaser.Plugins.PluginManager, pluginKey: string) { + super(scene, pluginManager, pluginKey); + var game = this.game = pluginManager.game; + this.isWebGL = this.game.config.renderType === 2; + this.gl = this.isWebGL ? (this.game.renderer as Phaser.Renderer.WebGL.WebGLRenderer).gl : null; + this.textureManager = this.game.textures; + this.phaserRenderer = this.game.renderer; + this.sceneRenderer = null; + this.skeletonDataCache = this.game.cache.addCustom(SPINE_SKELETON_DATA_CACHE_KEY); + this.atlasCache = this.game.cache.addCustom(SPINE_ATLAS_CACHE_KEY); - if (!this.phaserRenderer) { - this.phaserRenderer = { - width: game.scale.width, - height: game.scale.height, - preRender: () => { }, - postRender: () => { }, - render: () => { }, - destroy: () => { } - } as unknown as Phaser.Renderer.Canvas.CanvasRenderer; - } + if (!this.phaserRenderer) { + this.phaserRenderer = { + width: game.scale.width, + height: game.scale.height, + preRender: () => { }, + postRender: () => { }, + render: () => { }, + destroy: () => { } + } as unknown as Phaser.Renderer.Canvas.CanvasRenderer; + } - let fileCallback = function (this: any, key: string, - jsonURL: string, - atlasURL: string, - premultipliedAlpha: boolean, - jsonXhrSettings: Phaser.Types.Loader.XHRSettingsObject, - atlasXhrSettings: Phaser.Types.Loader.XHRSettingsObject) { - let file = new SpineFile(this as any, key, jsonURL, atlasURL, premultipliedAlpha, jsonXhrSettings, atlasXhrSettings); - this.addFile(file.files); - return this; - }; + let skeletonJsonFileCallback = function (this: any, key: string, + url: string, + xhrSettings: Phaser.Types.Loader.XHRSettingsObject) { + let file = new SpineSkeletonDataFile(this as any, key, url, SpineSkeletonDataFileType.json, xhrSettings); + this.addFile(file.files); + return this; + }; + pluginManager.registerFileType("spineJson", skeletonJsonFileCallback, scene); - let self = this; - let addSpineGameObject = function (this: Phaser.GameObjects.GameObjectFactory, x: number, y: number, key: string) { - let gameObject = new SpineGameObject(scene, self, x, y, key); - this.displayList.add(gameObject); - this.updateList.add(gameObject); - }; - let makeSpineGameObject = function (this: Phaser.GameObjects.GameObjectFactory, config: any, addToScene: boolean) { - let key = config.key ? config.key : null; - let gameObject = new SpineGameObject(this.scene, self, 0, 0, key); - if (addToScene !== undefined) { - config.add = addToScene; - } - Phaser.GameObjects.BuildGameObject(this.scene, gameObject, config); - } + let skeletonBinaryFileCallback = function (this: any, key: string, + url: string, + xhrSettings: Phaser.Types.Loader.XHRSettingsObject) { + let file = new SpineSkeletonDataFile(this as any, key, url, SpineSkeletonDataFileType.binary, xhrSettings); + this.addFile(file.files); + return this; + }; + pluginManager.registerFileType("spineBinary", skeletonBinaryFileCallback, scene); - pluginManager.registerFileType(SPINE_FILE_TYPE, fileCallback, scene); - pluginManager.registerGameObject(SPINE_GAME_OBJECT_TYPE, addSpineGameObject, makeSpineGameObject); - } - boot() { - if (this.isWebGL) { - // Monkeypatch the Spine setBlendMode functions, or batching is destroyed! - let setBlendMode = function (this: any, srcBlend: any, dstBlend: any) { - if (srcBlend !== this.srcBlend || dstBlend !== this.dstBlend) { - let gl = this.context.gl; - this.srcBlend = srcBlend; - this.dstBlend = dstBlend; - if (this.isDrawing) { - this.flush(); - gl.blendFunc(this.srcBlend, this.dstBlend); - } - } - }; + let atlasFileCallback = function (this: any, key: string, + url: string, + premultipliedAlpha: boolean, + xhrSettings: Phaser.Types.Loader.XHRSettingsObject) { + let file = new SpineAtlasFile(this as any, key, url, premultipliedAlpha, xhrSettings); + this.addFile(file.files); + return this; + }; + pluginManager.registerFileType("spineAtlas", atlasFileCallback, scene); - var sceneRenderer = this.sceneRenderer; - if (!sceneRenderer) { - sceneRenderer = new SceneRenderer((this.phaserRenderer! as Phaser.Renderer.WebGL.WebGLRenderer).canvas, this.gl!, true); - sceneRenderer.batcher.setBlendMode = setBlendMode; - (sceneRenderer as any).shapes.setBlendMode = setBlendMode; - } + let self = this; + let addSpineGameObject = function (this: Phaser.GameObjects.GameObjectFactory, x: number, y: number, dataKey: string, atlasKey: string) { + let gameObject = new SpineGameObject(scene, self, x, y, dataKey, atlasKey); + this.displayList.add(gameObject); + this.updateList.add(gameObject); + return gameObject; + }; - this.sceneRenderer = sceneRenderer; - } + let makeSpineGameObject = function (this: Phaser.GameObjects.GameObjectFactory, config: any, addToScene: boolean) { + let dataKey = config.dataKey ? config.dataKey : null; + let atlasKey = config.atlasKey ? config.atlasKey : null; + let gameObject = new SpineGameObject(this.scene, self, 0, 0, dataKey, atlasKey); + if (addToScene !== undefined) { + config.add = addToScene; + } + Phaser.GameObjects.BuildGameObject(this.scene, gameObject, config); + } + pluginManager.registerGameObject(SPINE_GAME_OBJECT_TYPE, addSpineGameObject, makeSpineGameObject); + } - var eventEmitter = this.systems.events; - eventEmitter.once('shutdown', this.shutdown, this); - eventEmitter.once('destroy', this.destroy, this); - this.game.events.once('destroy', this.gameDestroy, this); - } + boot () { + if (this.isWebGL) { + // Monkeypatch the Spine setBlendMode functions, or batching is destroyed! + let setBlendMode = function (this: any, srcBlend: any, dstBlend: any) { + if (srcBlend !== this.srcBlend || dstBlend !== this.dstBlend) { + let gl = this.context.gl; + this.srcBlend = srcBlend; + this.dstBlend = dstBlend; + if (this.isDrawing) { + this.flush(); + gl.blendFunc(this.srcBlend, this.dstBlend); + } + } + }; - onResize() { - var phaserRenderer = this.phaserRenderer; - var sceneRenderer = this.sceneRenderer; + var sceneRenderer = this.sceneRenderer; + if (!sceneRenderer) { + sceneRenderer = new SceneRenderer((this.phaserRenderer! as Phaser.Renderer.WebGL.WebGLRenderer).canvas, this.gl!, true); + sceneRenderer.batcher.setBlendMode = setBlendMode; + (sceneRenderer as any).shapes.setBlendMode = setBlendMode; + } - if (phaserRenderer && sceneRenderer) { - var viewportWidth = phaserRenderer.width; - var viewportHeight = phaserRenderer.height; - sceneRenderer.camera.position.x = viewportWidth / 2; - sceneRenderer.camera.position.y = viewportHeight / 2; - sceneRenderer.camera.setViewport(viewportWidth, viewportHeight); - } - } + this.sceneRenderer = sceneRenderer; + } - shutdown() { - this.systems.events.off("shutdown", this.shutdown, this); - if (this.isWebGL) { - this.game.scale.off(Phaser.Scale.Events.RESIZE, this.onResize, this); - } - } + var eventEmitter = this.systems.events; + eventEmitter.once('shutdown', this.shutdown, this); + eventEmitter.once('destroy', this.destroy, this); + this.game.events.once('destroy', this.gameDestroy, this); + } - destroy() { - this.shutdown() - } + onResize () { + var phaserRenderer = this.phaserRenderer; + var sceneRenderer = this.sceneRenderer; - gameDestroy() { - this.pluginManager.removeGameObject(SPINE_GAME_OBJECT_TYPE, true, true); - this.pluginManager.removeGameObject(SPINE_CONTAINER_TYPE, true, true); - if (this.sceneRenderer) this.sceneRenderer.dispose(); - } + if (phaserRenderer && sceneRenderer) { + var viewportWidth = phaserRenderer.width; + var viewportHeight = phaserRenderer.height; + sceneRenderer.camera.position.x = viewportWidth / 2; + sceneRenderer.camera.position.y = viewportHeight / 2; + sceneRenderer.camera.setViewport(viewportWidth, viewportHeight); + } + } + + shutdown () { + this.systems.events.off("shutdown", this.shutdown, this); + if (this.isWebGL) { + this.game.scale.off(Phaser.Scale.Events.RESIZE, this.onResize, this); + } + } + + destroy () { + this.shutdown() + } + + gameDestroy () { + this.pluginManager.removeGameObject(SPINE_GAME_OBJECT_TYPE, true, true); + this.pluginManager.removeGameObject(SPINE_CONTAINER_TYPE, true, true); + if (this.sceneRenderer) this.sceneRenderer.dispose(); + } + + createSkeleton (dataKey: string, atlasKey: string) { + let atlas: TextureAtlas; + if (this.atlasCache.exists(atlasKey)) { + atlas = this.atlasCache.get(atlasKey); + } else { + let atlasFile = this.game.cache.text.get(atlasKey) as string; + atlas = new TextureAtlas(atlasFile); + if (this.isWebGL) { + let gl = this.gl!; + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); + for (let atlasPage of atlas.pages) { + atlasPage.setTexture(new GLTexture(gl, this.textureManager.get(atlasKey + "!" + atlasPage.name).getSourceImage() as HTMLImageElement | ImageBitmap, false)); + } + } else { + for (let atlasPage of atlas.pages) { + atlasPage.setTexture(new CanvasTexture(this.textureManager.get(atlasKey + "!" + atlasPage.name).getSourceImage() as HTMLImageElement | ImageBitmap)); + } + } + this.atlasCache.add(atlasKey, atlas); + } + + let skeletonData: SkeletonData; + if (this.skeletonDataCache.exists(dataKey)) { + skeletonData = this.skeletonDataCache.get(dataKey); + } else { + if (this.game.cache.json.exists(dataKey)) { + let jsonFile = this.game.cache.json.get(dataKey) as any; + let json = new SkeletonJson(new AtlasAttachmentLoader(atlas)); + skeletonData = json.readSkeletonData(jsonFile); + } else { + let binaryFile = this.game.cache.binary.get(dataKey) as ArrayBuffer; + let binary = new SkeletonJson(new AtlasAttachmentLoader(atlas)); + skeletonData = binary.readSkeletonData(binaryFile); + } + this.skeletonDataCache.add(dataKey, skeletonData); + } + + return new Skeleton(skeletonData); + } } +export enum SpineSkeletonDataFileType { + json, + binary +} + +export class SpineSkeletonDataFile extends Phaser.Loader.MultiFile { + constructor (loader: Phaser.Loader.LoaderPlugin, key: string, url: string, public fileType: SpineSkeletonDataFileType, xhrSettings: Phaser.Types.Loader.XHRSettingsObject) { + let file = null; + let isJson = fileType == SpineSkeletonDataFileType.json; + if (isJson) { + file = new Phaser.Loader.FileTypes.JSONFile(loader, { + key: key, + url: url, + extension: "json", + xhrSettings: xhrSettings, + } as Phaser.Types.Loader.FileTypes.JSONFileConfig); + } else { + file = new Phaser.Loader.FileTypes.BinaryFile(loader, { + key: key, + url: url, + extension: "skel", + xhrSettings: xhrSettings, + } as Phaser.Types.Loader.FileTypes.BinaryFileConfig); + } + super(loader, SPINE_SKELETON_DATA_FILE_TYPE, key, [file]); + } + + onFileComplete (file: Phaser.Loader.File) { + this.pending--; + } + + addToCache () { + if (this.isReadyToProcess()) this.files[0].addToCache(); + } +} + +export class SpineAtlasFile extends Phaser.Loader.MultiFile { + constructor (loader: Phaser.Loader.LoaderPlugin, key: string, url: string, public premultipliedAlpha: boolean, xhrSettings: Phaser.Types.Loader.XHRSettingsObject) { + super(loader, SPINE_ATLAS_FILE_TYPE, key, [ + new Phaser.Loader.FileTypes.TextFile(loader, { + key: key, + url: url, + xhrSettings: xhrSettings, + extension: "atlas" + }) + ]); + } + + onFileComplete (file: Phaser.Loader.File) { + if (this.files.indexOf(file) != -1) { + this.pending--; + + if (file.type == "text") { + var lines = file.data.split('\n'); + let textures = []; + textures.push(lines[0]); + for (var t = 1; t < lines.length; t++) { + var line = lines[t]; + if (line.trim() === '' && t < lines.length - 1) { + line = lines[t + 1]; + textures.push(line); + } + } + + let basePath = file.src.match(/^.*\//); + for (var i = 0; i < textures.length; i++) { + var url = basePath + textures[i]; + var key = file.key + "!" + textures[i]; + var image = new Phaser.Loader.FileTypes.ImageFile(this.loader, key, url); + + if (!this.loader.keyExists(image)) { + this.addToMultiFile(image); + this.loader.addFile(image); + } + } + } + } + } + + addToCache () { + if (this.isReadyToProcess()) { + let textureManager = this.loader.textureManager; + for (let file of this.files) { + if (file.type == "image") { + if (!textureManager.exists(file.key)) { + textureManager.addImage(file.key, file.data); + } + } else { + file.addToCache(); + } + } + } + } +} \ No newline at end of file diff --git a/spine-ts/spine-phaser/src/index.ts b/spine-ts/spine-phaser/src/index.ts index c86582c84..0284b7bff 100644 --- a/spine-ts/spine-phaser/src/index.ts +++ b/spine-ts/spine-phaser/src/index.ts @@ -1,6 +1,5 @@ export * from "./require-shim" export * from "./SpinePlugin" -export * from "./SpineFile" export * from "./mixins" export * from "@esotericsoftware/spine-core"; export * from "@esotericsoftware/spine-canvas"; diff --git a/spine-ts/spine-phaser/src/keys.ts b/spine-ts/spine-phaser/src/keys.ts index 9366d1bd0..f13f0dda4 100644 --- a/spine-ts/spine-phaser/src/keys.ts +++ b/spine-ts/spine-phaser/src/keys.ts @@ -1,6 +1,8 @@ +export const SPINE_SKELETON_FILE_CACHE_KEY = "esotericsoftware.spine.skeletonFile.cache"; export const SPINE_ATLAS_CACHE_KEY = "esotericsoftware.spine.atlas.cache"; -export const SPINE_TEXTURE_CACHE_KEY = "esotericsoftware.spine.texture.cache"; +export const SPINE_ATLAS_TEXTURE_CACHE_KEY = "esotericsoftware.spine.atlas.texture.cache"; export const SPINE_LOADER_TYPE = "spine"; -export const SPINE_FILE_TYPE = "spine"; +export const SPINE_SKELETON_DATA_FILE_TYPE = "spineSkeletonData"; +export const SPINE_ATLAS_FILE_TYPE = "spineAtlasData"; export const SPINE_GAME_OBJECT_TYPE = "spine"; export const SPINE_CONTAINER_TYPE = "spineContainer"; diff --git a/spine-ts/spine-phaser/src/mixins.ts b/spine-ts/spine-phaser/src/mixins.ts index 58fd7d137..e38206562 100644 --- a/spine-ts/spine-phaser/src/mixins.ts +++ b/spine-ts/spine-phaser/src/mixins.ts @@ -33,41 +33,41 @@ export const Transform = components.Transform; export const Visible = components.Visible; export interface Type< - T, - P extends any[] = any[] -> extends Function { - new(...args: P): T; + T, + P extends any[] = any[] + > extends Function { + new(...args: P): T; } export type Mixin = < - GameObjectType extends Type ->( - BaseGameObject: GameObjectType + GameObjectType extends Type + >( + BaseGameObject: GameObjectType ) => GameObjectType & Type; export function createMixin< - GameObjectComponent, - GameObjectConstraint extends Phaser.GameObjects.GameObject = Phaser.GameObjects.GameObject ->( - ...component: GameObjectComponent[] + GameObjectComponent, + GameObjectConstraint extends Phaser.GameObjects.GameObject = Phaser.GameObjects.GameObject +> ( + ...component: GameObjectComponent[] ): Mixin { - return (BaseGameObject) => { - applyMixins(BaseGameObject, component); - return BaseGameObject as any; - }; + return (BaseGameObject) => { + applyMixins(BaseGameObject, component); + return BaseGameObject as any; + }; } -function applyMixins(derivedCtor: any, constructors: any[]) { - constructors.forEach((baseCtor) => { - Object.getOwnPropertyNames(baseCtor.prototype || baseCtor).forEach((name) => { - Object.defineProperty( - derivedCtor.prototype, - name, - Object.getOwnPropertyDescriptor(baseCtor.prototype || baseCtor, name) || - Object.create(null) - ); - }); - }); +function applyMixins (derivedCtor: any, constructors: any[]) { + constructors.forEach((baseCtor) => { + Object.getOwnPropertyNames(baseCtor.prototype || baseCtor).forEach((name) => { + Object.defineProperty( + derivedCtor.prototype, + name, + Object.getOwnPropertyDescriptor(baseCtor.prototype || baseCtor, name) || + Object.create(null) + ); + }); + }); } type ComputedSizeMixin = Mixin; diff --git a/spine-ts/spine-phaser/src/require-shim.ts b/spine-ts/spine-phaser/src/require-shim.ts index 3b812412a..62a5dca97 100644 --- a/spine-ts/spine-phaser/src/require-shim.ts +++ b/spine-ts/spine-phaser/src/require-shim.ts @@ -2,10 +2,10 @@ declare global { var require: any; } if (window.Phaser) { - let prevRequire = window.require; - window.require = (x: string) => { - if (prevRequire) return prevRequire(x); - else if (x === "Phaser") return window.Phaser; - } + let prevRequire = window.require; + window.require = (x: string) => { + if (prevRequire) return prevRequire(x); + else if (x === "Phaser") return window.Phaser; + } } -export {} \ No newline at end of file +export { } \ No newline at end of file