mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-21 01:36:02 +08:00
Spine Editor Utility Drag and Drop importer
This commit is contained in:
parent
a7bf0ca963
commit
8a68f5a75a
@ -80,8 +80,10 @@ public class SkeletonDataAssetInspector : Editor {
|
|||||||
EditorGUILayout.PropertyField(skeletonJSON);
|
EditorGUILayout.PropertyField(skeletonJSON);
|
||||||
EditorGUILayout.PropertyField(scale);
|
EditorGUILayout.PropertyField(scale);
|
||||||
if(EditorGUI.EndChangeCheck()){
|
if(EditorGUI.EndChangeCheck()){
|
||||||
m_previewUtility.Cleanup();
|
if(m_previewUtility != null){
|
||||||
m_previewUtility = null;
|
m_previewUtility.Cleanup();
|
||||||
|
m_previewUtility = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SkeletonData skeletonData = asset.GetSkeletonData(asset.atlasAsset == null || asset.skeletonJSON == null);
|
SkeletonData skeletonData = asset.GetSkeletonData(asset.atlasAsset == null || asset.skeletonJSON == null);
|
||||||
@ -262,7 +264,8 @@ public class SkeletonDataAssetInspector : Editor {
|
|||||||
|
|
||||||
public override bool HasPreviewGUI ()
|
public override bool HasPreviewGUI ()
|
||||||
{
|
{
|
||||||
return true;
|
//TODO: validate json data
|
||||||
|
return skeletonJSON.objectReferenceValue != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture m_previewTex = new Texture();
|
Texture m_previewTex = new Texture();
|
||||||
@ -584,10 +587,14 @@ public class SkeletonDataAssetInspector : Editor {
|
|||||||
this.m_previewUtility.m_Camera.transform.position = m_posGoal;
|
this.m_previewUtility.m_Camera.transform.position = m_posGoal;
|
||||||
this.m_previewUtility.BeginStaticPreview(new Rect(0,0,width,height));
|
this.m_previewUtility.BeginStaticPreview(new Rect(0,0,width,height));
|
||||||
this.DoRenderPreview(false);
|
this.DoRenderPreview(false);
|
||||||
Handles.SetCamera(this.m_previewUtility.m_Camera);
|
|
||||||
Handles.BeginGUI();
|
//TODO: Figure out why this is throwing errors on first attempt
|
||||||
GUI.DrawTexture(new Rect(40,60,width,height), SpineEditorUtilities.Icons.spine, ScaleMode.StretchToFill);
|
// if(m_previewUtility != null){
|
||||||
Handles.EndGUI();
|
// Handles.SetCamera(this.m_previewUtility.m_Camera);
|
||||||
|
// Handles.BeginGUI();
|
||||||
|
// GUI.DrawTexture(new Rect(40,60,width,height), SpineEditorUtilities.Icons.spine, ScaleMode.StretchToFill);
|
||||||
|
// Handles.EndGUI();
|
||||||
|
// }
|
||||||
tex = this.m_previewUtility.EndStaticPreview();
|
tex = this.m_previewUtility.EndStaticPreview();
|
||||||
return tex;
|
return tex;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
using UnityEngine;
|
#pragma warning disable 0219
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -7,7 +9,7 @@ using System.Text;
|
|||||||
using Spine;
|
using Spine;
|
||||||
|
|
||||||
[InitializeOnLoad]
|
[InitializeOnLoad]
|
||||||
public static class SpineEditorUtilities {
|
public class SpineEditorUtilities : AssetPostprocessor {
|
||||||
|
|
||||||
public static class Icons{
|
public static class Icons{
|
||||||
public static Texture2D skeleton;
|
public static Texture2D skeleton;
|
||||||
@ -122,10 +124,12 @@ public static class SpineEditorUtilities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MenuItem("Assets/Spine/Ingest")]
|
[MenuItem("Assets/Spine/Ingest")]
|
||||||
static void IngestSpineProject(){
|
static void IngestSpineProjectFromSelection(){
|
||||||
TextAsset spineJson = null;
|
TextAsset spineJson = null;
|
||||||
TextAsset atlasText = null;
|
TextAsset atlasText = null;
|
||||||
|
|
||||||
|
List<TextAsset> spineJsonList = new List<TextAsset>();
|
||||||
|
|
||||||
foreach(UnityEngine.Object o in Selection.objects){
|
foreach(UnityEngine.Object o in Selection.objects){
|
||||||
if(o.GetType() != typeof(TextAsset))
|
if(o.GetType() != typeof(TextAsset))
|
||||||
continue;
|
continue;
|
||||||
@ -150,58 +154,190 @@ public static class SpineEditorUtilities {
|
|||||||
string atlasPath = assetPath + "/" + primaryName + ".atlas.txt";
|
string atlasPath = assetPath + "/" + primaryName + ".atlas.txt";
|
||||||
atlasText = (TextAsset)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(TextAsset));
|
atlasText = (TextAsset)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(TextAsset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AtlasAsset atlasAsset = IngestSpineAtlas(atlasText);
|
||||||
|
|
||||||
|
IngestSpineProject(spineJson, atlasAsset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void OnPostprocessAllAssets(string[] imported, string[] deleted, string[] moved, string[] movedFromAssetPaths){
|
||||||
|
//debug
|
||||||
|
// return;
|
||||||
|
|
||||||
|
AtlasAsset sharedAtlas = null;
|
||||||
|
|
||||||
|
System.Array.Sort<string>(imported);
|
||||||
|
|
||||||
|
foreach(string str in imported){
|
||||||
|
if(Path.GetExtension(str).ToLower() == ".json"){
|
||||||
|
TextAsset spineJson = (TextAsset)AssetDatabase.LoadAssetAtPath(str, typeof(TextAsset));
|
||||||
|
if(IsSpineJSON(spineJson)){
|
||||||
|
|
||||||
|
if(sharedAtlas != null){
|
||||||
|
string spinePath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(spineJson));
|
||||||
|
string atlasPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(sharedAtlas));
|
||||||
|
if(spinePath != atlasPath)
|
||||||
|
sharedAtlas = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
SkeletonDataAsset data = AutoIngestSpineProject(spineJson, sharedAtlas);
|
||||||
|
if(data == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
sharedAtlas = data.atlasAsset;
|
||||||
|
|
||||||
|
SkeletonAnimation anim = SpawnAnimatedSkeleton(data);
|
||||||
|
string dir = Path.GetDirectoryName(Path.GetDirectoryName(AssetDatabase.GetAssetPath(data)));
|
||||||
|
string prefabPath = Path.Combine(dir, data.skeletonJSON.name + ".prefab").Replace("\\", "/");
|
||||||
|
PrefabUtility.CreatePrefab(prefabPath, anim.gameObject, ReplacePrefabOptions.ReplaceNameBased);
|
||||||
|
|
||||||
|
if(EditorApplication.isPlaying)
|
||||||
|
GameObject.Destroy(anim.gameObject);
|
||||||
|
else
|
||||||
|
GameObject.DestroyImmediate(anim.gameObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsSpineJSON(TextAsset asset){
|
||||||
|
object obj = Json.Deserialize( new StringReader(asset.text));
|
||||||
|
if(obj == null){
|
||||||
|
Debug.LogError("Is not valid JSON");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary<string, object> root = (Dictionary<string, object>)obj;
|
||||||
|
|
||||||
|
if(!root.ContainsKey("skeleton"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Dictionary<string, object> skeletonInfo = (Dictionary<string, object>)root["skeleton"];
|
||||||
|
|
||||||
|
string spineVersion = (string)skeletonInfo["spine"];
|
||||||
|
|
||||||
|
//TODO: reject old versions
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static SkeletonDataAsset AutoIngestSpineProject(TextAsset spineJson, Object atlasSource = null){
|
||||||
|
TextAsset atlasText = null;
|
||||||
|
AtlasAsset atlasAsset = null;
|
||||||
|
|
||||||
|
if(atlasSource != null){
|
||||||
|
if(atlasSource.GetType() == typeof(TextAsset)){
|
||||||
|
atlasText = (TextAsset)atlasSource;
|
||||||
|
}
|
||||||
|
else if(atlasSource.GetType() == typeof(AtlasAsset)){
|
||||||
|
atlasAsset = (AtlasAsset)atlasSource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(atlasText == null && atlasAsset == null){
|
||||||
|
string primaryName = Path.GetFileNameWithoutExtension(spineJson.name);
|
||||||
|
string assetPath = Path.GetDirectoryName( AssetDatabase.GetAssetPath(spineJson));
|
||||||
|
|
||||||
|
if(atlasText == null){
|
||||||
|
string atlasPath = assetPath + "/" + primaryName + ".atlas.txt";
|
||||||
|
atlasText = (TextAsset)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(TextAsset));
|
||||||
|
|
||||||
|
if(atlasText == null){
|
||||||
|
//can't find atlas, likely because using a shared atlas
|
||||||
|
bool abort = !EditorUtility.DisplayDialog("Atlas not Found", "Expecting " + spineJson.name + ".atlas\n" + "Press OK to select Atlas", "OK", "Abort");
|
||||||
|
if(abort){
|
||||||
|
//do nothing, let it error later
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
string path = EditorUtility.OpenFilePanel( "Find Atlas source...", Path.GetDirectoryName(Application.dataPath) + "/" + assetPath, "txt");
|
||||||
|
if(path != ""){
|
||||||
|
path = path.Replace("\\", "/");
|
||||||
|
path = path.Replace(Application.dataPath.Replace("\\", "/"), "Assets");
|
||||||
|
atlasText = (TextAsset)AssetDatabase.LoadAssetAtPath(path, typeof(TextAsset));
|
||||||
|
// Debug.Log("Atlas Path: " + path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(atlasAsset == null)
|
||||||
|
atlasAsset = IngestSpineAtlas(atlasText);
|
||||||
|
|
||||||
|
return IngestSpineProject(spineJson, atlasAsset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static AtlasAsset IngestSpineAtlas(TextAsset atlasText){
|
||||||
|
if(atlasText == null){
|
||||||
|
Debug.LogWarning("Atlas source cannot be null!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
string primaryName = Path.GetFileNameWithoutExtension(atlasText.name).Replace(".atlas", "");
|
||||||
|
string assetPath = Path.GetDirectoryName( AssetDatabase.GetAssetPath(atlasText));
|
||||||
|
|
||||||
|
string atlasPath = assetPath + "/" + primaryName + "_Atlas.asset";
|
||||||
|
|
||||||
|
if(File.Exists(atlasPath))
|
||||||
|
return (AtlasAsset)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(AtlasAsset));
|
||||||
|
|
||||||
|
AtlasAsset atlasAsset = AtlasAsset.CreateInstance<AtlasAsset>();
|
||||||
|
atlasAsset.atlasFile = atlasText;
|
||||||
|
|
||||||
if(spineJson != null && atlasText != null){
|
string[] atlasLines = atlasText.text.Split('\n');
|
||||||
|
List<string> pageFiles = new List<string>();
|
||||||
|
for(int i = 0; i < atlasLines.Length-1; i++){
|
||||||
|
if(atlasLines[i].Length == 0)
|
||||||
|
pageFiles.Add(atlasLines[i+1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
atlasAsset.materials = new Material[pageFiles.Count];
|
||||||
|
|
||||||
|
for(int i = 0; i < pageFiles.Count; i++){
|
||||||
|
string texturePath = assetPath + "/" + pageFiles[i];
|
||||||
|
Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D));
|
||||||
|
|
||||||
AssetPreview.GetMiniTypeThumbnail(typeof(bool));
|
TextureImporter texImporter = (TextureImporter)TextureImporter.GetAtPath(texturePath);
|
||||||
|
texImporter.textureFormat = TextureImporterFormat.AutomaticTruecolor;
|
||||||
AtlasAsset atlasAsset = AtlasAsset.CreateInstance<AtlasAsset>();
|
texImporter.mipmapEnabled = false;
|
||||||
atlasAsset.atlasFile = atlasText;
|
EditorUtility.SetDirty(texImporter);
|
||||||
|
AssetDatabase.ImportAsset(texturePath);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
string[] atlasLines = atlasText.text.Split('\n');
|
|
||||||
List<string> pageFiles = new List<string>();
|
|
||||||
for(int i = 0; i < atlasLines.Length-1; i++){
|
|
||||||
if(atlasLines[i].Length == 0)
|
|
||||||
pageFiles.Add(atlasLines[i+1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
atlasAsset.materials = new Material[pageFiles.Count];
|
|
||||||
|
|
||||||
for(int i = 0; i < pageFiles.Count; i++){
|
|
||||||
string texturePath = assetPath + "/" + pageFiles[i];
|
|
||||||
Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D));
|
|
||||||
|
|
||||||
TextureImporter texImporter = (TextureImporter)TextureImporter.GetAtPath(texturePath);
|
|
||||||
texImporter.textureFormat = TextureImporterFormat.AutomaticTruecolor;
|
|
||||||
texImporter.mipmapEnabled = false;
|
|
||||||
EditorUtility.SetDirty(texImporter);
|
|
||||||
AssetDatabase.ImportAsset(texturePath);
|
|
||||||
AssetDatabase.SaveAssets();
|
|
||||||
|
|
||||||
string pageName = Path.GetFileNameWithoutExtension(pageFiles[i]);
|
|
||||||
|
|
||||||
//because this looks silly
|
|
||||||
if(pageName == primaryName && pageFiles.Count == 1)
|
|
||||||
pageName = "Material";
|
|
||||||
|
|
||||||
string materialPath = assetPath + "/" + primaryName + "_" + pageName + ".mat";
|
|
||||||
|
|
||||||
Material mat = new Material(Shader.Find(defaultShader));
|
|
||||||
|
|
||||||
mat.mainTexture = texture;
|
|
||||||
|
|
||||||
AssetDatabase.CreateAsset(mat, materialPath);
|
|
||||||
AssetDatabase.SaveAssets();
|
|
||||||
|
|
||||||
atlasAsset.materials[i] = mat;
|
|
||||||
}
|
|
||||||
|
|
||||||
AssetDatabase.CreateAsset(atlasAsset, assetPath + "/" + primaryName + "_Atlas.asset");
|
|
||||||
AssetDatabase.SaveAssets();
|
AssetDatabase.SaveAssets();
|
||||||
|
|
||||||
|
string pageName = Path.GetFileNameWithoutExtension(pageFiles[i]);
|
||||||
|
|
||||||
|
//because this looks silly
|
||||||
|
if(pageName == primaryName && pageFiles.Count == 1)
|
||||||
|
pageName = "Material";
|
||||||
|
|
||||||
|
string materialPath = assetPath + "/" + primaryName + "_" + pageName + ".mat";
|
||||||
|
|
||||||
|
Material mat = new Material(Shader.Find(defaultShader));
|
||||||
|
|
||||||
|
mat.mainTexture = texture;
|
||||||
|
|
||||||
|
AssetDatabase.CreateAsset(mat, materialPath);
|
||||||
|
AssetDatabase.SaveAssets();
|
||||||
|
|
||||||
|
atlasAsset.materials[i] = mat;
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetDatabase.CreateAsset(atlasAsset, atlasPath);
|
||||||
|
AssetDatabase.SaveAssets();
|
||||||
|
|
||||||
|
return (AtlasAsset)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(AtlasAsset));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static SkeletonDataAsset IngestSpineProject(TextAsset spineJson, AtlasAsset atlasAsset = null){
|
||||||
|
|
||||||
|
string primaryName = Path.GetFileNameWithoutExtension(spineJson.name);
|
||||||
|
string assetPath = Path.GetDirectoryName( AssetDatabase.GetAssetPath(spineJson));
|
||||||
|
|
||||||
|
if(spineJson != null && atlasAsset != null){
|
||||||
|
|
||||||
SkeletonDataAsset skelDataAsset = SkeletonDataAsset.CreateInstance<SkeletonDataAsset>();
|
SkeletonDataAsset skelDataAsset = SkeletonDataAsset.CreateInstance<SkeletonDataAsset>();
|
||||||
skelDataAsset.atlasAsset = atlasAsset;
|
skelDataAsset.atlasAsset = atlasAsset;
|
||||||
skelDataAsset.skeletonJSON = spineJson;
|
skelDataAsset.skeletonJSON = spineJson;
|
||||||
@ -213,10 +349,12 @@ public static class SpineEditorUtilities {
|
|||||||
|
|
||||||
AssetDatabase.CreateAsset(skelDataAsset, assetPath + "/" + primaryName + "_SkeletonData.asset");
|
AssetDatabase.CreateAsset(skelDataAsset, assetPath + "/" + primaryName + "_SkeletonData.asset");
|
||||||
AssetDatabase.SaveAssets();
|
AssetDatabase.SaveAssets();
|
||||||
|
|
||||||
|
return skelDataAsset;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
EditorUtility.DisplayDialog("Error!", "Atlas file not found in selection!", "OK");
|
EditorUtility.DisplayDialog("Error!", "Must specify both Spine JSON and Atlas TextAsset", "OK");
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,3 +426,5 @@ public static class SpineEditorUtilities {
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f834d5cd806ec4645915ac315edbdc60
|
||||||
|
MonoImporter:
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
Loading…
x
Reference in New Issue
Block a user