Merge branch '3.8' into 3.9-beta

This commit is contained in:
badlogic 2020-05-06 19:47:25 +02:00
commit 0bcd19ef55
31 changed files with 1141 additions and 23 deletions

View File

@ -57,7 +57,7 @@ package spine {
public var worldY : Number;
internal var _sorted : Boolean;
public var active : Boolean;
/** @param parent May be null. */
public function Bone(data : BoneData, skeleton : Skeleton, parent : Bone) {
@ -68,7 +68,7 @@ package spine {
_parent = parent;
setToSetupPose();
}
public function isActive() : Boolean {
return active;
}
@ -102,8 +102,8 @@ package spine {
var parent : Bone = _parent;
if (!parent) { // Root bone.
rotationY = rotation + 90 + shearY;
var skeleton : Skeleton = _skeleton;
rotationY = rotation + 90 + shearY;
var skeleton : Skeleton = _skeleton;
this.a = MathUtils.cosDeg(rotation + shearX) * scaleX * sx;
this.b = MathUtils.cosDeg(rotationY) * scaleY * sx;
this.c = MathUtils.sinDeg(rotation + shearX) * scaleX * sy;
@ -161,7 +161,7 @@ package spine {
this.b = pa * lb - pb * ld;
this.c = pc * la + pd * lc;
this.d = pc * lb + pd * ld;
break;
return;
}
case TransformMode.noScale:
case TransformMode.noScaleOrReflection: {
@ -182,11 +182,11 @@ package spine {
la = MathUtils.cosDeg(shearX) * scaleX;
lb = MathUtils.cosDeg(90 + shearY) * scaleY;
lc = MathUtils.sinDeg(shearX) * scaleX;
ld = MathUtils.sinDeg(90 + shearY) * scaleY;
ld = MathUtils.sinDeg(90 + shearY) * scaleY;
this.a = za * la + zb * lc;
this.b = za * lb + zb * ld;
this.c = zc * la + zd * lc;
this.d = zc * lb + zd * ld;
this.d = zc * lb + zd * ld;
break;
}
}

View File

@ -139,7 +139,7 @@ void spBone_updateWorldTransformWith (spBone* self, float x, float y, float rota
CONST_CAST(float, self->b) = pa * lb - pb * ld;
CONST_CAST(float, self->c) = pc * la + pd * lc;
CONST_CAST(float, self->d) = pc * lb + pd * ld;
break;
return;
}
case SP_TRANSFORMMODE_NOSCALE:
case SP_TRANSFORMMODE_NOSCALEORREFLECTION: {

View File

@ -168,7 +168,7 @@ void Bone::updateWorldTransform(float x, float y, float rotation, float scaleX,
_b = pa * lb - pb * ld;
_c = pc * la + pd * lc;
_d = pc * lb + pd * ld;
break;
return;
}
case TransformMode_NoScale:
case TransformMode_NoScaleOrReflection: {

View File

@ -207,7 +207,7 @@ namespace Spine {
b = pa * lb - pb * ld;
c = pc * la + pd * lc;
d = pc * lb + pd * ld;
break;
return;
}
case TransformMode.NoScale:
case TransformMode.NoScaleOrReflection: {

View File

@ -0,0 +1,32 @@
{
"skeleton": { "hash": "hj8P+t8L2OIWCj7RHV1Nzql4Y5E", "spine": "3.8.95", "images": "", "audio": "" },
"bones": [
{ "name": "root" }
],
"events": {
"event": {}
},
"animations": {
"events0": {
"events": [
{ "name": "event", "string": "0" },
{ "time": 0.4667, "name": "event", "string": "14" },
{ "time": 1, "name": "event", "string": "30" }
]
},
"events1": {
"events": [
{ "name": "event", "string": "0" },
{ "time": 0.4667, "name": "event", "string": "14" },
{ "time": 1, "name": "event", "string": "30" }
]
},
"events2": {
"events": [
{ "name": "event", "string": "0" },
{ "time": 0.4667, "name": "event", "string": "14" },
{ "time": 1, "name": "event", "string": "30" }
]
}
}
}

View File

@ -0,0 +1,995 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
*
* Copyright (c) 2013-2020, Esoteric Software LLC
*
* Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license
*
* Otherwise, it is permitted to integrate the Spine Runtimes into software
* or otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
//#define RUN_ADDITIONAL_FORUM_RELATED_TEST
using Spine;
using System;
using System.Collections.Generic;
using System.Threading;
namespace Spine {
public class AnimationStateTests {
static readonly float FLOAT_ROUNDING_ERROR = 0.000001f; // 32 bits
static bool IsEqual (float a, float b) {
return Math.Abs(a - b) <= FLOAT_ROUNDING_ERROR;
}
class NullAttachmentLoader : AttachmentLoader {
public RegionAttachment NewRegionAttachment (Skin skin, string name, string path) {
return null;
}
public MeshAttachment NewMeshAttachment (Skin skin, string name, string path) {
return null;
}
public BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, string name) {
return null;
}
public ClippingAttachment NewClippingAttachment (Skin skin, string name) {
return null;
}
public PathAttachment NewPathAttachment (Skin skin, string name) {
return null;
}
public PointAttachment NewPointAttachment (Skin skin, string name) {
return null;
}
}
class LoggingAnimationStateListener {
AnimationStateTests tests;
public LoggingAnimationStateListener (AnimationStateTests tests) {
this.tests = tests;
}
public void RegisterAtAnimationState (AnimationState state) {
state.Start += Start;
state.Interrupt += Interrupt;
state.End += End;
state.Dispose += Dispose;
state.Complete += Complete;
state.Event += Event;
}
public void UnregisterFromAnimationState (AnimationState state) {
state.Start -= Start;
state.Interrupt -= Interrupt;
state.End -= End;
state.Dispose -= Dispose;
state.Complete -= Complete;
state.Event -= Event;
}
public void Start (TrackEntry entry) {
Add(tests.Actual("start", entry));
}
public void Interrupt (TrackEntry entry) {
Add(tests.Actual("interrupt", entry));
}
public void End (TrackEntry entry) {
Add(tests.Actual("end", entry));
}
public void Dispose (TrackEntry entry) {
Add(tests.Actual("dispose", entry));
}
public void Complete (TrackEntry entry) {
Add(tests.Actual("complete", entry));
}
public void Event (TrackEntry entry, Event ev) {
Add(tests.Actual("event " + ev.String, entry));
}
private void Add (Result result) {
while (tests.expected.Count > tests.actual.Count) {
Result note = tests.expected[tests.actual.Count];
if (!note.note) break;
tests.actual.Add(note);
Log(note.name);
}
string message = result.ToString();
if (tests.actual.Count >= tests.expected.Count) {
message += "FAIL: <none>";
tests.fail = true;
} else if (!tests.expected[tests.actual.Count].Equals(result)) {
message += "FAIL: " + tests.expected[tests.actual.Count];
tests.fail = true;
} else
message += "PASS";
Log(message);
tests.actual.Add(result);
}
};
readonly SkeletonJson json = new SkeletonJson();
LoggingAnimationStateListener stateListener = null;
readonly SkeletonData skeletonData;
readonly List<Result> actual = new List<Result>();
readonly List<Result> expected = new List<Result>();
AnimationStateData stateData;
AnimationState state;
float time = 0;
bool fail;
int test;
AnimationStateTests (string testJsonFilePath) {
skeletonData = json.ReadSkeletonData(testJsonFilePath);
TrackEntry entry;
Setup("0.1 time step", // 1
Expect(0, "start", 0, 0), //
Expect(0, "event 0", 0, 0), //
Expect(0, "event 14", 0.5f, 0.5f), //
Expect(0, "event 30", 1, 1), //
Expect(0, "complete", 1, 1), //
Expect(0, "end", 1, 1.1f), //
Expect(0, "dispose", 1, 1.1f) //
);
state.SetAnimation(0, "events0", false).TrackEnd = 1;
Run(0.1f, 1000, null);
Setup("1/60 time step, dispose queued", // 2
Expect(0, "start", 0, 0), //
Expect(0, "interrupt", 0, 0), //
Expect(0, "end", 0, 0), //
Expect(0, "dispose", 0, 0), //
Expect(1, "dispose", 0, 0), //
Expect(0, "dispose", 0, 0), //
Expect(1, "dispose", 0, 0), //
Note("First 2 set/addAnimation calls are done."),
Expect(0, "start", 0, 0), //
Expect(0, "event 0", 0, 0), //
Expect(0, "event 14", 0.483f, 0.483f), //
Expect(0, "event 30", 1, 1), //
Expect(0, "complete", 1, 1), //
Expect(0, "end", 1, 1.017f), //
Expect(0, "dispose", 1, 1.017f) //
);
state.SetAnimation(0, "events0", false);
state.AddAnimation(0, "events1", false, 0);
state.AddAnimation(0, "events0", false, 0);
state.AddAnimation(0, "events1", false, 0);
state.SetAnimation(0, "events0", false).TrackEnd = 1;
Run(1 / 60f, 1000, null);
Setup("30 time step", // 3
Expect(0, "start", 0, 0), //
Expect(0, "event 0", 0, 0), //
Expect(0, "event 14", 30, 30), //
Expect(0, "event 30", 30, 30), //
Expect(0, "complete", 30, 30), //
Expect(0, "end", 30, 60), //
Expect(0, "dispose", 30, 60) //
);
state.SetAnimation(0, "events0", false).TrackEnd = 1;
Run(30, 1000, null);
Setup("1 time step", // 4
Expect(0, "start", 0, 0), //
Expect(0, "event 0", 0, 0), //
Expect(0, "event 14", 1, 1), //
Expect(0, "event 30", 1, 1), //
Expect(0, "complete", 1, 1), //
Expect(0, "end", 1, 2), //
Expect(0, "dispose", 1, 2) //
);
state.SetAnimation(0, "events0", false).TrackEnd = 1;
Run(1, 1.01f, null);
Setup("interrupt", // 5
Expect(0, "start", 0, 0), //
Expect(0, "event 0", 0, 0), //
Expect(0, "event 14", 0.5f, 0.5f), //
Expect(0, "event 30", 1, 1), //
Expect(0, "complete", 1, 1), //
Expect(0, "interrupt", 1.1f, 1.1f), //
Expect(1, "start", 0.1f, 1.1f), //
Expect(1, "event 0", 0.1f, 1.1f), //
Expect(0, "end", 1.1f, 1.2f), //
Expect(0, "dispose", 1.1f, 1.2f), //
Expect(1, "event 14", 0.5f, 1.5f), //
Expect(1, "event 30", 1, 2), //
Expect(1, "complete", 1, 2), //
Expect(1, "interrupt", 1.1f, 2.1f), //
Expect(0, "start", 0.1f, 2.1f), //
Expect(0, "event 0", 0.1f, 2.1f), //
Expect(1, "end", 1.1f, 2.2f), //
Expect(1, "dispose", 1.1f, 2.2f), //
Expect(0, "event 14", 0.5f, 2.5f), //
Expect(0, "event 30", 1, 3), //
Expect(0, "complete", 1, 3), //
Expect(0, "end", 1, 3.1f), //
Expect(0, "dispose", 1, 3.1f) //
);
state.SetAnimation(0, "events0", false);
state.AddAnimation(0, "events1", false, 0);
state.AddAnimation(0, "events0", false, 0).TrackEnd = 1;
Run(0.1f, 4f, null);
Setup("interrupt with delay", // 6
Expect(0, "start", 0, 0), //
Expect(0, "event 0", 0, 0), //
Expect(0, "event 14", 0.5f, 0.5f), //
Expect(0, "interrupt", 0.6f, 0.6f), //
Expect(1, "start", 0.1f, 0.6f), //
Expect(1, "event 0", 0.1f, 0.6f), //
Expect(0, "end", 0.6f, 0.7f), //
Expect(0, "dispose", 0.6f, 0.7f), //
Expect(1, "event 14", 0.5f, 1.0f), //
Expect(1, "event 30", 1, 1.5f), //
Expect(1, "complete", 1, 1.5f), //
Expect(1, "end", 1, 1.6f), //
Expect(1, "dispose", 1, 1.6f) //
);
state.SetAnimation(0, "events0", false);
state.AddAnimation(0, "events1", false, 0.5f).TrackEnd = 1;
Run(0.1f, 1000, null);
Setup("interrupt with delay and mix time", // 7
Expect(0, "start", 0, 0), //
Expect(0, "event 0", 0, 0), //
Expect(0, "event 14", 0.5f, 0.5f), //
Expect(0, "interrupt", 1, 1), //
Expect(1, "start", 0.1f, 1), //
Expect(0, "complete", 1, 1), //
Expect(1, "event 0", 0.1f, 1), //
Expect(1, "event 14", 0.5f, 1.4f), //
Expect(0, "end", 1.6f, 1.7f), //
Expect(0, "dispose", 1.6f, 1.7f), //
Expect(1, "event 30", 1, 1.9f), //
Expect(1, "complete", 1, 1.9f), //
Expect(1, "end", 1, 2), //
Expect(1, "dispose", 1, 2) //
);
stateData.SetMix("events0", "events1", 0.7f);
state.SetAnimation(0, "events0", true);
state.AddAnimation(0, "events1", false, 0.9f).TrackEnd = 1;
Run(0.1f, 1000, null);
Setup("animation 0 events do not fire during mix", // 8
Expect(0, "start", 0, 0), //
Expect(0, "event 0", 0, 0), //
Expect(0, "interrupt", 0.5f, 0.5f), //
Expect(1, "start", 0.1f, 0.5f), //
Expect(1, "event 0", 0.1f, 0.5f), //
Expect(1, "event 14", 0.5f, 0.9f), //
Expect(0, "complete", 1, 1), //
Expect(0, "end", 1.1f, 1.2f), //
Expect(0, "dispose", 1.1f, 1.2f), //
Expect(1, "event 30", 1, 1.4f), //
Expect(1, "complete", 1, 1.4f), //
Expect(1, "end", 1, 1.5f), //
Expect(1, "dispose", 1, 1.5f) //
);
stateData.DefaultMix = 0.7f;
state.SetAnimation(0, "events0", false);
state.AddAnimation(0, "events1", false, 0.4f).TrackEnd = 1;
Run(0.1f, 1000, null);
Setup("event threshold, some animation 0 events fire during mix", // 9
Expect(0, "start", 0, 0), //
Expect(0, "event 0", 0, 0), //
Expect(0, "interrupt", 0.5f, 0.5f), //
Expect(1, "start", 0.1f, 0.5f), //
Expect(0, "event 14", 0.5f, 0.5f), //
Expect(1, "event 0", 0.1f, 0.5f), //
Expect(1, "event 14", 0.5f, 0.9f), //
Expect(0, "complete", 1, 1), //
Expect(0, "end", 1.1f, 1.2f), //
Expect(0, "dispose", 1.1f, 1.2f), //
Expect(1, "event 30", 1, 1.4f), //
Expect(1, "complete", 1, 1.4f), //
Expect(1, "end", 1, 1.5f), //
Expect(1, "dispose", 1, 1.5f) //
);
stateData.SetMix("events0", "events1", 0.7f);
state.SetAnimation(0, "events0", false).EventThreshold = 0.5f;
state.AddAnimation(0, "events1", false, 0.4f).TrackEnd = 1;
Run(0.1f, 1000, null);
Setup("event threshold, all animation 0 events fire during mix", // 10
Expect(0, "start", 0, 0), //
Expect(0, "event 0", 0, 0), //
Expect(0, "event 14", 0.5f, 0.5f), //
Expect(0, "interrupt", 0.9f, 0.9f), //
Expect(1, "start", 0.1f, 0.9f), //
Expect(1, "event 0", 0.1f, 0.9f), //
Expect(0, "event 30", 1, 1), //
Expect(0, "complete", 1, 1), //
Expect(0, "event 0", 1, 1), //
Expect(1, "event 14", 0.5f, 1.3f), //
Expect(0, "end", 1.5f, 1.6f), //
Expect(0, "dispose", 1.5f, 1.6f), //
Expect(1, "event 30", 1, 1.8f), //
Expect(1, "complete", 1, 1.8f), //
Expect(1, "end", 1, 1.9f), //
Expect(1, "dispose", 1, 1.9f) //
);
state.SetAnimation(0, "events0", true).EventThreshold = 1;
entry = state.AddAnimation(0, "events1", false, 0.8f);
entry.MixDuration = 0.7f;
entry.TrackEnd = 1;
Run(0.1f, 1000, null);
Setup("looping", // 11
Expect(0, "start", 0, 0), //
Expect(0, "event 0", 0, 0), //
Expect(0, "event 14", 0.5f, 0.5f), //
Expect(0, "event 30", 1, 1), //
Expect(0, "complete", 1, 1), //
Expect(0, "event 0", 1, 1), //
Expect(0, "event 14", 1.5f, 1.5f), //
Expect(0, "event 30", 2, 2), //
Expect(0, "complete", 2, 2), //
Expect(0, "event 0", 2, 2), //
Expect(0, "event 14", 2.5f, 2.5f), //
Expect(0, "event 30", 3, 3), //
Expect(0, "complete", 3, 3), //
Expect(0, "event 0", 3, 3), //
Expect(0, "event 14", 3.5f, 3.5f), //
Expect(0, "event 30", 4, 4), //
Expect(0, "complete", 4, 4), //
Expect(0, "event 0", 4, 4), //
Expect(0, "end", 4.1f, 4.1f), //
Expect(0, "dispose", 4.1f, 4.1f) //
);
state.SetAnimation(0, "events0", true);
Run(0.1f, 4, null);
Setup("not looping, track end past animation 0 duration", // 12
Expect(0, "start", 0, 0), //
Expect(0, "event 0", 0, 0), //
Expect(0, "event 14", 0.5f, 0.5f), //
Expect(0, "event 30", 1, 1), //
Expect(0, "complete", 1, 1), //
Expect(0, "interrupt", 2.1f, 2.1f), //
Expect(1, "start", 0.1f, 2.1f), //
Expect(1, "event 0", 0.1f, 2.1f), //
Expect(0, "end", 2.1f, 2.2f), //
Expect(0, "dispose", 2.1f, 2.2f), //
Expect(1, "event 14", 0.5f, 2.5f), //
Expect(1, "event 30", 1, 3), //
Expect(1, "complete", 1, 3), //
Expect(1, "end", 1, 3.1f), //
Expect(1, "dispose", 1, 3.1f) //
);
state.SetAnimation(0, "events0", false);
state.AddAnimation(0, "events1", false, 2).TrackEnd = 1;
Run(0.1f, 4f, null);
Setup("interrupt animation after first loop complete", // 13
Expect(0, "start", 0, 0), //
Expect(0, "event 0", 0, 0), //
Expect(0, "event 14", 0.5f, 0.5f), //
Expect(0, "event 30", 1, 1), //
Expect(0, "complete", 1, 1), //
Expect(0, "event 0", 1, 1), //
Expect(0, "event 14", 1.5f, 1.5f), //
Expect(0, "event 30", 2, 2), //
Expect(0, "complete", 2, 2), //
Expect(0, "event 0", 2, 2), //
Expect(0, "interrupt", 2.1f, 2.1f), //
Expect(1, "start", 0.1f, 2.1f), //
Expect(1, "event 0", 0.1f, 2.1f), //
Expect(0, "end", 2.1f, 2.2f), //
Expect(0, "dispose", 2.1f, 2.2f), //
Expect(1, "event 14", 0.5f, 2.5f), //
Expect(1, "event 30", 1, 3), //
Expect(1, "complete", 1, 3), //
Expect(1, "end", 1, 3.1f), //
Expect(1, "dispose", 1, 3.1f) //
);
state.SetAnimation(0, "events0", true);
Run(0.1f, 6, new TestListener(
(time) => {
if (IsEqual(time, 1.4f)) state.AddAnimation(0, "events1", false, 0).TrackEnd = 1;
}));
Setup ("add animation on empty track", // 14
Expect(0, "start", 0, 0), //
Expect(0, "event 0", 0, 0), //
Expect(0, "event 14", 0.5f, 0.5f), //
Expect(0, "event 30", 1, 1), //
Expect(0, "complete", 1, 1), //
Expect(0, "end", 1, 1.1f), //
Expect(0, "dispose", 1, 1.1f) //
);
state.AddAnimation(0, "events0", false, 0).TrackEnd = 1;
Run(0.1f, 1.9f, null);
Setup("end time beyond non-looping animation duration", // 15
Expect(0, "start", 0, 0), //
Expect(0, "event 0", 0, 0), //
Expect(0, "event 14", 0.5f, 0.5f), //
Expect(0, "event 30", 1, 1), //
Expect(0, "complete", 1, 1), //
Expect(0, "end", 9f, 9.1f), //
Expect(0, "dispose", 9f, 9.1f) //
);
state.SetAnimation(0, "events0", false).TrackEnd = 9;
Run(0.1f, 10, null);
Setup("looping with animation start", // 16
Expect(0, "start", 0, 0), //
Expect(0, "event 30", 0.4f, 0.4f), //
Expect(0, "complete", 0.4f, 0.4f), //
Expect(0, "event 30", 0.8f, 0.8f), //
Expect(0, "complete", 0.8f, 0.8f), //
Expect(0, "event 30", 1.2f, 1.2f), //
Expect(0, "complete", 1.2f, 1.2f), //
Expect(0, "end", 1.4f, 1.4f), //
Expect(0, "dispose", 1.4f, 1.4f) //
);
entry = state.SetAnimation(0, "events0", true);
entry.AnimationLast = 0.6f;
entry.AnimationStart = 0.6f;
Run(0.1f, 1.4f, null);
Setup("looping with animation start and end", // 17
Expect(0, "start", 0, 0), //
Expect(0, "event 14", 0.3f, 0.3f), //
Expect(0, "complete", 0.6f, 0.6f), //
Expect(0, "event 14", 0.9f, 0.9f), //
Expect(0, "complete", 1.2f, 1.2f), //
Expect(0, "event 14", 1.5f, 1.5f), //
Expect(0, "end", 1.8f, 1.8f), //
Expect(0, "dispose", 1.8f, 1.8f) //
);
entry = state.SetAnimation(0, "events0", true);
entry.AnimationStart = 0.2f;
entry.AnimationLast = 0.2f;
entry.AnimationEnd = 0.8f;
Run(0.1f, 1.8f, null);
Setup("non-looping with animation start and end", // 18
Expect(0, "start", 0, 0), //
Expect(0, "event 14", 0.3f, 0.3f), //
Expect(0, "complete", 0.6f, 0.6f), //
Expect(0, "end", 1, 1.1f), //
Expect(0, "dispose", 1, 1.1f) //
);
entry = state.SetAnimation(0, "events0", false);
entry.AnimationStart = 0.2f;
entry.AnimationLast = 0.2f;
entry.AnimationEnd = 0.8f;
entry.TrackEnd = 1;
Run(0.1f, 1.8f, null);
Setup("mix out looping with animation start and end", // 19
Expect(0, "start", 0, 0), //
Expect(0, "event 14", 0.3f, 0.3f), //
Expect(0, "complete", 0.6f, 0.6f), //
Expect(0, "interrupt", 0.8f, 0.8f), //
Expect(1, "start", 0.1f, 0.8f), //
Expect(1, "event 0", 0.1f, 0.8f), //
Expect(0, "event 14", 0.9f, 0.9f), //
Expect(0, "complete", 1.2f, 1.2f), //
Expect(1, "event 14", 0.5f, 1.2f), //
Expect(0, "end", 1.4f, 1.5f), //
Expect(0, "dispose", 1.4f, 1.5f), //
Expect(1, "event 30", 1, 1.7f), //
Expect(1, "complete", 1, 1.7f), //
Expect(1, "end", 1, 1.8f), //
Expect(1, "dispose", 1, 1.8f) //
);
entry = state.SetAnimation(0, "events0", true);
entry.AnimationStart = (0.2f);
entry.AnimationLast = (0.2f);
entry.AnimationEnd = (0.8f);
entry.EventThreshold = 1;
entry = state.AddAnimation(0, "events1", false, 0.7f);
entry.MixDuration = (0.7f);
entry.TrackEnd = 1;
Run(0.1f, 20, null);
Setup("setAnimation with track entry mix", // 20
Expect(0, "start", 0, 0), //
Expect(0, "event 0", 0, 0), //
Expect(0, "event 14", 0.5f, 0.5f), //
Expect(0, "event 30", 1, 1), //
Expect(0, "complete", 1, 1), //
Expect(0, "event 0", 1, 1), //
Expect(0, "interrupt", 1, 1), //
Expect(1, "start", 0, 1), //
Expect(1, "event 0", 0.1f, 1.1f), //
Expect(1, "event 14", 0.5f, 1.5f), //
Expect(0, "end", 1.7f, 1.8f), //
Expect(0, "dispose", 1.7f, 1.8f), //
Expect(1, "event 30", 1, 2), //
Expect(1, "complete", 1, 2), //
Expect(1, "end", 1, 2.1f), //
Expect(1, "dispose", 1, 2.1f) //
);
state.SetAnimation(0, "events0", true);
Run(0.1f, 1000, new TestListener(
(time) => {
if (IsEqual(time, 1f)) {
TrackEntry ent = state.SetAnimation(0, "events1", false);
ent.MixDuration = (0.7f);
ent.TrackEnd = 1;
}
}));
Setup("setAnimation twice", // 21
Expect(0, "start", 0, 0), //
Expect(0, "interrupt", 0, 0), //
Expect(0, "end", 0, 0), //
Expect(0, "dispose", 0, 0), //
Expect(1, "start", 0, 0), //
Expect(1, "event 0", 0, 0), //
Expect(1, "event 14", 0.5f, 0.5f), //
Note("First 2 setAnimation calls are done."),
Expect(1, "interrupt", 0.8f, 0.8f), //
Expect(0, "start", 0, 0.8f), //
Expect(0, "interrupt", 0, 0.8f), //
Expect(0, "end", 0, 0.8f), //
Expect(0, "dispose", 0, 0.8f), //
Expect(2, "start", 0, 0.8f), //
Expect(2, "event 0", 0.1f, 0.9f), //
Expect(1, "end", 0.9f, 1), //
Expect(1, "dispose", 0.9f, 1), //
Expect(2, "event 14", 0.5f, 1.3f), //
Expect(2, "event 30", 1, 1.8f), //
Expect(2, "complete", 1, 1.8f), //
Expect(2, "end", 1, 1.9f), //
Expect(2, "dispose", 1, 1.9f) //
);
state.SetAnimation(0, "events0", false); // First should be ignored.
state.SetAnimation(0, "events1", false);
Run(0.1f, 1000, new TestListener(
(time) => {
if (IsEqual(time, 0.8f)) {
state.SetAnimation(0, "events0", false); // First should be ignored.
state.SetAnimation(0, "events2", false).TrackEnd = 1;
}
}));
Setup("setAnimation twice with multiple mixing", // 22
Expect(0, "start", 0, 0), //
Expect(0, "interrupt", 0, 0), //
Expect(0, "end", 0, 0), //
Expect(0, "dispose", 0, 0), //
Expect(1, "start", 0, 0), //
Expect(1, "event 0", 0, 0), //
Note("First 2 setAnimation calls are done."),
Expect(1, "interrupt", 0.2f, 0.2f), //
Expect(0, "start", 0, 0.2f), //
Expect(0, "interrupt", 0, 0.2f), //
Expect(0, "end", 0, 0.2f), //
Expect(0, "dispose", 0, 0.2f), //
Expect(2, "start", 0, 0.2f), //
Expect(2, "event 0", 0.1f, 0.3f), //
Note("Second 2 setAnimation calls are done."),
Expect(2, "interrupt", 0.2f, 0.4f), //
Expect(1, "start", 0, 0.4f), //
Expect(1, "interrupt", 0, 0.4f), //
Expect(1, "end", 0, 0.4f), //
Expect(1, "dispose", 0, 0.4f), //
Expect(0, "start", 0, 0.4f), //
Expect(0, "event 0", 0.1f, 0.5f), //
Expect(1, "end", 0.8f, 0.9f), //
Expect(1, "dispose", 0.8f, 0.9f), //
Expect(0, "event 14", 0.5f, 0.9f), //
Expect(2, "end", 0.8f, 1.1f), //
Expect(2, "dispose", 0.8f, 1.1f), //
Expect(0, "event 30", 1, 1.4f), //
Expect(0, "complete", 1, 1.4f), //
Expect(0, "end", 1, 1.5f), //
Expect(0, "dispose", 1, 1.5f) //
);
stateData.DefaultMix = 0.6f;
state.SetAnimation(0, "events0", false); // First should be ignored.
state.SetAnimation(0, "events1", false);
Run(0.1f, 1000, new TestListener(
(time) => {
if (IsEqual(time, 0.2f)) {
state.SetAnimation(0, "events0", false); // First should be ignored.
state.SetAnimation(0, "events2", false);
}
if (IsEqual(time, 0.4f)) {
state.SetAnimation(0, "events1", false); // First should be ignored.
state.SetAnimation(0, "events0", false).TrackEnd = 1;
}
}));
Setup("addAnimation with delay on empty track", // 23
Expect(0, "start", 0, 0), //
Expect(0, "event 0", 0, 5), //
Expect(0, "event 14", 0.5f, 5.5f), //
Expect(0, "event 30", 1, 6), //
Expect(0, "complete", 1, 6), //
Expect(0, "end", 1, 6.1f), //
Expect(0, "dispose", 1, 6.1f) //
);
state.AddAnimation(0, "events0", false, 5).TrackEnd = 1;
Run(0.1f, 10, null);
Setup("setAnimation during AnimationStateListener"); // 24
state.Start += (trackEntry) => {
if (trackEntry.Animation.Name.Equals("events0")) state.SetAnimation(1, "events1", false);
};
state.Interrupt += (trackEntry) => {
state.AddAnimation(3, "events1", false, 0);
};
state.End += (trackEntry) => {
if (trackEntry.Animation.Name.Equals("events0")) state.SetAnimation(0, "events1", false);
};
state.Dispose += (trackEntry) => {
if (trackEntry.Animation.Name.Equals("events0")) state.SetAnimation(1, "events1", false);
};
state.Complete += (trackEntry) => {
if (trackEntry.Animation.Name.Equals("events0")) state.SetAnimation(1, "events1", false);
};
state.Event += (trackEntry, ev) => {
if (trackEntry.TrackIndex != 2) state.SetAnimation(2, "events1", false);
};
state.AddAnimation(0, "events0", false, 0);
state.AddAnimation(0, "events1", false, 0);
state.SetAnimation(1, "events1", false).TrackEnd = 1;
Run(0.1f, 10, null);
Setup("clearTrack", // 25
Expect(0, "start", 0, 0), //
Expect(0, "event 0", 0, 0), //
Expect(0, "event 14", 0.5f, 0.5f), //
Expect(0, "end", 0.7f, 0.7f), //
Expect(0, "dispose", 0.7f, 0.7f) //
);
state.AddAnimation(0, "events0", false, 0).TrackEnd = 1;
Run(0.1f, 10, new TestListener(
(time) => {
if (IsEqual(time, 0.7f)) state.ClearTrack(0);
}));
Setup("setEmptyAnimation", // 26
Expect(0, "start", 0, 0), //
Expect(0, "event 0", 0, 0), //
Expect(0, "event 14", 0.5f, 0.5f), //
Expect(0, "interrupt", 0.7f, 0.7f), //
Expect(-1, "start", 0, 0.7f), //
Expect(-1, "complete", 0.1f, 0.8f), //
Expect(0, "end", 0.8f, 0.9f), //
Expect(0, "dispose", 0.8f, 0.9f), //
Expect(-1, "end", 0.2f, 1), //
Expect(-1, "dispose", 0.2f, 1) //
);
state.AddAnimation(0, "events0", false, 0).TrackEnd = 1;
Run(0.1f, 10, new TestListener(
(time) => {
if (IsEqual(time, 0.7f)) state.SetEmptyAnimation(0, 0);
}));
Setup("TrackEntry listener"); // 27
int counter = 0;
entry = state.AddAnimation(0, "events0", false, 0);
entry.Start += (trackEntry) => {
Interlocked.Add(ref counter, 1 << 1);
};
entry.Interrupt += (trackEntry) => {
Interlocked.Add(ref counter, 1 << 5);
};
entry.End += (trackEntry) => {
Interlocked.Add(ref counter, 1 << 9);
};
entry.Dispose += (trackEntry) => {
Interlocked.Add(ref counter, 1 << 13);
};
entry.Complete += (trackEntry) => {
Interlocked.Add(ref counter, 1 << 17);
};
entry.Event += (trackEntry, ev) => {
Interlocked.Add(ref counter, 1 << 21);
};
state.AddAnimation(0, "events0", false, 0);
state.AddAnimation(0, "events1", false, 0);
state.SetAnimation(1, "events1", false).TrackEnd = 1;
Run(0.1f, 10, null);
if (counter != 15082016) {
string message = "TEST 27 FAILED! " + counter;
Log(message);
FailTestRun(message);
}
#if RUN_ADDITIONAL_FORUM_RELATED_TEST
Setup("0.1 time step, start and add", // 2
Expect(0, "start", 0, 0), //
Expect(0, "event 0", 0, 0), //
Expect(0, "event 14", 0.5f, 0.5f), //
Expect(0, "event 30", 1, 1), //
Expect(0, "complete", 1, 1), //
Expect(0, "interrupt", 1.1f, 1.1f), //
Expect(1, "start", 0.1f, 1.1f), //
Expect(1, "event 0", 0.1f, 1.1f), //
Expect(0, "end", 1.3f, 1.4f), //
Expect(0, "dispose", 1.3f, 1.4f), //
Expect(1, "event 14", 0.5f, 1.5f), //
Expect(1, "event 30", 1, 2), //
Expect(1, "complete", 1, 2), //
Expect(1, "end", 1, 2.1f), //
Expect(1, "dispose", 1, 2.1f) //
);
state.SetAnimation(0, "events0", false);
var entry1 = state.AddAnimation(0, "events1", false, 0);
entry1.MixDuration = 0.25f;
entry1.TrackEnd = 1.0f;
Run(0.1f, 1000, null);
#endif // RUN_ADDITIONAL_FORUM_RELATED_TEST
Log("AnimationState tests passed.");
}
void Setup (string description, params Result[] expectedArray) {
test++;
expected.AddRange(expectedArray);
stateData = new AnimationStateData(skeletonData);
state = new AnimationState(stateData);
stateListener = new LoggingAnimationStateListener(this);
time = 0;
fail = false;
Log(test + ": " + description);
if (expectedArray.Length > 0) {
stateListener.RegisterAtAnimationState(state);
Log(string.Format("{0,-3}{1,-12}{2,-7}{3,-7}{4,-7}", "#", "EVENT", "TRACK", "TOTAL", "RESULT"));
}
}
void Run (float incr, float endTime, TestListener listener) {
Skeleton skeleton = new Skeleton(skeletonData);
state.Apply(skeleton);
while (time < endTime) {
time += incr;
skeleton.Update(incr);
state.Update(incr);
// Reduce float discrepancies for tests.
foreach (TrackEntry entry in state.Tracks) {
if (entry == null) continue;
entry.TrackTime = Round(entry.TrackTime, 6);
entry.Delay = Round(entry.Delay, 3);
if (entry.MixingFrom != null) entry.MixingFrom.TrackTime = Round(entry.MixingFrom.TrackTime, 6);
}
state.Apply(skeleton);
// Apply multiple times to ensure no side effects.
if (expected.Count > 0) stateListener.UnregisterFromAnimationState(state);
state.Apply(skeleton);
state.Apply(skeleton);
if (expected.Count > 0) stateListener.RegisterAtAnimationState(state);
if (listener != null) listener.Frame(time);
}
state.ClearTracks();
// Expecting more than actual is a failure.
for (int i = actual.Count, n = expected.Count; i < n; i++) {
Log(string.Format("{0,-29}", "<none>") + "FAIL: " + expected[i]);
fail = true;
}
actual.Clear();
expected.Clear();
Log("");
if (fail) {
string message = "TEST " + test + " FAILED!";
Log(message);
FailTestRun(message);
}
}
Result Expect (int animationIndex, string name, float trackTime, float totalTime) {
Result result = new Result();
result.name = name;
result.animationIndex = animationIndex;
result.trackTime = trackTime;
result.totalTime = totalTime;
return result;
}
Result Actual (string name, TrackEntry entry) {
Result result = new Result();
result.name = name;
result.animationIndex = skeletonData.Animations.IndexOf(entry.Animation);
result.trackTime = (float)Math.Round(entry.TrackTime * 1000) / 1000f;
result.totalTime = (float)Math.Round(time * 1000) / 1000f;
return result;
}
Result Note (string message) {
Result result = new Result();
result.name = message;
result.note = true;
return result;
}
static void Log (string message) {
if (logImplementation != null) {
logImplementation(message);
return;
}
Console.WriteLine(message);
}
static void FailTestRun (string message) {
failImplementation(message);
}
class Result {
public string name;
public int animationIndex;
public float trackTime, totalTime;
public bool note;
public override int GetHashCode () {
int result = 31 + animationIndex;
result = 31 * result + name.GetHashCode();
result = 31 * result + totalTime.GetHashCode();
result = 31 * result + trackTime.GetHashCode();
return result;
}
public override bool Equals (object obj) {
Result other = (Result)obj;
if (animationIndex != other.animationIndex) return false;
if (!name.Equals(other.name)) return false;
if (!IsEqual(totalTime, other.totalTime)) return false;
if (!IsEqual(trackTime, other.trackTime)) return false;
return true;
}
public override string ToString () {
return string.Format("{0,-3}{1,-12}{2,-7}{3,-7}", "" + animationIndex, name, RoundTime(trackTime), RoundTime(totalTime));
}
}
static float Round (float value, int decimals) {
float shift = (float)Math.Pow(10, decimals);
return (float)Math.Round((double)value * shift) / shift;
}
static string RoundTime (float value) {
float roundedValue = Round(value, 3);
string text = roundedValue.ToString();
return text.EndsWith(".0") ? text.Substring(0, text.Length - 2) : text;
}
class TestListener {
public TestListener(FrameDelegate frame) {
this.frame = frame;
}
public delegate void FrameDelegate (float time);
public event FrameDelegate frame;
public void Frame(float time) {
frame(time);
}
}
#region Test API
static public void Main (string testJsonFilePath) {
new AnimationStateTests(testJsonFilePath);
}
public delegate void LogDelegate (string message);
public static event LogDelegate logImplementation;
public delegate void FailDelegate (string message);
public static event FailDelegate failImplementation;
#endregion
}
}

View File

@ -162,6 +162,7 @@ function Bone:updateWorldTransformWith (x, y, rotation, scaleX, scaleY, shearX,
self.b = pa * lb - pb * ld
self.c = pc * la + pd * lc
self.d = pc * lb + pd * ld
return
elseif transformMode == TransformMode.noScale or transformMode == TransformMode.noScaleOrReflection then
local cos = math_cos(math_rad(rotation))
local sin = math_sin(math_rad(rotation))

View File

@ -2583,7 +2583,7 @@ var spine;
this.b = pa * lb - pb * ld;
this.c = pc * la + pd * lc;
this.d = pc * lb + pd * ld;
break;
return;
}
case spine.TransformMode.NoScale:
case spine.TransformMode.NoScaleOrReflection: {

File diff suppressed because one or more lines are too long

View File

@ -2583,7 +2583,7 @@ var spine;
this.b = pa * lb - pb * ld;
this.c = pc * la + pd * lc;
this.d = pc * lb + pd * ld;
break;
return;
}
case spine.TransformMode.NoScale:
case spine.TransformMode.NoScaleOrReflection: {

File diff suppressed because one or more lines are too long

View File

@ -2583,7 +2583,7 @@ var spine;
this.b = pa * lb - pb * ld;
this.c = pc * la + pd * lc;
this.d = pc * lb + pd * ld;
break;
return;
}
case spine.TransformMode.NoScale:
case spine.TransformMode.NoScaleOrReflection: {

File diff suppressed because one or more lines are too long

View File

@ -2583,7 +2583,7 @@ var spine;
this.b = pa * lb - pb * ld;
this.c = pc * la + pd * lc;
this.d = pc * lb + pd * ld;
break;
return;
}
case spine.TransformMode.NoScale:
case spine.TransformMode.NoScaleOrReflection: {

File diff suppressed because one or more lines are too long

View File

@ -2583,7 +2583,7 @@ var spine;
this.b = pa * lb - pb * ld;
this.c = pc * la + pd * lc;
this.d = pc * lb + pd * ld;
break;
return;
}
case spine.TransformMode.NoScale:
case spine.TransformMode.NoScaleOrReflection: {

File diff suppressed because one or more lines are too long

View File

@ -2583,7 +2583,7 @@ var spine;
this.b = pa * lb - pb * ld;
this.c = pc * la + pd * lc;
this.d = pc * lb + pd * ld;
break;
return;
}
case spine.TransformMode.NoScale:
case spine.TransformMode.NoScaleOrReflection: {

File diff suppressed because one or more lines are too long

View File

@ -219,7 +219,7 @@ module spine {
this.b = pa * lb - pb * ld;
this.c = pc * la + pd * lc;
this.d = pc * lb + pd * ld;
break;
return;
}
case TransformMode.NoScale:
case TransformMode.NoScaleOrReflection: {

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f5588a995395d7d428bb39ca0bfb7bd8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,13 @@
{
"name": "SpineTests",
"optionalUnityReferences": [
"TestAssemblies"
],
"references" : [
"spine-unity",
"spine-csharp"
],
"includePlatforms": [
"Editor"
]
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 20ae6c9683f839243a01c1b259d5159f
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 25fb7418b1ef3784ea5c57726a348d2a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1 @@
Add the directory content of 'spine-csharp/tests' as 'tests' here (e.g. using a symlink).

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 21606d7e3a0ef4e4799397a605bf7bed
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a3f30b00835dcac44b588dd09758649d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,27 @@
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
namespace Spine.Unity.Tests
{
public class RunAnimationStateTests
{
[Test]
public void RunAnimationStateTestsSimplePasses ()
{
AnimationStateTests.logImplementation += Log;
AnimationStateTests.failImplementation += Fail;
AnimationStateTests.Main("Assets/SpineTests/spine-csharp-tests/tests/assets/test.json");
}
public void Log (string message) {
UnityEngine.Debug.Log(message);
}
public void Fail (string message) {
Assert.Fail(message);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 33608366930c2854399d13aea2543e3c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: