modify
This commit is contained in:
parent
51b3d2ae02
commit
b6d8704c75
@ -1,24 +1,38 @@
|
||||
// AtlasConfiguration.cs
|
||||
|
||||
using UnityEditor;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
[FilePath("ProjectSettings/AtlasConfiguration.asset",FilePathAttribute.Location.ProjectFolder)]
|
||||
public class AtlasConfiguration : ScriptableSingleton<AtlasConfiguration>
|
||||
[AlicizaX.Editor.Setting.FilePath("ProjectSettings/AtlasConfiguration.asset")]
|
||||
public class AtlasConfiguration : AlicizaX.Editor.Setting.ScriptableSingleton<AtlasConfiguration>
|
||||
{
|
||||
[Header("Directory Settings")]
|
||||
public string atlasOutputPath = "Assets/Art/Atlas";
|
||||
public string rawUIPath = "Assets/Art/UI/Raw";
|
||||
public string uiAtlasPath = "Assets/Art/UI/Atlases";
|
||||
[Header("目录设置")]
|
||||
[Tooltip("生成的图集输出目录")]
|
||||
public string outputAtlasDir = "Assets/Art/Atlas";
|
||||
|
||||
[Header("Texture Settings")]
|
||||
[Tooltip("需要生成图集的UI根目录")]
|
||||
public string sourceAtlasRoot = "Assets/Bundles/UIRaw/Atlas";
|
||||
|
||||
[Tooltip("不需要生成图集的UI目录")]
|
||||
public string excludeFolder = "Assets/Bundles/UIRaw/Raw";
|
||||
|
||||
[Header("平台格式设置")]
|
||||
public TextureImporterFormat androidFormat = TextureImporterFormat.ASTC_6x6;
|
||||
public TextureImporterFormat iosFormat = TextureImporterFormat.ASTC_5x5;
|
||||
public TextureImporterFormat webglFormat = TextureImporterFormat.ASTC_6x6;
|
||||
public int compressionQuality = 50;
|
||||
|
||||
[Header("Packing Settings")]
|
||||
[Header("PackingSetting")]
|
||||
public int padding = 2;
|
||||
public bool enableRotation = true;
|
||||
public int blockOffset = 1;
|
||||
public bool tightPacking = true;
|
||||
|
||||
[Header("其他设置")]
|
||||
[Range(0, 100)] public int compressionQuality = 50;
|
||||
public bool autoGenerate = true;
|
||||
public bool enableLogging = true;
|
||||
public bool enableV2 = true;
|
||||
|
||||
[Header("排除关键词")]
|
||||
public string[] excludeKeywords = { "_Delete", "_Temp" };
|
||||
}
|
||||
#endif
|
||||
|
@ -1,95 +1,158 @@
|
||||
// AtlasEditorWindow.cs
|
||||
|
||||
using AlicizaX.Editor;
|
||||
using AlicizaX.Editor.Extension;
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
public class AtlasEditorWindow : EditorWindow
|
||||
public class AtlasConfigWindow : EditorWindow
|
||||
{
|
||||
private const string AtlasProcessorKey = "AtlasProcessorKey";
|
||||
|
||||
private AtlasConfiguration config;
|
||||
private Vector2 scrollPos;
|
||||
private bool useAtlas = false;
|
||||
|
||||
[EditorToolFunction("图集工具")]
|
||||
[MenuItem("Tools/图集工具/配置面板")]
|
||||
public static void ShowWindow()
|
||||
{
|
||||
GetWindow<AtlasEditorWindow>("图集打包");
|
||||
GetWindow<AtlasConfigWindow>("Atlas Config").minSize = new Vector2(450, 400);
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
LoadOrCreateConfig();
|
||||
useAtlas = ScriptingDefineSymbols.HasScriptingDefineSymbol(BuildTargetGroup.Standalone, AtlasProcessorKey);
|
||||
}
|
||||
private Vector2 _scrollPosition;
|
||||
|
||||
private void LoadOrCreateConfig()
|
||||
{
|
||||
config = AtlasConfiguration.instance;
|
||||
}
|
||||
private int[] _paddingEnum = new int[] { 2, 4, 8 };
|
||||
private bool _showExcludeKeywords = false; // 新增折叠状态变量
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
if (config == null) return;
|
||||
var config = AtlasConfiguration.Instance;
|
||||
|
||||
|
||||
scrollPos = EditorGUILayout.BeginScrollView(scrollPos);
|
||||
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Atlas Configuration", EditorStyles.boldLabel);
|
||||
var useAtlasToggle = EditorGUILayout.Toggle("Enable", useAtlas);
|
||||
if (useAtlasToggle != useAtlas)
|
||||
using (var scrollScope = new EditorGUILayout.ScrollViewScope(_scrollPosition))
|
||||
{
|
||||
if (useAtlas)
|
||||
{
|
||||
ScriptingDefineSymbols.AddScriptingDefineSymbol(AtlasProcessorKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
ScriptingDefineSymbols.RemoveScriptingDefineSymbol(AtlasProcessorKey);
|
||||
}
|
||||
}
|
||||
_scrollPosition = scrollScope.scrollPosition;
|
||||
|
||||
DrawConfigurationGUI();
|
||||
EditorGUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
private void DrawConfigurationGUI()
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Paths", EditorStyles.boldLabel);
|
||||
config.atlasOutputPath = EditorGUILayout.TextField("Atlas Output", config.atlasOutputPath);
|
||||
config.rawUIPath = EditorGUILayout.TextField("Raw UI Path", config.rawUIPath);
|
||||
config.uiAtlasPath = EditorGUILayout.TextField("UI Atlas Path", config.uiAtlasPath);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Texture Settings", EditorStyles.boldLabel);
|
||||
config.androidFormat = (TextureImporterFormat)EditorGUILayout.EnumPopup("Android Format", config.androidFormat);
|
||||
config.iosFormat = (TextureImporterFormat)EditorGUILayout.EnumPopup("iOS Format", config.iosFormat);
|
||||
config.webglFormat = (TextureImporterFormat)EditorGUILayout.EnumPopup("WebGL Format", config.webglFormat);
|
||||
config.compressionQuality = EditorGUILayout.IntSlider("Compression Quality",
|
||||
config.compressionQuality, 0, 100);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Packing Settings", EditorStyles.boldLabel);
|
||||
config.padding = EditorGUILayout.IntField("Padding", config.padding);
|
||||
config.enableRotation = EditorGUILayout.Toggle("Enable Rotation", config.enableRotation);
|
||||
config.blockOffset = EditorGUILayout.IntField("Block Offset", config.blockOffset);
|
||||
DrawFolderSettings(config);
|
||||
DrawPlatformSettings(config);
|
||||
DrawPackingSettings(config);
|
||||
DrawAdvancedSettings(config);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
EditorUtility.SetDirty(config);
|
||||
AtlasConfiguration.Save(true);
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
if (GUILayout.Button("Force Rebuild All Atlases", GUILayout.Height(30)))
|
||||
DrawActionButtons();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawFolderSettings(AtlasConfiguration config)
|
||||
{
|
||||
AtlasProcessor.ForceRebuildAtlases(config);
|
||||
GUILayout.Label("目录设置", EditorStyles.boldLabel);
|
||||
config.outputAtlasDir = DrawFolderField("输出目录", config.outputAtlasDir);
|
||||
config.sourceAtlasRoot = DrawFolderField("收集目录", config.sourceAtlasRoot);
|
||||
config.excludeFolder = DrawFolderField("排除目录", config.excludeFolder);
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
|
||||
private string DrawFolderField(string label, string path)
|
||||
{
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
path = EditorGUILayout.TextField(label, path);
|
||||
if (GUILayout.Button("选择", GUILayout.Width(60)))
|
||||
{
|
||||
var newPath = EditorUtility.OpenFolderPanel(label, Application.dataPath, "");
|
||||
if (!string.IsNullOrEmpty(newPath))
|
||||
{
|
||||
path = "Assets" + newPath.Substring(Application.dataPath.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
private void DrawPlatformSettings(AtlasConfiguration config)
|
||||
{
|
||||
GUILayout.Label("平台设置", EditorStyles.boldLabel);
|
||||
config.androidFormat = (TextureImporterFormat)EditorGUILayout.EnumPopup("Android 格式", config.androidFormat);
|
||||
config.iosFormat = (TextureImporterFormat)EditorGUILayout.EnumPopup("iOS 格式", config.iosFormat);
|
||||
config.webglFormat = (TextureImporterFormat)EditorGUILayout.EnumPopup("WebGL 格式", config.webglFormat);
|
||||
config.compressionQuality = EditorGUILayout.IntSlider("压缩质量", config.compressionQuality, 0, 100);
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
|
||||
private void DrawPackingSettings(AtlasConfiguration config)
|
||||
{
|
||||
GUILayout.Label("PackingSetting", EditorStyles.boldLabel);
|
||||
config.padding = EditorGUILayout.IntPopup("Padding",
|
||||
config.padding,
|
||||
Array.ConvertAll(_paddingEnum, x => x.ToString()),
|
||||
_paddingEnum);
|
||||
config.blockOffset = EditorGUILayout.IntField("BlockOffset", config.blockOffset);
|
||||
config.enableRotation = EditorGUILayout.Toggle("Enable Rotation", config.enableRotation);
|
||||
config.tightPacking = EditorGUILayout.Toggle("剔除透明区域", config.tightPacking);
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
|
||||
|
||||
private void DrawAdvancedSettings(AtlasConfiguration config)
|
||||
{
|
||||
GUILayout.Label("高级设置", EditorStyles.boldLabel);
|
||||
config.autoGenerate = EditorGUILayout.Toggle("自动生成", config.autoGenerate);
|
||||
config.enableLogging = EditorGUILayout.Toggle("启用日志", config.enableLogging);
|
||||
config.enableV2 = EditorGUILayout.Toggle("启用V2打包", config.enableV2);
|
||||
// 优化后的排除关键词显示
|
||||
_showExcludeKeywords = EditorGUILayout.BeginFoldoutHeaderGroup(_showExcludeKeywords, "排除关键词");
|
||||
if (_showExcludeKeywords)
|
||||
{
|
||||
int keywordCount = config.excludeKeywords?.Length ?? 0;
|
||||
int newCount = EditorGUILayout.IntField("数量", keywordCount);
|
||||
|
||||
// 调整数组大小
|
||||
if (newCount != keywordCount)
|
||||
{
|
||||
Array.Resize(ref config.excludeKeywords, newCount);
|
||||
}
|
||||
|
||||
// 绘制每个元素
|
||||
for (int i = 0; i < newCount; i++)
|
||||
{
|
||||
config.excludeKeywords[i] = EditorGUILayout.TextField($"关键词 {i + 1}",
|
||||
config.excludeKeywords[i] ?? "");
|
||||
}
|
||||
|
||||
// 添加快捷按钮
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
if (GUILayout.Button("添加", GUILayout.Width(60)))
|
||||
{
|
||||
Array.Resize(ref config.excludeKeywords, newCount + 1);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("清空", GUILayout.Width(60)))
|
||||
{
|
||||
config.excludeKeywords = Array.Empty<string>();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
|
||||
private void DrawActionButtons()
|
||||
{
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("立即生成所有图集", GUILayout.Height(30)))
|
||||
{
|
||||
EditorSpriteSaveInfo.ForceGenerateAll();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("清空缓存", GUILayout.Height(30)))
|
||||
{
|
||||
EditorSpriteSaveInfo.ClearCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1,38 +0,0 @@
|
||||
#if AtlasProcessorKey
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
public class AtlasPostprocessor : AssetPostprocessor
|
||||
{
|
||||
private static AtlasConfiguration config;
|
||||
|
||||
private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets,
|
||||
string[] movedAssets, string[] movedFromAssetPaths)
|
||||
{
|
||||
if (config == null)
|
||||
{
|
||||
config = AtlasConfiguration.instance;
|
||||
}
|
||||
if (config == null) return;
|
||||
|
||||
foreach (var path in importedAssets) HandleAsset(path);
|
||||
foreach (var path in movedAssets) HandleAsset(path);
|
||||
foreach (var path in deletedAssets) HandleDeletedAsset(path);
|
||||
foreach (var path in movedFromAssetPaths) HandleDeletedAsset(path);
|
||||
}
|
||||
|
||||
private static void HandleAsset(string path)
|
||||
{
|
||||
if (path.EndsWith(".png") || path.EndsWith(".jpg"))
|
||||
{
|
||||
AtlasProcessor.ProcessSingleSprite(path, config);
|
||||
}
|
||||
}
|
||||
|
||||
private static void HandleDeletedAsset(string path)
|
||||
{
|
||||
// Handle removed sprites from atlases
|
||||
// Implementation depends on tracking system
|
||||
}
|
||||
}
|
||||
#endif
|
@ -1,210 +0,0 @@
|
||||
// AtlasProcessor.cs
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEditor.U2D;
|
||||
using UnityEngine;
|
||||
using UnityEngine.U2D;
|
||||
|
||||
public static class AtlasProcessor
|
||||
{
|
||||
private static readonly HashSet<string> DirtyAtlas = new HashSet<string>();
|
||||
private static readonly Dictionary<string, HashSet<string>> AtlasContents =
|
||||
new Dictionary<string, HashSet<string>>();
|
||||
|
||||
public static void ForceRebuildAtlases(AtlasConfiguration config)
|
||||
{
|
||||
InitializeAtlasData(config);
|
||||
ProcessAllSprites(config);
|
||||
PackAllAtlases(config);
|
||||
}
|
||||
|
||||
private static void InitializeAtlasData(AtlasConfiguration config)
|
||||
{
|
||||
AtlasContents.Clear();
|
||||
var atlasGuids = AssetDatabase.FindAssets("t:SpriteAtlas", new[] { config.atlasOutputPath });
|
||||
|
||||
foreach (var guid in atlasGuids)
|
||||
{
|
||||
var path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
var atlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(path);
|
||||
if (atlas == null) continue;
|
||||
|
||||
var atlasName = Path.GetFileNameWithoutExtension(path);
|
||||
var packed = atlas.GetPackables();
|
||||
AtlasContents[atlasName] = new HashSet<string>();
|
||||
|
||||
foreach (var obj in packed)
|
||||
{
|
||||
var assetPath = AssetDatabase.GetAssetPath(obj);
|
||||
if (!string.IsNullOrEmpty(assetPath))
|
||||
{
|
||||
AtlasContents[atlasName].Add(assetPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ProcessAllSprites(AtlasConfiguration config)
|
||||
{
|
||||
var allSprites = AssetDatabase.FindAssets("t:Sprite", new[] { config.rawUIPath });
|
||||
foreach (var guid in allSprites)
|
||||
{
|
||||
var path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
ProcessSingleSprite(path, config);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ProcessSingleSprite(string path, AtlasConfiguration config)
|
||||
{
|
||||
if (!path.StartsWith(config.rawUIPath)) return;
|
||||
|
||||
var importer = AssetImporter.GetAtPath(path) as TextureImporter;
|
||||
if (importer == null) return;
|
||||
|
||||
ConfigureTextureImporter(importer, config);
|
||||
AddToAtlas(path, config);
|
||||
}
|
||||
|
||||
private static void ConfigureTextureImporter(TextureImporter importer, AtlasConfiguration config)
|
||||
{
|
||||
var changed = false;
|
||||
var settings = new TextureImporterSettings();
|
||||
importer.ReadTextureSettings(settings);
|
||||
|
||||
if (importer.textureType != TextureImporterType.Sprite)
|
||||
{
|
||||
importer.textureType = TextureImporterType.Sprite;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (settings.spriteGenerateFallbackPhysicsShape)
|
||||
{
|
||||
settings.spriteGenerateFallbackPhysicsShape = false;
|
||||
importer.SetTextureSettings(settings);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
ApplyPlatformSettings(importer, "Android", config.androidFormat, config);
|
||||
ApplyPlatformSettings(importer, "iPhone", config.iosFormat, config);
|
||||
ApplyPlatformSettings(importer, "WebGL", config.webglFormat, config);
|
||||
|
||||
if (changed) importer.SaveAndReimport();
|
||||
}
|
||||
|
||||
private static void ApplyPlatformSettings(TextureImporter importer, string platform,
|
||||
TextureImporterFormat format, AtlasConfiguration config)
|
||||
{
|
||||
var settings = importer.GetPlatformTextureSettings(platform);
|
||||
if (!settings.overridden || settings.format != format ||
|
||||
settings.compressionQuality != config.compressionQuality)
|
||||
{
|
||||
settings.overridden = true;
|
||||
settings.format = format;
|
||||
settings.compressionQuality = config.compressionQuality;
|
||||
importer.SetPlatformTextureSettings(settings);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddToAtlas(string spritePath, AtlasConfiguration config)
|
||||
{
|
||||
var atlasName = GetAtlasName(spritePath, config);
|
||||
if (string.IsNullOrEmpty(atlasName)) return;
|
||||
|
||||
if (!AtlasContents.TryGetValue(atlasName, out var paths))
|
||||
{
|
||||
paths = new HashSet<string>();
|
||||
AtlasContents[atlasName] = paths;
|
||||
}
|
||||
|
||||
if (paths.Add(spritePath)) DirtyAtlas.Add(atlasName);
|
||||
}
|
||||
|
||||
private static string GetAtlasName(string path, AtlasConfiguration config)
|
||||
{
|
||||
var relativePath = path.Replace(config.rawUIPath, "").TrimStart('/');
|
||||
var directory = Path.GetDirectoryName(relativePath);
|
||||
return directory?.Replace("/", "_");
|
||||
}
|
||||
|
||||
private static void PackAllAtlases(AtlasConfiguration config)
|
||||
{
|
||||
foreach (var atlasName in DirtyAtlas)
|
||||
{
|
||||
CreateOrUpdateAtlas(atlasName, config);
|
||||
}
|
||||
DirtyAtlas.Clear();
|
||||
|
||||
SpriteAtlasUtility.PackAllAtlases(EditorUserBuildSettings.activeBuildTarget);
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
|
||||
private static void CreateOrUpdateAtlas(string atlasName, AtlasConfiguration config)
|
||||
{
|
||||
if (!System.IO.Directory.Exists(config.atlasOutputPath))
|
||||
{
|
||||
Directory.CreateDirectory(config.atlasOutputPath);
|
||||
}
|
||||
var path = $"{config.atlasOutputPath}/{atlasName}.spriteatlas";
|
||||
var atlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(path) ?? new SpriteAtlas();
|
||||
|
||||
ConfigureAtlasSettings(atlas, config);
|
||||
AddSpritesToAtlas(atlas, AtlasContents[atlasName]);
|
||||
|
||||
if (!AssetDatabase.Contains(atlas))
|
||||
{
|
||||
AssetDatabase.CreateAsset(atlas, path);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorUtility.SetDirty(atlas);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ConfigureAtlasSettings(SpriteAtlas atlas, AtlasConfiguration config)
|
||||
{
|
||||
// Packing Settings
|
||||
var packingSettings = new SpriteAtlasPackingSettings
|
||||
{
|
||||
padding = config.padding,
|
||||
enableRotation = config.enableRotation,
|
||||
blockOffset = config.blockOffset
|
||||
};
|
||||
atlas.SetPackingSettings(packingSettings);
|
||||
|
||||
// Texture Settings
|
||||
var textureSettings = new SpriteAtlasTextureSettings
|
||||
{
|
||||
generateMipMaps = false,
|
||||
sRGB = true,
|
||||
filterMode = FilterMode.Bilinear
|
||||
};
|
||||
atlas.SetTextureSettings(textureSettings);
|
||||
|
||||
// Platform Settings
|
||||
SetPlatformFormat(atlas, "Android", config.androidFormat, config);
|
||||
SetPlatformFormat(atlas, "iPhone", config.iosFormat, config);
|
||||
SetPlatformFormat(atlas, "WebGL", config.webglFormat, config);
|
||||
}
|
||||
|
||||
private static void SetPlatformFormat(SpriteAtlas atlas, string platform,
|
||||
TextureImporterFormat format, AtlasConfiguration config)
|
||||
{
|
||||
var settings = atlas.GetPlatformSettings(platform);
|
||||
settings.overridden = true;
|
||||
settings.format = format;
|
||||
settings.compressionQuality = config.compressionQuality;
|
||||
atlas.SetPlatformSettings(settings);
|
||||
}
|
||||
|
||||
private static void AddSpritesToAtlas(SpriteAtlas atlas, IEnumerable<string> spritePaths)
|
||||
{
|
||||
var packables = new List<Object>();
|
||||
foreach (var path in spritePaths)
|
||||
{
|
||||
var obj = AssetDatabase.LoadAssetAtPath<Object>(path);
|
||||
if (obj != null) packables.Add(obj);
|
||||
}
|
||||
atlas.Add(packables.ToArray());
|
||||
}
|
||||
}
|
361
Editor/Postprocessor/Atlas/EditorSpriteSaveInfo.cs
Normal file
361
Editor/Postprocessor/Atlas/EditorSpriteSaveInfo.cs
Normal file
@ -0,0 +1,361 @@
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.U2D;
|
||||
using UnityEngine;
|
||||
using UnityEngine.U2D;
|
||||
|
||||
public static class EditorSpriteSaveInfo
|
||||
{
|
||||
private static readonly HashSet<string> _dirtyAtlasNames = new HashSet<string>();
|
||||
private static readonly Dictionary<string, List<string>> _atlasMap = new Dictionary<string, List<string>>();
|
||||
private static bool _initialized;
|
||||
|
||||
private static AtlasConfiguration Config => AtlasConfiguration.Instance;
|
||||
|
||||
static EditorSpriteSaveInfo()
|
||||
{
|
||||
EditorApplication.update += OnUpdate;
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private static void Initialize()
|
||||
{
|
||||
if (_initialized) return;
|
||||
|
||||
ScanExistingSprites();
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
public static void OnImportSprite(string assetPath)
|
||||
{
|
||||
if (!ShouldProcess(assetPath)) return;
|
||||
|
||||
var atlasName = GetAtlasName(assetPath);
|
||||
if (string.IsNullOrEmpty(atlasName)) return;
|
||||
|
||||
if (!_atlasMap.TryGetValue(atlasName, out var list))
|
||||
{
|
||||
list = new List<string>();
|
||||
_atlasMap[atlasName] = list;
|
||||
}
|
||||
|
||||
if (!list.Contains(assetPath))
|
||||
{
|
||||
list.Add(assetPath);
|
||||
MarkDirty(atlasName);
|
||||
MarkParentAtlasesDirty(assetPath);
|
||||
}
|
||||
}
|
||||
|
||||
public static void OnDeleteSprite(string assetPath)
|
||||
{
|
||||
if (!ShouldProcess(assetPath)) return;
|
||||
|
||||
var atlasName = GetAtlasName(assetPath);
|
||||
if (string.IsNullOrEmpty(atlasName)) return;
|
||||
|
||||
if (_atlasMap.TryGetValue(atlasName, out var list))
|
||||
{
|
||||
if (list.Remove(assetPath))
|
||||
{
|
||||
MarkDirty(atlasName);
|
||||
MarkParentAtlasesDirty(assetPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("Tools/图集工具/ForceGenerateAll")]
|
||||
public static void ForceGenerateAll()
|
||||
{
|
||||
_atlasMap.Clear();
|
||||
ScanExistingSprites();
|
||||
_dirtyAtlasNames.UnionWith(_atlasMap.Keys);
|
||||
ProcessDirtyAtlases(true);
|
||||
}
|
||||
|
||||
public static void ClearCache()
|
||||
{
|
||||
_dirtyAtlasNames.Clear();
|
||||
_atlasMap.Clear();
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
public static void MarkParentAtlasesDirty(string assetPath)
|
||||
{
|
||||
var currentPath = Path.GetDirectoryName(assetPath);
|
||||
var rootPath = Config.sourceAtlasRoot.Replace("\\", "/").TrimEnd('/');
|
||||
|
||||
while (currentPath != null && currentPath.StartsWith(rootPath))
|
||||
{
|
||||
var parentAtlasName = GetAtlasNameForDirectory(currentPath);
|
||||
if (!string.IsNullOrEmpty(parentAtlasName))
|
||||
{
|
||||
MarkDirty(parentAtlasName);
|
||||
}
|
||||
|
||||
currentPath = Path.GetDirectoryName(currentPath);
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnUpdate()
|
||||
{
|
||||
if (_dirtyAtlasNames.Count > 0)
|
||||
{
|
||||
ProcessDirtyAtlases();
|
||||
}
|
||||
}
|
||||
|
||||
private static void ProcessDirtyAtlases(bool force = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
AssetDatabase.StartAssetEditing();
|
||||
|
||||
foreach (var atlasName in _dirtyAtlasNames.ToList())
|
||||
{
|
||||
if (force || ShouldUpdateAtlas(atlasName))
|
||||
{
|
||||
GenerateAtlas(atlasName);
|
||||
}
|
||||
|
||||
_dirtyAtlasNames.Remove(atlasName);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
AssetDatabase.StopAssetEditing();
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
private static void GenerateAtlas(string atlasName)
|
||||
{
|
||||
var outputPath = $"{Config.outputAtlasDir}/{atlasName}.spriteatlas";
|
||||
SpriteAtlasAsset spriteAtlasAsset = default;
|
||||
SpriteAtlas atlas = new SpriteAtlas();
|
||||
if (Config.enableV2)
|
||||
{
|
||||
outputPath = $"{Config.outputAtlasDir}/{atlasName}.spriteatlasv2";
|
||||
if (!File.Exists(outputPath))
|
||||
{
|
||||
spriteAtlasAsset = new SpriteAtlasAsset();
|
||||
}
|
||||
else
|
||||
{
|
||||
spriteAtlasAsset = SpriteAtlasAsset.Load(outputPath);
|
||||
atlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(outputPath);
|
||||
if (atlas != null)
|
||||
{
|
||||
var olds = atlas.GetPackables();
|
||||
if (olds != null) spriteAtlasAsset.Remove(olds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var sprites = LoadValidSprites(atlasName);
|
||||
EnsureOutputDirectory();
|
||||
if (sprites.Count == 0)
|
||||
{
|
||||
DeleteAtlas(outputPath);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Config.enableV2)
|
||||
{
|
||||
spriteAtlasAsset.Add(sprites.ToArray());
|
||||
SpriteAtlasAsset.Save(spriteAtlasAsset, outputPath);
|
||||
AssetDatabase.Refresh();
|
||||
EditorApplication.delayCall += () =>
|
||||
{
|
||||
SpriteAtlasImporter sai = (SpriteAtlasImporter)AssetImporter.GetAtPath(outputPath);
|
||||
ConfigureAtlasV2Settings(sai);
|
||||
AssetDatabase.WriteImportSettingsIfDirty(outputPath);
|
||||
AssetDatabase.Refresh();
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
ConfigureAtlasSettings(atlas);
|
||||
atlas.Add(sprites.ToArray());
|
||||
atlas.SetIsVariant(false);
|
||||
AssetDatabase.CreateAsset(atlas, outputPath);
|
||||
}
|
||||
|
||||
|
||||
if (Config.enableLogging)
|
||||
Debug.Log($"Generated atlas: {atlasName} ({sprites.Count} sprites)");
|
||||
}
|
||||
|
||||
private static List<Sprite> LoadValidSprites(string atlasName)
|
||||
{
|
||||
return _atlasMap[atlasName]
|
||||
.Where(File.Exists)
|
||||
.Select(p => AssetDatabase.LoadAssetAtPath<Sprite>(p))
|
||||
.Where(s => s != null)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private static void ConfigureAtlasV2Settings(SpriteAtlasImporter atlasImporter)
|
||||
{
|
||||
void SetPlatform(string platform, TextureImporterFormat format)
|
||||
{
|
||||
var settings = atlasImporter.GetPlatformSettings(platform);
|
||||
if (settings == null) return;
|
||||
;
|
||||
settings.overridden = true;
|
||||
settings.format = format;
|
||||
settings.compressionQuality = Config.compressionQuality;
|
||||
atlasImporter.SetPlatformSettings(settings);
|
||||
}
|
||||
|
||||
SetPlatform("Android", Config.androidFormat);
|
||||
SetPlatform("iPhone", Config.iosFormat);
|
||||
SetPlatform("WebGL", Config.webglFormat);
|
||||
|
||||
var packingSettings = new SpriteAtlasPackingSettings
|
||||
{
|
||||
padding = Config.padding,
|
||||
enableRotation = Config.enableRotation,
|
||||
blockOffset = Config.blockOffset,
|
||||
enableTightPacking = Config.tightPacking,
|
||||
enableAlphaDilation = true
|
||||
};
|
||||
atlasImporter.packingSettings = packingSettings;
|
||||
}
|
||||
|
||||
private static void ConfigureAtlasSettings(SpriteAtlas atlas)
|
||||
{
|
||||
void SetPlatform(string platform, TextureImporterFormat format)
|
||||
{
|
||||
var settings = atlas.GetPlatformSettings(platform);
|
||||
settings.overridden = true;
|
||||
settings.format = format;
|
||||
settings.compressionQuality = Config.compressionQuality;
|
||||
atlas.SetPlatformSettings(settings);
|
||||
}
|
||||
|
||||
SetPlatform("Android", Config.androidFormat);
|
||||
SetPlatform("iPhone", Config.iosFormat);
|
||||
SetPlatform("WebGL", Config.webglFormat);
|
||||
|
||||
var packingSettings = new SpriteAtlasPackingSettings
|
||||
{
|
||||
padding = Config.padding,
|
||||
enableRotation = Config.enableRotation,
|
||||
blockOffset = Config.blockOffset,
|
||||
};
|
||||
atlas.SetPackingSettings(packingSettings);
|
||||
}
|
||||
|
||||
private static string GetAtlasName(string assetPath)
|
||||
{
|
||||
var normalizedPath = assetPath.Replace("\\", "/");
|
||||
var rootPath = Config.sourceAtlasRoot.Replace("\\", "/").TrimEnd('/');
|
||||
|
||||
if (!normalizedPath.StartsWith(rootPath + "/")) return null;
|
||||
|
||||
var relativePath = normalizedPath
|
||||
.Substring(rootPath.Length + 1)
|
||||
.Split('/');
|
||||
|
||||
if (relativePath.Length < 2) return null;
|
||||
|
||||
var directories = relativePath.Take(relativePath.Length - 1);
|
||||
var atlasNamePart = string.Join("_", directories);
|
||||
var rootFolderName = Path.GetFileName(rootPath);
|
||||
|
||||
return $"{rootFolderName}_{atlasNamePart}";
|
||||
}
|
||||
|
||||
private static bool ShouldProcess(string assetPath)
|
||||
{
|
||||
return IsImageFile(assetPath) && !IsExcluded(assetPath);
|
||||
}
|
||||
|
||||
private static bool IsExcluded(string path)
|
||||
{
|
||||
return path.StartsWith(Config.excludeFolder) ||
|
||||
Config.excludeKeywords.Any(k => path.IndexOf(k, StringComparison.OrdinalIgnoreCase) >= 0);
|
||||
}
|
||||
|
||||
private static bool IsImageFile(string path)
|
||||
{
|
||||
var ext = Path.GetExtension(path).ToLower();
|
||||
return ext == ".png" || ext == ".jpg" || ext == ".jpeg";
|
||||
}
|
||||
|
||||
private static void MarkDirty(string atlasName)
|
||||
{
|
||||
_dirtyAtlasNames.Add(atlasName);
|
||||
}
|
||||
|
||||
private static bool ShouldUpdateAtlas(string atlasName)
|
||||
{
|
||||
// var outputPath = $"{Config.outputAtlasDir}/{atlasName}.spriteatlas";
|
||||
return true;
|
||||
}
|
||||
|
||||
private static DateTime GetLatestSpriteTime(string atlasName)
|
||||
{
|
||||
return _atlasMap[atlasName]
|
||||
.Select(p => new FileInfo(p).LastWriteTime)
|
||||
.DefaultIfEmpty()
|
||||
.Max();
|
||||
}
|
||||
|
||||
private static void DeleteAtlas(string path)
|
||||
{
|
||||
if (File.Exists(path))
|
||||
{
|
||||
AssetDatabase.DeleteAsset(path);
|
||||
if (Config.enableLogging)
|
||||
Debug.Log($"Deleted empty atlas: {Path.GetFileName(path)}");
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureOutputDirectory()
|
||||
{
|
||||
if (!Directory.Exists(Config.outputAtlasDir))
|
||||
{
|
||||
Directory.CreateDirectory(Config.outputAtlasDir);
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
private static void ScanExistingSprites()
|
||||
{
|
||||
var guids = AssetDatabase.FindAssets("t:Sprite", new[] { Config.sourceAtlasRoot });
|
||||
foreach (var guid in guids)
|
||||
{
|
||||
var path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
if (ShouldProcess(path))
|
||||
{
|
||||
OnImportSprite(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetAtlasNameForDirectory(string directoryPath)
|
||||
{
|
||||
var normalizedPath = directoryPath.Replace("\\", "/");
|
||||
var rootPath = Config.sourceAtlasRoot.Replace("\\", "/").TrimEnd('/');
|
||||
|
||||
if (!normalizedPath.StartsWith(rootPath + "/")) return null;
|
||||
|
||||
var relativePath = normalizedPath
|
||||
.Substring(rootPath.Length + 1)
|
||||
.Split('/');
|
||||
|
||||
var atlasNamePart = string.Join("_", relativePath);
|
||||
var rootFolderName = Path.GetFileName(rootPath);
|
||||
|
||||
return $"{rootFolderName}_{atlasNamePart}";
|
||||
}
|
||||
}
|
||||
#endif
|
131
Editor/Postprocessor/Atlas/SpritePostprocessor.cs
Normal file
131
Editor/Postprocessor/Atlas/SpritePostprocessor.cs
Normal file
@ -0,0 +1,131 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
public class SpritePostprocessor : AssetPostprocessor
|
||||
{
|
||||
private static void OnPostprocessAllAssets(
|
||||
string[] importedAssets,
|
||||
string[] deletedAssets,
|
||||
string[] movedAssets,
|
||||
string[] movedFromAssetPaths)
|
||||
{
|
||||
var config = AtlasConfiguration.Instance;
|
||||
|
||||
if (!config.autoGenerate) return;
|
||||
|
||||
try
|
||||
{
|
||||
ProcessAssetChanges(
|
||||
importedAssets: importedAssets,
|
||||
deletedAssets: deletedAssets,
|
||||
movedAssets: movedAssets,
|
||||
movedFromPaths: movedFromAssetPaths
|
||||
);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError($"Atlas processing error: {e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
private static void ProcessAssetChanges(
|
||||
string[] importedAssets,
|
||||
string[] deletedAssets,
|
||||
string[] movedAssets,
|
||||
string[] movedFromPaths)
|
||||
{
|
||||
ProcessAssets(importedAssets, (path) =>
|
||||
{
|
||||
EditorSpriteSaveInfo.OnImportSprite(path);
|
||||
LogProcessed("[Added]", path);
|
||||
});
|
||||
|
||||
ProcessAssets(deletedAssets, (path) =>
|
||||
{
|
||||
EditorSpriteSaveInfo.OnDeleteSprite(path);
|
||||
LogProcessed("[Deleted]", path);
|
||||
});
|
||||
|
||||
ProcessMovedAssets(movedFromPaths, movedAssets);
|
||||
}
|
||||
|
||||
private static void ProcessAssets(string[] assets, System.Action<string> processor)
|
||||
{
|
||||
if (assets == null) return;
|
||||
|
||||
foreach (var asset in assets)
|
||||
{
|
||||
if (ShouldProcessAsset(asset))
|
||||
{
|
||||
processor?.Invoke(asset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ProcessMovedAssets(string[] oldPaths, string[] newPaths)
|
||||
{
|
||||
if (oldPaths == null || newPaths == null) return;
|
||||
|
||||
for (int i = 0; i < oldPaths.Length; i++)
|
||||
{
|
||||
if (ShouldProcessAsset(oldPaths[i]))
|
||||
{
|
||||
EditorSpriteSaveInfo.OnDeleteSprite(oldPaths[i]);
|
||||
LogProcessed("[Moved From]", oldPaths[i]);
|
||||
EditorSpriteSaveInfo.MarkParentAtlasesDirty(oldPaths[i]);
|
||||
}
|
||||
|
||||
if (ShouldProcessAsset(newPaths[i]))
|
||||
{
|
||||
EditorSpriteSaveInfo.OnImportSprite(newPaths[i]);
|
||||
LogProcessed("[Moved To]", newPaths[i]);
|
||||
EditorSpriteSaveInfo.MarkParentAtlasesDirty(newPaths[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ShouldProcessAsset(string assetPath)
|
||||
{
|
||||
var config = AtlasConfiguration.Instance;
|
||||
|
||||
if (string.IsNullOrEmpty(assetPath)) return false;
|
||||
if (assetPath.StartsWith("Packages/")) return false;
|
||||
|
||||
if (!assetPath.StartsWith(config.sourceAtlasRoot)) return false;
|
||||
if (assetPath.StartsWith(config.excludeFolder)) return false;
|
||||
|
||||
if (!IsValidImageFile(assetPath)) return false;
|
||||
|
||||
foreach (var keyword in config.excludeKeywords)
|
||||
{
|
||||
if (assetPath.IndexOf(keyword, System.StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool IsValidImageFile(string path)
|
||||
{
|
||||
var ext = System.IO.Path.GetExtension(path).ToLower();
|
||||
return ext switch
|
||||
{
|
||||
".png" => true,
|
||||
".jpg" => true,
|
||||
".jpeg" => true,
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
|
||||
private static void LogProcessed(string operation, string path)
|
||||
{
|
||||
if (AtlasConfiguration.Instance.enableLogging)
|
||||
{
|
||||
Debug.Log($"{operation} {System.IO.Path.GetFileName(path)}\nPath: {path}");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,549 +0,0 @@
|
||||
// using System;
|
||||
// using System.Collections.Generic;
|
||||
// using System.IO;
|
||||
// using UnityEditor;
|
||||
// using UnityEditor.U2D;
|
||||
// using UnityEngine;
|
||||
// using UnityEngine.U2D;
|
||||
// using Object = UnityEngine.Object;
|
||||
//
|
||||
// namespace GameFramework.Editor
|
||||
// {
|
||||
// /// <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/AssetArt/Atlas";
|
||||
// private const string UISpritePath = "Assets/AssetRaw/UIRaw";
|
||||
// private const string UIAtlasPath = "Assets/AssetRaw/UIRaw/Atlas";
|
||||
// private static readonly List<string> _dirtyAtlasList = new List<string>();
|
||||
// private static readonly Dictionary<string, List<string>> _allASprites = new Dictionary<string, List<string>>();
|
||||
//
|
||||
// private static readonly Dictionary<string, string> _uiAtlasMap = new Dictionary<string, string>();
|
||||
// private static bool _isInit = false;
|
||||
// private static bool m_dirty = false;
|
||||
//
|
||||
// public static void Init()
|
||||
// {
|
||||
// if (_isInit)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// EditorApplication.update += CheckDirty;
|
||||
//
|
||||
// //读取所有图集信息
|
||||
// string[] findAssets = AssetDatabase.FindAssets("t:SpriteAtlas", new[] { NormalAtlasDir });
|
||||
// foreach (var findAsset in findAssets)
|
||||
// {
|
||||
// var path = AssetDatabase.GUIDToAssetPath(findAsset);
|
||||
// SpriteAtlas sa = AssetDatabase.LoadAssetAtPath(path, typeof(SpriteAtlas)) as SpriteAtlas;
|
||||
// if (sa == null)
|
||||
// {
|
||||
// Debug.LogError($"加载图集数据{path}失败");
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// string atlasName = Path.GetFileNameWithoutExtension(path);
|
||||
// var objects = sa.GetPackables();
|
||||
// foreach (var o in objects)
|
||||
// {
|
||||
// if (!_allASprites.TryGetValue(atlasName, out var list))
|
||||
// {
|
||||
// list = new List<string>();
|
||||
// _allASprites.Add(atlasName, list);
|
||||
// }
|
||||
//
|
||||
// list.Add(AssetDatabase.GetAssetPath(o));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// _isInit = true;
|
||||
// }
|
||||
//
|
||||
// public static void CheckDirty()
|
||||
// {
|
||||
// if (m_dirty)
|
||||
// {
|
||||
// m_dirty = false;
|
||||
//
|
||||
// AssetDatabase.Refresh();
|
||||
// float lastProgress = -1;
|
||||
// for (int i = 0; i < _dirtyAtlasList.Count; i++)
|
||||
// {
|
||||
// string atlasName = _dirtyAtlasList[i];
|
||||
// Debug.Log("更新图集 : " + atlasName);
|
||||
// var curProgress = (float)i / _dirtyAtlasList.Count;
|
||||
// if (curProgress > lastProgress + 0.01f)
|
||||
// {
|
||||
// lastProgress = curProgress;
|
||||
// var progressText = $"当前进度:{i}/{_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();
|
||||
// _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;
|
||||
// andPlatformSettings.compressionQuality = 50;
|
||||
// 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;
|
||||
// }
|
||||
//
|
||||
// //调整WebGL格式
|
||||
// var webglSettings = ti.GetPlatformTextureSettings("WebGL");
|
||||
// if (!webglSettings.overridden)
|
||||
// {
|
||||
// webglSettings.overridden = true;
|
||||
// modify = true;
|
||||
// }
|
||||
//
|
||||
// if (webglSettings.format != TextureImporterFormat.ASTC_6x6)
|
||||
// {
|
||||
// webglSettings.format = TextureImporterFormat.ASTC_6x6;
|
||||
// webglSettings.compressionQuality = 50;
|
||||
// ti.SetPlatformTextureSettings(webglSettings);
|
||||
// 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(".", StringComparison.Ordinal));
|
||||
// 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 (!_uiAtlasMap.TryGetValue(spriteName, out string oldAssetPath) || spritePath == oldAssetPath)
|
||||
// {
|
||||
// _uiAtlasMap[spriteName] = spritePath;
|
||||
// m_dirty = true;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Debug.LogError($"有重名的图片:{spriteName}\n旧图集:{oldAssetPath}\n新图集:{spritePath} ");
|
||||
// _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 (!_allASprites.TryGetValue(atlasName, out ret))
|
||||
// {
|
||||
// ret = new List<string>();
|
||||
// _allASprites.Add(atlasName, ret);
|
||||
// }
|
||||
//
|
||||
// if (!ret.Contains(assetPath))
|
||||
// {
|
||||
// ret.Add(assetPath);
|
||||
// m_dirty = true;
|
||||
// if (!_dirtyAtlasList.Contains(atlasName))
|
||||
// {
|
||||
// _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 (!_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 (_uiAtlasMap.ContainsKey(spriteName))
|
||||
// {
|
||||
// _uiAtlasMap.Remove(spriteName);
|
||||
// m_dirty = true;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// ret.Remove(assetPath);
|
||||
// m_dirty = true;
|
||||
// if (!_dirtyAtlasList.Contains(atlasName))
|
||||
// {
|
||||
// _dirtyAtlasList.Add(atlasName);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #region 更新图集
|
||||
//
|
||||
// public static void SaveAtlas(string atlasName, bool isUI)
|
||||
// {
|
||||
// List<Object> spriteList = new List<Object>();
|
||||
// if (_allASprites.TryGetValue(atlasName, out var list))
|
||||
// {
|
||||
// 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 atlas = new SpriteAtlasAsset();
|
||||
// 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 = TextureImporterFormat.ASTC_5x5;
|
||||
// iphonePlatformSetting.compressionQuality = 100;
|
||||
// atlas.SetPlatformSettings(iphonePlatformSetting);
|
||||
// }
|
||||
//
|
||||
// var androidPlatformSetting = atlas.GetPlatformSettings("Android");
|
||||
// if (!androidPlatformSetting.overridden)
|
||||
// {
|
||||
// androidPlatformSetting.overridden = true;
|
||||
// androidPlatformSetting.format = TextureImporterFormat.ASTC_6x6;
|
||||
// androidPlatformSetting.compressionQuality = 100;
|
||||
// atlas.SetPlatformSettings(androidPlatformSetting);
|
||||
// }
|
||||
//
|
||||
// var webglSettings = atlas.GetPlatformSettings("WebGL");
|
||||
// if (!webglSettings.overridden)
|
||||
// {
|
||||
// webglSettings.overridden = true;
|
||||
// webglSettings.format = TextureImporterFormat.ASTC_6x6;
|
||||
// webglSettings.compressionQuality = 50;
|
||||
// atlas.SetPlatformSettings(webglSettings);
|
||||
// }
|
||||
//
|
||||
// atlas.SetPackingSettings(setting);
|
||||
// atlas.Add(spriteList.ToArray());
|
||||
//
|
||||
// AssetDatabase.CreateAsset(atlas, path);
|
||||
// AssetDatabase.SaveAssets();
|
||||
// AssetDatabase.Refresh();
|
||||
// }
|
||||
//
|
||||
// #endregion
|
||||
//
|
||||
// #region 重新生成图集
|
||||
//
|
||||
// private static readonly Dictionary<string, List<string>> m_tempAllASprites = new Dictionary<string, List<string>>();
|
||||
//
|
||||
// [MenuItem("开发工具/Atlas/重新生成UI图集", false, 90)]
|
||||
// static void ForceGenAtlas()
|
||||
// {
|
||||
// Init();
|
||||
// List<string> needSaveAtlas = new List<string>();
|
||||
// m_tempAllASprites.Clear();
|
||||
// _allASprites.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;
|
||||
//
|
||||
// if (_allASprites.TryGetValue(atlasName, out var 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;
|
||||
// _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
|
||||
// }
|
||||
// }
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d7342886aa5c4714bb6064c63e116892
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Reference in New Issue
Block a user