diff --git a/spine-unity/Assets/spine-unity/Asset Types/Editor.meta b/spine-unity/Assets/spine-unity/Asset Types/Editor.meta deleted file mode 100644 index ad248b556..000000000 --- a/spine-unity/Assets/spine-unity/Asset Types/Editor.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: cbe5d97ed1d75964cab2e2882a52a200 -folderAsset: yes -timeCreated: 1455489536 -licenseType: Free -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/spine-unity/Assets/spine-unity/BoneFollower.cs b/spine-unity/Assets/spine-unity/BoneFollower.cs index 2681c4ff2..c7d3ea1a2 100644 --- a/spine-unity/Assets/spine-unity/BoneFollower.cs +++ b/spine-unity/Assets/spine-unity/BoneFollower.cs @@ -73,7 +73,7 @@ public SkeletonRenderer SkeletonRenderer { bool skeletonTransformIsParent; /// - /// Sets the target bone by its bone name. Returns false if no bone was found. + /// Sets the target bone by its bone name. Returns false if no bone was found. To set the bone by reference, use BoneFollower.bone directly. public bool SetBone (string name) { bone = skeletonRenderer.skeleton.FindBone(name); if (bone == null) { diff --git a/spine-unity/Assets/spine-unity/Asset Types/Editor/AtlasAssetInspector.cs b/spine-unity/Assets/spine-unity/Editor/AtlasAssetInspector.cs similarity index 96% rename from spine-unity/Assets/spine-unity/Asset Types/Editor/AtlasAssetInspector.cs rename to spine-unity/Assets/spine-unity/Editor/AtlasAssetInspector.cs index 2ea42ca3b..7b7349351 100644 --- a/spine-unity/Assets/spine-unity/Asset Types/Editor/AtlasAssetInspector.cs +++ b/spine-unity/Assets/spine-unity/Editor/AtlasAssetInspector.cs @@ -1,366 +1,366 @@ -/****************************************************************************** - * Spine Runtimes Software License v2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "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 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 THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -//#define BAKE_ALL_BUTTON -//#define REGION_BAKING_MESH - -using System; -using System.Collections.Generic; -using System.Reflection; -using UnityEditor; -using UnityEngine; -using Spine; - -namespace Spine.Unity.Editor { - using Event = UnityEngine.Event; - - [CustomEditor(typeof(AtlasAsset)), CanEditMultipleObjects] - public class AtlasAssetInspector : UnityEditor.Editor { - SerializedProperty atlasFile, materials; - AtlasAsset atlasAsset; - - GUIContent spriteSlicesLabel; - GUIContent SpriteSlicesLabel { - get { - if (spriteSlicesLabel == null) { - spriteSlicesLabel = new GUIContent( - "Apply Regions as Texture Sprite Slices", - SpineEditorUtilities.Icons.unity, - "Adds Sprite slices to atlas texture(s). " + - "Updates existing slices if ones with matching names exist. \n\n" + - "If your atlas was exported with Premultiply Alpha, " + - "your SpriteRenderer should use the generated Spine _Material asset (or any Material with a PMA shader) instead of Sprites-Default."); - } - return spriteSlicesLabel; - } - } - - static List GetRegions (Atlas atlas) { - FieldInfo regionsField = typeof(Atlas).GetField("regions", BindingFlags.Instance | BindingFlags.NonPublic); - return (List)regionsField.GetValue(atlas); - } - - void OnEnable () { - SpineEditorUtilities.ConfirmInitialization(); - atlasFile = serializedObject.FindProperty("atlasFile"); - materials = serializedObject.FindProperty("materials"); - materials.isExpanded = true; - atlasAsset = (AtlasAsset)target; - #if REGION_BAKING_MESH - UpdateBakedList(); - #endif - } - - #if REGION_BAKING_MESH - private List baked; - private List bakedObjects; - - void UpdateBakedList () { - AtlasAsset asset = (AtlasAsset)target; - baked = new List(); - bakedObjects = new List(); - if (atlasFile.objectReferenceValue != null) { - List regions = this.Regions; - string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset); - string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath); - string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name); - for (int i = 0; i < regions.Count; i++) { - AtlasRegion region = regions[i]; - string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeRegionName(region) + ".prefab").Replace("\\", "/"); - GameObject prefab = (GameObject)AssetDatabase.LoadAssetAtPath(bakedPrefabPath, typeof(GameObject)); - baked.Add(prefab != null); - bakedObjects.Add(prefab); - } - } - } - #endif - - override public void OnInspectorGUI () { - if (serializedObject.isEditingMultipleObjects) { - DrawDefaultInspector(); - return; - } - - serializedObject.Update(); - atlasAsset = atlasAsset ?? (AtlasAsset)target; - EditorGUI.BeginChangeCheck(); - EditorGUILayout.PropertyField(atlasFile); - EditorGUILayout.PropertyField(materials, true); - if (EditorGUI.EndChangeCheck()) { - serializedObject.ApplyModifiedProperties(); - atlasAsset.Clear(); - atlasAsset.GetAtlas(); - } - - if (materials.arraySize == 0) { - EditorGUILayout.HelpBox("No materials", MessageType.Error); - return; - } - - for (int i = 0; i < materials.arraySize; i++) { - SerializedProperty prop = materials.GetArrayElementAtIndex(i); - Material mat = (Material)prop.objectReferenceValue; - if (mat == null) { - EditorGUILayout.HelpBox("Materials cannot be null.", MessageType.Error); - return; - } - } - - EditorGUILayout.Space(); - if (SpineInspectorUtility.LargeCenteredButton(SpineInspectorUtility.TempContent("Set Mipmap Bias to " + SpineEditorUtilities.DEFAULT_MIPMAPBIAS))) { - foreach (var m in atlasAsset.materials) { - var texture = m.mainTexture; - texture.mipMapBias = SpineEditorUtilities.DEFAULT_MIPMAPBIAS; - } - Debug.Log("Texture mipmap bias set to " + SpineEditorUtilities.DEFAULT_MIPMAPBIAS); - } - - EditorGUILayout.Space(); - if (atlasFile.objectReferenceValue != null) { - if (SpineInspectorUtility.LargeCenteredButton(SpriteSlicesLabel)) { - var atlas = atlasAsset.GetAtlas(); - foreach (var m in atlasAsset.materials) - UpdateSpriteSlices(m.mainTexture, atlas); - } - } - - EditorGUILayout.Space(); - - #if REGION_BAKING_MESH - if (atlasFile.objectReferenceValue != null) { - Atlas atlas = asset.GetAtlas(); - FieldInfo field = typeof(Atlas).GetField("regions", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.NonPublic); - List regions = (List)field.GetValue(atlas); - EditorGUILayout.LabelField(new GUIContent("Region Baking", SpineEditorUtilities.Icons.unityIcon)); - EditorGUI.indentLevel++; - AtlasPage lastPage = null; - for (int i = 0; i < regions.Count; i++) { - if (lastPage != regions[i].page) { - if (lastPage != null) { - EditorGUILayout.Separator(); - EditorGUILayout.Separator(); - } - lastPage = regions[i].page; - Material mat = ((Material)lastPage.rendererObject); - if (mat != null) { - GUILayout.BeginHorizontal(); - { - EditorGUI.BeginDisabledGroup(true); - EditorGUILayout.ObjectField(mat, typeof(Material), false, GUILayout.Width(250)); - EditorGUI.EndDisabledGroup(); - } - GUILayout.EndHorizontal(); - - } else { - EditorGUILayout.LabelField(new GUIContent("Page missing material!", SpineEditorUtilities.Icons.warning)); - } - } - GUILayout.BeginHorizontal(); - { - //EditorGUILayout.ToggleLeft(baked[i] ? "" : regions[i].name, baked[i]); - bool result = baked[i] ? EditorGUILayout.ToggleLeft("", baked[i], GUILayout.Width(24)) : EditorGUILayout.ToggleLeft(" " + regions[i].name, baked[i]); - if(baked[i]){ - EditorGUILayout.ObjectField(bakedObjects[i], typeof(GameObject), false, GUILayout.Width(250)); - } - if (result && !baked[i]) { - //bake - baked[i] = true; - bakedObjects[i] = SpineEditorUtilities.BakeRegion(atlasAsset, regions[i]); - EditorGUIUtility.PingObject(bakedObjects[i]); - } else if (!result && baked[i]) { - //unbake - bool unbakeResult = EditorUtility.DisplayDialog("Delete Baked Region", "Do you want to delete the prefab for " + regions[i].name, "Yes", "Cancel"); - switch (unbakeResult) { - case true: - //delete - string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset); - string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath); - string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name); - string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeRegionName(regions[i]) + ".prefab").Replace("\\", "/"); - AssetDatabase.DeleteAsset(bakedPrefabPath); - baked[i] = false; - break; - case false: - //do nothing - break; - } - } - } - GUILayout.EndHorizontal(); - } - EditorGUI.indentLevel--; - - #if BAKE_ALL_BUTTON - // Check state - bool allBaked = true; - bool allUnbaked = true; - for (int i = 0; i < regions.Count; i++) { - allBaked &= baked[i]; - allUnbaked &= !baked[i]; - } - - if (!allBaked && GUILayout.Button("Bake All")) { - for (int i = 0; i < regions.Count; i++) { - if (!baked[i]) { - baked[i] = true; - bakedObjects[i] = SpineEditorUtilities.BakeRegion(atlasAsset, regions[i]); - } - } - - } else if (!allUnbaked && GUILayout.Button("Unbake All")) { - bool unbakeResult = EditorUtility.DisplayDialog("Delete All Baked Regions", "Are you sure you want to unbake all region prefabs? This cannot be undone.", "Yes", "Cancel"); - switch (unbakeResult) { - case true: - //delete - for (int i = 0; i < regions.Count; i++) { - if (baked[i]) { - string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset); - string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath); - string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name); - string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeRegionName(regions[i]) + ".prefab").Replace("\\", "/"); - AssetDatabase.DeleteAsset(bakedPrefabPath); - baked[i] = false; - } - } - break; - case false: - //do nothing - break; - } - - } - #endif - - } - #else - if (atlasFile.objectReferenceValue != null) { - EditorGUILayout.LabelField("Atlas Regions", EditorStyles.boldLabel); - int baseIndent = EditorGUI.indentLevel; - - var regions = AtlasAssetInspector.GetRegions(atlasAsset.GetAtlas()); - AtlasPage lastPage = null; - for (int i = 0; i < regions.Count; i++) { - if (lastPage != regions[i].page) { - if (lastPage != null) { - EditorGUILayout.Separator(); - EditorGUILayout.Separator(); - } - lastPage = regions[i].page; - Material mat = ((Material)lastPage.rendererObject); - if (mat != null) { - EditorGUI.indentLevel = baseIndent; - using (new GUILayout.HorizontalScope()) - using (new EditorGUI.DisabledGroupScope(true)) - EditorGUILayout.ObjectField(mat, typeof(Material), false, GUILayout.Width(250)); - EditorGUI.indentLevel = baseIndent + 1; - } else { - EditorGUILayout.HelpBox("Page missing material!", MessageType.Warning); - } - } - - EditorGUILayout.LabelField(new GUIContent(regions[i].name, SpineEditorUtilities.Icons.image)); - } - EditorGUI.indentLevel = baseIndent; - } - #endif - - if (serializedObject.ApplyModifiedProperties() || SpineInspectorUtility.UndoRedoPerformed(Event.current)) - atlasAsset.Clear(); - } - - static public void UpdateSpriteSlices (Texture texture, Atlas atlas) { - string texturePath = AssetDatabase.GetAssetPath(texture.GetInstanceID()); - var t = (TextureImporter)TextureImporter.GetAtPath(texturePath); - t.spriteImportMode = SpriteImportMode.Multiple; - var spriteSheet = t.spritesheet; - var sprites = new List(spriteSheet); - - var regions = AtlasAssetInspector.GetRegions(atlas); - char[] FilenameDelimiter = {'.'}; - int updatedCount = 0; - int addedCount = 0; - - foreach (var r in regions) { - string pageName = r.page.name.Split(FilenameDelimiter, StringSplitOptions.RemoveEmptyEntries)[0]; - string textureName = texture.name; - bool pageMatch = string.Equals(pageName, textureName, StringComparison.Ordinal); - -// if (pageMatch) { -// int pw = r.page.width; -// int ph = r.page.height; -// bool mismatchSize = pw != texture.width || pw > t.maxTextureSize || ph != texture.height || ph > t.maxTextureSize; -// if (mismatchSize) -// Debug.LogWarningFormat("Size mismatch found.\nExpected atlas size is {0}x{1}. Texture Import Max Size of texture '{2}'({4}x{5}) is currently set to {3}.", pw, ph, texture.name, t.maxTextureSize, texture.width, texture.height); -// } - - int spriteIndex = pageMatch ? sprites.FindIndex( - (s) => string.Equals(s.name, r.name, StringComparison.Ordinal) - ) : -1; - bool spriteNameMatchExists = spriteIndex >= 0; - - if (pageMatch) { - Rect spriteRect = new Rect(); - - if (r.rotate) { - spriteRect.width = r.height; - spriteRect.height = r.width; - } else { - spriteRect.width = r.width; - spriteRect.height = r.height; - } - spriteRect.x = r.x; - spriteRect.y = r.page.height - spriteRect.height - r.y; - - if (spriteNameMatchExists) { - var s = sprites[spriteIndex]; - s.rect = spriteRect; - sprites[spriteIndex] = s; - updatedCount++; - } else { - sprites.Add(new SpriteMetaData { - name = r.name, - pivot = new Vector2(0.5f, 0.5f), - rect = spriteRect - }); - addedCount++; - } - } - - } - - t.spritesheet = sprites.ToArray(); - EditorUtility.SetDirty(t); - AssetDatabase.ImportAsset(texturePath, ImportAssetOptions.ForceUpdate); - EditorGUIUtility.PingObject(texture); - Debug.Log(string.Format("Applied sprite slices to {2}. {0} added. {1} updated.", addedCount, updatedCount, texture.name)); - } - } - -} +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "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 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 THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +//#define BAKE_ALL_BUTTON +//#define REGION_BAKING_MESH + +using System; +using System.Collections.Generic; +using System.Reflection; +using UnityEditor; +using UnityEngine; +using Spine; + +namespace Spine.Unity.Editor { + using Event = UnityEngine.Event; + + [CustomEditor(typeof(AtlasAsset)), CanEditMultipleObjects] + public class AtlasAssetInspector : UnityEditor.Editor { + SerializedProperty atlasFile, materials; + AtlasAsset atlasAsset; + + GUIContent spriteSlicesLabel; + GUIContent SpriteSlicesLabel { + get { + if (spriteSlicesLabel == null) { + spriteSlicesLabel = new GUIContent( + "Apply Regions as Texture Sprite Slices", + SpineEditorUtilities.Icons.unity, + "Adds Sprite slices to atlas texture(s). " + + "Updates existing slices if ones with matching names exist. \n\n" + + "If your atlas was exported with Premultiply Alpha, " + + "your SpriteRenderer should use the generated Spine _Material asset (or any Material with a PMA shader) instead of Sprites-Default."); + } + return spriteSlicesLabel; + } + } + + static List GetRegions (Atlas atlas) { + FieldInfo regionsField = typeof(Atlas).GetField("regions", BindingFlags.Instance | BindingFlags.NonPublic); + return (List)regionsField.GetValue(atlas); + } + + void OnEnable () { + SpineEditorUtilities.ConfirmInitialization(); + atlasFile = serializedObject.FindProperty("atlasFile"); + materials = serializedObject.FindProperty("materials"); + materials.isExpanded = true; + atlasAsset = (AtlasAsset)target; + #if REGION_BAKING_MESH + UpdateBakedList(); + #endif + } + + #if REGION_BAKING_MESH + private List baked; + private List bakedObjects; + + void UpdateBakedList () { + AtlasAsset asset = (AtlasAsset)target; + baked = new List(); + bakedObjects = new List(); + if (atlasFile.objectReferenceValue != null) { + List regions = this.Regions; + string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset); + string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath); + string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name); + for (int i = 0; i < regions.Count; i++) { + AtlasRegion region = regions[i]; + string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeRegionName(region) + ".prefab").Replace("\\", "/"); + GameObject prefab = (GameObject)AssetDatabase.LoadAssetAtPath(bakedPrefabPath, typeof(GameObject)); + baked.Add(prefab != null); + bakedObjects.Add(prefab); + } + } + } + #endif + + override public void OnInspectorGUI () { + if (serializedObject.isEditingMultipleObjects) { + DrawDefaultInspector(); + return; + } + + serializedObject.Update(); + atlasAsset = atlasAsset ?? (AtlasAsset)target; + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(atlasFile); + EditorGUILayout.PropertyField(materials, true); + if (EditorGUI.EndChangeCheck()) { + serializedObject.ApplyModifiedProperties(); + atlasAsset.Clear(); + atlasAsset.GetAtlas(); + } + + if (materials.arraySize == 0) { + EditorGUILayout.HelpBox("No materials", MessageType.Error); + return; + } + + for (int i = 0; i < materials.arraySize; i++) { + SerializedProperty prop = materials.GetArrayElementAtIndex(i); + var material = (Material)prop.objectReferenceValue; + if (material == null) { + EditorGUILayout.HelpBox("Materials cannot be null.", MessageType.Error); + return; + } + } + + EditorGUILayout.Space(); + if (SpineInspectorUtility.LargeCenteredButton(SpineInspectorUtility.TempContent("Set Mipmap Bias to " + SpineEditorUtilities.DEFAULT_MIPMAPBIAS))) { + foreach (var m in atlasAsset.materials) { + var texture = m.mainTexture; + texture.mipMapBias = SpineEditorUtilities.DEFAULT_MIPMAPBIAS; + } + Debug.Log("Texture mipmap bias set to " + SpineEditorUtilities.DEFAULT_MIPMAPBIAS); + } + + EditorGUILayout.Space(); + if (atlasFile.objectReferenceValue != null) { + if (SpineInspectorUtility.LargeCenteredButton(SpriteSlicesLabel)) { + var atlas = atlasAsset.GetAtlas(); + foreach (var m in atlasAsset.materials) + UpdateSpriteSlices(m.mainTexture, atlas); + } + } + + EditorGUILayout.Space(); + + #if REGION_BAKING_MESH + if (atlasFile.objectReferenceValue != null) { + Atlas atlas = asset.GetAtlas(); + FieldInfo field = typeof(Atlas).GetField("regions", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.NonPublic); + List regions = (List)field.GetValue(atlas); + EditorGUILayout.LabelField(new GUIContent("Region Baking", SpineEditorUtilities.Icons.unityIcon)); + EditorGUI.indentLevel++; + AtlasPage lastPage = null; + for (int i = 0; i < regions.Count; i++) { + if (lastPage != regions[i].page) { + if (lastPage != null) { + EditorGUILayout.Separator(); + EditorGUILayout.Separator(); + } + lastPage = regions[i].page; + Material mat = ((Material)lastPage.rendererObject); + if (mat != null) { + GUILayout.BeginHorizontal(); + { + EditorGUI.BeginDisabledGroup(true); + EditorGUILayout.ObjectField(mat, typeof(Material), false, GUILayout.Width(250)); + EditorGUI.EndDisabledGroup(); + } + GUILayout.EndHorizontal(); + + } else { + EditorGUILayout.LabelField(new GUIContent("Page missing material!", SpineEditorUtilities.Icons.warning)); + } + } + GUILayout.BeginHorizontal(); + { + //EditorGUILayout.ToggleLeft(baked[i] ? "" : regions[i].name, baked[i]); + bool result = baked[i] ? EditorGUILayout.ToggleLeft("", baked[i], GUILayout.Width(24)) : EditorGUILayout.ToggleLeft(" " + regions[i].name, baked[i]); + if(baked[i]){ + EditorGUILayout.ObjectField(bakedObjects[i], typeof(GameObject), false, GUILayout.Width(250)); + } + if (result && !baked[i]) { + //bake + baked[i] = true; + bakedObjects[i] = SpineEditorUtilities.BakeRegion(atlasAsset, regions[i]); + EditorGUIUtility.PingObject(bakedObjects[i]); + } else if (!result && baked[i]) { + //unbake + bool unbakeResult = EditorUtility.DisplayDialog("Delete Baked Region", "Do you want to delete the prefab for " + regions[i].name, "Yes", "Cancel"); + switch (unbakeResult) { + case true: + //delete + string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset); + string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath); + string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name); + string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeRegionName(regions[i]) + ".prefab").Replace("\\", "/"); + AssetDatabase.DeleteAsset(bakedPrefabPath); + baked[i] = false; + break; + case false: + //do nothing + break; + } + } + } + GUILayout.EndHorizontal(); + } + EditorGUI.indentLevel--; + + #if BAKE_ALL_BUTTON + // Check state + bool allBaked = true; + bool allUnbaked = true; + for (int i = 0; i < regions.Count; i++) { + allBaked &= baked[i]; + allUnbaked &= !baked[i]; + } + + if (!allBaked && GUILayout.Button("Bake All")) { + for (int i = 0; i < regions.Count; i++) { + if (!baked[i]) { + baked[i] = true; + bakedObjects[i] = SpineEditorUtilities.BakeRegion(atlasAsset, regions[i]); + } + } + + } else if (!allUnbaked && GUILayout.Button("Unbake All")) { + bool unbakeResult = EditorUtility.DisplayDialog("Delete All Baked Regions", "Are you sure you want to unbake all region prefabs? This cannot be undone.", "Yes", "Cancel"); + switch (unbakeResult) { + case true: + //delete + for (int i = 0; i < regions.Count; i++) { + if (baked[i]) { + string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset); + string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath); + string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name); + string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeRegionName(regions[i]) + ".prefab").Replace("\\", "/"); + AssetDatabase.DeleteAsset(bakedPrefabPath); + baked[i] = false; + } + } + break; + case false: + //do nothing + break; + } + + } + #endif + + } + #else + if (atlasFile.objectReferenceValue != null) { + EditorGUILayout.LabelField("Atlas Regions", EditorStyles.boldLabel); + int baseIndent = EditorGUI.indentLevel; + + var regions = AtlasAssetInspector.GetRegions(atlasAsset.GetAtlas()); + AtlasPage lastPage = null; + for (int i = 0; i < regions.Count; i++) { + if (lastPage != regions[i].page) { + if (lastPage != null) { + EditorGUILayout.Separator(); + EditorGUILayout.Separator(); + } + lastPage = regions[i].page; + Material mat = ((Material)lastPage.rendererObject); + if (mat != null) { + EditorGUI.indentLevel = baseIndent; + using (new GUILayout.HorizontalScope()) + using (new EditorGUI.DisabledGroupScope(true)) + EditorGUILayout.ObjectField(mat, typeof(Material), false, GUILayout.Width(250)); + EditorGUI.indentLevel = baseIndent + 1; + } else { + EditorGUILayout.HelpBox("Page missing material!", MessageType.Warning); + } + } + + EditorGUILayout.LabelField(new GUIContent(regions[i].name, SpineEditorUtilities.Icons.image)); + } + EditorGUI.indentLevel = baseIndent; + } + #endif + + if (serializedObject.ApplyModifiedProperties() || SpineInspectorUtility.UndoRedoPerformed(Event.current)) + atlasAsset.Clear(); + } + + static public void UpdateSpriteSlices (Texture texture, Atlas atlas) { + string texturePath = AssetDatabase.GetAssetPath(texture.GetInstanceID()); + var t = (TextureImporter)TextureImporter.GetAtPath(texturePath); + t.spriteImportMode = SpriteImportMode.Multiple; + var spriteSheet = t.spritesheet; + var sprites = new List(spriteSheet); + + var regions = AtlasAssetInspector.GetRegions(atlas); + char[] FilenameDelimiter = {'.'}; + int updatedCount = 0; + int addedCount = 0; + + foreach (var r in regions) { + string pageName = r.page.name.Split(FilenameDelimiter, StringSplitOptions.RemoveEmptyEntries)[0]; + string textureName = texture.name; + bool pageMatch = string.Equals(pageName, textureName, StringComparison.Ordinal); + +// if (pageMatch) { +// int pw = r.page.width; +// int ph = r.page.height; +// bool mismatchSize = pw != texture.width || pw > t.maxTextureSize || ph != texture.height || ph > t.maxTextureSize; +// if (mismatchSize) +// Debug.LogWarningFormat("Size mismatch found.\nExpected atlas size is {0}x{1}. Texture Import Max Size of texture '{2}'({4}x{5}) is currently set to {3}.", pw, ph, texture.name, t.maxTextureSize, texture.width, texture.height); +// } + + int spriteIndex = pageMatch ? sprites.FindIndex( + (s) => string.Equals(s.name, r.name, StringComparison.Ordinal) + ) : -1; + bool spriteNameMatchExists = spriteIndex >= 0; + + if (pageMatch) { + Rect spriteRect = new Rect(); + + if (r.rotate) { + spriteRect.width = r.height; + spriteRect.height = r.width; + } else { + spriteRect.width = r.width; + spriteRect.height = r.height; + } + spriteRect.x = r.x; + spriteRect.y = r.page.height - spriteRect.height - r.y; + + if (spriteNameMatchExists) { + var s = sprites[spriteIndex]; + s.rect = spriteRect; + sprites[spriteIndex] = s; + updatedCount++; + } else { + sprites.Add(new SpriteMetaData { + name = r.name, + pivot = new Vector2(0.5f, 0.5f), + rect = spriteRect + }); + addedCount++; + } + } + + } + + t.spritesheet = sprites.ToArray(); + EditorUtility.SetDirty(t); + AssetDatabase.ImportAsset(texturePath, ImportAssetOptions.ForceUpdate); + EditorGUIUtility.PingObject(texture); + Debug.Log(string.Format("Applied sprite slices to {2}. {0} added. {1} updated.", addedCount, updatedCount, texture.name)); + } + } + +} diff --git a/spine-unity/Assets/spine-unity/Asset Types/Editor/AtlasAssetInspector.cs.meta b/spine-unity/Assets/spine-unity/Editor/AtlasAssetInspector.cs.meta similarity index 100% rename from spine-unity/Assets/spine-unity/Asset Types/Editor/AtlasAssetInspector.cs.meta rename to spine-unity/Assets/spine-unity/Editor/AtlasAssetInspector.cs.meta diff --git a/spine-unity/Assets/spine-unity/Asset Types/Editor/SkeletonDataAssetInspector.cs b/spine-unity/Assets/spine-unity/Editor/SkeletonDataAssetInspector.cs similarity index 100% rename from spine-unity/Assets/spine-unity/Asset Types/Editor/SkeletonDataAssetInspector.cs rename to spine-unity/Assets/spine-unity/Editor/SkeletonDataAssetInspector.cs diff --git a/spine-unity/Assets/spine-unity/Asset Types/Editor/SkeletonDataAssetInspector.cs.meta b/spine-unity/Assets/spine-unity/Editor/SkeletonDataAssetInspector.cs.meta similarity index 100% rename from spine-unity/Assets/spine-unity/Asset Types/Editor/SkeletonDataAssetInspector.cs.meta rename to spine-unity/Assets/spine-unity/Editor/SkeletonDataAssetInspector.cs.meta diff --git a/spine-unity/Assets/spine-unity/ISkeletonAnimation.cs b/spine-unity/Assets/spine-unity/ISkeletonAnimation.cs index 5e49db79a..f5e423adf 100644 --- a/spine-unity/Assets/spine-unity/ISkeletonAnimation.cs +++ b/spine-unity/Assets/spine-unity/ISkeletonAnimation.cs @@ -37,10 +37,16 @@ public interface ISkeletonAnimation { event UpdateBonesDelegate UpdateWorld; event UpdateBonesDelegate UpdateComplete; - void LateUpdate (); + //void LateUpdate (); Skeleton Skeleton { get; } } + /// Holds a reference to a SkeletonDataAsset. + public interface ISkeletonDataAssetComponent { + /// Gets the SkeletonDataAsset of the Spine Component. + SkeletonDataAsset SkeletonDataAsset { get; } + } + /// A Spine-Unity Component that manages a Spine.Skeleton instance, instantiated from a SkeletonDataAsset. public interface ISkeletonComponent { /// Gets the SkeletonDataAsset of the Spine Component. diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/SpineMesh.cs b/spine-unity/Assets/spine-unity/Mesh Generation/SpineMesh.cs index 68f1db3f0..40be3a896 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/SpineMesh.cs +++ b/spine-unity/Assets/spine-unity/Mesh Generation/SpineMesh.cs @@ -501,6 +501,7 @@ public void AddSubmesh (SubmeshInstruction instruction, bool updateTriangles = t Color c = default(Color); + // Identify and prepare values. var region = attachment as RegionAttachment; if (region != null) { region.ComputeWorldVertices(slot.bone, workingVerts, 0); @@ -531,6 +532,9 @@ public void AddSubmesh (SubmeshInstruction instruction, bool updateTriangles = t continue; } } + + // If not any renderable attachment. + clipper.ClipEnd(slot); continue; } } @@ -557,6 +561,7 @@ public void AddSubmesh (SubmeshInstruction instruction, bool updateTriangles = t uvs = clipper.clippedUVs.Items; } + // Actually add slot/attachment data into buffers. if (attachmentVertexCount != 0 && attachmentIndexCount != 0) { if (tintBlack) AddAttachmentTintBlack(slot.r2, slot.g2, slot.b2, attachmentVertexCount); @@ -633,6 +638,7 @@ public void AddSubmesh (SubmeshInstruction instruction, bool updateTriangles = t submeshItems[oldTriangleCount + i] = attachmentTriangleIndices[i] + ovc; } } + clipper.ClipEnd(slot); } clipper.ClipEnd(); @@ -1155,7 +1161,7 @@ public void Initialize () { doubleBufferedMesh = new DoubleBuffered(); } - public Material[] GetUpdatedShaderdMaterialsArray () { + public Material[] GetUpdatedSharedMaterialsArray () { if (submeshMaterials.Count == sharedMaterials.Length) submeshMaterials.CopyTo(sharedMaterials); else diff --git a/spine-unity/Assets/spine-unity/Modules/AttachmentTools/AttachmentTools.cs b/spine-unity/Assets/spine-unity/Modules/AttachmentTools/AttachmentTools.cs index 88b10647f..a1e2bc9ec 100644 --- a/spine-unity/Assets/spine-unity/Modules/AttachmentTools/AttachmentTools.cs +++ b/spine-unity/Assets/spine-unity/Modules/AttachmentTools/AttachmentTools.cs @@ -486,6 +486,7 @@ public static Skin GetRepackedSkin (this Skin o, string newName, Material materi /// Creates and populates a duplicate skin with cloned attachments that are backed by a new packed texture atlas comprised of all the regions from the original skin. /// No Spine.Atlas object is created so there is no way to find AtlasRegions except through the Attachments using them. public static Skin GetRepackedSkin (this Skin o, string newName, Shader shader, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, Material materialPropertySource = null, bool clearCache = false) { + if (o == null) throw new System.NullReferenceException("Skin was null"); var skinAttachments = o.Attachments; var newSkin = new Skin(newName); diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs index f19a0ab22..25e4d688c 100644 --- a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs @@ -35,7 +35,7 @@ namespace Spine.Unity { [ExecuteInEditMode, RequireComponent(typeof(CanvasRenderer), typeof(RectTransform)), DisallowMultipleComponent] [AddComponentMenu("Spine/SkeletonGraphic (Unity UI Canvas)")] - public class SkeletonGraphic : MaskableGraphic, ISkeletonComponent, IAnimationStateComponent, ISkeletonAnimation { + public class SkeletonGraphic : MaskableGraphic, ISkeletonComponent, IAnimationStateComponent, ISkeletonAnimation, ISkeletonDataAssetComponent { #region Inspector public SkeletonDataAsset skeletonDataAsset; diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonPartsRenderer.cs b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonPartsRenderer.cs index e89f2c5c1..f1fc26685 100644 --- a/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonPartsRenderer.cs +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonPartsRenderer.cs @@ -112,9 +112,9 @@ public void RenderParts (ExposedList instructions, int start meshGenerator.FillVertexData(mesh); if (updateTriangles) { meshGenerator.FillTriangles(mesh); - meshRenderer.sharedMaterials = buffers.GetUpdatedShaderdMaterialsArray(); + meshRenderer.sharedMaterials = buffers.GetUpdatedSharedMaterialsArray(); } else if (buffers.MaterialsChangedInLastUpdate()) { - meshRenderer.sharedMaterials = buffers.GetUpdatedShaderdMaterialsArray(); + meshRenderer.sharedMaterials = buffers.GetUpdatedSharedMaterialsArray(); } } diff --git a/spine-unity/Assets/spine-unity/SkeletonAnimation.cs b/spine-unity/Assets/spine-unity/SkeletonAnimation.cs index f69546429..28463c371 100644 --- a/spine-unity/Assets/spine-unity/SkeletonAnimation.cs +++ b/spine-unity/Assets/spine-unity/SkeletonAnimation.cs @@ -126,11 +126,16 @@ public static SkeletonAnimation NewSkeletonAnimationGameObject (SkeletonDataAsse } #endregion + /// + /// Clears the previously generated mesh, resets the skeleton's pose, and clears all previously active animations. public override void ClearState () { base.ClearState(); if (state != null) state.ClearTracks(); } + /// + /// Initialize this component. Attempts to load the SkeletonData and creates the internal Spine objects and buffers. + /// If set to true, force overwrite an already initialized object. public override void Initialize (bool overwrite) { if (valid && !overwrite) return; diff --git a/spine-unity/Assets/spine-unity/SkeletonRenderer.cs b/spine-unity/Assets/spine-unity/SkeletonRenderer.cs index e12b0b0d0..356cbd21f 100644 --- a/spine-unity/Assets/spine-unity/SkeletonRenderer.cs +++ b/spine-unity/Assets/spine-unity/SkeletonRenderer.cs @@ -38,7 +38,7 @@ namespace Spine.Unity { /// Renders a skeleton. [ExecuteInEditMode, RequireComponent(typeof(MeshFilter), typeof(MeshRenderer)), DisallowMultipleComponent] [HelpURL("http://esotericsoftware.com/spine-unity-documentation#Rendering")] - public class SkeletonRenderer : MonoBehaviour, ISkeletonComponent { + public class SkeletonRenderer : MonoBehaviour, ISkeletonComponent, ISkeletonDataAssetComponent { public delegate void SkeletonRendererDelegate (SkeletonRenderer skeletonRenderer); public event SkeletonRendererDelegate OnRebuild; @@ -163,12 +163,17 @@ void OnDestroy () { valid = false; } + /// + /// Clears the previously generated mesh and resets the skeleton's pose. public virtual void ClearState () { meshFilter.sharedMesh = null; currentInstructions.Clear(); if (skeleton != null) skeleton.SetToSetupPose(); } + /// + /// Initialize this component. Attempts to load the SkeletonData and creates the internal Skeleton object and buffers. + /// If set to true, it will overwrite internal objects if they were already generated. Otherwise, the initialized component will ignore subsequent calls to initialize. public virtual void Initialize (bool overwrite) { if (valid && !overwrite) return; @@ -219,6 +224,8 @@ public virtual void Initialize (bool overwrite) { OnRebuild(this); } + /// + /// Generates a new UnityEngine.Mesh from the internal Skeleton. public virtual void LateUpdate () { if (!valid) return; @@ -305,9 +312,9 @@ public virtual void LateUpdate () { rendererBuffers.UpdateSharedMaterials(workingSubmeshInstructions); if (updateTriangles) { // Check if the triangles should also be updated. meshGenerator.FillTriangles(currentMesh); - meshRenderer.sharedMaterials = rendererBuffers.GetUpdatedShaderdMaterialsArray(); + meshRenderer.sharedMaterials = rendererBuffers.GetUpdatedSharedMaterialsArray(); } else if (rendererBuffers.MaterialsChangedInLastUpdate()) { - meshRenderer.sharedMaterials = rendererBuffers.GetUpdatedShaderdMaterialsArray(); + meshRenderer.sharedMaterials = rendererBuffers.GetUpdatedSharedMaterialsArray(); }