HoloprojStreaming/Assets/lilToon/Editor/lilTextureUtils.cs

441 lines
20 KiB
C#

#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<colorKey.Length;i++)
{
colorKey[i].color = material.GetColor(emissionName + "c" + i.ToString());
colorKey[i].time = material.GetColor(emissionName + "c" + i.ToString()).a;
}
for(int j=0;j<alphaKey.Length;j++)
{
alphaKey[j].alpha = material.GetColor(emissionName + "a" + j.ToString()).r;
alphaKey[j].time = material.GetColor(emissionName + "a" + j.ToString()).a;
}
outgrad.SetKeys(colorKey, alphaKey);
return outgrad;
}
private static void GradientToMaterial(Material material, string emissionName, Gradient ingrad)
{
material.SetInt(emissionName + "ci", ingrad.colorKeys.Length);
material.SetInt(emissionName + "ai", ingrad.alphaKeys.Length);
for(int ic=0;ic<ingrad.colorKeys.Length;ic++)
{
material.SetColor(emissionName + "c" + ic.ToString(), new Color(ingrad.colorKeys[ic].color.r, ingrad.colorKeys[ic].color.g, ingrad.colorKeys[ic].color.b, ingrad.colorKeys[ic].time));
}
for(int ia=0;ia<ingrad.alphaKeys.Length;ia++)
{
material.SetColor(emissionName + "a" + ia.ToString(), new Color(ingrad.alphaKeys[ia].alpha, 0, 0, ingrad.alphaKeys[ia].time));
}
}
private static Texture2D GradientToTexture(Gradient grad, bool setLinear = false)
{
Texture2D tex = new Texture2D(128, 4, TextureFormat.ARGB32, true, setLinear);
// Set colors
for(int w = 0; w < tex.width; w++)
{
for(int h = 0; h < tex.height; h++)
{
tex.SetPixel(w, h, grad.Evaluate((float)w / tex.width));
}
}
tex.Apply();
return tex;
}
#endregion
//------------------------------------------------------------------------------------------------------------------------------
// Load Texture
#region
private static void GetReadableTexture(ref Texture2D tex)
{
if(tex == null) return;
#if UNITY_2018_3_OR_NEWER
if(!tex.isReadable)
#endif
{
RenderTexture bufRT = RenderTexture.active;
RenderTexture texR = RenderTexture.GetTemporary(tex.width, tex.height);
Graphics.Blit(tex, texR);
RenderTexture.active = texR;
tex = new Texture2D(texR.width, texR.height);
tex.ReadPixels(new Rect(0, 0, texR.width, texR.height), 0, 0);
tex.Apply();
RenderTexture.active = bufRT;
RenderTexture.ReleaseTemporary(texR);
}
}
public static void LoadTexture(ref Texture2D tex, string path)
{
if(string.IsNullOrEmpty(path)) return;
tex = AssetDatabase.LoadAssetAtPath<Texture2D>(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<Texture2D>(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<Texture2D>(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<Texture2D>(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<Color>();
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