From fdfc4642ad57cee748dcbcb25174dbaadd911e59 Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Wed, 13 Sep 2023 15:35:53 +0200 Subject: [PATCH] =?UTF-8?q?[haxe]=C2=A0minimal=20scene=20framework,=20fixe?= =?UTF-8?q?s=20for=20Haxe=20C++,=20clean-up=20of=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spine-haxe/example/src/BasicExample.hx | 29 ++++++++ spine-haxe/example/src/Main.hx | 54 +------------- spine-haxe/example/src/Scene.hx | 46 ++++++++++++ spine-haxe/spine-haxe/spine/SkeletonBinary.hx | 13 ++-- spine-haxe/spine-haxe/spine/SkeletonData.hx | 19 +++++ spine-haxe/spine-haxe/spine/SkeletonJson.hx | 27 +++---- .../spine/atlas/AssetsTextureLoader.hx | 30 ++++++++ .../spine-haxe/spine/atlas/TextureAtlas.hx | 14 +++- .../spine/starling/SkeletonAnimation.hx | 32 --------- .../spine/starling/SkeletonSprite.hx | 40 ++++++++--- .../spine/starling/StarlingTextureLoader.hx | 70 ------------------- 11 files changed, 182 insertions(+), 192 deletions(-) create mode 100644 spine-haxe/example/src/BasicExample.hx create mode 100644 spine-haxe/example/src/Scene.hx create mode 100644 spine-haxe/spine-haxe/spine/atlas/AssetsTextureLoader.hx delete mode 100644 spine-haxe/spine-haxe/spine/starling/SkeletonAnimation.hx delete mode 100644 spine-haxe/spine-haxe/spine/starling/StarlingTextureLoader.hx diff --git a/spine-haxe/example/src/BasicExample.hx b/spine-haxe/example/src/BasicExample.hx new file mode 100644 index 000000000..a332906df --- /dev/null +++ b/spine-haxe/example/src/BasicExample.hx @@ -0,0 +1,29 @@ +import openfl.utils.Assets; +import spine.SkeletonBinary; +import spine.SkeletonData; +import spine.SkeletonJson; +import spine.animation.AnimationStateData; +import spine.atlas.TextureAtlas; +import spine.attachments.AtlasAttachmentLoader; +import spine.starling.SkeletonSprite; +import starling.core.Starling; + +class BasicExample extends Scene { + var loadBinary = true; + + public function load():Void { + var atlas = TextureAtlas.fromAssets("assets/raptor.atlas"); + var skeletondata = SkeletonData.fromAssets("assets/raptor-pro" + (loadBinary ? ".skel" : ".json"), atlas); + var animationStateData = new AnimationStateData(skeletondata); + animationStateData.defaultMix = 0.25; + + var skeletonSprite = new SkeletonSprite(skeletondata, animationStateData); + skeletonSprite.x = Starling.current.stage.stageWidth / 2; + skeletonSprite.y = Starling.current.stage.stageHeight * 0.5; + + skeletonSprite.state.setAnimationByName(0, "walk", true); + + addChild(skeletonSprite); + juggler.add(skeletonSprite); + } +} diff --git a/spine-haxe/example/src/Main.hx b/spine-haxe/example/src/Main.hx index 5c854fb38..96995bfb2 100644 --- a/spine-haxe/example/src/Main.hx +++ b/spine-haxe/example/src/Main.hx @@ -1,29 +1,12 @@ package; -import starling.display.Image; -import haxe.io.Bytes; -import openfl.display.Bitmap; -import openfl.display.BitmapData; +import Scene.SceneManager; import openfl.display.Sprite; -import openfl.Assets; import openfl.geom.Rectangle; -import openfl.utils.ByteArray; -import openfl.utils.Endian; -import spine.animation.AnimationStateData; -import spine.atlas.TextureAtlas; -import spine.attachments.AtlasAttachmentLoader; -import spine.SkeletonBinary; -import spine.SkeletonData; -import spine.SkeletonJson; -import spine.starling.SkeletonAnimation; -import spine.starling.StarlingTextureLoader; import starling.core.Starling; import starling.events.Event; -import starling.textures.Texture; class Main extends Sprite { - private static inline var loadBinary:Bool = false; - private var starlingSingleton:Starling; public function new() { @@ -39,39 +22,6 @@ class Main extends Sprite { starlingSingleton.start(); Starling.current.stage.color = 0x000000; - loadSpineAnimation(); - } - - private function loadSpineAnimation():Void { - var textureAtlasBitmapData:BitmapData = Assets.getBitmapData("assets/raptor.png"); - var stAtlas = Assets.getText("assets/raptor.atlas"); - var binaryData = Assets.getBytes("assets/raptor-pro.skel"); - var jsonData = Assets.getText("assets/raptor-pro.json"); - - var textureAtlas = Texture.fromBitmapData(textureAtlasBitmapData); - var textureloader = new StarlingTextureLoader(textureAtlas); - var atlas = new TextureAtlas(stAtlas, textureloader); - - var skeletondata:SkeletonData; - if (loadBinary) { - var skeletonBinary:SkeletonBinary = new SkeletonBinary(new AtlasAttachmentLoader(atlas)); - var bytearray:ByteArray = ByteArray.fromBytes(binaryData); - bytearray.endian = Endian.BIG_ENDIAN; - skeletondata = skeletonBinary.readSkeletonData(bytearray); - } else { - var skeletonJson:SkeletonJson = new SkeletonJson(new AtlasAttachmentLoader(atlas)); - skeletondata = skeletonJson.readSkeletonData(jsonData); - } - - var stateData:AnimationStateData = new AnimationStateData(skeletondata); - stateData.defaultMix = 0.25; - - var skeletonanimation:SkeletonAnimation = new SkeletonAnimation(skeletondata, stateData); - skeletonanimation.x = Starling.current.stage.stageWidth / 2; - skeletonanimation.y = Starling.current.stage.stageHeight * 0.5; - - Starling.current.stage.addChild(skeletonanimation); - Starling.current.juggler.add(skeletonanimation); - skeletonanimation.state.setAnimationByName(0, "walk", true); + SceneManager.getInstance().switchScene(new BasicExample()); } } diff --git a/spine-haxe/example/src/Scene.hx b/spine-haxe/example/src/Scene.hx new file mode 100644 index 000000000..64b7cf4f0 --- /dev/null +++ b/spine-haxe/example/src/Scene.hx @@ -0,0 +1,46 @@ +import starling.core.Starling; +import starling.display.Sprite; + +class SceneManager { + private static var instance:SceneManager; + + private var currentScene:Sprite; + + private function new() { + // Singleton pattern to ensure only one instance of SceneManager + } + + public static function getInstance():SceneManager { + if (instance == null) { + instance = new SceneManager(); + } + return instance; + } + + public function switchScene(newScene:Scene):Void { + if (currentScene != null) { + currentScene.dispose(); + currentScene.removeFromParent(true); + } + currentScene = newScene; + starling.core.Starling.current.stage.addChild(currentScene); + newScene.load(); + } +} + +abstract class Scene extends Sprite { + var juggler = new starling.animation.Juggler(); + + public function new() { + super(); + Starling.current.juggler.add(juggler); + } + + abstract public function load():Void; + + public override function dispose():Void { + juggler.purge(); + Starling.current.juggler.remove(juggler); + super.dispose(); + } +} diff --git a/spine-haxe/spine-haxe/spine/SkeletonBinary.hx b/spine-haxe/spine-haxe/spine/SkeletonBinary.hx index 75ddd81b8..ef47b15a6 100644 --- a/spine-haxe/spine-haxe/spine/SkeletonBinary.hx +++ b/spine-haxe/spine-haxe/spine/SkeletonBinary.hx @@ -1,5 +1,7 @@ package spine; +import spine.attachments.AtlasAttachmentLoader; +import openfl.utils.Endian; import spine.animation.SequenceTimeline; import openfl.errors.ArgumentError; import openfl.errors.Error; @@ -81,20 +83,17 @@ class SkeletonBinary { private static inline var CURVE_STEPPED:Int = 1; private static inline var CURVE_BEZIER:Int = 2; - public function new(attachmentLoader:AttachmentLoader = null) { + public function new(attachmentLoader:AttachmentLoader) { this.attachmentLoader = attachmentLoader; } - public function readSkeletonData(object:ByteArray):SkeletonData { - if (object == null) - throw new ArgumentError("Object cannot be null"); - if (!Std.isOfType(object, ByteArrayData)) - throw new ArgumentError("Object must be ByteArrayData"); + public function readSkeletonData(bytes:ByteArray):SkeletonData { + bytes.endian = Endian.BIG_ENDIAN; var skeletonData:SkeletonData = new SkeletonData(); skeletonData.name = null; - var input:BinaryInput = new BinaryInput(object); + var input:BinaryInput = new BinaryInput(bytes); var lowHash:Int = input.readInt32(); var highHash:Int = input.readInt32(); diff --git a/spine-haxe/spine-haxe/spine/SkeletonData.hx b/spine-haxe/spine-haxe/spine/SkeletonData.hx index d6361d77a..c16c1336c 100644 --- a/spine-haxe/spine-haxe/spine/SkeletonData.hx +++ b/spine-haxe/spine-haxe/spine/SkeletonData.hx @@ -1,5 +1,8 @@ package spine; +import spine.attachments.AtlasAttachmentLoader; +import openfl.utils.Assets; +import spine.atlas.TextureAtlas; import openfl.errors.ArgumentError; import openfl.Vector; import spine.animation.Animation; @@ -27,6 +30,22 @@ class SkeletonData { public var imagesPath:String; public var audioPath:String; + public static function fromAssets(path:String, atlas:TextureAtlas, scale:Float = 1.0):SkeletonData { + if (StringTools.endsWith(path, ".skel")) { + var byteData = Assets.getBytes(path); + var loader = new SkeletonBinary(new AtlasAttachmentLoader(atlas)); + loader.scale = scale; + return loader.readSkeletonData(byteData); + } else if (StringTools.endsWith(path, ".json")) { + var jsonData = Assets.getText(path); + var loader = new SkeletonJson(new AtlasAttachmentLoader(atlas)); + loader.scale = scale; + return loader.readSkeletonData(jsonData); + } else { + throw new SpineException("Path of skeleton data file must end with .json or .skel"); + } + } + public function new() {} // --- Bones. diff --git a/spine-haxe/spine-haxe/spine/SkeletonJson.hx b/spine-haxe/spine-haxe/spine/SkeletonJson.hx index 9c7061386..873d72dbd 100644 --- a/spine-haxe/spine-haxe/spine/SkeletonJson.hx +++ b/spine-haxe/spine-haxe/spine/SkeletonJson.hx @@ -54,28 +54,17 @@ class SkeletonJson { private var linkedMeshes:Vector = new Vector(); - public function new(attachmentLoader:AttachmentLoader = null) { + public function new(attachmentLoader:AttachmentLoader) { this.attachmentLoader = attachmentLoader; } - /** @param object A String or ByteArray. */ - public function readSkeletonData(object:Object, name:String = null):SkeletonData { - if (object == null) + public function readSkeletonData(json:String):SkeletonData { + if (json == null) throw new ArgumentError("object cannot be null."); - var root:Object; - if (Std.isOfType(object, String)) { - root = Json.parse(cast(object, String)); - } else if (Std.isOfType(object, ByteArrayData)) { - root = Json.parse(cast(object, ByteArray).readUTFBytes(cast(object, ByteArray).length)); - } else if (Std.isOfType(object, Dynamic)) { - root = object; - } else { - throw new ArgumentError("object must be a String, ByteArray or Object."); - } + var root = Json.parse(json); var skeletonData:SkeletonData = new SkeletonData(); - skeletonData.name = name; // Skeleton. var skeletonMap:Object = getString(root, "skeleton", ""); @@ -1172,10 +1161,10 @@ class SkeletonJson { } var i:Int = value << 2; - var cx1:Float = curve[Std.string(i)]; - var cy1:Float = curve[Std.string(i + 1)] * scale; - var cx2:Float = curve[Std.string(i + 2)]; - var cy2:Float = curve[Std.string(i + 3)] * scale; + var cx1:Float = curve[i]; + var cy1:Float = curve[i + 1] * scale; + var cx2:Float = curve[i + 2]; + var cy2:Float = curve[i + 3] * scale; timeline.setBezier(bezier, frame, value, time1, value1, cx1, cy1, cx2, cy2, time2, value2); return bezier + 1; } diff --git a/spine-haxe/spine-haxe/spine/atlas/AssetsTextureLoader.hx b/spine-haxe/spine-haxe/spine/atlas/AssetsTextureLoader.hx new file mode 100644 index 000000000..443bc2817 --- /dev/null +++ b/spine-haxe/spine-haxe/spine/atlas/AssetsTextureLoader.hx @@ -0,0 +1,30 @@ +package spine.atlas; + +import starling.textures.Texture; +import spine.atlas.TextureAtlasRegion; +import spine.atlas.TextureAtlasPage; +import spine.atlas.TextureLoader; + +class AssetsTextureLoader implements TextureLoader { + private var basePath:String; + + public function new(basePath:String) { + this.basePath = basePath; + } + + public function loadPage(page:TextureAtlasPage, path:String) { + var bitmapData = openfl.utils.Assets.getBitmapData(basePath + "/" + path); + if (bitmapData == null) { + throw new SpineException("Could not load atlas page texture " + basePath + "/" + path); + } + page.texture = Texture.fromBitmapData(bitmapData); + } + + public function loadRegion(region:TextureAtlasRegion):Void { + region.texture = region.page.texture; + } + + public function unloadPage(page:TextureAtlasPage):Void { + cast(page.texture, Texture).dispose(); + } +} diff --git a/spine-haxe/spine-haxe/spine/atlas/TextureAtlas.hx b/spine-haxe/spine-haxe/spine/atlas/TextureAtlas.hx index 6bb23c5fd..b965a90de 100644 --- a/spine-haxe/spine-haxe/spine/atlas/TextureAtlas.hx +++ b/spine-haxe/spine-haxe/spine/atlas/TextureAtlas.hx @@ -1,5 +1,6 @@ package spine.atlas; +import openfl.utils.Assets; import openfl.errors.ArgumentError; import openfl.utils.ByteArray; import openfl.utils.Dictionary; @@ -10,6 +11,17 @@ class TextureAtlas { private var regions = new Vector(); private var textureLoader:TextureLoader; + public static function fromAssets(path:String) { + var basePath = ""; + var slashIndex = path.lastIndexOf("/"); + if (slashIndex != -1) { + basePath = path.substring(0, slashIndex); + } + + var textureLoader = new AssetsTextureLoader(basePath); + return new TextureAtlas(Assets.getText("assets/raptor.atlas"), textureLoader); + } + /** @param object A String or ByteArray. */ public function new(object:Dynamic, textureLoader:TextureLoader) { if (object == null) { @@ -132,7 +144,7 @@ class TextureAtlas { field(); } } - textureLoader.loadPage(page, line); + textureLoader.loadPage(page, page.name); pages.push(page); } else { region = new TextureAtlasRegion(page, line); diff --git a/spine-haxe/spine-haxe/spine/starling/SkeletonAnimation.hx b/spine-haxe/spine-haxe/spine/starling/SkeletonAnimation.hx deleted file mode 100644 index 99bce0d6f..000000000 --- a/spine-haxe/spine-haxe/spine/starling/SkeletonAnimation.hx +++ /dev/null @@ -1,32 +0,0 @@ -package spine.starling; - -import starling.core.Starling; -import spine.animation.AnimationState; -import spine.animation.AnimationStateData; -import spine.SkeletonData; -import starling.animation.IAnimatable; - -class SkeletonAnimation extends SkeletonSprite implements IAnimatable { - public var state:AnimationState; - - private var functionUpdate:Void->Void; - - public function new(skeletonData:SkeletonData, stateData:AnimationStateData = null) { - super(skeletonData); - state = new AnimationState(stateData != null ? stateData : new AnimationStateData(skeletonData)); - } - - public function advanceTime(time:Float):Void { - var stage = Starling.current.stage; - state.update(time); - state.apply(skeleton); - skeleton.updateWorldTransform(); - this.setRequiresRedraw(); - if (this.functionUpdate != null) - this.functionUpdate(); - } - - public function setFunctionAnimationUpdate(functionUpdate:Void->Void):Void { - this.functionUpdate = functionUpdate; - } -} diff --git a/spine-haxe/spine-haxe/spine/starling/SkeletonSprite.hx b/spine-haxe/spine-haxe/spine/starling/SkeletonSprite.hx index eaf407e1e..e95d595d6 100644 --- a/spine-haxe/spine-haxe/spine/starling/SkeletonSprite.hx +++ b/spine-haxe/spine-haxe/spine/starling/SkeletonSprite.hx @@ -1,37 +1,41 @@ package spine.starling; -import starling.textures.Texture; -import starling.utils.Max; +import starling.animation.IAnimatable; +import openfl.Vector; import openfl.geom.Matrix; import openfl.geom.Point; import openfl.geom.Rectangle; -import openfl.Vector; -import spine.atlas.TextureAtlasRegion; -import spine.attachments.Attachment; -import spine.attachments.ClippingAttachment; -import spine.attachments.MeshAttachment; -import spine.attachments.RegionAttachment; import spine.Bone; import spine.Skeleton; import spine.SkeletonClipping; import spine.SkeletonData; import spine.Slot; +import spine.animation.AnimationState; +import spine.animation.AnimationStateData; +import spine.attachments.Attachment; +import spine.attachments.ClippingAttachment; +import spine.attachments.MeshAttachment; +import spine.attachments.RegionAttachment; import starling.display.BlendMode; import starling.display.DisplayObject; -import starling.display.Image; import starling.rendering.IndexData; import starling.rendering.Painter; import starling.rendering.VertexData; +import starling.textures.Texture; import starling.utils.Color; import starling.utils.MatrixUtil; +import starling.utils.Max; -class SkeletonSprite extends DisplayObject { +class SkeletonSprite extends DisplayObject implements IAnimatable { static private var _tempPoint:Point = new Point(); static private var _tempMatrix:Matrix = new Matrix(); static private var _tempVertices:Vector = new Vector(); static private var blendModes:Vector = Vector.ofArray([BlendMode.NORMAL, BlendMode.ADD, BlendMode.MULTIPLY, BlendMode.SCREEN]); private var _skeleton:Skeleton; + + public var _state:AnimationState; + private var _smoothing:String = "bilinear"; private static var clipper:SkeletonClipping = new SkeletonClipping(); @@ -40,11 +44,12 @@ class SkeletonSprite extends DisplayObject { private var tempLight:spine.Color = new spine.Color(0, 0, 0); private var tempDark:spine.Color = new spine.Color(0, 0, 0); - public function new(skeletonData:SkeletonData) { + public function new(skeletonData:SkeletonData, animationStateData:AnimationStateData = null) { super(); Bone.yDown = true; _skeleton = new Skeleton(skeletonData); _skeleton.updateWorldTransform(); + _state = new AnimationState(animationStateData != null ? animationStateData : new AnimationStateData(skeletonData)); } override public function render(painter:Painter):Void { @@ -285,6 +290,12 @@ class SkeletonSprite extends DisplayObject { return _skeleton; } + public var state(get, never):AnimationState; + + private function get_state():AnimationState { + return _state; + } + public var smoothing(get, set):String; private function get_smoothing():String { @@ -295,4 +306,11 @@ class SkeletonSprite extends DisplayObject { _smoothing = smoothing; return _smoothing; } + + public function advanceTime(time:Float):Void { + _state.update(time); + _state.apply(skeleton); + skeleton.updateWorldTransform(); + this.setRequiresRedraw(); + } } diff --git a/spine-haxe/spine-haxe/spine/starling/StarlingTextureLoader.hx b/spine-haxe/spine-haxe/spine/starling/StarlingTextureLoader.hx deleted file mode 100644 index 0c11acc88..000000000 --- a/spine-haxe/spine-haxe/spine/starling/StarlingTextureLoader.hx +++ /dev/null @@ -1,70 +0,0 @@ -package spine.starling; - -import openfl.display.Bitmap; -import openfl.display.BitmapData; -import openfl.errors.ArgumentError; -import openfl.utils.Object; -import spine.atlas.TextureAtlasPage; -import spine.atlas.TextureAtlasRegion; -import spine.atlas.TextureLoader; -import starling.display.Image; -import starling.textures.Texture; - -class StarlingTextureLoader implements TextureLoader { - public var bitmapDatasOrTextures:Object = {}; - public var singleBitmapDataOrTexture:Dynamic; - - /** @param bitmaps A Bitmap or BitmapData or Texture for an atlas that has only one page, or for a multi page atlas an object where the - * key is the image path and the value is the Bitmap or BitmapData or Texture. */ - public function new(bitmapsOrTextures:Dynamic) { - if (Std.isOfType(bitmapsOrTextures, BitmapData)) { - singleBitmapDataOrTexture = cast(bitmapsOrTextures, BitmapData); - return; - } - if (Std.isOfType(bitmapsOrTextures, Bitmap)) { - singleBitmapDataOrTexture = cast(bitmapsOrTextures, Bitmap).bitmapData; - return; - } - if (Std.isOfType(bitmapsOrTextures, Texture)) { - singleBitmapDataOrTexture = cast(bitmapsOrTextures, Texture); - return; - } - - for (path in Reflect.fields(bitmapsOrTextures)) { - var object:Dynamic = Reflect.getProperty(bitmapsOrTextures, path); - var bitmapDataOrTexture:Dynamic; - if (Std.isOfType(object, BitmapData)) { - bitmapDataOrTexture = cast(object, BitmapData); - } else if (Std.isOfType(object, Bitmap)) { - bitmapDataOrTexture = cast(object, Bitmap).bitmapData; - } else if (Std.isOfType(object, Texture)) { - bitmapDataOrTexture = cast(object, Texture); - } else { - throw new ArgumentError("Object for path \"" + path + "\" must be a Bitmap, BitmapData or Texture: " + object); - } - bitmapDatasOrTextures[path] = bitmapDataOrTexture; - } - } - - public function loadPage(page:TextureAtlasPage, path:String):Void { - var bitmapDataOrTexture:Dynamic = singleBitmapDataOrTexture != null ? singleBitmapDataOrTexture : bitmapDatasOrTextures[path]; - if (bitmapDataOrTexture == null) { - throw new ArgumentError("BitmapData/Texture not found with name: " + path); - } - if (Std.isOfType(bitmapDataOrTexture, BitmapData)) { - var bitmapData:BitmapData = cast(bitmapDataOrTexture, BitmapData); - page.texture = Texture.fromBitmapData(bitmapData); - } else { - var texture:Texture = cast(bitmapDataOrTexture, Texture); - page.texture = texture; - } - } - - public function loadRegion(region:TextureAtlasRegion):Void { - region.texture = region.page.texture; - } - - public function unloadPage(page:TextureAtlasPage):Void { - cast(page.texture, Texture).dispose(); - } -}