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 <Skin>(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); } } }
void OnGUI() { so = so ?? new SerializedObject(this); EditorGUIUtility.wideMode = true; EditorGUILayout.LabelField("Spine Skeleton Prefab Baking", EditorStyles.boldLabel); const string BakingWarningMessage = "\nSkeleton baking is not the primary use case for Spine skeletons." + "\nUse baking if you have specialized uses, such as simplified skeletons with movement driven by physics." + "\n\nBaked Skeletons do not support the following:" + "\n\tDisabled rotation or scale inheritance" + "\n\tLocal Shear" + "\n\tAll Constraint types" + "\n\tWeighted mesh verts with more than 4 bound bones" + "\n\nBaked Animations do not support the following:" + "\n\tMesh Deform Keys" + "\n\tColor Keys" + "\n\tDraw Order Keys" + "\n\nAnimation Curves are sampled at 60fps and are not realtime." + "\nConstraint animations are also baked into animation curves." + "\nSee 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; } bool hasExtraSkins = skeletonData.Skins.Count > 1; 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)); EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Slots: " + skeletonData.Slots.Count, Icons.slotRoot)); if (hasExtraSkins) { EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Skins: " + skeletonData.Skins.Count, Icons.skinsRoot)); EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Current skin attachments: " + (bakeSkin == null ? 0 : bakeSkin.Attachments.Count), Icons.skinPlaceholder)); } else if (skeletonData.Skins.Count == 1) { EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Skins: 1 (only default Skin)", Icons.skinsRoot)); } int totalAttachments = 0; foreach (var s in skeletonData.Skins) { totalAttachments += s.Attachments.Count; } EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Total Attachments: " + totalAttachments, Icons.genericAttachment)); } } using (new SpineInspectorUtility.BoxScope(false)) { EditorGUILayout.LabelField("Animations", EditorStyles.boldLabel); EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Animations: " + skeletonData.Animations.Count, Icons.animation)); using (new SpineInspectorUtility.IndentScope()) { bakeAnimations = EditorGUILayout.Toggle(SpineInspectorUtility.TempContent("Bake Animations", Icons.animationRoot), bakeAnimations); using (new EditorGUI.DisabledScope(!bakeAnimations)) { using (new SpineInspectorUtility.IndentScope()) { bakeIK = EditorGUILayout.Toggle(SpineInspectorUtility.TempContent("Bake IK", Icons.constraintIK), bakeIK); bakeEventOptions = (SendMessageOptions)EditorGUILayout.EnumPopup(SpineInspectorUtility.TempContent("Event Options", Icons.userEvent), bakeEventOptions); } } } } EditorGUILayout.Space(); if (!string.IsNullOrEmpty(skinToBake) && UnityEngine.Event.current.type == EventType.Repaint) { bakeSkin = skeletonData.FindSkin(skinToBake) ?? skeletonData.DefaultSkin; } var prefabIcon = EditorGUIUtility.FindTexture("PrefabModel Icon"); if (hasExtraSkins) { EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(so.FindProperty("skinToBake")); if (EditorGUI.EndChangeCheck()) { so.ApplyModifiedProperties(); Repaint(); } if (SpineInspectorUtility.LargeCenteredButton(SpineInspectorUtility.TempContent(string.Format("Bake Skeleton with Skin ({0})", (bakeSkin == null ? "default" : bakeSkin.Name)), prefabIcon))) { SkeletonBaker.BakeToPrefab(skeletonDataAsset, new ExposedList <Skin>(new[] { bakeSkin }), "", bakeAnimations, bakeIK, bakeEventOptions); } if (SpineInspectorUtility.LargeCenteredButton(SpineInspectorUtility.TempContent(string.Format("Bake All ({0} skins)", skeletonData.Skins.Count), prefabIcon))) { SkeletonBaker.BakeToPrefab(skeletonDataAsset, skeletonData.Skins, "", bakeAnimations, bakeIK, bakeEventOptions); } } else { if (SpineInspectorUtility.LargeCenteredButton(SpineInspectorUtility.TempContent("Bake Skeleton", prefabIcon))) { SkeletonBaker.BakeToPrefab(skeletonDataAsset, new ExposedList <Skin>(new[] { bakeSkin }), "", bakeAnimations, bakeIK, bakeEventOptions); } } }
static List<AtlasRegion> GetRegions (Atlas atlas) { FieldInfo regionsField = SpineInspectorUtility.GetNonPublicField(typeof(Atlas), "regions"); return (List<AtlasRegion>)regionsField.GetValue(atlas); }
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { SerializedProperty = property; if (property.propertyType != SerializedPropertyType.String) { EditorGUI.LabelField(position, "ERROR:", "May only apply to type string"); return; } SerializedProperty dataField = property.FindBaseOrSiblingProperty(TargetAttribute.dataField); if (dataField != null) { var objectReferenceValue = dataField.objectReferenceValue; if (objectReferenceValue is SkeletonDataAsset) { skeletonDataAsset = (SkeletonDataAsset)objectReferenceValue; } else if (objectReferenceValue is IHasSkeletonDataAsset) { var hasSkeletonDataAsset = (IHasSkeletonDataAsset)objectReferenceValue; if (hasSkeletonDataAsset != null) { skeletonDataAsset = hasSkeletonDataAsset.SkeletonDataAsset; } } else if (objectReferenceValue != null) { EditorGUI.LabelField(position, "ERROR:", "Invalid reference type"); return; } } else if (property.serializedObject.targetObject is Component) { var component = (Component)property.serializedObject.targetObject; var hasSkeletonDataAsset = component.GetComponentInChildren(typeof(IHasSkeletonDataAsset)) as IHasSkeletonDataAsset; if (hasSkeletonDataAsset != null) { skeletonDataAsset = hasSkeletonDataAsset.SkeletonDataAsset; } } if (skeletonDataAsset == null) { if (TargetAttribute.fallbackToTextField) { EditorGUI.PropertyField(position, property); //EditorGUI.TextField(position, label, property.stringValue); } else { EditorGUI.LabelField(position, "ERROR:", "Must have reference to a SkeletonDataAsset"); } skeletonDataAsset = property.serializedObject.targetObject as SkeletonDataAsset; if (skeletonDataAsset == null) { return; } } position = EditorGUI.PrefixLabel(position, label); var image = Icon; var propertyStringValue = (property.hasMultipleDifferentValues) ? SpineInspectorUtility.EmDash : property.stringValue; if (GUI.Button(position, string.IsNullOrEmpty(propertyStringValue) ? NoneLabel(image) : SpineInspectorUtility.TempContent(propertyStringValue, image), EditorStyles.popup)) { Selector(property); } }
public static void SetSeparatorSlotNames(SkeletonRenderer skeletonRenderer, string[] newSlotNames) { var field = SpineInspectorUtility.GetNonPublicField(typeof(SkeletonRenderer), SeparatorSlotNamesFieldName); field.SetValue(skeletonRenderer, newSlotNames); }
protected virtual void DrawInspectorGUI(bool multi) { bool valid = TargetIsValid; var reloadWidth = GUILayout.Width(GUI.skin.label.CalcSize(new GUIContent(ReloadButtonLabel)).x + 20); var reloadButtonStyle = EditorStyles.miniButtonRight; if (multi) { using (new EditorGUILayout.HorizontalScope(EditorStyles.helpBox)) { SpineInspectorUtility.PropertyFieldFitLabel(skeletonDataAsset, SkeletonDataAssetLabel); if (GUILayout.Button(ReloadButtonLabel, reloadButtonStyle, reloadWidth)) { foreach (var c in targets) { var component = c as SkeletonRenderer; if (component.skeletonDataAsset != null) { foreach (AtlasAsset aa in component.skeletonDataAsset.atlasAssets) { if (aa != null) { aa.Clear(); } } component.skeletonDataAsset.Clear(); } component.Initialize(true); } } } foreach (var c in targets) { var component = c as SkeletonRenderer; if (!component.valid) { if (Event.current.type == EventType.Layout) { component.Initialize(true); component.LateUpdate(); } if (!component.valid) { continue; } } #if NO_PREFAB_MESH if (isInspectingPrefab) { MeshFilter meshFilter = component.GetComponent <MeshFilter>(); if (meshFilter != null) { meshFilter.sharedMesh = null; } } #endif } if (valid) { EditorGUILayout.PropertyField(initialSkinName); } } else { var component = (SkeletonRenderer)target; if (!component.valid && Event.current.type == EventType.Layout) { component.Initialize(true); component.LateUpdate(); } using (new EditorGUILayout.HorizontalScope(EditorStyles.helpBox)) { SpineInspectorUtility.PropertyFieldFitLabel(skeletonDataAsset, SkeletonDataAssetLabel); if (component.valid) { if (GUILayout.Button(ReloadButtonLabel, reloadButtonStyle, reloadWidth)) { if (component.skeletonDataAsset != null) { foreach (AtlasAsset aa in component.skeletonDataAsset.atlasAssets) { if (aa != null) { aa.Clear(); } } component.skeletonDataAsset.Clear(); } component.Initialize(true); } } } if (component.skeletonDataAsset == null) { EditorGUILayout.HelpBox("Skeleton Data Asset required", MessageType.Warning); return; } #if NO_PREFAB_MESH if (isInspectingPrefab) { MeshFilter meshFilter = component.GetComponent <MeshFilter>(); if (meshFilter != null) { meshFilter.sharedMesh = null; } } #endif // Initial skin name. if (component.valid) { string[] skins = new string[component.skeleton.Data.Skins.Count]; int skinIndex = 0; for (int i = 0; i < skins.Length; i++) { string skinNameString = component.skeleton.Data.Skins.Items[i].Name; skins[i] = skinNameString; if (skinNameString == initialSkinName.stringValue) { skinIndex = i; } } skinIndex = EditorGUILayout.Popup("Initial Skin", skinIndex, skins); initialSkinName.stringValue = skins[skinIndex]; } } EditorGUILayout.Space(); // Sorting Layers SpineInspectorUtility.SortingPropertyFields(sortingProperties, applyModifiedProperties: true); if (!TargetIsValid) { return; } // More Render Options... using (new SpineInspectorUtility.BoxScope()) { if (advancedFoldout = EditorGUILayout.Foldout(advancedFoldout, "Advanced")) { using (new SpineInspectorUtility.IndentScope()) { SeparatorsField(separatorSlotNames); EditorGUILayout.Space(); using (new SpineInspectorUtility.LabelWidthScope()) { // Optimization options EditorGUILayout.PropertyField(meshes, MeshesLabel); EditorGUILayout.PropertyField(immutableTriangles, ImmubleTrianglesLabel); EditorGUILayout.Space(); } // Render options const float MinZSpacing = -0.1f; const float MaxZSpacing = 0f; EditorGUILayout.Slider(zSpacing, MinZSpacing, MaxZSpacing, ZSpacingLabel); EditorGUILayout.Space(); using (new SpineInspectorUtility.LabelWidthScope()) { EditorGUILayout.PropertyField(pmaVertexColors, PMAVertexColorsLabel); EditorGUILayout.PropertyField(clearStateOnDisable, ClearStateOnDisableLabel); // Optional fields. May be disabled in SkeletonRenderer. if (normals != null) { EditorGUILayout.PropertyField(normals, NormalsLabel); } if (tangents != null) { EditorGUILayout.PropertyField(tangents, TangentsLabel); } if (frontFacing != null) { EditorGUILayout.PropertyField(frontFacing); } } EditorGUILayout.Space(); } } } }
public override void OnInspectorGUI() { #pragma warning disable bool isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab); #pragma warning restore // Try to auto-assign SkeletonRenderer field. if (skeletonRenderer.objectReferenceValue == null) { var foundSkeletonRenderer = follower.GetComponentInParent <SkeletonRenderer>(); if (foundSkeletonRenderer != null) { Debug.Log("BoundingBoxFollower automatically assigned: " + foundSkeletonRenderer.gameObject.name); } else if (Event.current.type == EventType.Repaint) { Debug.Log("No Spine GameObject detected. Make sure to set this GameObject as a child of the Spine GameObject; or set BoundingBoxFollower's 'Skeleton Renderer' field in the inspector."); } skeletonRenderer.objectReferenceValue = foundSkeletonRenderer; serializedObject.ApplyModifiedProperties(); } var sr = skeletonRenderer.objectReferenceValue as SkeletonRenderer; if (sr != null && sr.gameObject == follower.gameObject) { using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) { EditorGUILayout.HelpBox("It's ideal to add BoundingBoxFollower to a separate child GameObject of the Spine GameObject.", MessageType.Warning); if (GUILayout.Button(new GUIContent("Move BoundingBoxFollower to new GameObject", Icons.boundingBox), GUILayout.Height(50f))) { AddBoundingBoxFollowerChild(sr, follower); DestroyImmediate(follower); return; } } EditorGUILayout.Space(); } EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(skeletonRenderer); EditorGUILayout.PropertyField(slotName, new GUIContent("Slot")); if (EditorGUI.EndChangeCheck()) { serializedObject.ApplyModifiedProperties(); if (!isInspectingPrefab) { rebuildRequired = true; } } using (new SpineInspectorUtility.LabelWidthScope(150f)) { EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(isTrigger); bool triggerChanged = EditorGUI.EndChangeCheck(); EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(clearStateOnDisable, new GUIContent(clearStateOnDisable.displayName, "Enable this if you are pooling your Spine GameObject")); bool clearStateChanged = EditorGUI.EndChangeCheck(); if (clearStateChanged || triggerChanged) { serializedObject.ApplyModifiedProperties(); if (triggerChanged) { foreach (var col in follower.colliderTable.Values) { col.isTrigger = isTrigger.boolValue; } } } } if (isInspectingPrefab) { follower.colliderTable.Clear(); follower.nameTable.Clear(); EditorGUILayout.HelpBox("BoundingBoxAttachments cannot be previewed in prefabs.", MessageType.Info); // How do you prevent components from being saved into the prefab? No such HideFlag. DontSaveInEditor | DontSaveInBuild does not work. DestroyImmediate does not work. var collider = follower.GetComponent <PolygonCollider2D>(); if (collider != null) { Debug.LogWarning("Found BoundingBoxFollower collider components in prefab. These are disposed and regenerated at runtime."); } } else { using (new SpineInspectorUtility.BoxScope()) { if (debugIsExpanded = EditorGUILayout.Foldout(debugIsExpanded, "Debug Colliders")) { EditorGUI.indentLevel++; EditorGUILayout.LabelField(string.Format("Attachment Names ({0} PolygonCollider2D)", follower.colliderTable.Count)); EditorGUI.BeginChangeCheck(); foreach (var kp in follower.nameTable) { string attachmentName = kp.Value; var collider = follower.colliderTable[kp.Key]; bool isPlaceholder = attachmentName != kp.Key.Name; collider.enabled = EditorGUILayout.ToggleLeft(new GUIContent(!isPlaceholder ? attachmentName : string.Format("{0} [{1}]", attachmentName, kp.Key.Name), isPlaceholder ? Icons.skinPlaceholder : Icons.boundingBox), collider.enabled); } sceneRepaintRequired |= EditorGUI.EndChangeCheck(); EditorGUI.indentLevel--; } } } bool hasBoneFollower = follower.GetComponent <BoneFollower>() != null; if (!hasBoneFollower) { bool buttonDisabled = follower.Slot == null; using (new EditorGUI.DisabledGroupScope(buttonDisabled)) { addBoneFollower |= SpineInspectorUtility.LargeCenteredButton(AddBoneFollowerLabel, true); EditorGUILayout.Space(); } } if (Event.current.type == EventType.Repaint) { if (addBoneFollower) { var boneFollower = follower.gameObject.AddComponent <BoneFollower>(); boneFollower.SetBone(follower.Slot.Data.BoneData.Name); addBoneFollower = false; } if (sceneRepaintRequired) { SceneView.RepaintAll(); sceneRepaintRequired = false; } if (rebuildRequired) { follower.Initialize(); rebuildRequired = false; } } }
override public void OnInspectorGUI() { // Multi-Editing if (serializedObject.isEditingMultipleObjects) { OnInspectorGUIMulti(); return; } { // Lazy initialization because accessing EditorStyles values in OnEnable during a recompile causes UnityEditor to throw null exceptions. (Unity 5.3.5) idlePlayButtonStyle = idlePlayButtonStyle ?? new GUIStyle(EditorStyles.miniButton); if (activePlayButtonStyle == null) { activePlayButtonStyle = new GUIStyle(idlePlayButtonStyle); activePlayButtonStyle.normal.textColor = Color.red; } } serializedObject.Update(); // Header EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(target.name + " (SkeletonDataAsset)", Icons.spine), EditorStyles.whiteLargeLabel); if (targetSkeletonData != null) { EditorGUILayout.LabelField("(Drag and Drop to instantiate.)", EditorStyles.miniLabel); } // Main Serialized Fields using (var changeCheck = new EditorGUI.ChangeCheckScope()) { using (new SpineInspectorUtility.BoxScope()) DrawSkeletonDataFields(); using (new SpineInspectorUtility.BoxScope()) { DrawAtlasAssetsFields(); HandleAtlasAssetsNulls(); } if (changeCheck.changed) { if (serializedObject.ApplyModifiedProperties()) { this.Clear(); this.InitializeEditor(); return; } } } // Unity Quirk: Some code depends on valid preview. If preview is initialized elsewhere, this can cause contents to change between Layout and Repaint events, causing GUILayout control count errors. if (warnings.Count <= 0) { preview.Initialize(targetSkeletonDataAsset, this.LastSkinName); } if (targetSkeletonData != null) { GUILayout.Space(20f); using (new SpineInspectorUtility.BoxScope(false)) { EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Mix Settings", Icons.animationRoot), EditorStyles.boldLabel); DrawAnimationStateInfo(); EditorGUILayout.Space(); } EditorGUILayout.LabelField("Preview", EditorStyles.boldLabel); DrawAnimationList(); EditorGUILayout.Space(); DrawSlotList(); EditorGUILayout.Space(); DrawUnityTools(); } else { #if !SPINE_TK2D // Draw Reimport Button using (new EditorGUI.DisabledGroupScope(skeletonJSON.objectReferenceValue == null)) { if (GUILayout.Button(SpineInspectorUtility.TempContent("Attempt Reimport", Icons.warning))) { DoReimport(); } } #else EditorGUILayout.HelpBox("Couldn't load SkeletonData.", MessageType.Error); #endif DrawWarningList(); } if (!Application.isPlaying) { serializedObject.ApplyModifiedProperties(); } }
void DrawAnimationList() { showAnimationList = EditorGUILayout.Foldout(showAnimationList, SpineInspectorUtility.TempContent(string.Format("Animations [{0}]", targetSkeletonData.Animations.Count), Icons.animationRoot)); if (!showAnimationList) { return; } bool isPreviewWindowOpen = preview.IsValid; if (isPreviewWindowOpen) { if (GUILayout.Button(SpineInspectorUtility.TempContent("Setup Pose", Icons.skeleton), GUILayout.Width(105), GUILayout.Height(18))) { preview.ClearAnimationSetupPose(); preview.RefreshOnNextUpdate(); } } else { EditorGUILayout.HelpBox("Animations can be previewed if you expand the Preview window below.", MessageType.Info); } EditorGUILayout.LabelField("Name", " Duration"); bool nonessential = targetSkeletonData.ImagesPath != null; // Currently the only way to determine if skeleton data has nonessential data. (Spine 3.6) float fps = targetSkeletonData.Fps; if (nonessential && fps == 0) { fps = 30; } var activeTrack = preview.ActiveTrack; foreach (Animation animation in targetSkeletonData.Animations) { using (new GUILayout.HorizontalScope()) { if (isPreviewWindowOpen) { bool active = activeTrack != null && activeTrack.Animation == animation; //bool sameAndPlaying = active && activeTrack.TimeScale > 0f; if (GUILayout.Button("\u25BA", active ? activePlayButtonStyle : idlePlayButtonStyle, GUILayout.Width(24))) { preview.PlayPauseAnimation(animation.Name, true); activeTrack = preview.ActiveTrack; } } else { GUILayout.Label("-", GUILayout.Width(24)); } string frameCountString = (fps > 0) ? ("(" + (Mathf.RoundToInt(animation.Duration * fps)) + ")").PadLeft(12, ' ') : string.Empty; EditorGUILayout.LabelField(new GUIContent(animation.Name, Icons.animation), SpineInspectorUtility.TempContent(animation.Duration.ToString("f3") + "s" + frameCountString)); } } }
void OnGUI() { so = so ?? new SerializedObject(this); EditorGUIUtility.wideMode = true; EditorGUILayout.LabelField("Spine SpriteAtlas Import", EditorStyles.boldLabel); using (new SpineInspectorUtility.BoxScope()) { EditorGUI.BeginChangeCheck(); var spriteAtlasAssetProperty = so.FindProperty("spriteAtlasAsset"); EditorGUILayout.PropertyField(spriteAtlasAssetProperty, new GUIContent("SpriteAtlas", EditorGUIUtility.IconContent("SpriteAtlas Icon").image)); if (EditorGUI.EndChangeCheck()) { so.ApplyModifiedProperties(); if (spriteAtlasAsset != null) { if (AssetUtility.SpriteAtlasSettingsNeedAdjustment(spriteAtlasAsset)) { AssetUtility.AdjustSpriteAtlasSettings(spriteAtlasAsset); } GenerateAssetsFromSpriteAtlas(spriteAtlasAsset); } } var spineSpriteAtlasAssetProperty = so.FindProperty("spineSpriteAtlasAsset"); EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(spineSpriteAtlasAssetProperty, new GUIContent("SpineSpriteAtlasAsset", EditorGUIUtility.IconContent("ScriptableObject Icon").image)); if (spineSpriteAtlasAssetProperty.objectReferenceValue == null) { spineSpriteAtlasAssetProperty.objectReferenceValue = spineSpriteAtlasAsset = FindSpineSpriteAtlasAsset(spriteAtlasAsset); } if (EditorGUI.EndChangeCheck()) { so.ApplyModifiedProperties(); } EditorGUILayout.Space(); using (new EditorGUI.DisabledScope(spineSpriteAtlasAsset == null)) { if (SpineInspectorUtility.LargeCenteredButton(new GUIContent("Load regions by entering Play mode"))) { GenerateAssetsFromSpriteAtlas(spriteAtlasAsset); SpineSpriteAtlasAsset.UpdateByStartingEditorPlayMode(); } } using (new SpineInspectorUtility.BoxScope()) { if (spriteAtlasAsset == null) { EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Please assign SpriteAtlas file.", Icons.warning), GUILayout.Height(46)); } else if (spineSpriteAtlasAsset == null || spineSpriteAtlasAsset.RegionsNeedLoading) { EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Please hit 'Load regions ..' to load\nregion info. Play mode is started\nand stopped automatically.", Icons.warning), GUILayout.Height(54)); } else { EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("SpriteAtlas imported\nsuccessfully.", Icons.spine), GUILayout.Height(46)); } } } bool isAtlasComplete = (spineSpriteAtlasAsset != null && !spineSpriteAtlasAsset.RegionsNeedLoading); bool canImportSkeleton = (spriteAtlasAsset != null && skeletonDataFile != null); using (new SpineInspectorUtility.BoxScope()) { using (new EditorGUI.DisabledScope(!isAtlasComplete)) { var skeletonDataAssetProperty = so.FindProperty("skeletonDataFile"); EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(skeletonDataAssetProperty, SpineInspectorUtility.TempContent("Skeleton json/skel file", Icons.spine)); if (EditorGUI.EndChangeCheck()) { so.ApplyModifiedProperties(); } EditorGUILayout.Space(); } using (new EditorGUI.DisabledScope(!canImportSkeleton)) { if (SpineInspectorUtility.LargeCenteredButton(new GUIContent("Import Skeleton"))) { //AssetUtility.IngestSpriteAtlas(spriteAtlasAsset, null); string skeletonPath = AssetDatabase.GetAssetPath(skeletonDataFile); string[] skeletons = new string[] { skeletonPath }; AssetUtility.ImportSpineContent(skeletons, null); } } } }
override public void OnInspectorGUI() { if (serializedObject.isEditingMultipleObjects) { DrawDefaultInspector(); return; } serializedObject.Update(); atlasAsset = (atlasAsset == null) ? (SpineSpriteAtlasAsset)target : atlasAsset; if (atlasAsset.RegionsNeedLoading) { if (GUILayout.Button(SpineInspectorUtility.TempContent("Load regions by entering Play mode"), GUILayout.Height(20))) { EditorApplication.isPlaying = true; } } EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(atlasFile); EditorGUILayout.PropertyField(materials, true); if (EditorGUI.EndChangeCheck()) { serializedObject.ApplyModifiedProperties(); atlasAsset.Clear(); atlasAsset.GetAtlas(); atlasAsset.updateRegionsInPlayMode = true; } 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; } } if (atlasFile.objectReferenceValue != null) { int baseIndent = EditorGUI.indentLevel; var regions = SpineSpriteAtlasAssetInspector.GetRegions(atlasAsset.GetAtlas()); int regionsCount = regions.Count; using (new EditorGUILayout.HorizontalScope()) { EditorGUILayout.LabelField("Atlas Regions", EditorStyles.boldLabel); EditorGUILayout.LabelField(string.Format("{0} regions total", regionsCount)); } AtlasPage lastPage = null; for (int i = 0; i < regionsCount; 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); } } string regionName = regions[i].name; Texture2D icon = SpineEditorUtilities.Icons.image; if (regionName.EndsWith(" ")) { regionName = string.Format("'{0}'", regions[i].name); icon = SpineEditorUtilities.Icons.warning; EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(regionName, icon, "Region name ends with whitespace. This may cause errors. Please check your source image filenames.")); } else { EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(regionName, icon)); } } EditorGUI.indentLevel = baseIndent; } if (serializedObject.ApplyModifiedProperties() || SpineInspectorUtility.UndoRedoPerformed(Event.current)) { atlasAsset.Clear(); } }
public override void OnInspectorGUI () { animationNameProperty = animationNameProperty ?? serializedObject.FindProperty("animationName"); string animationName = animationNameProperty.stringValue; Animation animation = null; if (ThisSkeletonDataAsset != null) { var skeletonData = ThisSkeletonDataAsset.GetSkeletonData(true); if (skeletonData != null) { animation = skeletonData.FindAnimation(animationName); } } bool animationNotFound = (animation == null); if (changeNextFrame) { changeNextFrame = false; if (ThisSkeletonDataAsset != lastSkeletonDataAsset) { preview.Clear(); preview.Initialize(Repaint, ThisSkeletonDataAsset, LastSkinName); if (animationNotFound) { animationNameProperty.stringValue = ""; preview.ClearAnimationSetupPose(); } } preview.ClearAnimationSetupPose(); if (!string.IsNullOrEmpty(animationNameProperty.stringValue)) preview.PlayPauseAnimation(animationNameProperty.stringValue, true); } lastSkeletonDataAsset = ThisSkeletonDataAsset; //EditorGUILayout.HelpBox(AnimationReferenceAssetEditor.InspectorHelpText, MessageType.Info, true); EditorGUILayout.Space(); EditorGUI.BeginChangeCheck(); DrawDefaultInspector(); if (EditorGUI.EndChangeCheck()) { changeNextFrame = true; } // Draw extra info below default inspector. EditorGUILayout.Space(); if (ThisSkeletonDataAsset == null) { EditorGUILayout.HelpBox("SkeletonDataAsset is missing.", MessageType.Error); } else if (string.IsNullOrEmpty(animationName)) { EditorGUILayout.HelpBox("No animation selected.", MessageType.Warning); } else if (animationNotFound) { EditorGUILayout.HelpBox(string.Format("Animation named {0} was not found for this Skeleton.", animationNameProperty.stringValue), MessageType.Warning); } else { using (new SpineInspectorUtility.BoxScope()) { if (!string.Equals(SpineEditorUtilities.GetPathSafeName(animationName), ThisAnimationReferenceAsset.name, System.StringComparison.OrdinalIgnoreCase)) EditorGUILayout.HelpBox("Animation name value does not match this asset's name. Inspectors using this asset may be misleading.", MessageType.None); EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(animationName, SpineEditorUtilities.Icons.animation)); if (animation != null) { EditorGUILayout.LabelField(string.Format("Timelines: {0}", animation.Timelines.Count)); EditorGUILayout.LabelField(string.Format("Duration: {0} sec", animation.Duration)); } } } }
protected virtual void DrawInspectorGUI() { SkeletonRenderer component = (SkeletonRenderer)target; EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(skeletonDataAsset); float reloadWidth = GUI.skin.label.CalcSize(new GUIContent("Reload")).x + 20; if (GUILayout.Button("Reload", GUILayout.Width(reloadWidth))) { if (component.skeletonDataAsset != null) { foreach (AtlasAsset aa in component.skeletonDataAsset.atlasAssets) { if (aa != null) { aa.Reset(); } } component.skeletonDataAsset.Reset(); } component.Initialize(true); } EditorGUILayout.EndHorizontal(); if (!component.valid) { component.Initialize(true); component.LateUpdate(); if (!component.valid) { return; } } // Initial skin name. { String[] skins = new String[component.skeleton.Data.Skins.Count]; int skinIndex = 0; for (int i = 0; i < skins.Length; i++) { String skinNameString = component.skeleton.Data.Skins.Items[i].Name; skins[i] = skinNameString; if (skinNameString == initialSkinName.stringValue) { skinIndex = i; } } skinIndex = EditorGUILayout.Popup("Initial Skin", skinIndex, skins); initialSkinName.stringValue = skins[skinIndex]; } EditorGUILayout.Space(); // Sorting Layers { SpineInspectorUtility.SortingPropertyFields(sortingProperties, applyModifiedProperties: true); } // More Render Options... { using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) { EditorGUI.indentLevel++; advancedFoldout = EditorGUILayout.Foldout(advancedFoldout, "Advanced"); if (advancedFoldout) { EditorGUI.indentLevel++; SeparatorsField(separatorSlotNames); EditorGUILayout.PropertyField(meshes, new GUIContent("Render Mesh Attachments", "Disable to optimize rendering for skeletons that don't use Mesh Attachments")); EditorGUILayout.PropertyField(immutableTriangles, new GUIContent("Immutable Triangles", "Enable to optimize rendering for skeletons that never change attachment visbility")); EditorGUILayout.Space(); const float MinZSpacing = -0.1f; const float MaxZSpacing = 0f; EditorGUILayout.Slider(zSpacing, MinZSpacing, MaxZSpacing); if (normals != null) { EditorGUILayout.PropertyField(normals); EditorGUILayout.PropertyField(tangents); } if (front != null) { EditorGUILayout.PropertyField(front); } EditorGUI.indentLevel--; } EditorGUI.indentLevel--; } } }
public override void OnInspectorGUI() { #if !NEW_PREFAB_SYSTEM if (isPrefab) { GUILayout.Label(new GUIContent("Cannot edit Prefabs", Icons.warning)); return; } #endif serializedObject.Update(); if ((skeletonRenderer != null && !skeletonRenderer.valid) || (skeletonGraphic != null && !skeletonGraphic.IsValid)) { GUILayout.Label(new GUIContent("Spine Component invalid. Check Skeleton Data Asset.", Icons.warning)); return; } EditorGUILayout.PropertyField(serializedObject.FindProperty("boneRoot"), SpineInspectorUtility.TempContent("Skeleton Root")); EditorGUILayout.PropertyField(serializedObject.FindProperty("flipBy180DegreeRotation"), SpineInspectorUtility.TempContent("Flip by Rotation", null, "If true, Skeleton.ScaleX and Skeleton.ScaleY are followed " + "by 180 degree rotation. If false, negative Transform scale is used. " + "Note that using negative scale is consistent with previous behaviour (hence the default), " + "however causes serious problems with rigidbodies and physics. Therefore, it is recommended to " + "enable this parameter where possible. When creating hinge chains for a chain of skeleton bones " + "via SkeletonUtilityBone, it is mandatory to have this parameter enabled.")); bool hasRootBone = skeletonUtility.boneRoot != null; if (!hasRootBone) { EditorGUILayout.HelpBox("No hierarchy found. Use Spawn Hierarchy to generate GameObjects for bones.", MessageType.Info); } using (new EditorGUI.DisabledGroupScope(hasRootBone)) { if (SpineInspectorUtility.LargeCenteredButton(SpawnHierarchyButtonLabel)) { SpawnHierarchyContextMenu(); } } if (hasRootBone) { if (SpineInspectorUtility.CenteredButton(new GUIContent("Remove Hierarchy"))) { Undo.RegisterCompleteObjectUndo(skeletonUtility, "Remove Hierarchy"); Undo.DestroyObjectImmediate(skeletonUtility.boneRoot.gameObject); skeletonUtility.boneRoot = null; } } serializedObject.ApplyModifiedProperties(); }
public override void OnInspectorGUI() { if (UnityEngine.Event.current.type == EventType.Layout) { if (forceReloadQueued) { forceReloadQueued = false; foreach (var c in targets) { SpineEditorUtilities.ReloadSkeletonDataAssetAndComponent(c as SkeletonGraphic); } } else { foreach (var c in targets) { var component = c as SkeletonGraphic; if (!component.IsValid) { SpineEditorUtilities.ReinitializeComponent(component); if (!component.IsValid) { continue; } } } } } bool wasChanged = false; EditorGUI.BeginChangeCheck(); using (new EditorGUILayout.HorizontalScope(EditorStyles.helpBox)) { SpineInspectorUtility.PropertyFieldFitLabel(skeletonDataAsset, SkeletonDataAssetLabel); if (GUILayout.Button(ReloadButtonString, ReloadButtonStyle, ReloadButtonWidth)) { forceReloadQueued = true; } } EditorGUILayout.PropertyField(material); EditorGUILayout.PropertyField(color); if (thisSkeletonGraphic.skeletonDataAsset == null) { EditorGUILayout.HelpBox("You need to assign a SkeletonDataAsset first.", MessageType.Info); serializedObject.ApplyModifiedProperties(); serializedObject.Update(); return; } bool isSingleRendererOnly = (!allowMultipleCanvasRenderers.hasMultipleDifferentValues && allowMultipleCanvasRenderers.boolValue == false); bool isSeparationEnabledButNotMultipleRenderers = isSingleRendererOnly && (!enableSeparatorSlots.hasMultipleDifferentValues && enableSeparatorSlots.boolValue == true); bool meshRendersIncorrectlyWithSingleRenderer = isSingleRendererOnly && SkeletonHasMultipleSubmeshes(); if (isSeparationEnabledButNotMultipleRenderers || meshRendersIncorrectlyWithSingleRenderer) { meshGeneratorSettings.isExpanded = true; } using (new SpineInspectorUtility.BoxScope()) { EditorGUILayout.PropertyField(meshGeneratorSettings, SpineInspectorUtility.TempContent("Advanced..."), includeChildren: true); SkeletonRendererInspector.advancedFoldout = meshGeneratorSettings.isExpanded; if (meshGeneratorSettings.isExpanded) { EditorGUILayout.Space(); using (new SpineInspectorUtility.IndentScope()) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(allowMultipleCanvasRenderers, SpineInspectorUtility.TempContent("Multiple CanvasRenderers")); if (GUILayout.Button(new GUIContent("Trim Renderers", "Remove currently unused CanvasRenderer GameObjects. These will be regenerated whenever needed."), EditorStyles.miniButton, GUILayout.Width(100f))) { foreach (var skeletonGraphic in targets) { ((SkeletonGraphic)skeletonGraphic).TrimRenderers(); } } EditorGUILayout.EndHorizontal(); // warning box if (isSeparationEnabledButNotMultipleRenderers) { using (new SpineInspectorUtility.BoxScope()) { meshGeneratorSettings.isExpanded = true; EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("'Multiple Canvas Renderers' must be enabled\nwhen 'Enable Separation' is enabled.", Icons.warning), GUILayout.Height(42), GUILayout.Width(340)); } } else if (meshRendersIncorrectlyWithSingleRenderer) { using (new SpineInspectorUtility.BoxScope()) { meshGeneratorSettings.isExpanded = true; EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("This mesh uses multiple atlas pages. You\n" + "need to enable 'Multiple Canvas Renderers'\n" + "for correct rendering. Consider packing\n" + "attachments to a single atlas page if possible.", Icons.warning), GUILayout.Height(60), GUILayout.Width(340)); } } } EditorGUILayout.Space(); SeparatorsField(separatorSlotNames, enableSeparatorSlots, updateSeparatorPartLocation); } } EditorGUILayout.Space(); EditorGUILayout.PropertyField(initialSkinName); { var rect = GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, EditorGUIUtility.singleLineHeight); EditorGUI.PrefixLabel(rect, SpineInspectorUtility.TempContent("Initial Flip")); rect.x += EditorGUIUtility.labelWidth; rect.width = 30f; SpineInspectorUtility.ToggleLeft(rect, initialFlipX, SpineInspectorUtility.TempContent("X", tooltip: "initialFlipX")); rect.x += 35f; SpineInspectorUtility.ToggleLeft(rect, initialFlipY, SpineInspectorUtility.TempContent("Y", tooltip: "initialFlipY")); } EditorGUILayout.Space(); EditorGUILayout.LabelField("Animation", EditorStyles.boldLabel); EditorGUILayout.PropertyField(startingAnimation); EditorGUILayout.PropertyField(startingLoop); EditorGUILayout.PropertyField(timeScale); EditorGUILayout.PropertyField(unscaledTime, SpineInspectorUtility.TempContent(unscaledTime.displayName, tooltip: "If checked, this will use Time.unscaledDeltaTime to make this update independent of game Time.timeScale. Instance SkeletonGraphic.timeScale will still be applied.")); EditorGUILayout.Space(); EditorGUILayout.PropertyField(freeze); EditorGUILayout.Space(); SkeletonRendererInspector.SkeletonRootMotionParameter(targets); EditorGUILayout.Space(); EditorGUILayout.LabelField("UI", EditorStyles.boldLabel); EditorGUILayout.PropertyField(raycastTarget); EditorGUILayout.BeginHorizontal(GUILayout.Height(EditorGUIUtility.singleLineHeight + 5)); EditorGUILayout.PrefixLabel("Match RectTransform with Mesh"); if (GUILayout.Button("Match", EditorStyles.miniButton, GUILayout.Width(65f))) { foreach (var skeletonGraphic in targets) { MatchRectTransformWithBounds((SkeletonGraphic)skeletonGraphic); } } EditorGUILayout.EndHorizontal(); if (TargetIsValid && !isInspectingPrefab) { EditorGUILayout.Space(); if (SpineInspectorUtility.CenteredButton(new GUIContent("Add Skeleton Utility", Icons.skeletonUtility), 21, true, 200f)) { foreach (var t in targets) { var component = t as Component; if (component.GetComponent <SkeletonUtility>() == null) { component.gameObject.AddComponent <SkeletonUtility>(); } } } } wasChanged |= EditorGUI.EndChangeCheck(); if (wasChanged) { serializedObject.ApplyModifiedProperties(); slotsReapplyRequired = true; } if (slotsReapplyRequired && UnityEngine.Event.current.type == EventType.Repaint) { foreach (var target in targets) { var skeletonGraphic = (SkeletonGraphic)target; skeletonGraphic.ReapplySeparatorSlotNames(); skeletonGraphic.LateUpdate(); SceneView.RepaintAll(); } slotsReapplyRequired = false; } }
public override void OnInspectorGUI() { serializedObject.Update(); EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(mode); if (EditorGUI.EndChangeCheck()) { containsOverrides = mode.enumValueIndex == 1; containsFollows = mode.enumValueIndex == 0; } using (new EditorGUI.DisabledGroupScope(multiObject)) { string str = boneName.stringValue; if (str == "") { str = "<None>"; } if (multiObject) { str = "<Multiple>"; } using (new GUILayout.HorizontalScope()) { EditorGUILayout.PrefixLabel("Bone"); if (GUILayout.Button(str, EditorStyles.popup)) { BoneSelectorContextMenu(str, ((SkeletonUtilityBone)target).hierarchy.skeletonRenderer.skeleton.Bones, "<None>", TargetBoneSelected); } } } EditorGUILayout.PropertyField(zPosition); EditorGUILayout.PropertyField(position); EditorGUILayout.PropertyField(rotation); EditorGUILayout.PropertyField(scale); using (new EditorGUI.DisabledGroupScope(containsFollows)) { EditorGUILayout.PropertyField(overrideAlpha); EditorGUILayout.PropertyField(parentReference); } EditorGUILayout.Space(); using (new GUILayout.HorizontalScope()) { EditorGUILayout.Space(); using (new EditorGUI.DisabledGroupScope(multiObject || !utilityBone.valid || utilityBone.bone == null || utilityBone.bone.Children.Count == 0)) { if (GUILayout.Button(SpineInspectorUtility.TempContent("Add Child Bone", Icons.bone), GUILayout.MinWidth(120), GUILayout.Height(24))) { BoneSelectorContextMenu("", utilityBone.bone.Children, "<Recursively>", SpawnChildBoneSelected); } } using (new EditorGUI.DisabledGroupScope(multiObject || !utilityBone.valid || utilityBone.bone == null || containsOverrides)) { if (GUILayout.Button(SpineInspectorUtility.TempContent("Add Override", Icons.poseBones), GUILayout.MinWidth(120), GUILayout.Height(24))) { SpawnOverride(); } } EditorGUILayout.Space(); } EditorGUILayout.Space(); using (new GUILayout.HorizontalScope()) { EditorGUILayout.Space(); using (new EditorGUI.DisabledGroupScope(multiObject || !utilityBone.valid || !canCreateHingeChain)) { if (GUILayout.Button(SpineInspectorUtility.TempContent("Create 3D Hinge Chain", Icons.hingeChain), GUILayout.MinWidth(120), GUILayout.Height(24))) { CreateHingeChain(); } if (GUILayout.Button(SpineInspectorUtility.TempContent("Create 2D Hinge Chain", Icons.hingeChain), GUILayout.MinWidth(120), GUILayout.Height(24))) { CreateHingeChain2D(); } } EditorGUILayout.Space(); } using (new EditorGUI.DisabledGroupScope(multiObject || boundingBoxTable.Count == 0)) { EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Bounding Boxes", Icons.boundingBox), EditorStyles.boldLabel); foreach (var entry in boundingBoxTable) { Slot slot = entry.Key; var boundingBoxes = entry.Value; EditorGUI.indentLevel++; EditorGUILayout.LabelField(slot.Data.Name); EditorGUI.indentLevel++; { foreach (var box in boundingBoxes) { using (new GUILayout.HorizontalScope()) { GUILayout.Space(30); string buttonLabel = box.IsWeighted() ? box.Name + " (!)" : box.Name; if (GUILayout.Button(buttonLabel, GUILayout.Width(200))) { utilityBone.bone.Skeleton.UpdateWorldTransform(); var bbTransform = utilityBone.transform.Find("[BoundingBox]" + box.Name); // Use FindChild in older versions of Unity. if (bbTransform != null) { var originalCollider = bbTransform.GetComponent <PolygonCollider2D>(); if (originalCollider != null) { SkeletonUtility.SetColliderPointsLocal(originalCollider, slot, box); } else { SkeletonUtility.AddBoundingBoxAsComponent(box, slot, bbTransform.gameObject); } } else { var newPolygonCollider = SkeletonUtility.AddBoundingBoxGameObject(null, box, slot, utilityBone.transform); bbTransform = newPolygonCollider.transform; } EditorGUIUtility.PingObject(bbTransform); } } } } EditorGUI.indentLevel--; EditorGUI.indentLevel--; } } BoneFollowerInspector.RecommendRigidbodyButton(utilityBone); serializedObject.ApplyModifiedProperties(); }
protected virtual void DrawInspectorGUI() { // JOHN: todo: support multiediting. SkeletonRenderer component = (SkeletonRenderer)target; using (new EditorGUILayout.HorizontalScope()) { EditorGUILayout.PropertyField(skeletonDataAsset); const string ReloadButtonLabel = "Reload"; float reloadWidth = GUI.skin.label.CalcSize(new GUIContent(ReloadButtonLabel)).x + 20; if (GUILayout.Button(ReloadButtonLabel, GUILayout.Width(reloadWidth))) { if (component.skeletonDataAsset != null) { foreach (AtlasAsset aa in component.skeletonDataAsset.atlasAssets) { if (aa != null) { aa.Reset(); } } component.skeletonDataAsset.Reset(); } component.Initialize(true); } } if (!component.valid) { component.Initialize(true); component.LateUpdate(); if (!component.valid) { return; } } #if NO_PREFAB_MESH if (meshFilter == null) { meshFilter = component.GetComponent <MeshFilter>(); } if (isInspectingPrefab) { meshFilter.sharedMesh = null; } #endif // Initial skin name. { string[] skins = new string[component.skeleton.Data.Skins.Count]; int skinIndex = 0; for (int i = 0; i < skins.Length; i++) { string skinNameString = component.skeleton.Data.Skins.Items[i].Name; skins[i] = skinNameString; if (skinNameString == initialSkinName.stringValue) { skinIndex = i; } } skinIndex = EditorGUILayout.Popup("Initial Skin", skinIndex, skins); initialSkinName.stringValue = skins[skinIndex]; } EditorGUILayout.Space(); // Sorting Layers SpineInspectorUtility.SortingPropertyFields(sortingProperties, applyModifiedProperties: true); // More Render Options... using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) { EditorGUI.indentLevel++; advancedFoldout = EditorGUILayout.Foldout(advancedFoldout, "Advanced"); if (advancedFoldout) { EditorGUI.indentLevel++; SeparatorsField(separatorSlotNames); EditorGUILayout.Space(); // Optimization options SpineInspectorUtility.PropertyFieldWideLabel(meshes, new GUIContent("Render MeshAttachments", "Disable to optimize rendering for skeletons that don't use Mesh Attachments")); SpineInspectorUtility.PropertyFieldWideLabel(immutableTriangles, new GUIContent("Immutable Triangles", "Enable to optimize rendering for skeletons that never change attachment visbility")); EditorGUILayout.Space(); // Render options const float MinZSpacing = -0.1f; const float MaxZSpacing = 0f; EditorGUILayout.Slider(zSpacing, MinZSpacing, MaxZSpacing); EditorGUILayout.Space(); SpineInspectorUtility.PropertyFieldWideLabel(pmaVertexColors, new GUIContent("PMA Vertex Colors", "Use this if you are using the default Spine/Skeleton shader or any premultiply-alpha shader.")); // Optional fields. May be disabled in SkeletonRenderer. if (normals != null) { SpineInspectorUtility.PropertyFieldWideLabel(normals, new GUIContent("Add Normals")); } if (tangents != null) { SpineInspectorUtility.PropertyFieldWideLabel(tangents, new GUIContent("Solve Tangents")); } if (frontFacing != null) { SpineInspectorUtility.PropertyFieldWideLabel(frontFacing); } EditorGUI.indentLevel--; } EditorGUI.indentLevel--; } }
// MITCH: left todo: Implement preview panning /* * static Vector2 Drag2D(Vector2 scrollPosition, Rect position) * { * int controlID = GUIUtility.GetControlID(sliderHash, FocusType.Passive); * UnityEngine.Event current = UnityEngine.Event.current; * switch (current.GetTypeForControl(controlID)) * { * case EventType.MouseDown: * if (position.Contains(current.mousePosition) && (position.width > 50f)) * { * GUIUtility.hotControl = controlID; * current.Use(); * EditorGUIUtility.SetWantsMouseJumping(1); * } * return scrollPosition; * * case EventType.MouseUp: * if (GUIUtility.hotControl == controlID) * { * GUIUtility.hotControl = 0; * } * EditorGUIUtility.SetWantsMouseJumping(0); * return scrollPosition; * * case EventType.MouseMove: * return scrollPosition; * * case EventType.MouseDrag: * if (GUIUtility.hotControl == controlID) * { * scrollPosition -= (Vector2) (((current.delta * (!current.shift ? ((float) 1) : ((float) 3))) / Mathf.Min(position.width, position.height)) * 140f); * scrollPosition.y = Mathf.Clamp(scrollPosition.y, -90f, 90f); * current.Use(); * GUI.changed = true; * } * return scrollPosition; * } * return scrollPosition; * } */ public override GUIContent GetPreviewTitle() { return(SpineInspectorUtility.TempContent("Preview")); }
protected override void DrawInspectorGUI(bool multi) { base.DrawInspectorGUI(multi); if (!TargetIsValid) { return; } bool sameData = SpineInspectorUtility.TargetsUseSameData(serializedObject); if (multi) { foreach (var o in targets) { TrySetAnimation(o, multi); } EditorGUILayout.Space(); if (!sameData) { EditorGUILayout.DelayedTextField(animationName); } else { EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(animationName); wasAnimationNameChanged |= EditorGUI.EndChangeCheck(); // Value used in the next update. } EditorGUILayout.PropertyField(loop); EditorGUILayout.PropertyField(timeScale); EditorGUILayout.PropertyField(ignoreTimeScale); foreach (var o in targets) { var component = o as SkeletonAnimation; component.timeScale = Mathf.Max(component.timeScale, 0); } } else { TrySetAnimation(target, multi); EditorGUILayout.Space(); EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(animationName); wasAnimationNameChanged |= EditorGUI.EndChangeCheck(); // Value used in the next update. EditorGUILayout.PropertyField(loop, LoopLabel); EditorGUILayout.PropertyField(timeScale, TimeScaleLabel); EditorGUILayout.PropertyField(ignoreTimeScale, IgnoreTimeScaleLabel); var component = (SkeletonAnimation)target; component.timeScale = Mathf.Max(component.timeScale, 0); } if (!isInspectingPrefab) { if (requireRepaint) { SceneView.RepaintAll(); requireRepaint = false; } DrawSkeletonUtilityButton(multi); } }
override public void OnInspectorGUI() { if (serializedObject.isEditingMultipleObjects) { using (new SpineInspectorUtility.BoxScope()) { EditorGUILayout.LabelField("SkeletonData", EditorStyles.boldLabel); EditorGUILayout.PropertyField(skeletonJSON, SpineInspectorUtility.TempContent(skeletonJSON.displayName, Icons.spine)); EditorGUILayout.PropertyField(scale); } using (new SpineInspectorUtility.BoxScope()) { EditorGUILayout.LabelField("Atlas", EditorStyles.boldLabel); #if !SPINE_TK2D EditorGUILayout.PropertyField(atlasAssets, true); #else using (new EditorGUI.DisabledGroupScope(spriteCollection.objectReferenceValue != null)) { EditorGUILayout.PropertyField(atlasAssets, true); } EditorGUILayout.LabelField("spine-tk2d", EditorStyles.boldLabel); EditorGUILayout.PropertyField(spriteCollection, true); #endif } using (new SpineInspectorUtility.BoxScope()) { EditorGUILayout.LabelField("Mix Settings", EditorStyles.boldLabel); SpineInspectorUtility.PropertyFieldWideLabel(defaultMix, DefaultMixLabel, 160); EditorGUILayout.Space(); } return; } { // Lazy initialization because accessing EditorStyles values in OnEnable during a recompile causes UnityEditor to throw null exceptions. (Unity 5.3.5) idlePlayButtonStyle = idlePlayButtonStyle ?? new GUIStyle(EditorStyles.miniButton); if (activePlayButtonStyle == null) { activePlayButtonStyle = new GUIStyle(idlePlayButtonStyle); activePlayButtonStyle.normal.textColor = Color.red; } } serializedObject.Update(); EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(target.name + " (SkeletonDataAsset)", Icons.spine), EditorStyles.whiteLargeLabel); if (m_skeletonData != null) { EditorGUILayout.LabelField("(Drag and Drop to instantiate.)", EditorStyles.miniLabel); } EditorGUI.BeginChangeCheck(); // SkeletonData using (new SpineInspectorUtility.BoxScope()) { using (new EditorGUILayout.HorizontalScope()) { EditorGUILayout.LabelField("SkeletonData", EditorStyles.boldLabel); if (m_skeletonData != null) { var sd = m_skeletonData; string m = string.Format("{8} - {0} {1}\nBones: {2}\nConstraints: \n {5} IK \n {6} Path \n {7} Transform\n\nSlots: {3}\nSkins: {4}\n\nAnimations: {9}", sd.Version, string.IsNullOrEmpty(sd.Version) ? "" : "export ", sd.Bones.Count, sd.Slots.Count, sd.Skins.Count, sd.IkConstraints.Count, sd.PathConstraints.Count, sd.TransformConstraints.Count, skeletonJSON.objectReferenceValue.name, sd.Animations.Count); EditorGUILayout.LabelField(GUIContent.none, new GUIContent(Icons.info, m), GUILayout.Width(30f)); } } EditorGUILayout.PropertyField(skeletonJSON, SpineInspectorUtility.TempContent(skeletonJSON.displayName, Icons.spine)); EditorGUILayout.PropertyField(scale); } // if (m_skeletonData != null) { // if (SpineInspectorUtility.CenteredButton(new GUIContent("Instantiate", Icons.spine, "Creates a new Spine GameObject in the active scene using this Skeleton Data.\nYou can also instantiate by dragging the SkeletonData asset from Project view into Scene View."))) // SpineEditorUtilities.ShowInstantiateContextMenu(this.m_skeletonDataAsset, Vector3.zero); // } // Atlas using (new SpineInspectorUtility.BoxScope()) { EditorGUILayout.LabelField("Atlas", EditorStyles.boldLabel); #if !SPINE_TK2D EditorGUILayout.PropertyField(atlasAssets, true); #else using (new EditorGUI.DisabledGroupScope(spriteCollection.objectReferenceValue != null)) { EditorGUILayout.PropertyField(atlasAssets, true); } EditorGUILayout.LabelField("spine-tk2d", EditorStyles.boldLabel); EditorGUILayout.PropertyField(spriteCollection, true); #endif { bool hasNulls = false; foreach (var a in m_skeletonDataAsset.atlasAssets) { if (a == null) { hasNulls = true; break; } } if (hasNulls) { if (m_skeletonDataAsset.atlasAssets.Length == 1) { EditorGUILayout.HelpBox("Atlas array cannot have null entries!", MessageType.None); } else { EditorGUILayout.HelpBox("Atlas array should not have null entries!", MessageType.Error); if (SpineInspectorUtility.CenteredButton(SpineInspectorUtility.TempContent("Remove null entries"))) { var trimmedAtlasAssets = new List <AtlasAsset>(); foreach (var a in m_skeletonDataAsset.atlasAssets) { if (a != null) { trimmedAtlasAssets.Add(a); } } m_skeletonDataAsset.atlasAssets = trimmedAtlasAssets.ToArray(); serializedObject.Update(); } } } } } if (EditorGUI.EndChangeCheck()) { if (serializedObject.ApplyModifiedProperties()) { if (m_previewUtility != null) { m_previewUtility.Cleanup(); m_previewUtility = null; } m_skeletonDataAsset.Clear(); m_skeletonData = null; OnEnable(); // Should call RepopulateWarnings. return; } } // Some code depends on the existence of m_skeletonAnimation instance. // If m_skeletonAnimation is lazy-instantiated elsewhere, this can cause contents to change between Layout and Repaint events, causing GUILayout control count errors. InitPreview(); if (m_skeletonData != null) { GUILayout.Space(20f); using (new SpineInspectorUtility.BoxScope(false)) { EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Mix Settings", Icons.animationRoot), EditorStyles.boldLabel); DrawAnimationStateInfo(); EditorGUILayout.Space(); } EditorGUILayout.LabelField("Preview", EditorStyles.boldLabel); DrawAnimationList(); EditorGUILayout.Space(); DrawSlotList(); EditorGUILayout.Space(); DrawUnityTools(); } else { #if !SPINE_TK2D // Reimport Button using (new EditorGUI.DisabledGroupScope(skeletonJSON.objectReferenceValue == null)) { if (GUILayout.Button(SpineInspectorUtility.TempContent("Attempt Reimport", Icons.warning))) { DoReimport(); } } #else EditorGUILayout.HelpBox("Couldn't load SkeletonData.", MessageType.Error); #endif // List warnings. foreach (var line in warnings) { EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(line, Icons.warning)); } } if (!Application.isPlaying) { serializedObject.ApplyModifiedProperties(); } }
// Window GUI void OnGUI() { bool requireRepaint = false; if (staticLostValues) { Clear(); OnSelectionChange(); staticLostValues = false; requireRepaint = true; } if (SlotsRootLabel == null) { SlotsRootLabel = new GUIContent("Slots", Icons.slotRoot); SkeletonRootLabel = new GUIContent("Skeleton", Icons.skeleton); BoldFoldoutStyle = new GUIStyle(EditorStyles.foldout); BoldFoldoutStyle.fontStyle = FontStyle.Bold; BoldFoldoutStyle.stretchWidth = true; BoldFoldoutStyle.fixedWidth = 0; } EditorGUILayout.Space(); EditorGUI.BeginDisabledGroup(true); EditorGUILayout.ObjectField(SpineInspectorUtility.TempContent("Debug Selection", Icons.spine), skeletonRenderer, typeof(SkeletonRenderer), true); EditorGUI.EndDisabledGroup(); if (skeleton == null || skeletonRenderer == null) { EditorGUILayout.HelpBox("No SkeletonRenderer Spine GameObject selected.", MessageType.Info); return; } if (isPrefab) { EditorGUILayout.HelpBox("SkeletonDebug only debugs Spine GameObjects in the scene.", MessageType.Warning); return; } if (!skeletonRenderer.valid) { EditorGUILayout.HelpBox("Spine Component is invalid. Check SkeletonData Asset.", MessageType.Error); return; } if (activeSkin != skeleton.Skin) { UpdateAttachments(); } scrollPos = EditorGUILayout.BeginScrollView(scrollPos); using (new SpineInspectorUtility.BoxScope(false)) { if (SpineInspectorUtility.CenteredButton(SpineInspectorUtility.TempContent("Skeleton.SetToSetupPose()"))) { skeleton.SetToSetupPose(); requireRepaint = true; } EditorGUI.BeginChangeCheck(); EditorGUILayout.LabelField("Scene View", EditorStyles.boldLabel); using (new SpineInspectorUtility.LabelWidthScope()) { showBoneNames = EditorGUILayout.Toggle("Show Bone Names", showBoneNames); showPaths = EditorGUILayout.Toggle("Show Paths", showPaths); showShapes = EditorGUILayout.Toggle("Show Shapes", showShapes); showConstraints = EditorGUILayout.Toggle("Show Constraints", showConstraints); } requireRepaint |= EditorGUI.EndChangeCheck(); // Skeleton showSkeleton.target = EditorGUILayout.Foldout(showSkeleton.target, SkeletonRootLabel, BoldFoldoutStyle); if (showSkeleton.faded > 0) { using (new SpineInspectorUtility.IndentScope()) { using (new EditorGUILayout.FadeGroupScope(showSkeleton.faded)) { EditorGUI.BeginChangeCheck(); EditorGUI.BeginDisabledGroup(true); FalseDropDown(".Skin", skeleton.Skin != null ? skeletonRenderer.Skeleton.Skin.Name : "<None>", Icons.skin); EditorGUI.EndDisabledGroup(); // Flip EditorGUILayout.BeginHorizontal(GUILayout.MaxWidth(160f)); EditorGUILayout.LabelField("Flip", GUILayout.MaxWidth(EditorGUIUtility.labelWidth - 20f)); skeleton.FlipX = EditorGUILayout.ToggleLeft(".FlipX", skeleton.FlipX, GUILayout.MaxWidth(70f)); skeleton.FlipY = EditorGUILayout.ToggleLeft(".FlipY", skeleton.FlipY, GUILayout.MaxWidth(70f)); GUILayout.EndHorizontal(); // Color skeleton.SetColor(EditorGUILayout.ColorField(".R .G .B .A", skeleton.GetColor())); requireRepaint |= EditorGUI.EndChangeCheck(); } } } // Bone showInspectBoneTree.target = EditorGUILayout.Foldout(showInspectBoneTree.target, SpineInspectorUtility.TempContent("Bone", Icons.bone), BoldFoldoutStyle); if (showInspectBoneTree.faded > 0) { using (new SpineInspectorUtility.IndentScope()) { using (new EditorGUILayout.FadeGroupScope(showInspectBoneTree.faded)) { showBoneNames = EditorGUILayout.Toggle("Show Bone Names", showBoneNames); if (bpo == null) { bpo = new SerializedObject(this).FindProperty("boneName"); } EditorGUILayout.PropertyField(bpo, SpineInspectorUtility.TempContent("Bone")); if (!string.IsNullOrEmpty(bpo.stringValue)) { if (bone == null || bone.Data.Name != bpo.stringValue) { bone = skeleton.FindBone(bpo.stringValue); } if (bone != null) { using (new EditorGUI.DisabledGroupScope(true)) { var wm = EditorGUIUtility.wideMode; EditorGUIUtility.wideMode = true; EditorGUILayout.Slider("Local Rotation", ViewRound(bone.Rotation), -180f, 180f); EditorGUILayout.Vector2Field("Local Position", RoundVector2(bone.X, bone.Y)); EditorGUILayout.Vector2Field("Local Scale", RoundVector2(bone.ScaleX, bone.ScaleY)); EditorGUILayout.Vector2Field("Local Shear", RoundVector2(bone.ShearX, bone.ShearY)); EditorGUILayout.Space(); var boneParent = bone.Parent; if (boneParent != null) { FalseDropDown("Parent", boneParent.Data.Name, Icons.bone); } const string RoundFormat = "0.##"; var lw = EditorGUIUtility.labelWidth; var fw = EditorGUIUtility.fieldWidth; EditorGUIUtility.labelWidth *= 0.25f; EditorGUIUtility.fieldWidth *= 0.5f; EditorGUILayout.LabelField("LocalToWorld"); EditorGUILayout.BeginHorizontal(); EditorGUILayout.Space(); EditorGUILayout.TextField(".A", bone.A.ToString(RoundFormat)); EditorGUILayout.TextField(".B", bone.B.ToString(RoundFormat)); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.Space(); EditorGUILayout.TextField(".C", bone.C.ToString(RoundFormat)); EditorGUILayout.TextField(".D", bone.D.ToString(RoundFormat)); EditorGUILayout.EndHorizontal(); EditorGUIUtility.labelWidth = lw * 0.5f; EditorGUILayout.BeginHorizontal(); EditorGUILayout.Space(); EditorGUILayout.Space(); EditorGUILayout.TextField(".WorldX", bone.WorldX.ToString(RoundFormat)); EditorGUILayout.TextField(".WorldY", bone.WorldY.ToString(RoundFormat)); EditorGUILayout.EndHorizontal(); EditorGUIUtility.labelWidth = lw; EditorGUIUtility.fieldWidth = fw; EditorGUIUtility.wideMode = wm; } } requireRepaint = true; } else { bone = null; } } } } // Slots int preSlotsIndent = EditorGUI.indentLevel; showSlotsTree.target = EditorGUILayout.Foldout(showSlotsTree.target, SlotsRootLabel, BoldFoldoutStyle); if (showSlotsTree.faded > 0) { using (new EditorGUILayout.FadeGroupScope(showSlotsTree.faded)) { if (SpineInspectorUtility.CenteredButton(SpineInspectorUtility.TempContent("Skeleton.SetSlotsToSetupPose()"))) { skeleton.SetSlotsToSetupPose(); requireRepaint = true; } int baseIndent = EditorGUI.indentLevel; foreach (KeyValuePair <Slot, List <Attachment> > pair in attachmentTable) { Slot slot = pair.Key; using (new EditorGUILayout.HorizontalScope()) { EditorGUI.indentLevel = baseIndent + 1; EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(slot.Data.Name, Icons.slot), GUILayout.ExpandWidth(false)); EditorGUI.BeginChangeCheck(); Color c = EditorGUILayout.ColorField(new Color(slot.R, slot.G, slot.B, slot.A), GUILayout.Width(60)); if (EditorGUI.EndChangeCheck()) { slot.SetColor(c); requireRepaint = true; } } foreach (var attachment in pair.Value) { GUI.contentColor = slot.Attachment == attachment ? Color.white : Color.grey; EditorGUI.indentLevel = baseIndent + 2; var icon = Icons.GetAttachmentIcon(attachment); bool isAttached = (attachment == slot.Attachment); bool swap = EditorGUILayout.ToggleLeft(SpineInspectorUtility.TempContent(attachment.Name, icon), attachment == slot.Attachment); if (isAttached != swap) { slot.Attachment = isAttached ? null : attachment; requireRepaint = true; } GUI.contentColor = Color.white; } } } } EditorGUI.indentLevel = preSlotsIndent; // Constraints const string NoneText = "<none>"; showConstraintsTree.target = EditorGUILayout.Foldout(showConstraintsTree.target, SpineInspectorUtility.TempContent("Constraints", Icons.constraintRoot), BoldFoldoutStyle); if (showConstraintsTree.faded > 0) { using (new SpineInspectorUtility.IndentScope()) { using (new EditorGUILayout.FadeGroupScope(showConstraintsTree.faded)) { const float MixMin = 0f; const float MixMax = 1f; EditorGUI.BeginChangeCheck(); showConstraints = EditorGUILayout.Toggle("Show Constraints", showConstraints); requireRepaint |= EditorGUI.EndChangeCheck(); EditorGUILayout.Space(); EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(string.Format("IK Constraints ({0})", skeleton.IkConstraints.Count), Icons.constraintIK), EditorStyles.boldLabel); using (new SpineInspectorUtility.IndentScope()) { if (skeleton.IkConstraints.Count > 0) { foreach (var c in skeleton.IkConstraints) { EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(c.Data.Name, Icons.constraintIK)); FalseDropDown("Goal", c.Data.Target.Name, Icons.bone, true); EditorGUI.BeginChangeCheck(); c.Mix = EditorGUILayout.Slider("Mix", c.Mix, MixMin, MixMax); c.BendDirection = EditorGUILayout.Toggle(SpineInspectorUtility.TempContent("Bend Clockwise", tooltip: "IkConstraint.BendDirection == 1 if clockwise; -1 if counterclockwise."), c.BendDirection > 0) ? 1 : -1; if (EditorGUI.EndChangeCheck()) { requireRepaint = true; } EditorGUILayout.Space(); } } else { EditorGUILayout.LabelField(NoneText); } } EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(string.Format("Transform Constraints ({0})", skeleton.TransformConstraints.Count), Icons.constraintTransform), EditorStyles.boldLabel); using (new SpineInspectorUtility.IndentScope()) { if (skeleton.TransformConstraints.Count > 0) { foreach (var c in skeleton.TransformConstraints) { EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(c.Data.Name, Icons.constraintTransform)); EditorGUI.BeginDisabledGroup(true); FalseDropDown("Goal", c.Data.Target.Name, Icons.bone); EditorGUI.EndDisabledGroup(); EditorGUI.BeginChangeCheck(); c.TranslateMix = EditorGUILayout.Slider("TranslateMix", c.TranslateMix, MixMin, MixMax); c.RotateMix = EditorGUILayout.Slider("RotateMix", c.RotateMix, MixMin, MixMax); c.ScaleMix = EditorGUILayout.Slider("ScaleMix", c.ScaleMix, MixMin, MixMax); c.ShearMix = EditorGUILayout.Slider("ShearMix", c.ShearMix, MixMin, MixMax); if (EditorGUI.EndChangeCheck()) { requireRepaint = true; } EditorGUILayout.Space(); } } else { EditorGUILayout.LabelField(NoneText); } } EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(string.Format("Path Constraints ({0})", skeleton.PathConstraints.Count), Icons.constraintPath), EditorStyles.boldLabel); EditorGUI.BeginChangeCheck(); showPaths = EditorGUILayout.Toggle("Show Paths", showPaths); requireRepaint |= EditorGUI.EndChangeCheck(); using (new SpineInspectorUtility.IndentScope()) { if (skeleton.PathConstraints.Count > 0) { foreach (var c in skeleton.PathConstraints) { EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(c.Data.Name, Icons.constraintPath)); EditorGUI.BeginDisabledGroup(true); FalseDropDown("Path Slot", c.Data.Target.Name, Icons.slot); var activeAttachment = c.Target.Attachment; FalseDropDown("Active Path", activeAttachment != null ? activeAttachment.Name : "<None>", activeAttachment is PathAttachment ? Icons.path : null); EditorGUILayout.LabelField("PositionMode." + c.Data.PositionMode); EditorGUILayout.LabelField("SpacingMode." + c.Data.SpacingMode); EditorGUILayout.LabelField("RotateMode." + c.Data.RotateMode); EditorGUI.EndDisabledGroup(); EditorGUI.BeginChangeCheck(); c.RotateMix = EditorGUILayout.Slider("RotateMix", c.RotateMix, MixMin, MixMax); c.TranslateMix = EditorGUILayout.Slider("TranslateMix", c.TranslateMix, MixMin, MixMax); c.Position = EditorGUILayout.FloatField("Position", c.Position); c.Spacing = EditorGUILayout.FloatField("Spacing", c.Spacing); if (EditorGUI.EndChangeCheck()) { requireRepaint = true; } EditorGUILayout.Space(); } } else { EditorGUILayout.LabelField(NoneText); } } } } } showDrawOrderTree.target = EditorGUILayout.Foldout(showDrawOrderTree.target, SpineInspectorUtility.TempContent("Draw Order and Separators", Icons.slotRoot), BoldFoldoutStyle); if (showDrawOrderTree.faded > 0) { using (new SpineInspectorUtility.IndentScope()) { using (new EditorGUILayout.FadeGroupScope(showDrawOrderTree.faded)) { const string SeparatorString = "------------- v SEPARATOR v -------------"; if (Application.isPlaying) { foreach (var slot in skeleton.DrawOrder) { if (skeletonRenderer.separatorSlots.Contains(slot)) { EditorGUILayout.LabelField(SeparatorString); } EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(slot.Data.Name, Icons.slot), GUILayout.ExpandWidth(false)); } } else { foreach (var slot in skeleton.DrawOrder) { var slotNames = skeletonRenderer.separatorSlotNames; for (int i = 0, n = slotNames.Length; i < n; i++) { if (string.Equals(slotNames[i], slot.Data.Name, System.StringComparison.Ordinal)) { EditorGUILayout.LabelField(SeparatorString); break; } } EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(slot.Data.Name, Icons.slot), GUILayout.ExpandWidth(false)); } } } } } showEventDataTree.target = EditorGUILayout.Foldout(showEventDataTree.target, SpineInspectorUtility.TempContent("Events", Icons.userEvent), BoldFoldoutStyle); if (showEventDataTree.faded > 0) { using (new SpineInspectorUtility.IndentScope()) { using (new EditorGUILayout.FadeGroupScope(showEventDataTree.faded)) { if (skeleton.Data.Events.Count > 0) { foreach (var e in skeleton.Data.Events) { EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(e.Name, Icons.userEvent)); } } else { EditorGUILayout.LabelField(NoneText); } } } } showDataTree.target = EditorGUILayout.Foldout(showDataTree.target, SpineInspectorUtility.TempContent("Data Counts", Icons.spine), BoldFoldoutStyle); if (showDataTree.faded > 0) { using (new SpineInspectorUtility.IndentScope()) { using (new EditorGUILayout.FadeGroupScope(showDataTree.faded)) { using (new SpineInspectorUtility.LabelWidthScope()) { var skeletonData = skeleton.Data; EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Bones", Icons.bone, "Skeleton.Data.Bones"), new GUIContent(skeletonData.Bones.Count.ToString())); EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Slots", Icons.slotRoot, "Skeleton.Data.Slots"), new GUIContent(skeletonData.Slots.Count.ToString())); EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Skins", Icons.skinsRoot, "Skeleton.Data.Skins"), new GUIContent(skeletonData.Skins.Count.ToString())); EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Events", Icons.userEvent, "Skeleton.Data.Events"), new GUIContent(skeletonData.Events.Count.ToString())); EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("IK Constraints", Icons.constraintIK, "Skeleton.Data.IkConstraints"), new GUIContent(skeletonData.IkConstraints.Count.ToString())); EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Transform Constraints", Icons.constraintTransform, "Skeleton.Data.TransformConstraints"), new GUIContent(skeletonData.TransformConstraints.Count.ToString())); EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Path Constraints", Icons.constraintPath, "Skeleton.Data.PathConstraints"), new GUIContent(skeletonData.PathConstraints.Count.ToString())); } } } } if (IsAnimating(showSlotsTree, showSkeleton, showConstraintsTree, showDrawOrderTree, showEventDataTree, showInspectBoneTree, showDataTree)) { Repaint(); } } if (requireRepaint) { skeletonRenderer.LateUpdate(); Repaint(); SceneView.RepaintAll(); } EditorGUILayout.EndScrollView(); }
void DrawUnityTools() { #if SPINE_SKELETON_ANIMATOR using (new SpineInspectorUtility.BoxScope()) { isMecanimExpanded = EditorGUILayout.Foldout(isMecanimExpanded, SpineInspectorUtility.TempContent("SkeletonAnimator", SpineInspectorUtility.UnityIcon <SceneAsset>())); if (isMecanimExpanded) { EditorGUI.indentLevel++; EditorGUILayout.PropertyField(controller, SpineInspectorUtility.TempContent("Controller", SpineInspectorUtility.UnityIcon <Animator>())); if (controller.objectReferenceValue == null) { // Generate Mecanim Controller Button using (new GUILayout.HorizontalScope()) { GUILayout.Space(EditorGUIUtility.labelWidth); if (GUILayout.Button(SpineInspectorUtility.TempContent("Generate Mecanim Controller"), GUILayout.Height(20))) { SkeletonBaker.GenerateMecanimAnimationClips(m_skeletonDataAsset); } } EditorGUILayout.HelpBox("SkeletonAnimator is the Mecanim alternative to SkeletonAnimation.\nIt is not required.", MessageType.Info); } else { // Update AnimationClips button. using (new GUILayout.HorizontalScope()) { GUILayout.Space(EditorGUIUtility.labelWidth); if (GUILayout.Button(SpineInspectorUtility.TempContent("Force Update AnimationClips"), GUILayout.Height(20))) { SkeletonBaker.GenerateMecanimAnimationClips(m_skeletonDataAsset); } } } EditorGUI.indentLevel--; } } #endif }
protected virtual void DrawInspectorGUI(bool multi) { // Initialize. if (Event.current.type == EventType.Layout) { if (forceReloadQueued) { forceReloadQueued = false; if (multi) { foreach (var c in targets) { EditorForceReloadSkeletonDataAssetAndComponent(c as SkeletonRenderer); } } else { EditorForceReloadSkeletonDataAssetAndComponent(target as SkeletonRenderer); } } else { if (multi) { foreach (var c in targets) { var component = c as SkeletonRenderer; if (!component.valid) { EditorForceInitializeComponent(component); if (!component.valid) { continue; } } } } else { var component = (SkeletonRenderer)target; if (!component.valid) { EditorForceInitializeComponent(component); } } } #if BUILT_IN_SPRITE_MASK_COMPONENT if (setMaskNoneMaterialsQueued) { setMaskNoneMaterialsQueued = false; foreach (var c in targets) { EditorSetMaskMaterials(c as SkeletonRenderer, SpriteMaskInteraction.None); } } if (setInsideMaskMaterialsQueued) { setInsideMaskMaterialsQueued = false; foreach (var c in targets) { EditorSetMaskMaterials(c as SkeletonRenderer, SpriteMaskInteraction.VisibleInsideMask); } } if (setOutsideMaskMaterialsQueued) { setOutsideMaskMaterialsQueued = false; foreach (var c in targets) { EditorSetMaskMaterials(c as SkeletonRenderer, SpriteMaskInteraction.VisibleOutsideMask); } } if (deleteInsideMaskMaterialsQueued) { deleteInsideMaskMaterialsQueued = false; foreach (var c in targets) { EditorDeleteMaskMaterials(c as SkeletonRenderer, SpriteMaskInteraction.VisibleInsideMask); } } if (deleteOutsideMaskMaterialsQueued) { deleteOutsideMaskMaterialsQueued = false; foreach (var c in targets) { EditorDeleteMaskMaterials(c as SkeletonRenderer, SpriteMaskInteraction.VisibleOutsideMask); } } #endif #if NO_PREFAB_MESH if (isInspectingPrefab) { if (multi) { foreach (var c in targets) { var component = (SkeletonRenderer)c; MeshFilter meshFilter = component.GetComponent <MeshFilter>(); if (meshFilter != null && meshFilter.sharedMesh != null) { meshFilter.sharedMesh = null; } } } else { var component = (SkeletonRenderer)target; MeshFilter meshFilter = component.GetComponent <MeshFilter>(); if (meshFilter != null && meshFilter.sharedMesh != null) { meshFilter.sharedMesh = null; } } } #endif } bool valid = TargetIsValid; // Fields. if (multi) { using (new EditorGUILayout.HorizontalScope(EditorStyles.helpBox)) { SpineInspectorUtility.PropertyFieldFitLabel(skeletonDataAsset, SkeletonDataAssetLabel); if (GUILayout.Button(ReloadButtonString, ReloadButtonStyle, ReloadButtonWidth)) { forceReloadQueued = true; } } if (valid) { EditorGUILayout.PropertyField(initialSkinName, SpineInspectorUtility.TempContent("Initial Skin")); } } else { var component = (SkeletonRenderer)target; using (new EditorGUILayout.HorizontalScope(EditorStyles.helpBox)) { SpineInspectorUtility.PropertyFieldFitLabel(skeletonDataAsset, SkeletonDataAssetLabel); if (component.valid) { if (GUILayout.Button(ReloadButtonString, ReloadButtonStyle, ReloadButtonWidth)) { forceReloadQueued = true; } } } if (component.skeletonDataAsset == null) { EditorGUILayout.HelpBox("Skeleton Data Asset required", MessageType.Warning); return; } if (!SkeletonDataAssetIsValid(component.skeletonDataAsset)) { EditorGUILayout.HelpBox("Skeleton Data Asset error. Please check Skeleton Data Asset.", MessageType.Error); return; } if (valid) { EditorGUILayout.PropertyField(initialSkinName, SpineInspectorUtility.TempContent("Initial Skin")); } } EditorGUILayout.Space(); // Sorting Layers SpineInspectorUtility.SortingPropertyFields(sortingProperties, applyModifiedProperties: true); if (maskInteraction != null) { EditorGUILayout.PropertyField(maskInteraction, MaskInteractionLabel); } if (!valid) { return; } string errorMessage = null; if (MaterialChecks.IsMaterialSetupProblematic((SkeletonRenderer)this.target, ref errorMessage)) { EditorGUILayout.HelpBox(errorMessage, MessageType.Error, true); } // More Render Options... using (new SpineInspectorUtility.BoxScope()) { EditorGUI.BeginChangeCheck(); EditorGUILayout.BeginHorizontal(GUILayout.Height(EditorGUIUtility.singleLineHeight + 5)); advancedFoldout = EditorGUILayout.Foldout(advancedFoldout, "Advanced"); if (advancedFoldout) { EditorGUILayout.Space(); if (GUILayout.Button("Debug", EditorStyles.miniButton, GUILayout.Width(65f))) { SkeletonDebugWindow.Init(); } } else { EditorGUILayout.Space(); } EditorGUILayout.EndHorizontal(); if (advancedFoldout) { using (new SpineInspectorUtility.IndentScope()) { using (new EditorGUILayout.HorizontalScope()) { SpineInspectorUtility.ToggleLeftLayout(initialFlipX); SpineInspectorUtility.ToggleLeftLayout(initialFlipY); EditorGUILayout.Space(); } EditorGUILayout.Space(); EditorGUILayout.LabelField("Renderer Settings", EditorStyles.boldLabel); using (new SpineInspectorUtility.LabelWidthScope()) { // Optimization options if (singleSubmesh != null) { EditorGUILayout.PropertyField(singleSubmesh, SingleSubmeshLabel); } #if PER_MATERIAL_PROPERTY_BLOCKS if (fixDrawOrder != null) { EditorGUILayout.PropertyField(fixDrawOrder, FixDrawOrderLabel); } #endif if (immutableTriangles != null) { EditorGUILayout.PropertyField(immutableTriangles, ImmubleTrianglesLabel); } EditorGUILayout.PropertyField(clearStateOnDisable, ClearStateOnDisableLabel); EditorGUILayout.Space(); } SeparatorsField(separatorSlotNames); EditorGUILayout.Space(); // Render options const float MinZSpacing = -0.1f; const float MaxZSpacing = 0f; EditorGUILayout.Slider(zSpacing, MinZSpacing, MaxZSpacing, ZSpacingLabel); EditorGUILayout.Space(); using (new SpineInspectorUtility.LabelWidthScope()) { EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Vertex Data", SpineInspectorUtility.UnityIcon <MeshFilter>()), EditorStyles.boldLabel); if (pmaVertexColors != null) { EditorGUILayout.PropertyField(pmaVertexColors, PMAVertexColorsLabel); } EditorGUILayout.PropertyField(tintBlack, TintBlackLabel); // Optional fields. May be disabled in SkeletonRenderer. if (normals != null) { EditorGUILayout.PropertyField(normals, NormalsLabel); } if (tangents != null) { EditorGUILayout.PropertyField(tangents, TangentsLabel); } } #if BUILT_IN_SPRITE_MASK_COMPONENT EditorGUILayout.Space(); if (maskMaterialsNone.arraySize > 0 || maskMaterialsInside.arraySize > 0 || maskMaterialsOutside.arraySize > 0) { EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Mask Interaction Materials", SpineInspectorUtility.UnityIcon <SpriteMask>()), EditorStyles.boldLabel); bool differentMaskModesSelected = maskInteraction.hasMultipleDifferentValues; int activeMaskInteractionValue = differentMaskModesSelected ? -1 : maskInteraction.intValue; bool ignoredParam = true; MaskMaterialsEditingField(ref setMaskNoneMaterialsQueued, ref ignoredParam, maskMaterialsNone, MaskMaterialsNoneLabel, differentMaskModesSelected, allowDelete: false, isActiveMaterial: activeMaskInteractionValue == (int)SpriteMaskInteraction.None); MaskMaterialsEditingField(ref setInsideMaskMaterialsQueued, ref deleteInsideMaskMaterialsQueued, maskMaterialsInside, MaskMaterialsInsideLabel, differentMaskModesSelected, allowDelete: true, isActiveMaterial: activeMaskInteractionValue == (int)SpriteMaskInteraction.VisibleInsideMask); MaskMaterialsEditingField(ref setOutsideMaskMaterialsQueued, ref deleteOutsideMaskMaterialsQueued, maskMaterialsOutside, MaskMaterialsOutsideLabel, differentMaskModesSelected, allowDelete: true, isActiveMaterial: activeMaskInteractionValue == (int)SpriteMaskInteraction.VisibleOutsideMask); } #endif EditorGUILayout.Space(); if (valid && !isInspectingPrefab) { if (multi) { // Support multi-edit SkeletonUtility button. // EditorGUILayout.Space(); // bool addSkeletonUtility = GUILayout.Button(buttonContent, GUILayout.Height(30)); // foreach (var t in targets) { // var component = t as Component; // if (addSkeletonUtility && component.GetComponent<SkeletonUtility>() == null) // component.gameObject.AddComponent<SkeletonUtility>(); // } } else { var component = (Component)target; if (component.GetComponent <SkeletonUtility>() == null) { if (SpineInspectorUtility.CenteredButton(SkeletonUtilityButtonContent, 21, true, 200f)) { component.gameObject.AddComponent <SkeletonUtility>(); } } } } EditorGUILayout.Space(); } } if (EditorGUI.EndChangeCheck()) { SceneView.RepaintAll(); } } }
void DrawAnimationList() { showAnimationList = EditorGUILayout.Foldout(showAnimationList, SpineInspectorUtility.TempContent(string.Format("Animations [{0}]", m_skeletonData.Animations.Count), Icons.animationRoot)); if (!showAnimationList) { return; } if (m_skeletonAnimation != null && m_skeletonAnimation.state != null) { if (GUILayout.Button(SpineInspectorUtility.TempContent("Setup Pose", Icons.skeleton), GUILayout.Width(105), GUILayout.Height(18))) { StopAnimation(); m_skeletonAnimation.skeleton.SetToSetupPose(); m_requireRefresh = true; } } else { EditorGUILayout.HelpBox("Animations can be previewed if you expand the Preview window below.", MessageType.Info); } EditorGUILayout.LabelField("Name", " Duration"); bool nonessential = m_skeletonData.ImagesPath != null; float fps = m_skeletonData.Fps; if (nonessential && fps == 0) { fps = 30; } foreach (Spine.Animation animation in m_skeletonData.Animations) { using (new GUILayout.HorizontalScope()) { if (m_skeletonAnimation != null && m_skeletonAnimation.state != null) { var activeTrack = m_skeletonAnimation.state.GetCurrent(0); if (activeTrack != null && activeTrack.Animation == animation) { if (GUILayout.Button("\u25BA", activePlayButtonStyle, GUILayout.Width(24))) { StopAnimation(); } } else { if (GUILayout.Button("\u25BA", idlePlayButtonStyle, GUILayout.Width(24))) { PlayAnimation(animation.Name, true); } } } else { GUILayout.Label("-", GUILayout.Width(24)); } string frameCountString = (fps > 0) ? ("(" + (Mathf.RoundToInt(animation.Duration * fps)) + ")").PadLeft(12, ' ') : string.Empty; EditorGUILayout.LabelField(new GUIContent(animation.Name, Icons.animation), SpineInspectorUtility.TempContent(animation.Duration.ToString("f3") + "s" + frameCountString)); } } }
public static string[] GetSeparatorSlotNames(SkeletonRenderer skeletonRenderer) { var field = SpineInspectorUtility.GetNonPublicField(typeof(SkeletonRenderer), SeparatorSlotNamesFieldName); return(field.GetValue(skeletonRenderer) as string[]); }
void DrawSlotList() { showSlotList = EditorGUILayout.Foldout(showSlotList, SpineInspectorUtility.TempContent("Slots", Icons.slotRoot)); if (!showSlotList) { return; } if (m_skeletonAnimation == null || m_skeletonAnimation.skeleton == null) { return; } EditorGUI.indentLevel++; showAttachments = EditorGUILayout.ToggleLeft("Show Attachments", showAttachments); var slotAttachments = new List <Attachment>(); var slotAttachmentNames = new List <string>(); var defaultSkinAttachmentNames = new List <string>(); var defaultSkin = m_skeletonData.Skins.Items[0]; Skin skin = m_skeletonAnimation.skeleton.Skin ?? defaultSkin; var slotsItems = m_skeletonAnimation.skeleton.Slots.Items; for (int i = m_skeletonAnimation.skeleton.Slots.Count - 1; i >= 0; i--) { Slot slot = slotsItems[i]; EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(slot.Data.Name, Icons.slot)); if (showAttachments) { EditorGUI.indentLevel++; slotAttachments.Clear(); slotAttachmentNames.Clear(); defaultSkinAttachmentNames.Clear(); skin.FindNamesForSlot(i, slotAttachmentNames); skin.FindAttachmentsForSlot(i, slotAttachments); if (skin != defaultSkin) { defaultSkin.FindNamesForSlot(i, defaultSkinAttachmentNames); defaultSkin.FindNamesForSlot(i, slotAttachmentNames); defaultSkin.FindAttachmentsForSlot(i, slotAttachments); } else { defaultSkin.FindNamesForSlot(i, defaultSkinAttachmentNames); } for (int a = 0; a < slotAttachments.Count; a++) { Attachment attachment = slotAttachments[a]; string attachmentName = slotAttachmentNames[a]; Texture2D icon = Icons.GetAttachmentIcon(attachment); bool initialState = slot.Attachment == attachment; bool toggled = EditorGUILayout.ToggleLeft(SpineInspectorUtility.TempContent(attachmentName, icon), slot.Attachment == attachment); if (!defaultSkinAttachmentNames.Contains(attachmentName)) { Rect skinPlaceHolderIconRect = GUILayoutUtility.GetLastRect(); skinPlaceHolderIconRect.width = Icons.skinPlaceholder.width; skinPlaceHolderIconRect.height = Icons.skinPlaceholder.height; GUI.DrawTexture(skinPlaceHolderIconRect, Icons.skinPlaceholder); } if (toggled != initialState) { slot.Attachment = toggled ? attachment : null; m_requireRefresh = true; } } EditorGUI.indentLevel--; } } EditorGUI.indentLevel--; }
override public void OnInspectorGUI () { if (serializedObject.isEditingMultipleObjects) { DrawDefaultInspector(); return; } serializedObject.Update(); atlasAsset = atlasAsset ?? (SpineAtlasAsset)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 " + SpinePreferences.DEFAULT_MIPMAPBIAS, tooltip: "This may help textures with mipmaps be less blurry when used for 2D sprites."))) { foreach (var m in atlasAsset.materials) { var texture = m.mainTexture; texture.mipMapBias = SpinePreferences.DEFAULT_MIPMAPBIAS; } Debug.Log("Texture mipmap bias set to " + SpinePreferences.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<AtlasRegion> regions = (List<AtlasRegion>)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) { int baseIndent = EditorGUI.indentLevel; var regions = SpineAtlasAssetInspector.GetRegions(atlasAsset.GetAtlas()); int regionsCount = regions.Count; using (new EditorGUILayout.HorizontalScope()) { EditorGUILayout.LabelField("Atlas Regions", EditorStyles.boldLabel); EditorGUILayout.LabelField(string.Format("{0} regions total", regionsCount)); } AtlasPage lastPage = null; for (int i = 0; i < regionsCount; 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); } } string regionName = regions[i].name; Texture2D icon = SpineEditorUtilities.Icons.image; if (regionName.EndsWith(" ")) { regionName = string.Format("'{0}'", regions[i].name); icon = SpineEditorUtilities.Icons.warning; EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(regionName, icon, "Region name ends with whitespace. This may cause errors. Please check your source image filenames.")); } else { EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(regionName, icon)); } } EditorGUI.indentLevel = baseIndent; } #endif if (serializedObject.ApplyModifiedProperties() || SpineInspectorUtility.UndoRedoPerformed(Event.current)) atlasAsset.Clear(); }
protected virtual void DrawInspectorGUI(bool multi) { bool valid = TargetIsValid; var reloadWidth = GUILayout.Width(GUI.skin.label.CalcSize(new GUIContent(ReloadButtonLabel)).x + 20); var reloadButtonStyle = EditorStyles.miniButtonRight; if (multi) { using (new EditorGUILayout.HorizontalScope(EditorStyles.helpBox)) { SpineInspectorUtility.PropertyFieldFitLabel(skeletonDataAsset, SkeletonDataAssetLabel); if (GUILayout.Button(ReloadButtonLabel, reloadButtonStyle, reloadWidth)) { foreach (var c in targets) { var component = c as SkeletonRenderer; if (component.skeletonDataAsset != null) { foreach (AtlasAsset aa in component.skeletonDataAsset.atlasAssets) { if (aa != null) { aa.Clear(); } } component.skeletonDataAsset.Clear(); } component.Initialize(true); } } } foreach (var c in targets) { var component = c as SkeletonRenderer; if (!component.valid) { if (Event.current.type == EventType.Layout) { component.Initialize(true); component.LateUpdate(); } if (!component.valid) { continue; } } #if NO_PREFAB_MESH if (isInspectingPrefab) { MeshFilter meshFilter = component.GetComponent <MeshFilter>(); if (meshFilter != null) { meshFilter.sharedMesh = null; } } #endif } if (valid) { EditorGUILayout.PropertyField(initialSkinName); } } else { var component = (SkeletonRenderer)target; if (!component.valid && Event.current.type == EventType.Layout) { component.Initialize(true); component.LateUpdate(); } using (new EditorGUILayout.HorizontalScope(EditorStyles.helpBox)) { SpineInspectorUtility.PropertyFieldFitLabel(skeletonDataAsset, SkeletonDataAssetLabel); if (component.valid) { if (GUILayout.Button(ReloadButtonLabel, reloadButtonStyle, reloadWidth)) { if (component.skeletonDataAsset != null) { foreach (AtlasAsset aa in component.skeletonDataAsset.atlasAssets) { if (aa != null) { aa.Clear(); } } component.skeletonDataAsset.Clear(); } component.Initialize(true); } } } if (component.skeletonDataAsset == null) { EditorGUILayout.HelpBox("Skeleton Data Asset required", MessageType.Warning); return; } #if NO_PREFAB_MESH if (isInspectingPrefab) { MeshFilter meshFilter = component.GetComponent <MeshFilter>(); if (meshFilter != null) { meshFilter.sharedMesh = null; } } #endif // Initial skin name. if (component.valid) { var skeletonDataSkins = component.skeleton.Data.Skins; int skinCount = skeletonDataSkins.Count; if (loadedSkinList != skeletonDataSkins) { skins = new GUIContent[skinCount]; loadedSkinList = skeletonDataSkins; for (int i = 0; i < skins.Length; i++) { string skinNameString = skeletonDataSkins.Items[i].Name; skins[i] = new GUIContent(skinNameString, Icons.skin); } } int skinIndex = 0; for (int i = 0; i < skins.Length; i++) { string skinNameString = skeletonDataSkins.Items[i].Name; if (skinNameString == initialSkinName.stringValue) { skinIndex = i; } } skinIndex = EditorGUILayout.Popup(SpineInspectorUtility.TempContent("Initial Skin"), skinIndex, skins); if (skins.Length > 0) // Support attachmentless/skinless SkeletonData. { initialSkinName.stringValue = skins[skinIndex].text; } } } EditorGUILayout.Space(); // Sorting Layers SpineInspectorUtility.SortingPropertyFields(sortingProperties, applyModifiedProperties: true); if (!TargetIsValid) { return; } // More Render Options... using (new SpineInspectorUtility.BoxScope()) { EditorGUI.BeginChangeCheck(); EditorGUILayout.BeginHorizontal(GUILayout.Height(EditorGUIUtility.singleLineHeight + 5)); advancedFoldout = EditorGUILayout.Foldout(advancedFoldout, "Advanced"); if (advancedFoldout) { EditorGUILayout.Space(); if (GUILayout.Button("Debug", EditorStyles.miniButton, GUILayout.Width(65f))) { SkeletonDebugWindow.Init(); } } else { EditorGUILayout.Space(); } EditorGUILayout.EndHorizontal(); if (advancedFoldout) { using (new SpineInspectorUtility.IndentScope()) { using (new EditorGUILayout.HorizontalScope()) { initialFlipX.boolValue = EditorGUILayout.ToggleLeft(initialFlipX.displayName, initialFlipX.boolValue, GUILayout.Width(120f)); initialFlipY.boolValue = EditorGUILayout.ToggleLeft(initialFlipY.displayName, initialFlipY.boolValue, GUILayout.Width(120f)); EditorGUILayout.Space(); } EditorGUILayout.Space(); EditorGUILayout.LabelField("Renderer Settings", EditorStyles.boldLabel); using (new SpineInspectorUtility.LabelWidthScope()) { // Optimization options if (singleSubmesh != null) { EditorGUILayout.PropertyField(singleSubmesh, SingleSubmeshLabel); } //if (meshes != null) EditorGUILayout.PropertyField(meshes, MeshesLabel); if (immutableTriangles != null) { EditorGUILayout.PropertyField(immutableTriangles, ImmubleTrianglesLabel); } EditorGUILayout.PropertyField(clearStateOnDisable, ClearStateOnDisableLabel); EditorGUILayout.Space(); } SeparatorsField(separatorSlotNames); EditorGUILayout.Space(); // Render options const float MinZSpacing = -0.1f; const float MaxZSpacing = 0f; EditorGUILayout.Slider(zSpacing, MinZSpacing, MaxZSpacing, ZSpacingLabel); EditorGUILayout.Space(); using (new SpineInspectorUtility.LabelWidthScope()) { EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Vertex Data", SpineInspectorUtility.UnityIcon <MeshFilter>()), EditorStyles.boldLabel); if (pmaVertexColors != null) { EditorGUILayout.PropertyField(pmaVertexColors, PMAVertexColorsLabel); } EditorGUILayout.PropertyField(tintBlack, TintBlackLabel); // Optional fields. May be disabled in SkeletonRenderer. if (normals != null) { EditorGUILayout.PropertyField(normals, NormalsLabel); } if (tangents != null) { EditorGUILayout.PropertyField(tangents, TangentsLabel); } } EditorGUILayout.Space(); if (TargetIsValid && !isInspectingPrefab) { if (multi) { // Support multi-edit SkeletonUtility button. // EditorGUILayout.Space(); // bool addSkeletonUtility = GUILayout.Button(buttonContent, GUILayout.Height(30)); // foreach (var t in targets) { // var component = t as Component; // if (addSkeletonUtility && component.GetComponent<SkeletonUtility>() == null) // component.gameObject.AddComponent<SkeletonUtility>(); // } } else { var component = (Component)target; if (component.GetComponent <SkeletonUtility>() == null) { if (SpineInspectorUtility.CenteredButton(SkeletonUtilityButtonContent, 21, true, 200f)) { component.gameObject.AddComponent <SkeletonUtility>(); } } } } EditorGUILayout.Space(); } } if (EditorGUI.EndChangeCheck()) { SceneView.RepaintAll(); } } }
public override void OnInspectorGUI() { component = (SkeletonRendererCustomMaterials)target; var skeletonRenderer = component.skeletonRenderer; // Draw the default inspector DrawDefaultInspector(); if (serializedObject.isEditingMultipleObjects) { return; } if (componentCustomMaterialOverrides == null) { Type cm = typeof(SkeletonRendererCustomMaterials); componentCustomMaterialOverrides = cm.GetField("customMaterialOverrides", PrivateInstance).GetValue(component) as List <SkeletonRendererCustomMaterials.AtlasMaterialOverride>; componentCustomSlotMaterials = cm.GetField("customSlotMaterials", PrivateInstance).GetValue(component) as List <SkeletonRendererCustomMaterials.SlotMaterialOverride>; if (componentCustomMaterialOverrides == null) { Debug.Log("Reflection failed."); return; } } // Fill with current values at start if (_customMaterialOverridesPrev == null || _customSlotMaterialsPrev == null) { _customMaterialOverridesPrev = CopyList(componentCustomMaterialOverrides); _customSlotMaterialsPrev = CopyList(componentCustomSlotMaterials); } // Compare new values with saved. If change is detected: // store new values, restore old values, remove overrides, restore new values, restore overrides. // 1. Store new values var customMaterialOverridesNew = CopyList(componentCustomMaterialOverrides); var customSlotMaterialsNew = CopyList(componentCustomSlotMaterials); // Detect changes if (!_customMaterialOverridesPrev.SequenceEqual(customMaterialOverridesNew) || !_customSlotMaterialsPrev.SequenceEqual(customSlotMaterialsNew)) { // 2. Restore old values componentCustomMaterialOverrides.Clear(); componentCustomSlotMaterials.Clear(); componentCustomMaterialOverrides.AddRange(_customMaterialOverridesPrev); componentCustomSlotMaterials.AddRange(_customSlotMaterialsPrev); // 3. Remove overrides RemoveCustomMaterials(); // 4. Restore new values componentCustomMaterialOverrides.Clear(); componentCustomSlotMaterials.Clear(); componentCustomMaterialOverrides.AddRange(customMaterialOverridesNew); componentCustomSlotMaterials.AddRange(customSlotMaterialsNew); // 5. Restore overrides SetCustomMaterials(); if (skeletonRenderer != null) { skeletonRenderer.LateUpdate(); } } _customMaterialOverridesPrev = CopyList(componentCustomMaterialOverrides); _customSlotMaterialsPrev = CopyList(componentCustomSlotMaterials); if (SpineInspectorUtility.LargeCenteredButton(SpineInspectorUtility.TempContent("Clear and Reapply Changes", tooltip: "Removes all non-serialized overrides in the SkeletonRenderer and reapplies the overrides on this component."))) { if (skeletonRenderer != null) { #if SPINE_OPTIONAL_MATERIALOVERRIDE skeletonRenderer.CustomMaterialOverride.Clear(); #endif skeletonRenderer.CustomSlotMaterials.Clear(); RemoveCustomMaterials(); SetCustomMaterials(); skeletonRenderer.LateUpdate(); } } }
public override void OnInspectorGUI() { EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(skeletonDataAsset); EditorGUILayout.PropertyField(material); EditorGUILayout.PropertyField(color); if (thisSkeletonGraphic.skeletonDataAsset == null) { EditorGUILayout.HelpBox("You need to assign a SkeletonDataAsset first.", MessageType.Info); serializedObject.ApplyModifiedProperties(); serializedObject.Update(); return; } using (new SpineInspectorUtility.BoxScope()) { EditorGUILayout.PropertyField(meshGeneratorSettings, SpineInspectorUtility.TempContent("Advanced..."), includeChildren: true); SkeletonRendererInspector.advancedFoldout = meshGeneratorSettings.isExpanded; } EditorGUILayout.Space(); EditorGUILayout.PropertyField(initialSkinName); { var rect = GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, EditorGUIUtility.singleLineHeight); EditorGUI.PrefixLabel(rect, SpineInspectorUtility.TempContent("Initial Flip")); rect.x += EditorGUIUtility.labelWidth; rect.width = 30f; SpineInspectorUtility.ToggleLeft(rect, initialFlipX, SpineInspectorUtility.TempContent("X", tooltip: "initialFlipX")); rect.x += 35f; SpineInspectorUtility.ToggleLeft(rect, initialFlipY, SpineInspectorUtility.TempContent("Y", tooltip: "initialFlipY")); } EditorGUILayout.Space(); EditorGUILayout.LabelField("Animation", EditorStyles.boldLabel); EditorGUILayout.PropertyField(startingAnimation); EditorGUILayout.PropertyField(startingLoop); EditorGUILayout.PropertyField(timeScale); EditorGUILayout.PropertyField(unscaledTime, SpineInspectorUtility.TempContent(unscaledTime.displayName, tooltip: "If checked, this will use Time.unscaledDeltaTime to make this update independent of game Time.timeScale. Instance SkeletonGraphic.timeScale will still be applied.")); EditorGUILayout.Space(); EditorGUILayout.PropertyField(freeze); EditorGUILayout.Space(); EditorGUILayout.LabelField("UI", EditorStyles.boldLabel); EditorGUILayout.PropertyField(raycastTarget); EditorGUILayout.BeginHorizontal(GUILayout.Height(EditorGUIUtility.singleLineHeight + 5)); EditorGUILayout.PrefixLabel("Match RectTransform with Mesh"); if (GUILayout.Button("Match", EditorStyles.miniButton, GUILayout.Width(65f))) { foreach (var skeletonGraphic in targets) { MatchRectTransformWithBounds((SkeletonGraphic)skeletonGraphic); } } EditorGUILayout.EndHorizontal(); bool wasChanged = EditorGUI.EndChangeCheck(); if (wasChanged) { serializedObject.ApplyModifiedProperties(); } }