public override void OnInspectorGUI() { if (isPrefab) { GUILayout.Label(new GUIContent("Cannot edit Prefabs", Icons.warning)); return; } if (!skeletonRenderer.valid) { GUILayout.Label(new GUIContent("Spine Component invalid. Check Skeleton Data Asset.", Icons.warning)); return; } skeletonUtility.boneRoot = (Transform)EditorGUILayout.ObjectField("Bone Root", skeletonUtility.boneRoot, typeof(Transform), true); bool hasRootBone = skeletonUtility.boneRoot != null; 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; } } }
public void DrawSkeletonUtilityButton(bool multi) { 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 { EditorGUILayout.Space(); var component = (Component)target; if (component.GetComponent <SkeletonUtility>() == null) { if (SpineInspectorUtility.LargeCenteredButton(SkeletonUtilityButtonContent)) { component.gameObject.AddComponent <SkeletonUtility>(); } } } }
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 !NEW_PREFAB_SYSTEM if (isPrefab) { GUILayout.Label(new GUIContent("Cannot edit Prefabs", Icons.warning)); return; } #endif if (!skeletonRenderer.valid) { GUILayout.Label(new GUIContent("Spine Component invalid. Check Skeleton Data Asset.", Icons.warning)); return; } EditorGUILayout.PropertyField(serializedObject.FindProperty("boneRoot"), SpineInspectorUtility.TempContent("Skeleton Root")); 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; } } }
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); } } }
public override void OnInspectorGUI() { bool requireRepaint = false; if (skeletonRenderer.skeleton != skeleton || activeSkin != skeleton.Skin) { UpdateAttachments(); } if (isPrefab) { GUILayout.Label(new GUIContent("Cannot edit Prefabs", Icons.warning)); return; } if (!skeletonRenderer.valid) { GUILayout.Label(new GUIContent("Spine Component invalid. Check Skeleton Data Asset.", Icons.warning)); return; } skeletonUtility.boneRoot = (Transform)EditorGUILayout.ObjectField("Bone Root", skeletonUtility.boneRoot, typeof(Transform), true); using (new EditorGUI.DisabledGroupScope(skeletonUtility.boneRoot != null)) { if (SpineInspectorUtility.LargeCenteredButton(SpawnHierarchyButtonLabel)) { SpawnHierarchyContextMenu(); } } using (new SpineInspectorUtility.BoxScope()) { debugSkeleton = EditorGUILayout.Foldout(debugSkeleton, "Debug Skeleton"); if (debugSkeleton) { EditorGUI.BeginChangeCheck(); skeleton.FlipX = EditorGUILayout.ToggleLeft("skeleton.FlipX", skeleton.FlipX); skeleton.FlipY = EditorGUILayout.ToggleLeft("skeleton.FlipY", skeleton.FlipY); requireRepaint |= EditorGUI.EndChangeCheck(); // foreach (var t in skeleton.IkConstraints) // EditorGUILayout.LabelField(t.Data.Name + " " + t.Mix + " " + t.Target.Data.Name); showSlots.target = EditorGUILayout.Foldout(showSlots.target, SlotsRootLabel); if (showSlots.faded > 0) { using (new EditorGUILayout.FadeGroupScope(showSlots.faded)) { 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(new GUIContent(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 = (attachment is MeshAttachment) ? Icons.mesh : Icons.image; bool isAttached = (attachment == slot.Attachment); bool swap = EditorGUILayout.ToggleLeft(new GUIContent(attachment.Name, icon), attachment == slot.Attachment); if (isAttached != swap) { slot.Attachment = isAttached ? null : attachment; requireRepaint = true; } GUI.contentColor = Color.white; } } } } } if (showSlots.isAnimating) { Repaint(); } } if (requireRepaint) { skeletonRenderer.LateUpdate(); SceneView.RepaintAll(); } }
override public void OnInspectorGUI() { serializedObject.Update(); atlasAsset = atlasAsset ?? (AtlasAsset)target; EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(atlasFile); EditorGUILayout.PropertyField(materials, true); if (EditorGUI.EndChangeCheck()) { serializedObject.ApplyModifiedProperties(); atlasAsset.Clear(); atlasAsset.GetAtlas(); } if (materials.arraySize == 0) { EditorGUILayout.LabelField(new GUIContent("Error: Missing materials", SpineEditorUtilities.Icons.warning)); return; } for (int i = 0; i < materials.arraySize; i++) { SerializedProperty prop = materials.GetArrayElementAtIndex(i); Material mat = (Material)prop.objectReferenceValue; if (mat == null) { EditorGUILayout.LabelField(new GUIContent("Error: Materials cannot be null", SpineEditorUtilities.Icons.warning)); return; } } EditorGUILayout.Space(); if (atlasFile.objectReferenceValue != null) { if (SpineInspectorUtility.LargeCenteredButton(SpriteSlicesLabel)) { var atlas = atlasAsset.GetAtlas(); foreach (var m in atlasAsset.materials) { UpdateSpriteSlices(m.mainTexture, atlas); } } } #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) { EditorGUILayout.LabelField("Atlas Regions", EditorStyles.boldLabel); int baseIndent = EditorGUI.indentLevel; var regions = AtlasAssetInspector.GetRegions(atlasAsset.GetAtlas()); AtlasPage lastPage = null; for (int i = 0; i < regions.Count; i++) { if (lastPage != regions[i].page) { if (lastPage != null) { EditorGUILayout.Separator(); EditorGUILayout.Separator(); } lastPage = regions[i].page; Material mat = ((Material)lastPage.rendererObject); if (mat != null) { EditorGUI.indentLevel = baseIndent; using (new GUILayout.HorizontalScope()) using (new EditorGUI.DisabledGroupScope(true)) EditorGUILayout.ObjectField(mat, typeof(Material), false, GUILayout.Width(250)); EditorGUI.indentLevel = baseIndent + 1; } else { EditorGUILayout.HelpBox("Page missing material!", MessageType.Warning); } } EditorGUILayout.LabelField(new GUIContent(regions[i].name, SpineEditorUtilities.Icons.image)); } EditorGUI.indentLevel = baseIndent; } #endif if (serializedObject.ApplyModifiedProperties() || SpineInspectorUtility.UndoRedoPerformed(Event.current)) { atlasAsset.Clear(); } }
public override void OnInspectorGUI() { #if !NEW_PREFAB_SYSTEM bool isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab); #else bool isInspectingPrefab = false; #endif // 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 skeletonRendererValue = skeletonRenderer.objectReferenceValue as SkeletonRenderer; if (skeletonRendererValue != null && skeletonRendererValue.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(skeletonRendererValue, follower); DestroyImmediate(follower); return; } } EditorGUILayout.Space(); } EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(skeletonRenderer); EditorGUILayout.PropertyField(slotName, new GUIContent("Slot")); if (EditorGUI.EndChangeCheck()) { serializedObject.ApplyModifiedProperties(); #if !NEW_PREFAB_SYSTEM if (!isInspectingPrefab) { rebuildRequired = true; } #endif } 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.skeletonRenderer = skeletonRendererValue; 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() { if (serializedObject.isEditingMultipleObjects) { DrawDefaultInspector(); return; } serializedObject.Update(); atlasAsset = (atlasAsset == null) ? (SpineAtlasAsset)target : atlasAsset; 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; string texturePath = AssetDatabase.GetAssetPath(texture.GetInstanceID()); var importer = (TextureImporter)TextureImporter.GetAtPath(texturePath); importer.mipMapBias = SpinePreferences.DEFAULT_MIPMAPBIAS; EditorUtility.SetDirty(texture); } 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(); } }
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(new GUIContent("Clear and Reapply Changes", "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(); } } }
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); } } } }
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); } } }