Files
TEngine/Assets/GameScripts/Editor/SpritePostprocessor.cs
2023-04-13 16:11:15 +08:00

489 lines
15 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEditor.U2D;
using UnityEngine;
using UnityEngine.U2D;
using Object = UnityEngine.Object;
/// <summary>
/// 图集导入管线。
/// </summary>
public class SpritePostprocessor : AssetPostprocessor
{
static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
{
foreach (var s in importedAssets)
{
EditorSpriteSaveInfo.OnImportSprite(s);
}
foreach (var s in deletedAssets)
{
EditorSpriteSaveInfo.OnDeleteSprite(s);
}
foreach (var s in movedFromAssetPaths)
{
EditorSpriteSaveInfo.OnDeleteSprite(s);
}
foreach (var s in movedAssets)
{
EditorSpriteSaveInfo.OnImportSprite(s);
}
}
}
public static class EditorSpriteSaveInfo
{
private const string NormalAtlasDir = "Assets/Atlas";
private const string UISpritePath = "Assets/AssetRaw/UIRaw";
private const string UIAtlasPath = "Assets/AssetRaw/UIRaw/Atlas";
private const string UIRawPath = "Assets/AssetRaw/UIRaw/UIRaw";
private static List<string> m_dirtyAtlasList = new List<string>();
private static Dictionary<string, List<string>> m_allASprites = new Dictionary<string, List<string>>();
private static Dictionary<string, string> m_uiAtlasMap = new Dictionary<string, string>();
private static bool m_inited = false;
private static bool m_dirty = false;
public static void Init()
{
if (m_inited)
{
return;
}
EditorApplication.update += CheckDirty;
}
public static void CheckDirty()
{
if (m_dirty)
{
m_dirty = false;
AssetDatabase.Refresh();
float lastProgress = -1;
for (int i = 0; i < m_dirtyAtlasList.Count; i++)
{
string atlasName = m_dirtyAtlasList[i];
Debug.Log("更新图集 : " + atlasName);
var curProgress = (float)i / m_dirtyAtlasList.Count;
if (curProgress > lastProgress + 0.01f)
{
lastProgress = curProgress;
var progressText = $"当前进度:{i}/{m_dirtyAtlasList.Count} {atlasName}";
bool cancel = EditorUtility.DisplayCancelableProgressBar("刷新图集" + atlasName, progressText, curProgress);
if (cancel)
{
break;
}
}
bool isUI = atlasName.StartsWith("UIRaw");
SaveAtlas(atlasName, isUI);
}
EditorUtility.ClearProgressBar();
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
m_dirtyAtlasList.Clear();
}
}
public static void OnImportSprite(string assetPath)
{
if (!assetPath.StartsWith(UISpritePath))
{
return;
}
TextureImporter ti = AssetImporter.GetAtPath(assetPath) as TextureImporter;
if (ti != null)
{
var modify = false;
if (assetPath.StartsWith(UISpritePath))
{
if (ti.textureType != TextureImporterType.Sprite)
{
ti.textureType = TextureImporterType.Sprite;
modify = true;
}
if (!string.IsNullOrEmpty(ti.spritePackingTag))
{
ti.spritePackingTag = string.Empty;
modify = true;
}
var setting = new TextureImporterSettings();
ti.ReadTextureSettings(setting);
if (setting.spriteGenerateFallbackPhysicsShape)
{
setting.spriteGenerateFallbackPhysicsShape = false;
ti.SetTextureSettings(setting);
modify = true;
}
if (IsKeepRawImage(assetPath))
{
//调整android格式
var andPlatformSettings = ti.GetPlatformTextureSettings("Android");
if (!andPlatformSettings.overridden)
{
andPlatformSettings.overridden = true;
modify = true;
}
if (andPlatformSettings.format != TextureImporterFormat.ASTC_6x6)
{
andPlatformSettings.format = TextureImporterFormat.ASTC_6x6;
ti.SetPlatformTextureSettings(andPlatformSettings);
modify = true;
}
//调整ios格式
var iosPlatformSettings = ti.GetPlatformTextureSettings("iPhone");
if (!iosPlatformSettings.overridden)
{
iosPlatformSettings.overridden = true;
modify = true;
}
if (iosPlatformSettings.format != TextureImporterFormat.ASTC_5x5)
{
iosPlatformSettings.format = TextureImporterFormat.ASTC_5x5;
iosPlatformSettings.compressionQuality = 50;
ti.SetPlatformTextureSettings(iosPlatformSettings);
modify = true;
}
}
}
if (modify)
{
ti.SaveAndReimport();
}
if (ti.textureType == TextureImporterType.Sprite)
{
OnProcessSprite(assetPath);
}
}
}
/// <summary>
/// 是否保持散图(不打图集)
/// </summary>
/// <param name="dirPath"></param>
/// <returns></returns>
public static bool IsKeepRawImage(string dirPath)
{
return dirPath.Contains("UIRaw/Raw/") || dirPath.Contains("UIRaw_Raw_");
}
public static string GetSpritePath(string assetPath)
{
string path = assetPath.Substring(0, assetPath.LastIndexOf("."));
path = path.Replace("Assets/AssetRaw/", "");
return path;
}
/// <summary>
/// 根据文件路径,返回图集名称
/// </summary>
/// <param name="fullName"></param>
/// <returns></returns>
public static string GetPackageTag(string fullName)
{
fullName = fullName.Replace("\\", "/");
int idx = fullName.LastIndexOf("UIRaw", StringComparison.Ordinal);
if (idx == -1)
{
return "";
}
if (IsKeepRawImage(fullName))
{
return "";
}
var atlasPath = fullName.Substring(idx);
string str = atlasPath;
str = str.Substring(0, str.LastIndexOf("/", StringComparison.Ordinal)).Replace("/", "_");
return str;
}
public static void OnProcessSprite(string assetPath)
{
if (!assetPath.StartsWith("Assets"))
{
return;
}
if (assetPath.StartsWith("Assets/UIRaw_Delete"))
{
return;
}
Init();
var spriteName = Path.GetFileNameWithoutExtension(assetPath);
var spritePath = GetSpritePath(assetPath);
if (!m_uiAtlasMap.TryGetValue(spriteName, out string oldAssetPath) || spritePath == oldAssetPath)
{
m_uiAtlasMap[spriteName] = spritePath;
m_dirty = true;
}
else
{
Debug.LogError($"有重名的图片:{spriteName}\n旧图集{oldAssetPath}\n新图集{spritePath} ");
m_uiAtlasMap[spriteName] = spritePath;
m_dirty = true;
}
string atlasName = GetPackageTag(assetPath);
if (string.IsNullOrEmpty(atlasName))
{
bool keepRaw = IsKeepRawImage(assetPath);
if (!keepRaw)
{
Debug.LogError($"empty packingTag of asset :{assetPath} !!!");
}
return;
}
else
{
List<string> ret;
if (!m_allASprites.TryGetValue(atlasName, out ret))
{
ret = new List<string>();
m_allASprites.Add(atlasName, ret);
}
if (!ret.Contains(assetPath))
{
ret.Add(assetPath);
m_dirty = true;
if (!m_dirtyAtlasList.Contains(atlasName))
{
m_dirtyAtlasList.Add(atlasName);
}
}
}
}
public static void OnDeleteSprite(string assetPath)
{
if (assetPath.StartsWith("Assets/UIRaw_Delete"))
{
return;
}
if (!assetPath.StartsWith(UISpritePath))
{
return;
}
Init();
string atlasName = GetPackageTag(assetPath);
if (!m_allASprites.TryGetValue(atlasName, out var ret))
{
return;
}
//改成文件名的匹配
if (!ret.Exists(s => Path.GetFileName(s) == Path.GetFileName(assetPath)))
{
return;
}
if (assetPath.StartsWith(UISpritePath))
{
var spriteName = Path.GetFileNameWithoutExtension(assetPath);
if (m_uiAtlasMap.ContainsKey(spriteName))
{
m_uiAtlasMap.Remove(spriteName);
m_dirty = true;
}
}
ret.Remove(assetPath);
m_dirty = true;
if (!m_dirtyAtlasList.Contains(atlasName))
{
m_dirtyAtlasList.Add(atlasName);
}
}
#region
public static void SaveAtlas(string atlasName, bool isUI)
{
List<Object> spriteList = new List<Object>();
if (m_allASprites.ContainsKey(atlasName))
{
var list = m_allASprites[atlasName];
list.Sort(StringComparer.Ordinal);
foreach (var s in list)
{
var sprite = AssetDatabase.LoadAssetAtPath<Sprite>(s);
if (sprite != null)
{
spriteList.Add(sprite);
}
}
}
var path = $"{NormalAtlasDir}/{atlasName}.spriteatlas";
if (spriteList.Count == 0)
{
if (File.Exists(path))
{
AssetDatabase.DeleteAsset(path);
}
return;
}
var atlas = new SpriteAtlas();
var setting = new SpriteAtlasPackingSettings
{
blockOffset = 1,
padding = 2,
enableRotation = true
};
bool isOpaque = atlasName.Contains("Opaque");
var textureSetting = new SpriteAtlasTextureSettings
{
generateMipMaps = false,
sRGB = true,
filterMode = FilterMode.Bilinear
};
atlas.SetTextureSettings(textureSetting);
var iphonePlatformSetting = atlas.GetPlatformSettings("iPhone");
if (!iphonePlatformSetting.overridden)
{
iphonePlatformSetting.overridden = true;
iphonePlatformSetting.format = isOpaque ? TextureImporterFormat.ASTC_5x5 : TextureImporterFormat.ASTC_5x5;
iphonePlatformSetting.compressionQuality = 100;
atlas.SetPlatformSettings(iphonePlatformSetting);
}
var androidPlatformSetting = atlas.GetPlatformSettings("Android");
if (isOpaque && !androidPlatformSetting.overridden)
{
androidPlatformSetting.overridden = true;
androidPlatformSetting.format = TextureImporterFormat.ETC_RGB4;
androidPlatformSetting.compressionQuality = 100;
atlas.SetPlatformSettings(androidPlatformSetting);
}
atlas.SetPackingSettings(setting);
atlas.Add(spriteList.ToArray());
AssetDatabase.CreateAsset(atlas, path);
}
#endregion
#region
private static Dictionary<string, List<string>> m_tempAllASprites = new Dictionary<string, List<string>>();
[MenuItem("TEngine/图集/重新生成UI图集")]
static void ForceGenAtlas()
{
Init();
List<string> needSaveAtlas = new List<string>();
m_tempAllASprites.Clear();
var findAssets = AssetDatabase.FindAssets("t:sprite", new[] { UIAtlasPath });
foreach (var findAsset in findAssets)
{
var path = AssetDatabase.GUIDToAssetPath(findAsset);
var atlasName = GetPackageTag(path);
if (!m_tempAllASprites.TryGetValue(atlasName, out var spriteList))
{
spriteList = new List<string>();
m_tempAllASprites[atlasName] = spriteList;
}
if (!spriteList.Contains(path))
{
spriteList.Add(path);
}
}
//有变化的才刷
var iter = m_tempAllASprites.GetEnumerator();
while (iter.MoveNext())
{
bool needSave = false;
var atlasName = iter.Current.Key;
var newSpritesList = iter.Current.Value;
List<string> existSprites;
if (m_allASprites.TryGetValue(atlasName, out existSprites))
{
if (existSprites.Count != newSpritesList.Count)
{
needSave = true;
existSprites.Clear();
existSprites.AddRange(newSpritesList);
}
else
{
for (int i = 0; i < newSpritesList.Count; i++)
{
if (!existSprites.Contains(newSpritesList[i]))
{
needSave = true;
break;
}
}
if (needSave)
{
existSprites.Clear();
existSprites.AddRange(newSpritesList);
}
}
}
else
{
needSave = true;
m_allASprites.Add(atlasName, new List<string>(newSpritesList));
}
if (needSave && !needSaveAtlas.Contains(atlasName))
{
needSaveAtlas.Add(atlasName);
}
}
iter.Dispose();
foreach (var atlas in needSaveAtlas)
{
Debug.LogFormat("Gen atlas:{0}", atlas);
SaveAtlas(atlas, true);
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
SpriteAtlasUtility.PackAllAtlases(EditorUserBuildSettings.activeBuildTarget);
Debug.Log("Gen end");
}
#endregion
}