diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a2ef2101..03f55cce9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -82,6 +82,7 @@ * **[SpineAttribute(includeNone:false)]** SpineAttributes now have an `includeNone` optional parameter to specify if you want to include or exclude a none ("") value option in the dropdown menu. Default is `includeNone:true`. * **[SpineAttachment(skinField:"mySkin")]** The SpineAttachment attribute now has a skinField optional parameter to limit the dropdown items to attachments in a specific skin instead of the just default skin or all the skins in SkeletonData. * **SkeletonDebugWindow**. Debugging tools have been moved from the SkeletonRenderer and SkeletonUtility component inspectors into its own utility window. You can access "Skeleton Debug" under the `Advanced...` foldout in the SkeletonRenderer inspector, or in SkeletonRenderer's right-click/context menu. + * **Skeleton Baking Window** The old Skeleton Baking feature is also now accessible through the SkeletonDataAsset's right-click/context menu. * **AttachmentTools source material**. `AttachmentTools` methods can now accept a `sourceMaterial` argument to copy material properties from. * **AttachmentTools Skin Extensions**. Using AttachmentTools, you can now add entries by slot name by also providing a skeleton argument. Also `Append(Skin)`, `RemoveAttachment` and `Clear` have been added. * **BoneFollower and SkeletonUtilityBone Add RigidBody Button**. The BoneFollower and SkeletonUtilityBone component inspectors will now offer to add a `Rigidbody` or `Rigidbody2D` if it detects a collider of the appropriate type. Having a rigidbody on a moving transform with a collider fits better with the Unity physics systems and prevents excess calculations. It will not detect colliders on child objects so you have to add Rigidbody components manually accordingly. diff --git a/spine-unity/Assets/spine-unity/Asset Types/Editor/SkeletonDataAssetInspector.cs b/spine-unity/Assets/spine-unity/Asset Types/Editor/SkeletonDataAssetInspector.cs index c4a09dfc4..c4b6d2811 100644 --- a/spine-unity/Assets/spine-unity/Asset Types/Editor/SkeletonDataAssetInspector.cs +++ b/spine-unity/Assets/spine-unity/Asset Types/Editor/SkeletonDataAssetInspector.cs @@ -287,73 +287,6 @@ namespace Spine.Unity.Editor { } } #endif - - #if SPINE_BAKING - bool pre = isBakingExpanded; - isBakingExpanded = EditorGUILayout.Foldout(isBakingExpanded, new GUIContent("Baking", Icons.unityIcon)); - if (pre != isBakingExpanded) - EditorPrefs.SetBool(ShowBakingPrefsKey, isBakingExpanded); - - if (isBakingExpanded) { - EditorGUI.indentLevel++; - const string BakingWarningMessage = -// "WARNING!" + -// "\nBaking is NOT the same as SkeletonAnimator!" + -// "\n\n" + - "The main use of Baking is to export Spine projects to be used without the Spine Runtime (ie: for sale on the Asset Store, or background objects that are animated only with a wind noise generator)" + - - "\n\nBaking does not support the following:" + - "\n\tDisabled transform inheritance" + - "\n\tShear" + - "\n\tColor Keys" + - "\n\tDraw Order Keys" + - "\n\tAll Constraint types" + - - "\n\nCurves are sampled at 60fps and are not realtime." + - "\nPlease read SkeletonBaker.cs comments for full details."; - EditorGUILayout.HelpBox(BakingWarningMessage, MessageType.Info, true); - - EditorGUI.indentLevel++; - bakeAnimations = EditorGUILayout.Toggle("Bake Animations", bakeAnimations); - using (new EditorGUI.DisabledGroupScope(!bakeAnimations)) { - EditorGUI.indentLevel++; - bakeIK = EditorGUILayout.Toggle("Bake IK", bakeIK); - bakeEventOptions = (SendMessageOptions)EditorGUILayout.EnumPopup("Event Options", bakeEventOptions); - EditorGUI.indentLevel--; - } - - // Bake Skin buttons. - using (new GUILayout.HorizontalScope()) { - if (GUILayout.Button(new GUIContent("Bake All Skins", Icons.unityIcon), GUILayout.Height(32), GUILayout.Width(150))) - SkeletonBaker.BakeToPrefab(m_skeletonDataAsset, m_skeletonData.Skins, "", bakeAnimations, bakeIK, bakeEventOptions); - - if (m_skeletonAnimation != null && m_skeletonAnimation.skeleton != null) { - Skin bakeSkin = m_skeletonAnimation.skeleton.Skin; - - string skinName = ""; - if (bakeSkin == null) { - skinName = "Default"; - bakeSkin = m_skeletonData.Skins.Items[0]; - } else - skinName = m_skeletonAnimation.skeleton.Skin.Name; - - using (new GUILayout.VerticalScope()) { - if (GUILayout.Button(new GUIContent("Bake \"" + skinName + "\"", Icons.unityIcon), GUILayout.Height(32), GUILayout.Width(250))) - SkeletonBaker.BakeToPrefab(m_skeletonDataAsset, new ExposedList(new [] { bakeSkin }), "", bakeAnimations, bakeIK, bakeEventOptions); - using (new GUILayout.HorizontalScope()) { - GUILayout.Label(new GUIContent("Skins", Icons.skinsRoot), GUILayout.Width(50)); - if (GUILayout.Button(skinName, EditorStyles.popup, GUILayout.Width(196))) { - DrawSkinDropdown(); - } - } - } - } - } - - EditorGUI.indentLevel--; - EditorGUI.indentLevel--; - } - #endif } void DoReimport () { diff --git a/spine-unity/Assets/spine-unity/Editor/SkeletonBaker.cs b/spine-unity/Assets/spine-unity/Editor/SkeletonBaker.cs index 424f13f68..521b71f42 100644 --- a/spine-unity/Assets/spine-unity/Editor/SkeletonBaker.cs +++ b/spine-unity/Assets/spine-unity/Editor/SkeletonBaker.cs @@ -42,36 +42,35 @@ using System.Reflection; using System.IO; using Spine; - -/// -/// [SUPPORTS] -/// Linear, Constant, and Bezier Curves* -/// Inverse Kinematics* -/// Inherit Rotation -/// Translate Timeline -/// Rotate Timeline -/// Scale Timeline** -/// Event Timeline*** -/// Attachment Timeline -/// -/// RegionAttachment -/// MeshAttachment -/// SkinnedMeshAttachment -/// -/// [LIMITATIONS] -/// *Inverse Kinematics & Bezier Curves are baked into the animation at 60fps and are not realtime. Use bakeIncrement constant to adjust key density if desired. -/// **Non-uniform Scale Keys (ie: if ScaleX and ScaleY are not equal to eachother, it will not be accurate to Spine source) -/// ***Events may only fire 1 type of data per event in Unity safely so priority to String data if present in Spine key, otherwise a Float is sent whether the Spine key was Int or Float with priority given to Int. -/// -/// [DOES NOT SUPPORT] -/// FlipX or FlipY (Maybe one day) -/// FFD (Unity does not provide access to BlendShapes with code) -/// Color Keys (Maybe one day when Unity supports full FBX standard and provides access with code) -/// InheritScale (Never. Unity and Spine do scaling very differently) -/// Draw Order Keyframes -/// -/// namespace Spine.Unity.Editor { + + /// + /// [SUPPORTS] + /// Linear, Constant, and Bezier Curves* + /// Inverse Kinematics* + /// Inherit Rotation + /// Translate Timeline + /// Rotate Timeline + /// Scale Timeline** + /// Event Timeline*** + /// Attachment Timeline + /// + /// RegionAttachment + /// MeshAttachment + /// SkinnedMeshAttachment + /// + /// [LIMITATIONS] + /// *Inverse Kinematics & Bezier Curves are baked into the animation at 60fps and are not realtime. Use bakeIncrement constant to adjust key density if desired. + /// **Non-uniform Scale Keys (ie: if ScaleX and ScaleY are not equal to eachother, it will not be accurate to Spine source) + /// ***Events may only fire 1 type of data per event in Unity safely so priority to String data if present in Spine key, otherwise a Float is sent whether the Spine key was Int or Float with priority given to Int. + /// + /// [DOES NOT SUPPORT] + /// FlipX or FlipY (Maybe one day) + /// FFD (Unity does not provide access to BlendShapes with code) + /// Color Keys (Maybe one day when Unity supports full FBX standard and provides access with code) + /// InheritScale (Never. Unity and Spine do scaling very differently) + /// Draw Order Keyframes + /// public static class SkeletonBaker { #region SkeletonAnimator's Mecanim Clips diff --git a/spine-unity/Assets/spine-unity/Editor/SkeletonBakingWindow.cs b/spine-unity/Assets/spine-unity/Editor/SkeletonBakingWindow.cs new file mode 100644 index 000000000..295f51c43 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Editor/SkeletonBakingWindow.cs @@ -0,0 +1,121 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +namespace Spine.Unity.Editor { + + using Editor = UnityEditor.Editor; + using Icons = SpineEditorUtilities.Icons; + + public class SkeletonBakingWindow : EditorWindow { + const bool IsUtilityWindow = true; + + [MenuItem("CONTEXT/SkeletonDataAsset/Skeleton Baking", false, 5000)] + public static void Init (MenuCommand command) { + var window = EditorWindow.GetWindow(IsUtilityWindow); + window.minSize = new Vector2(330f, 530f); + window.maxSize = new Vector2(600f, 1000f); + window.titleContent = new GUIContent("Skeleton Baking", Icons.spine); + window.skeletonDataAsset = command.context as SkeletonDataAsset; + window.Show(); + } + + public SkeletonDataAsset skeletonDataAsset; + [SpineSkin(dataField:"skeletonDataAsset")] + public string skinToBake = "default"; + + // Settings + bool bakeAnimations = false; + bool bakeIK = true; + SendMessageOptions bakeEventOptions; + + SerializedObject so; + Skin bakeSkin; + + + void DataAssetChanged () { + bakeSkin = null; + } + + void OnGUI () { + so = so ?? new SerializedObject(this); + + EditorGUIUtility.wideMode = true; + EditorGUILayout.LabelField("Spine Skeleton Prefab Baking", EditorStyles.boldLabel); + + const string BakingWarningMessage = "\nThe main use of Baking is to export Spine projects to be used without the Spine Runtime (ie: for sale on the Asset Store, or background objects that are animated only with a wind noise generator)" + + + "\n\nBaking does not support the following:" + + "\n\tDisabled transform inheritance" + + "\n\tShear" + + "\n\tColor Keys" + + "\n\tDraw Order Keys" + + "\n\tAll Constraint types" + + + "\n\nCurves are sampled at 60fps and are not realtime." + + "\nPlease read SkeletonBaker.cs comments for full details.\n"; + EditorGUILayout.HelpBox(BakingWarningMessage, MessageType.Info, true); + + EditorGUI.BeginChangeCheck(); + var skeletonDataAssetProperty = so.FindProperty("skeletonDataAsset"); + EditorGUILayout.PropertyField(skeletonDataAssetProperty, SpineInspectorUtility.TempContent("SkeletonDataAsset", Icons.spine)); + if (EditorGUI.EndChangeCheck()) { + so.ApplyModifiedProperties(); + DataAssetChanged(); + } + EditorGUILayout.Space(); + + if (skeletonDataAsset == null) return; + var skeletonData = skeletonDataAsset.GetSkeletonData(false); + if (skeletonData == null) return; + + using (new SpineInspectorUtility.BoxScope(false)) { + EditorGUILayout.LabelField(skeletonDataAsset.name, EditorStyles.boldLabel); + using (new SpineInspectorUtility.IndentScope()) { + EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Bones: " + skeletonData.Bones.Count, Icons.bone)); + + int totalAttachments = 0; + foreach (var s in skeletonData.Skins) totalAttachments += s.Attachments.Count; + + EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Total Attachments: " + totalAttachments, Icons.genericAttachment)); + EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Current skin attachments: " + (bakeSkin == null ? 0 : bakeSkin.Attachments.Count), Icons.skinPlaceholder)); + EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Animations: " + skeletonData.Animations.Count, Icons.animation)); + } + } + using (new SpineInspectorUtility.BoxScope(false)) { + EditorGUILayout.LabelField("Settings", EditorStyles.boldLabel); + using (new SpineInspectorUtility.IndentScope()) { + bakeAnimations = EditorGUILayout.Toggle(SpineInspectorUtility.TempContent("Bake Animations", Icons.animationRoot), bakeAnimations); + bakeIK = EditorGUILayout.Toggle(SpineInspectorUtility.TempContent("Bake IK", Icons.constraintIK), bakeIK); + bakeEventOptions = (SendMessageOptions)EditorGUILayout.EnumPopup(SpineInspectorUtility.TempContent("Event Options", Icons.userEvent), bakeEventOptions); + } + } + EditorGUILayout.Space(); + + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(so.FindProperty("skinToBake")); + if (EditorGUI.EndChangeCheck()) { + so.ApplyModifiedProperties(); + Repaint(); + } + + if (!string.IsNullOrEmpty(skinToBake) && UnityEngine.Event.current.type == EventType.Repaint) + bakeSkin = skeletonData.FindSkin(skinToBake) ?? skeletonData.DefaultSkin; + + var prefabIcon = EditorGUIUtility.FindTexture("PrefabModel Icon"); + + if (SpineInspectorUtility.LargeCenteredButton(SpineInspectorUtility.TempContent(string.Format("Bake Skin ({0})", (bakeSkin == null ? "default" : bakeSkin.Name)), prefabIcon))) { + SkeletonBaker.BakeToPrefab(skeletonDataAsset, new ExposedList(new [] { bakeSkin }), "", bakeAnimations, bakeIK, bakeEventOptions); + } + + + if (skeletonData.Skins.Count > 1) { + if (SpineInspectorUtility.LargeCenteredButton(SpineInspectorUtility.TempContent(string.Format("Bake All ({0} skins)", skeletonData.Skins.Count), prefabIcon))) { + SkeletonBaker.BakeToPrefab(skeletonDataAsset, skeletonData.Skins, "", bakeAnimations, bakeIK, bakeEventOptions); + } + } + + } + } +} diff --git a/spine-unity/Assets/spine-unity/Editor/SkeletonBakingWindow.cs.meta b/spine-unity/Assets/spine-unity/Editor/SkeletonBakingWindow.cs.meta new file mode 100644 index 000000000..4e1aa1dc1 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Editor/SkeletonBakingWindow.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 868b0caae5b3e65408ece1ab400c4a99 +timeCreated: 1495203966 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs b/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs index 748417435..5a9be7ce4 100644 --- a/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs +++ b/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs @@ -305,7 +305,7 @@ namespace Spine.Unity.Editor { prefix = skinPrefix; for (int i = 0; i < data.Slots.Count; i++) { - if (slotMatch.Length > 0 && !(data.Slots.Items[i].Name.ToLower().Contains(slotMatch))) + if (slotMatch.Length > 0 && !(data.Slots.Items[i].Name.Equals(slotMatch, StringComparison.OrdinalIgnoreCase))) continue; attachmentNames.Clear(); diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilityBoneInspector.cs b/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilityBoneInspector.cs index 1779851a5..0a6632e11 100644 --- a/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilityBoneInspector.cs +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilityBoneInspector.cs @@ -200,7 +200,7 @@ namespace Spine.Unity.Editor { string buttonLabel = box.IsWeighted() ? box.Name + " (!)" : box.Name; if (GUILayout.Button(buttonLabel, GUILayout.Width(200))) { utilityBone.bone.Skeleton.UpdateWorldTransform(); - var bbTransform = utilityBone.transform.FindChild("[BoundingBox]" + box.Name); + var bbTransform = utilityBone.transform.Find("[BoundingBox]" + box.Name); // Use FindChild in older versions of Unity. if (bbTransform != null) { var originalCollider = bbTransform.GetComponent(); if (originalCollider != null) diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityBone.cs b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityBone.cs index a2cb83770..f4670d8f1 100644 --- a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityBone.cs +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityBone.cs @@ -166,7 +166,6 @@ namespace Spine.Unity { bone.y = Mathf.Lerp(bone.y, pos.y, overrideAlpha); } - // MITCH if (rotation) { float angle = Mathf.LerpAngle(bone.Rotation, Quaternion.LookRotation(Vector3.forward, parentReference.InverseTransformDirection(cachedTransform.up)).eulerAngles.z, overrideAlpha); bone.Rotation = angle; diff --git a/spine-unity/Assets/spine-unity/SpineAttributes.cs b/spine-unity/Assets/spine-unity/SpineAttributes.cs index 50693ce0b..1876c55df 100644 --- a/spine-unity/Assets/spine-unity/SpineAttributes.cs +++ b/spine-unity/Assets/spine-unity/SpineAttributes.cs @@ -144,10 +144,7 @@ namespace Spine.Unity { public static Spine.Attachment GetAttachment (string attachmentPath, Spine.SkeletonData skeletonData) { var hierarchy = SpineAttachment.GetHierarchy(attachmentPath); - if (hierarchy.name == "") - return null; - - return skeletonData.FindSkin(hierarchy.skin).GetAttachment(skeletonData.FindSlotIndex(hierarchy.slot), hierarchy.name); + return string.IsNullOrEmpty(hierarchy.name) ? null : skeletonData.FindSkin(hierarchy.skin).GetAttachment(skeletonData.FindSlotIndex(hierarchy.slot), hierarchy.name); } public static Spine.Attachment GetAttachment (string attachmentPath, SkeletonDataAsset skeletonDataAsset) {