diff --git a/CHANGELOG.md b/CHANGELOG.md
index b9e242abc..69e9495c2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -178,6 +178,7 @@
3) Copy the original material, add *_Outline* to its name and set the shader to your outline-only shader like `Universal Render Pipeline/Spine/Outline/Skeleton-OutlineOnly` or `Spine/Outline/OutlineOnly-ZWrite`.
4) Assign this *_Outline* material at the new child GameObject's `MeshRenderer` component.
If you are using `SkeletonRenderSeparator` and need to enable and disable the `SkeletonRenderSeparator` component at runtime, you can increase the `RenderCombinedMesh` `Reference Renderers` array by one and assign the `SkeletonRenderer` itself at the last entry after the parts renderers. Disabled `MeshRenderer` components will be skipped when combining the final mesh, so the combined mesh is automatically filled from the desired active renderers.
+ * Timeline extension package: Added static `EditorEvent` callback to allow editor scripts to react to animation events outside of play-mode. Register to the events via `Spine.Unity.Playables.SpineAnimationStateMixerBehaviour.EditorEvent += YourCallback;`.
* **Breaking changes**
* Made `SkeletonGraphic.unscaledTime` parameter protected, use the new property `UnscaledTime` instead.
diff --git a/spine-haxe/.vscode/launch.json b/spine-haxe/.vscode/launch.json
index 6c29a8961..09a92a9da 100644
--- a/spine-haxe/.vscode/launch.json
+++ b/spine-haxe/.vscode/launch.json
@@ -4,13 +4,6 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
- {
- "name": "web",
- "request": "launch",
- "type": "chrome",
- "url": "http://localhost:3000",
- "webRoot": "${workspaceFolder}"
- },
{
"name": "lime",
"type": "lime",
diff --git a/spine-haxe/example/src/BasicExample.hx b/spine-haxe/example/src/BasicExample.hx
new file mode 100644
index 000000000..6e29895fc
--- /dev/null
+++ b/spine-haxe/example/src/BasicExample.hx
@@ -0,0 +1,28 @@
+import openfl.geom.Rectangle;
+import spine.SkeletonData;
+import spine.animation.AnimationStateData;
+import spine.atlas.TextureAtlas;
+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);
+ var bounds = skeletonSprite.skeleton.getBounds();
+ skeletonSprite.scale = Starling.current.stage.stageWidth / bounds.width * 0.5;
+ skeletonSprite.x = Starling.current.stage.stageWidth / 2;
+ skeletonSprite.y = Starling.current.stage.stageHeight * 0.9;
+
+ 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/project.xml b/spine-haxe/project.xml
index 620685391..ceeafb6fb 100644
--- a/spine-haxe/project.xml
+++ b/spine-haxe/project.xml
@@ -11,5 +11,6 @@
+
\ No newline at end of file
diff --git a/spine-haxe/spine-haxe/spine/BinaryInput.hx b/spine-haxe/spine-haxe/spine/BinaryInput.hx
index fc9f0be43..149b5c6e4 100644
--- a/spine-haxe/spine-haxe/spine/BinaryInput.hx
+++ b/spine-haxe/spine-haxe/spine/BinaryInput.hx
@@ -76,7 +76,7 @@ class BinaryInput {
chars += String.fromCharCode(((b & 0x0F) << 12 | (readByte() & 0x3F) << 6 | readByte() & 0x3F));
i += 3;
default:
- chars += String.fromCharCode(b);
+ chars += String.fromCharCode(b & 0xff);
i++;
}
}
diff --git a/spine-haxe/spine-haxe/spine/Skeleton.hx b/spine-haxe/spine-haxe/spine/Skeleton.hx
index 80f567293..cfb55991c 100644
--- a/spine-haxe/spine-haxe/spine/Skeleton.hx
+++ b/spine-haxe/spine-haxe/spine/Skeleton.hx
@@ -1,5 +1,6 @@
package spine;
+import openfl.geom.Rectangle;
import openfl.errors.ArgumentError;
import openfl.utils.Dictionary;
import openfl.Vector;
@@ -561,11 +562,10 @@ class Skeleton {
return _data.name != null ? _data.name : "Skeleton?";
}
- public function getBounds(offset:Vector, size:Vector, temp:Vector):Void {
- if (offset == null)
- throw new ArgumentError("offset cannot be null.");
- if (size == null)
- throw new ArgumentError("size cannot be null.");
+ private var _tempVertices = new Vector();
+ private var _bounds = new Rectangle();
+
+ public function getBounds():Rectangle {
var minX:Float = Math.POSITIVE_INFINITY;
var minY:Float = Math.POSITIVE_INFINITY;
var maxX:Float = Math.NEGATIVE_INFINITY;
@@ -576,14 +576,14 @@ class Skeleton {
var attachment:Attachment = slot.attachment;
if (Std.isOfType(attachment, RegionAttachment)) {
verticesLength = 8;
- temp.length = verticesLength;
- vertices = temp;
+ _tempVertices.length = verticesLength;
+ vertices = _tempVertices;
cast(attachment, RegionAttachment).computeWorldVertices(slot, vertices, 0, 2);
} else if (Std.isOfType(attachment, MeshAttachment)) {
var mesh:MeshAttachment = cast(attachment, MeshAttachment);
verticesLength = mesh.worldVerticesLength;
- temp.length = verticesLength;
- vertices = temp;
+ _tempVertices.length = verticesLength;
+ vertices = _tempVertices;
mesh.computeWorldVertices(slot, 0, verticesLength, vertices, 0, 2);
}
if (vertices != null) {
@@ -599,9 +599,10 @@ class Skeleton {
}
}
}
- offset[0] = minX;
- offset[1] = minY;
- size[0] = maxX - minX;
- size[1] = maxY - minY;
+ _bounds.x = minX;
+ _bounds.y = minY;
+ _bounds.width = maxX - minX;
+ _bounds.height = maxY - minY;
+ return _bounds;
}
}
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();
- }
-}
diff --git a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/RenderCombinedMesh.cs b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/RenderCombinedMesh.cs
index d1dfddcf3..2a5536cb4 100644
--- a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/RenderCombinedMesh.cs
+++ b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/RenderCombinedMesh.cs
@@ -178,12 +178,12 @@ namespace Spine.Unity.Examples {
indexBuffer = new ExposedList(combinedIndexCount);
}
- if (positionBuffer.Count < combinedVertexCount) {
+ if (positionBuffer.Count != combinedVertexCount) {
positionBuffer.Resize(combinedVertexCount);
uvBuffer.Resize(combinedVertexCount);
colorBuffer.Resize(combinedVertexCount);
}
- if (indexBuffer.Count < combinedIndexCount) {
+ if (indexBuffer.Count != combinedIndexCount) {
indexBuffer.Resize(combinedIndexCount);
}
}
@@ -223,32 +223,27 @@ namespace Spine.Unity.Examples {
System.Array.Copy(positions, 0, this.positionBuffer.Items, combinedV, vertexCount);
System.Array.Copy(uvs, 0, this.uvBuffer.Items, combinedV, vertexCount);
System.Array.Copy(colors, 0, this.colorBuffer.Items, combinedV, vertexCount);
- combinedV += vertexCount;
for (int s = 0, submeshCount = mesh.subMeshCount; s < submeshCount; ++s) {
int submeshIndexCount = (int)mesh.GetIndexCount(s);
int[] submeshIndices = mesh.GetIndices(s);
- System.Array.Copy(submeshIndices, 0, this.indexBuffer.Items, combinedI, submeshIndexCount);
+ int[] dstIndices = this.indexBuffer.Items;
+ for (int i = 0; i < submeshIndexCount; ++i)
+ dstIndices[i + combinedI] = submeshIndices[i] + combinedV;
combinedI += submeshIndexCount;
}
+ combinedV += vertexCount;
}
Mesh combinedMesh = doubleBufferedMesh.GetNext();
+ combinedMesh.Clear();
#if SET_VERTICES_HAS_LENGTH_PARAMETER
combinedMesh.SetVertices(this.positionBuffer.Items, 0, this.positionBuffer.Count);
combinedMesh.SetUVs(0, this.uvBuffer.Items, 0, this.uvBuffer.Count);
combinedMesh.SetColors(this.colorBuffer.Items, 0, this.colorBuffer.Count);
combinedMesh.SetTriangles(this.indexBuffer.Items, 0, this.indexBuffer.Count, 0);
#else
- // fill excess with zero positions
- {
- int listCount = this.positionBuffer.Count;
- Vector3[] positionArray = this.positionBuffer.Items;
- int arrayLength = positionArray.Length;
- Vector3 vector3zero = Vector3.zero;
- for (int i = listCount; i < arrayLength; i++)
- positionArray[i] = vector3zero;
- }
+ // Note: excess already contains zero positions and indices after ExposedList.Resize().
combinedMesh.vertices = this.positionBuffer.Items;
combinedMesh.uv = this.uvBuffer.Items;
combinedMesh.colors32 = this.colorBuffer.Items;
diff --git a/spine-unity/Assets/Spine Examples/package.json b/spine-unity/Assets/Spine Examples/package.json
index 3c54d422a..79a117857 100644
--- a/spine-unity/Assets/Spine Examples/package.json
+++ b/spine-unity/Assets/Spine Examples/package.json
@@ -2,7 +2,7 @@
"name": "com.esotericsoftware.spine.spine-unity-examples",
"displayName": "spine-unity Runtime Examples",
"description": "This plugin provides example scenes and scripts for the spine-unity runtime.",
- "version": "4.2.21",
+ "version": "4.2.22",
"unity": "2018.3",
"author": {
"name": "Esoteric Software",
diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs
index 2a277ced3..553331415 100644
--- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs
+++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs
@@ -31,7 +31,9 @@
#define SPEED_INCLUDED_IN_CLIP_TIME
#endif
+#if UNITY_EDITOR
#define SPINE_EDITMODEPOSE
+#endif
using System;
using UnityEngine;
@@ -250,8 +252,11 @@ namespace Spine.Unity.Playables {
}
#if SPINE_EDITMODEPOSE
+ /// Animation event callback for editor scripts when outside of play-mode.
+ public static event AnimationState.TrackEntryEventDelegate EditorEvent;
AnimationState dummyAnimationState;
+ ExposedList editorAnimationEvents = new ExposedList();
public void PreviewEditModePose (Playable playable,
ISkeletonComponent skeletonComponent, IAnimationStateComponent animationStateComponent,
@@ -259,6 +264,7 @@ namespace Spine.Unity.Playables {
if (Application.isPlaying) return;
if (animationStateComponent.IsNullOrDestroyed() || skeletonComponent == null) return;
+ editorAnimationEvents.Clear(false);
int inputCount = playable.GetInputCount();
float rootSpeed = GetRootPlayableSpeed(playable);
@@ -341,11 +347,19 @@ namespace Spine.Unity.Playables {
}
// Apply Pose
+ dummyAnimationState.Event += EditorEvent;
dummyAnimationState.Update(0);
dummyAnimationState.Apply(skeleton);
+ dummyAnimationState.Event -= EditorEvent;
} else {
- if (toAnimation != null)
- toAnimation.Apply(skeleton, 0, toClipTime, clipData.loop, null, clipData.alpha, MixBlend.Setup, MixDirection.In);
+ if (toAnimation != null) {
+ toAnimation.Apply(skeleton, 0, toClipTime, clipData.loop, editorAnimationEvents, clipData.alpha, MixBlend.Setup, MixDirection.In);
+ if (EditorEvent != null) {
+ foreach (Spine.Event e in editorAnimationEvents) {
+ EditorEvent(null, e);
+ }
+ }
+ }
}
skeleton.UpdateWorldTransform();
diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/package.json b/spine-unity/Modules/com.esotericsoftware.spine.timeline/package.json
index bbfb13d59..808594124 100644
--- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/package.json
+++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/package.json
@@ -2,7 +2,7 @@
"name": "com.esotericsoftware.spine.timeline",
"displayName": "Spine Timeline Extensions",
"description": "This plugin provides integration of spine-unity for the Unity Timeline.\n\nPrerequisites:\nIt requires a working installation of the spine-unity and spine-csharp runtimes as UPM packages (not as spine-unity unitypackage), version 4.2.\n(See http://esotericsoftware.com/git/spine-runtimes/spine-unity)",
- "version": "4.2.12",
+ "version": "4.2.13",
"unity": "2018.3",
"author": {
"name": "Esoteric Software",