#if UNITY_EDITOR using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Reflection; using UnityEditor; using UnityEngine; using Object = UnityEngine.Object; namespace lilToon { public class lilTextureUtils { //------------------------------------------------------------------------------------------------------------------------------ // Gradient #region internal static void GradientEditor(Material material, Gradient ingrad, MaterialProperty texprop, bool setLinear = false) { #if UNITY_2018_3_OR_NEWER ingrad = EditorGUILayout.GradientField(lilLanguageManager.GetLoc("sGradColor"), ingrad); #else MethodInfo setMethod = typeof(EditorGUILayout).GetMethod( "GradientField", BindingFlags.NonPublic | BindingFlags.Static, null, new [] {typeof(string), typeof(Gradient), typeof(GUILayoutOption[])}, null); if(setMethod != null) { ingrad = (Gradient)setMethod.Invoke(null, new object[]{lilLanguageManager.GetLoc("sGradColor"), ingrad, null});; } #endif GUILayout.BeginHorizontal(); GUILayout.Space(EditorGUI.indentLevel * 16); if(GUILayout.Button("Test")) { texprop.textureValue = GradientToTexture(ingrad, setLinear); } if(GUILayout.Button("Save")) { Texture2D tex = GradientToTexture(ingrad, setLinear); tex = SaveTextureToPng(material, tex, texprop.name); if(setLinear) SetLinear(tex); texprop.textureValue = tex; } GUILayout.EndHorizontal(); } internal static void GradientEditor(Material material, string emissionName, Gradient ingrad, MaterialProperty texprop, bool setLinear = false) { ingrad = MaterialToGradient(material, emissionName); #if UNITY_2018_3_OR_NEWER ingrad = EditorGUILayout.GradientField(lilLanguageManager.GetLoc("sGradColor"), ingrad); #else MethodInfo setMethod = typeof(EditorGUILayout).GetMethod( "GradientField", BindingFlags.NonPublic | BindingFlags.Static, null, new [] {typeof(string), typeof(Gradient), typeof(GUILayoutOption[])}, null); if(setMethod != null) { ingrad = (Gradient)setMethod.Invoke(null, new object[]{lilLanguageManager.GetLoc("sGradColor"), ingrad, null});; } #endif GradientToMaterial(material, emissionName, ingrad); GUILayout.BeginHorizontal(); GUILayout.Space(EditorGUI.indentLevel * 16); if(GUILayout.Button("Test")) { texprop.textureValue = GradientToTexture(ingrad, setLinear); } if(GUILayout.Button("Save")) { Texture2D tex = GradientToTexture(ingrad, setLinear); tex = SaveTextureToPng(material, tex, texprop.name); if(setLinear) SetLinear(tex); texprop.textureValue = tex; } GUILayout.EndHorizontal(); } private static void SetLinear(Texture2D tex) { if(tex != null) { string path = AssetDatabase.GetAssetPath(tex); TextureImporter textureImporter = (TextureImporter)AssetImporter.GetAtPath(path); textureImporter.sRGBTexture = false; AssetDatabase.ImportAsset(path); } } private static Gradient MaterialToGradient(Material material, string emissionName) { Gradient outgrad = new Gradient(); GradientColorKey[] colorKey = new GradientColorKey[material.GetInt(emissionName + "ci")]; GradientAlphaKey[] alphaKey = new GradientAlphaKey[material.GetInt(emissionName + "ai")]; for(int i=0;i(path); GetReadableTexture(ref tex); if(path.EndsWith(".png", StringComparison.OrdinalIgnoreCase) || path.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) || path.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase)) { byte[] bytes = File.ReadAllBytes(Path.GetFullPath(path)); tex.LoadImage(bytes); } if(tex != null) tex.filterMode = FilterMode.Bilinear; } #endregion //------------------------------------------------------------------------------------------------------------------------------ // Save Texture #region internal static Texture2D SaveTextureToPng(Material material, Texture2D tex, string texname, string customName = "") { string path = AssetDatabase.GetAssetPath(material.GetTexture(texname)); if(string.IsNullOrEmpty(path)) path = AssetDatabase.GetAssetPath(material); string filename = Path.GetFileNameWithoutExtension(path); if(!string.IsNullOrEmpty(customName)) filename += customName; else filename += "_2"; if(!string.IsNullOrEmpty(path)) path = EditorUtility.SaveFilePanel("Save Texture", Path.GetDirectoryName(path), filename, "png"); else path = EditorUtility.SaveFilePanel("Save Texture", "Assets", tex.name + ".png", "png"); if(!string.IsNullOrEmpty(path)) { File.WriteAllBytes(path, tex.EncodeToPNG()); Object.DestroyImmediate(tex); AssetDatabase.Refresh(); return AssetDatabase.LoadAssetAtPath(path.Substring(path.IndexOf("Assets"))); } else { return (Texture2D)material.GetTexture(texname); } } internal static Texture2D SaveTextureToPng(Texture2D tex, Texture2D origTex) { string path = AssetDatabase.GetAssetPath(origTex); if(!string.IsNullOrEmpty(path)) path = EditorUtility.SaveFilePanel("Save Texture", Path.GetDirectoryName(path), Path.GetFileNameWithoutExtension(path)+"_alpha", "png"); else path = EditorUtility.SaveFilePanel("Save Texture", "Assets", tex.name + "_alpha.png", "png"); if(!string.IsNullOrEmpty(path)) { File.WriteAllBytes(path, tex.EncodeToPNG()); Object.DestroyImmediate(tex); AssetDatabase.Refresh(); return AssetDatabase.LoadAssetAtPath(path.Substring(path.IndexOf("Assets"))); } else { return origTex; } } internal static Texture2D SaveTextureToPng(Texture2D tex, string path, string customName = "") { string filename = customName + Path.GetFileNameWithoutExtension(path); if(!string.IsNullOrEmpty(path)) path = EditorUtility.SaveFilePanel("Save Texture", Path.GetDirectoryName(path), filename, "png"); else path = EditorUtility.SaveFilePanel("Save Texture", "Assets", filename, "png"); if(!string.IsNullOrEmpty(path)) { File.WriteAllBytes(path, tex.EncodeToPNG()); Object.DestroyImmediate(tex); AssetDatabase.Refresh(); return AssetDatabase.LoadAssetAtPath(path.Substring(path.IndexOf("Assets"))); } else { return tex; } } public static string SaveTextureToPng(string path, string add, Texture2D tex) { string savePath = Path.GetDirectoryName(path) + "/" + Path.GetFileNameWithoutExtension(path) + add + ".png"; File.WriteAllBytes(savePath, tex.EncodeToPNG()); return savePath; } #endregion //------------------------------------------------------------------------------------------------------------------------------ // Gif to Atlas #region #if SYSTEM_DRAWING public static string ConvertGifToAtlas(Object tex) { int frameCount, loopXY, duration; float xScale, yScale; return ConvertGifToAtlas(tex, out frameCount, out loopXY, out duration, out xScale, out yScale); } public static string ConvertGifToAtlas(Object tex, out int frameCount, out int loopXY, out int duration, out float xScale, out float yScale) { string path = AssetDatabase.GetAssetPath(tex); System.Drawing.Image origGif = System.Drawing.Image.FromFile(path); System.Drawing.Imaging.FrameDimension dimension = new System.Drawing.Imaging.FrameDimension(origGif.FrameDimensionsList[0]); frameCount = origGif.GetFrameCount(dimension); loopXY = Mathf.CeilToInt(Mathf.Sqrt(frameCount)); duration = BitConverter.ToInt32(origGif.GetPropertyItem(20736).Value, 0); int finalWidth = 1; int finalHeight = 1; if(EditorUtility.DisplayDialog(lilLanguageManager.GetLoc("sDialogGifToAtlas"), lilLanguageManager.GetLoc("sUtilGif2AtlasPow2"), lilLanguageManager.GetLoc("sYes"), lilLanguageManager.GetLoc("sNo"))) { while(finalWidth < origGif.Width * loopXY) finalWidth *= 2; while(finalHeight < origGif.Height * loopXY) finalHeight *= 2; } else { finalWidth = origGif.Width * loopXY; finalHeight = origGif.Height * loopXY; } Texture2D atlasTexture = new Texture2D(finalWidth, finalHeight); xScale = (float)(origGif.Width * loopXY) / finalWidth; yScale = (float)(origGif.Height * loopXY) / finalHeight; for(int x = 0; x < finalWidth; x++) { for(int y = 0; y < finalHeight; y++) { atlasTexture.SetPixel(x, finalHeight - 1 - y, Color.clear); } } for(int i = 0; i < frameCount; i++) { int offsetX = i%loopXY; int offsetY = Mathf.FloorToInt(i/loopXY); origGif.SelectActiveFrame(dimension, i); System.Drawing.Bitmap frame = new System.Drawing.Bitmap(origGif.Width, origGif.Height); System.Drawing.Graphics.FromImage(frame).DrawImage(origGif, System.Drawing.Point.Empty); for(int x = 0; x < frame.Width; x++) { for(int y = 0; y < frame.Height; y++) { System.Drawing.Color sourceColor = frame.GetPixel(x, y); atlasTexture.SetPixel(x + (frame.Width * offsetX), finalHeight - (frame.Height * offsetY) - 1 - y, new Color32(sourceColor.R, sourceColor.G, sourceColor.B, sourceColor.A)); } } } atlasTexture.Apply(); // Save string savePath = SaveTextureToPng(path, "_gif2png_" + loopXY + "_" + frameCount + "_" + duration, atlasTexture); AssetDatabase.Refresh(); return savePath; } #else public static string ConvertGifToAtlas(Object tex) { int frameCount, loopXY, duration; float xScale, yScale; return ConvertGifToAtlas(tex, out frameCount, out loopXY, out duration, out xScale, out yScale); } public static string ConvertGifToAtlas(Object tex, out int frameCount, out int loopXY, out int duration, out float xScale, out float yScale) { frameCount = 0; loopXY = 0; duration = 0; xScale = 1.0f; yScale = 1.0f; return ""; } #endif #endregion //------------------------------------------------------------------------------------------------------------------------------ // Cube to PNG #region private static Texture3D ReadCube(string path) { int size = -1; var sr = new StreamReader(path); string line; var colors = new List(); while((line = sr.ReadLine()) != null) { line = line.Trim(); int c = line.IndexOf("#"); if(c >= 0) line = line.Substring(0, c); if(line.StartsWith("TITLE") || line.StartsWith("DOMAIN_")) continue; if(line.StartsWith("LUT_3D_SIZE")) { try { size = int.Parse(line.Substring(11).TrimStart()); } catch(Exception e) { Debug.LogException(e); sr.Close(); return null; } continue; } var vals = line.Split(); if(vals.Length != 3) continue; try { colors.Add(new Color( float.Parse(vals[0], CultureInfo.InvariantCulture), float.Parse(vals[1], CultureInfo.InvariantCulture), float.Parse(vals[2], CultureInfo.InvariantCulture) )); } catch(Exception e) { Debug.LogException(e); sr.Close(); return null; } } sr.Close(); if(size <= 0 || colors == null || colors.Count < size*size*size) return null; var tex = new Texture3D(size, size, size, TextureFormat.RGBA32, false); tex.SetPixels(colors.GetRange(0,size*size*size).ToArray()); tex.Apply(); return tex; } internal static Texture2D ConvertLUT3Dto2D(Texture3D tex) { int resX = 16; int resY = 1; int width = resX * resY * resX; int height = resX * resY * resY; Material material = new Material(lilShaderManager.ltsbaker); material.SetTexture("_MainTex3D", tex); material.SetFloat("_ResX", resX); material.SetFloat("_ResY", resY); material.EnableKeyword("_LUT3D_TO_2D"); var outTexture = new Texture2D(width, height, TextureFormat.RGBA32, false); RenderTexture bufRT = RenderTexture.active; RenderTexture srcTexture = RenderTexture.GetTemporary(width, height); RenderTexture dstTexture = RenderTexture.GetTemporary(width, height); Graphics.Blit(srcTexture, dstTexture, material); RenderTexture.active = dstTexture; outTexture.ReadPixels(new Rect(0, 0, width, height), 0, 0); outTexture.Apply(); RenderTexture.active = bufRT; RenderTexture.ReleaseTemporary(dstTexture); return outTexture; } internal static void ConvertLUTToPNG(Object obj) { string path = AssetDatabase.GetAssetPath(obj); Texture3D texOrig = null; if(path.EndsWith(".cube")) texOrig = ReadCube(path); if(texOrig == null) { EditorUtility.DisplayDialog("[lilToon] Convert LUT to PNG", lilLanguageManager.GetLoc("sUtilInvalidFormat"), lilLanguageManager.GetLoc("sOK")); return; } Texture2D tex = ConvertLUT3Dto2D(texOrig); SaveTextureToPng(path, "_conv", tex); AssetDatabase.Refresh(); } #endregion } } #endif