From 15e4f2ff4eb6e20588ce482e1968f9a584bff9b9 Mon Sep 17 00:00:00 2001 From: Nathan Sweet Date: Tue, 22 Aug 2017 22:54:28 +0200 Subject: [PATCH 01/11] Fixed mouse scroll after focusing list. Fixed loading atlas for .skel.bytes data file. --- .../esotericsoftware/spine/SkeletonViewer.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java b/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java index e329e694d..79deaba19 100644 --- a/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java +++ b/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java @@ -142,7 +142,8 @@ public class SkeletonViewer extends ApplicationAdapter { pixmap.dispose(); String atlasFileName = skeletonFile.nameWithoutExtension(); - if (atlasFileName.endsWith(".json")) atlasFileName = new FileHandle(atlasFileName).nameWithoutExtension(); + if (atlasFileName.endsWith(".json") || atlasFileName.endsWith(".skel")) + atlasFileName = atlasFileName.substring(0, atlasFileName.length() - 5); FileHandle atlasFile = skeletonFile.sibling(atlasFileName + ".atlas"); if (!atlasFile.exists()) { if (atlasFileName.endsWith("-pro") || atlasFileName.endsWith("-ess")) @@ -706,6 +707,16 @@ public class SkeletonViewer extends ApplicationAdapter { } }); + InputListener scrollFocusListener = new InputListener() { + public void enter (InputEvent event, float x, float y, int pointer, Actor fromActor) { + stage.setScrollFocus(event.getListenerActor()); + } + + public void exit (InputEvent event, float x, float y, int pointer, Actor toActor) { + if (stage.getScrollFocus() == event.getListenerActor()) stage.setScrollFocus(null); + } + }; + animationList.addListener(new ChangeListener() { public void changed (ChangeEvent event, Actor actor) { if (state != null) { @@ -717,6 +728,7 @@ public class SkeletonViewer extends ApplicationAdapter { } } }); + animationList.addListener(scrollFocusListener); loopCheckbox.addListener(new ChangeListener() { public void changed (ChangeEvent event, Actor actor) { @@ -736,6 +748,7 @@ public class SkeletonViewer extends ApplicationAdapter { } } }); + skinList.addListener(scrollFocusListener); ChangeListener trackButtonListener = new ChangeListener() { public void changed (ChangeEvent event, Actor actor) { From 6b0f88cb7dc86c9b389ecae09d6e52f116151b8d Mon Sep 17 00:00:00 2001 From: John Date: Wed, 23 Aug 2017 09:32:41 +0800 Subject: [PATCH 02/11] [unity] Add warnings for renamed atlas pages. --- .../spine-unity/Editor/SpineEditorUtilities.cs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs b/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs index 9f4cb07ba..e58db714c 100644 --- a/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs +++ b/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs @@ -1020,13 +1020,18 @@ namespace Spine.Unity.Editor { pageFiles.Add(atlasLines[i + 1].Trim()); } - atlasAsset.materials = new Material[pageFiles.Count]; + var populatingMaterials = new List(pageFiles.Count);//atlasAsset.materials = new Material[pageFiles.Count]; for (int i = 0; i < pageFiles.Count; i++) { string texturePath = assetPath + "/" + pageFiles[i]; Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D)); TextureImporter texImporter = (TextureImporter)TextureImporter.GetAtPath(texturePath); + if (texImporter == null) { + Debug.LogWarning(string.Format("{0} ::: Texture asset \"{1}\" not found. Skipping. Please check your atlas file for renamed files.", atlasAsset.name, texturePath)); + continue; + } + #if UNITY_5_5_OR_NEWER texImporter.textureCompression = TextureImporterCompression.Uncompressed; texImporter.alphaSource = TextureImporterAlphaSource.FromInput; @@ -1039,7 +1044,6 @@ namespace Spine.Unity.Editor { texImporter.spriteImportMode = SpriteImportMode.None; texImporter.maxTextureSize = 2048; - EditorUtility.SetDirty(texImporter); AssetDatabase.ImportAsset(texturePath); AssetDatabase.SaveAssets(); @@ -1064,9 +1068,11 @@ namespace Spine.Unity.Editor { EditorUtility.SetDirty(mat); AssetDatabase.SaveAssets(); - atlasAsset.materials[i] = mat; + populatingMaterials.Add(mat); //atlasAsset.materials[i] = mat; } + atlasAsset.materials = populatingMaterials.ToArray(); + for (int i = 0; i < vestigialMaterials.Count; i++) AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(vestigialMaterials[i])); @@ -1078,6 +1084,11 @@ namespace Spine.Unity.Editor { EditorUtility.SetDirty(atlasAsset); AssetDatabase.SaveAssets(); + if (pageFiles.Count != atlasAsset.materials.Length) + Debug.LogWarning(string.Format("{0} ::: Not all atlas pages were imported. If you rename your image files, please make sure you also edit the filenames specified in the atlas file.", atlasAsset.name)); + else + Debug.Log(string.Format("{0} ::: Imported with {1} material", atlasAsset.name, atlasAsset.materials.Length)); + // Iterate regions and bake marked. Atlas atlas = atlasAsset.GetAtlas(); FieldInfo field = typeof(Atlas).GetField("regions", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.NonPublic); From 916167e02895cc0d00fbddd2e06b736817bbf606 Mon Sep 17 00:00:00 2001 From: Nathan Sweet Date: Wed, 23 Aug 2017 11:25:57 +0200 Subject: [PATCH 03/11] Fixed skin name not being saved. --- .../src/com/esotericsoftware/spine/SkeletonViewer.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java b/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java index 79deaba19..4fda0a265 100644 --- a/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java +++ b/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java @@ -128,6 +128,7 @@ public class SkeletonViewer extends ApplicationAdapter { Gdx.files.internal(Gdx.app.getPreferences("spine-skeletonviewer").getString("lastFile", "spineboy/spineboy.json"))); ui.loadPrefs(); + ui.prefsLoaded = true; } void loadSkeleton (final FileHandle skeletonFile) { @@ -381,6 +382,8 @@ public class SkeletonViewer extends ApplicationAdapter { } class UI { + boolean prefsLoaded; + Stage stage = new Stage(new ScreenViewport()); com.badlogic.gdx.scenes.scene2d.ui.Skin skin = new com.badlogic.gdx.scenes.scene2d.ui.Skin( Gdx.files.internal("skin/skin.json")); @@ -437,7 +440,6 @@ public class SkeletonViewer extends ApplicationAdapter { Label statusLabel = new Label("", skin); WidgetGroup toasts = new WidgetGroup(); - boolean prefsLoaded; UI () { initialize(); @@ -922,7 +924,6 @@ public class SkeletonViewer extends ApplicationAdapter { scaleSlider.setValue(prefs.getFloat("scale", 1)); animationList.setSelected(prefs.getString("animationName", null)); skinList.setSelected(prefs.getString("skinName", null)); - prefsLoaded = true; } } From df9f7ba0406ed638ef9088f9bcac2f540d87a802 Mon Sep 17 00:00:00 2001 From: Nathan Sweet Date: Wed, 23 Aug 2017 12:14:32 +0200 Subject: [PATCH 04/11] Fixed list scroll focus. --- .../src/com/esotericsoftware/spine/SkeletonViewer.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java b/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java index 4fda0a265..a85aa6f55 100644 --- a/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java +++ b/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java @@ -711,11 +711,11 @@ public class SkeletonViewer extends ApplicationAdapter { InputListener scrollFocusListener = new InputListener() { public void enter (InputEvent event, float x, float y, int pointer, Actor fromActor) { - stage.setScrollFocus(event.getListenerActor()); + if (pointer == -1) stage.setScrollFocus(event.getListenerActor()); } public void exit (InputEvent event, float x, float y, int pointer, Actor toActor) { - if (stage.getScrollFocus() == event.getListenerActor()) stage.setScrollFocus(null); + if (pointer == -1 && stage.getScrollFocus() == event.getListenerActor()) stage.setScrollFocus(null); } }; @@ -730,7 +730,7 @@ public class SkeletonViewer extends ApplicationAdapter { } } }); - animationList.addListener(scrollFocusListener); + animationScroll.addListener(scrollFocusListener); loopCheckbox.addListener(new ChangeListener() { public void changed (ChangeEvent event, Actor actor) { @@ -750,7 +750,7 @@ public class SkeletonViewer extends ApplicationAdapter { } } }); - skinList.addListener(scrollFocusListener); + skinScroll.addListener(scrollFocusListener); ChangeListener trackButtonListener = new ChangeListener() { public void changed (ChangeEvent event, Actor actor) { From c8d595565b2fd982ca27ef4d04dabc1366fe8026 Mon Sep 17 00:00:00 2001 From: Nathan Sweet Date: Wed, 23 Aug 2017 12:15:58 +0200 Subject: [PATCH 05/11] Fixed interrupting a mix with a new entry that has 0 mixDuration. closes #970 --- .../src/com/esotericsoftware/spine/AnimationState.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java index 044bda43d..a0d4cd193 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java @@ -144,7 +144,8 @@ public class AnimationState { // Require mixTime > 0 to ensure the mixing from entry was applied at least once. if (to.mixTime > 0 && (to.mixTime >= to.mixDuration || to.timeScale == 0)) { - if (from.totalAlpha == 0) { + // Require totalAlpha == 0 to ensure mixing is complete, unless mixDuration == 0 (the transition is a single frame). + if (from.totalAlpha == 0 || to.mixDuration == 0) { to.mixingFrom = from.mixingFrom; to.interruptAlpha = from.interruptAlpha; queue.end(from); From 50730c7a5cff6acfa6b7975003c7ab9b320cbafa Mon Sep 17 00:00:00 2001 From: John Date: Wed, 23 Aug 2017 18:28:44 +0800 Subject: [PATCH 06/11] [csharp] Fixed interrupting a mix with mixDuration 0. Port of https://github.com/EsotericSoftware/spine-runtimes/commit/c8d595565b2fd982ca27ef4d04dabc1366fe8026 closes https://github.com/EsotericSoftware/spine-runtimes/issues/970 --- spine-csharp/src/AnimationState.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spine-csharp/src/AnimationState.cs b/spine-csharp/src/AnimationState.cs index 2f7a47bc2..615d0766a 100644 --- a/spine-csharp/src/AnimationState.cs +++ b/spine-csharp/src/AnimationState.cs @@ -139,8 +139,9 @@ namespace Spine { bool finished = UpdateMixingFrom(from, delta); // Require mixTime > 0 to ensure the mixing from entry was applied at least once. - if (to.mixTime > 0 && (to.mixTime >= to.mixDuration || to.timeScale == 0)) { - if (from.totalAlpha == 0) { + if (to.mixTime > 0 && (to.mixTime >= to.mixDuration || to.timeScale == 0)) { + // Require totalAlpha == 0 to ensure mixing is complete, unless mixDuration == 0 (the transition is a single frame). + if (from.totalAlpha == 0 || to.mixDuration == 0) { to.mixingFrom = from.mixingFrom; to.interruptAlpha = from.interruptAlpha; queue.End(from); From a96d92d27dfa369c38749bbc7ecc0d7c729d9d09 Mon Sep 17 00:00:00 2001 From: pharan Date: Wed, 23 Aug 2017 18:34:05 +0800 Subject: [PATCH 07/11] [unity] Make SkeletonRenderer invalid when destroying. --- .../Assets/spine-unity/Modules/SlotBlendModes/SlotBlendModes.cs | 2 +- spine-unity/Assets/spine-unity/SkeletonRenderer.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/spine-unity/Assets/spine-unity/Modules/SlotBlendModes/SlotBlendModes.cs b/spine-unity/Assets/spine-unity/Modules/SlotBlendModes/SlotBlendModes.cs index 632494380..44177f04d 100644 --- a/spine-unity/Assets/spine-unity/Modules/SlotBlendModes/SlotBlendModes.cs +++ b/spine-unity/Assets/spine-unity/Modules/SlotBlendModes/SlotBlendModes.cs @@ -133,7 +133,7 @@ namespace Spine.Unity.Modules { } Applied = false; - skeletonRenderer.LateUpdate(); + if (skeletonRenderer.valid) skeletonRenderer.LateUpdate(); } public void GetTexture () { diff --git a/spine-unity/Assets/spine-unity/SkeletonRenderer.cs b/spine-unity/Assets/spine-unity/SkeletonRenderer.cs index 78b114194..ab6e71b56 100644 --- a/spine-unity/Assets/spine-unity/SkeletonRenderer.cs +++ b/spine-unity/Assets/spine-unity/SkeletonRenderer.cs @@ -147,6 +147,7 @@ namespace Spine.Unity { void OnDestroy () { rendererBuffers.Dispose(); + valid = false; } public virtual void ClearState () { From 3a1b77871f8427d84fd5515411c917093ab0c97e Mon Sep 17 00:00:00 2001 From: pharan Date: Wed, 23 Aug 2017 18:35:17 +0800 Subject: [PATCH 08/11] [unity] Bone.SetPositionSkeletonSpace --- .../Assets/spine-unity/SkeletonExtensions.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/spine-unity/Assets/spine-unity/SkeletonExtensions.cs b/spine-unity/Assets/spine-unity/SkeletonExtensions.cs index 0e2dd1f60..e178907a0 100644 --- a/spine-unity/Assets/spine-unity/SkeletonExtensions.cs +++ b/spine-unity/Assets/spine-unity/SkeletonExtensions.cs @@ -185,6 +185,20 @@ namespace Spine.Unity { bone.WorldToLocal(worldPosition.x, worldPosition.y, out o.x, out o.y); return o; } + + /// Sets the skeleton-space position of a bone. + /// The local position in its parent bone space, or in skeleton space if it is the root bone. + public static Vector2 SetPositionSkeletonSpace (this Bone bone, Vector2 skeletonSpacePosition) { + if (bone.parent == null) { // root bone + bone.SetPosition(skeletonSpacePosition); + return skeletonSpacePosition; + } else { + var parent = bone.parent; + Vector2 parentLocal = parent.WorldToLocal(skeletonSpacePosition); + bone.SetPosition(parentLocal); + return parentLocal; + } + } #endregion #region Attachments From 4d89539b1b25255a0ac8ef9aa8ebe099248389f6 Mon Sep 17 00:00:00 2001 From: pharan Date: Wed, 23 Aug 2017 18:36:05 +0800 Subject: [PATCH 09/11] [unity] SkeletonRenderer.SetMeshSettings --- .../Assets/spine-unity/SkeletonRenderer.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/spine-unity/Assets/spine-unity/SkeletonRenderer.cs b/spine-unity/Assets/spine-unity/SkeletonRenderer.cs index ab6e71b56..1d2f004aa 100644 --- a/spine-unity/Assets/spine-unity/SkeletonRenderer.cs +++ b/spine-unity/Assets/spine-unity/SkeletonRenderer.cs @@ -61,13 +61,14 @@ namespace Spine.Unity { public bool useClipping = true; public bool immutableTriangles = false; public bool pmaVertexColors = true; + /// Clears the state when this component or its GameObject is disabled. This prevents previous state from being retained when it is enabled again. When pooling your skeleton, setting this to true can be helpful. public bool clearStateOnDisable = false; public bool tintBlack = false; public bool singleSubmesh = false; [UnityEngine.Serialization.FormerlySerializedAs("calculateNormals")] - public bool addNormals; - public bool calculateTangents; + public bool addNormals = false; + public bool calculateTangents = false; public bool logErrors = false; @@ -134,6 +135,18 @@ namespace Spine.Unity { } return c; } + + /// Applies MeshGenerator settings to the SkeletonRenderer and its internal MeshGenerator. + public void SetMeshSettings (MeshGenerator.Settings settings) { + this.calculateTangents = settings.calculateTangents; + this.immutableTriangles = settings.immutableTriangles; + this.pmaVertexColors = settings.pmaVertexColors; + this.tintBlack = settings.tintBlack; + this.useClipping = settings.useClipping; + this.zSpacing = settings.zSpacing; + + this.meshGenerator.settings = settings; + } #endregion public virtual void Awake () { From f796d15f310cb575f140a54a7fffe84a33618ae1 Mon Sep 17 00:00:00 2001 From: John Date: Wed, 23 Aug 2017 18:44:17 +0800 Subject: [PATCH 10/11] [csharp] Match libGDX setTimelineData --- spine-csharp/src/AnimationState.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/spine-csharp/src/AnimationState.cs b/spine-csharp/src/AnimationState.cs index 615d0766a..772ecc08b 100644 --- a/spine-csharp/src/AnimationState.cs +++ b/spine-csharp/src/AnimationState.cs @@ -708,10 +708,13 @@ namespace Spine { } else { for (int ii = mixingToLast; ii >= 0; ii--) { var entry = mixingTo[ii]; - if (entry.mixDuration > 0 && !entry.HasTimeline(id)) { - timelineDataItems[i] = AnimationState.DipMix; - timelineDipMixItems[i] = entry; - goto outer; // continue outer; + if (!entry.HasTimeline(id)) { + if (entry.mixDuration > 0) { + timelineDataItems[i] = AnimationState.DipMix; + timelineDipMixItems[i] = entry; + goto outer; // continue outer; + } + break; } } timelineDataItems[i] = AnimationState.Dip; From 4abea9e4ad16ec5c856a2772ebca8839c5d86b12 Mon Sep 17 00:00:00 2001 From: pharan Date: Wed, 23 Aug 2017 18:49:27 +0800 Subject: [PATCH 11/11] [csharp] Reduce access to internal methods. --- spine-csharp/src/SkeletonClipping.cs | 2 +- spine-csharp/src/Triangulator.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spine-csharp/src/SkeletonClipping.cs b/spine-csharp/src/SkeletonClipping.cs index 1dcbb0a0e..07d052895 100644 --- a/spine-csharp/src/SkeletonClipping.cs +++ b/spine-csharp/src/SkeletonClipping.cs @@ -258,7 +258,7 @@ namespace Spine { return clipped; } - public static void MakeClockwise (ExposedList polygon) { + static void MakeClockwise (ExposedList polygon) { float[] vertices = polygon.Items; int verticeslength = polygon.Count; diff --git a/spine-csharp/src/Triangulator.cs b/spine-csharp/src/Triangulator.cs index a4083c3ec..dd1768b52 100644 --- a/spine-csharp/src/Triangulator.cs +++ b/spine-csharp/src/Triangulator.cs @@ -31,7 +31,7 @@ using System; namespace Spine { - public class Triangulator { + internal class Triangulator { private readonly ExposedList> convexPolygons = new ExposedList>(); private readonly ExposedList> convexPolygonsIndices = new ExposedList>();