using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; using BundleV2; using UnityEditor; using UnityEngine; public static class TextureUtility { public const string t4MControlTextureHeader = "Assets/T4MOBJ/Terrains/Texture/"; public const string postProcessTextureHeader = "Assets/Plugins/PostProcessing/"; [MenuItem("ProTool/PurgeAssets/Reimport All Sprites", false, 5)] public static void ReimportAllSprites() { var action = new ReimportSpriteAction(GetAllTexturePaths()); action.Start(); } [MenuItem("ProTool/PurgeAssets/Get All Non Power2", false, 5)] public static void GetAllNonPower2() { var action = new GetAllNonPowerAction(GetAllTexturePaths()); action.Start(); } private static HashSet GetNonCompressTextures() { // 特殊处理T4M相关的法线贴图 var materials = (from assetPath in AssetDatabase.GetAllAssetPaths() where assetPath.StartsWith("Assets/") where ".mat" == Path.GetExtension(assetPath) let material = AssetDatabase.LoadAssetAtPath(assetPath) where material && material.shader let shaderName = material.shader.name where shaderName.Contains("/T4M", StringComparison.OrdinalIgnoreCase) || shaderName.Contains("/T3M", StringComparison.OrdinalIgnoreCase) || shaderName.Contains("/T2M", StringComparison.OrdinalIgnoreCase) select assetPath).ToArray(); var hashSet = new HashSet(); for (var i = 0; i < materials.Length; i++) { EditorUtility.DisplayProgressBar("Collect Textures", string.Format("({0} / {1})", i, materials.Length), (float) i / materials.Length); var dependencies = AssetDatabase.GetDependencies(materials[i], true); foreach (var dependency in dependencies) if (EditorAssetConst.textureExtensions.Contains(Path.GetExtension(dependency))) hashSet.Add(dependency); } var normals = hashSet.ToArray(); // 重新装入保护系统 hashSet.Clear(); for (var i = 0; i < normals.Length; i++) { EditorUtility.DisplayProgressBar("Get T4M Normals", string.Format("({0} / {1})", i, normals.Length), (float) i / normals.Length); var textureImporter = AssetImporter.GetAtPath(normals[i]) as TextureImporter; if (textureImporter && textureImporter.textureType == TextureImporterType.NormalMap) hashSet.Add(normals[i]); } EditorUtility.ClearProgressBar(); // 特殊处理T4M的控制贴图 var controls = from assetPath in AssetDatabase.GetAllAssetPaths() where assetPath.StartsWith(t4MControlTextureHeader) || assetPath.StartsWith(postProcessTextureHeader) where EditorAssetConst.textureExtensions.Contains(Path.GetExtension(assetPath)) select assetPath; foreach (var control in controls) hashSet.Add(control); return hashSet; } private static void SetIosCompression(TextureImporter importer, bool isCompress) { var platformSetting = importer.GetPlatformTextureSettings("iPhone"); if (isCompress) { platformSetting.overridden = true; platformSetting.textureCompression = TextureImporterCompression.Compressed; platformSetting.crunchedCompression = true; var useRgba = importer.textureCompression.ToString().StartsWith("RGBA", StringComparison.OrdinalIgnoreCase); platformSetting.format = useRgba ? TextureImporterFormat.ETC2_RGBA8Crunched : TextureImporterFormat.ETC_RGB4Crunched; } else platformSetting.overridden = false; } [MenuItem("Bundle V2/Purge/Set All IPhone Textures")] public static void SetAllIPhoneTextures() { var importers = (from assetPath in AssetDatabase.GetAllAssetPaths() where assetPath.StartsWith(AssetConst.nonInternalHeader) where EditorAssetConst.textureExtensions.Contains(Path.GetExtension(assetPath)) let importer = AssetImporter.GetAtPath(assetPath) as TextureImporter where importer select importer).ToArray(); for (var i = 0; i < importers.Length; i++) { EditorUtility.DisplayProgressBar("配置苹果压缩格式", string.Format("{0} / {1}", i + 1, importers.Length), (float)i / importers.Length); var importer = importers[i]; var platformSetting = importer.GetPlatformTextureSettings("iPhone"); if (importer.textureCompression != TextureImporterCompression.Uncompressed && importer.textureType == TextureImporterType.Sprite) { platformSetting.overridden = true; platformSetting.textureCompression = TextureImporterCompression.Compressed; platformSetting.crunchedCompression = true; platformSetting.format = TextureImporterFormat.ETC2_RGBA8Crunched; } else { platformSetting.overridden = false; } importer.SetPlatformTextureSettings(platformSetting); importer.SaveAndReimport(); } } [MenuItem("Bundle V2/Purge/Texture Compress")] public static void PurgeCompression() { var nonCompress = GetNonCompressTextures(); var allTextures = (from assetPath in AssetDatabase.GetAllAssetPaths() where assetPath.StartsWith("Assets/") where EditorAssetConst.textureExtensions.Contains(Path.GetExtension(assetPath)) select assetPath).ToArray(); for (var i = 0; i < allTextures.Length; i++) { var texture = allTextures[i]; EditorUtility.DisplayProgressBar("Check Texture", string.Format("({0} / {1})", i, allTextures.Length), (float) i / allTextures.Length); var importer = AssetImporter.GetAtPath(texture) as TextureImporter; if (importer) { var dirty = false; var compress = nonCompress.Contains(texture) ? TextureImporterCompression.Uncompressed : TextureImporterCompression.Compressed; if (compress != importer.textureCompression) { dirty = true; importer.textureCompression = compress; SetIosCompression(importer, compress != TextureImporterCompression.Uncompressed); } if (compress == TextureImporterCompression.Compressed && !importer.crunchedCompression) { dirty = true; importer.crunchedCompression = true; } if (importer.textureType == TextureImporterType.Sprite && importer.mipmapEnabled) { dirty = true; importer.mipmapEnabled = false; } if (dirty) importer.SaveAndReimport(); } } EditorUtility.ClearProgressBar(); } private static string[] GetAllTexturePaths() { var assetPaths = from assetPath in AssetDatabase.GetAllAssetPaths() where EditorAssetConst.textureExtensions.Contains(Path.GetExtension(assetPath)) select assetPath; return assetPaths.ToArray(); } private class ReimportSpriteAction : EditorPerFrameActionBase { private readonly string[] _assetPaths; private int _index; public ReimportSpriteAction(string[] assetPaths) { _assetPaths = assetPaths; } protected override int GetTotalCount() { return _assetPaths.Length; } protected override int GetCurrentIndex() { return _index; } protected override void PerFrameAction() { var assetPath = _assetPaths[_index]; var importer = AssetImporter.GetAtPath(assetPath) as TextureImporter; if (importer != null && importer.textureType == TextureImporterType.Sprite) importer.SaveAndReimport(); _index++; } } private class GetAllNonPowerAction : EditorPerFrameActionBase { private const string _filePath = "Assets/_Test/NonPower2Textures.txt"; private readonly string[] _assetPaths; private readonly StringBuilder _builder; private int _index; public GetAllNonPowerAction(string[] assetPaths) { _assetPaths = assetPaths; _builder = new StringBuilder(); } protected override int GetTotalCount() { return _assetPaths.Length; } protected override int GetCurrentIndex() { return _index; } protected override void PerFrameAction() { var assetPath = _assetPaths[_index]; var importer = AssetImporter.GetAtPath(assetPath) as TextureImporter; if (importer != null && importer.textureType != TextureImporterType.Sprite) { var args = new object[2]; var mi = typeof(TextureImporter).GetMethod("GetWidthAndHeight", BindingFlags.NonPublic | BindingFlags.Instance); if (mi != null) mi.Invoke(importer, args); if (args[0] == null || args[1] == null) { Debug.LogError("无法获得贴图尺寸,于" + importer.assetPath); _builder.AppendLine(importer.assetPath + "; 尺寸无法获得!"); } else { var width = (int) args[0]; var height = (int) args[1]; if (!IsPowerOf2(width) || !IsPowerOf2(height)) _builder.AppendLine(importer.assetPath + string.Format("; 尺寸 {0} x {1} 不是2的次方!", width, height)); } } _index++; } protected override void OnFinish() { base.OnFinish(); var filePath = Application.dataPath.MoveUp().Open(_filePath); File.WriteAllText(filePath, _builder.ToString()); Debug.LogWarning("贴图尺寸扫描结果已输出到 " + filePath); } private static bool IsPowerOf2(int number) { // 如果小于等于1 if (number < 2) return false; // 或者二进制中1的位数超过1位,即不是二的次方 int count; for (count = 0; count < number; count++) number &= number - 1; // 清除最低位的1 return count < 2; } } }