1110 lines
46 KiB
C#
1110 lines
46 KiB
C#
using System.Collections.Generic;
|
|
using System.IO;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace DreadScripts.TextureUtility
|
|
{
|
|
public class TextureUtility : EditorWindow
|
|
{
|
|
private readonly string[] DimensionPresets = {
|
|
"128x128",
|
|
"256x256",
|
|
"512x512",
|
|
"1024x1024",
|
|
"2048x2048",
|
|
"4096x4096",
|
|
};
|
|
|
|
private static GUIContent resetIcon;
|
|
private static Texture2D titleTexture;
|
|
|
|
private static Texture2D mainTexture;
|
|
private static Texture2D maskTexture;
|
|
|
|
private static int jpgQuality = 75;
|
|
private static int texWidth, texHeight;
|
|
private static bool copyImport = true;
|
|
private static bool pingTexture = true;
|
|
|
|
private static bool rotating;
|
|
private static TexRotation rotationType;
|
|
|
|
private static bool inverting;
|
|
private static bool maskInvert=true;
|
|
private static bool invertRedS = true, invertGreenS = true, invertBlueS = true, invertAlphaS;
|
|
|
|
private static bool unpacking=true,packing;
|
|
private static bool editingTab=true, packingTab,creatingTab;
|
|
|
|
|
|
private static readonly ChannelTexture redChannel = new ChannelTexture("Red", 0);
|
|
private static readonly ChannelTexture greenChannel = new ChannelTexture("Green", 1);
|
|
private static readonly ChannelTexture blueChannel = new ChannelTexture("Blue", 2);
|
|
private static readonly ChannelTexture alphaChannel = new ChannelTexture("Alpha", 0);
|
|
private static readonly ChannelTexture[] channelTextures = { redChannel, greenChannel, blueChannel, alphaChannel };
|
|
|
|
private static bool hueShifting;
|
|
private static bool maskHueShift=true;
|
|
private static float hueShiftFloat;
|
|
|
|
private static bool saturating;
|
|
private static SaturationMethodEnum saturationMethod = SaturationMethodEnum.Poiyomi;
|
|
private static bool maskSaturate=true;
|
|
private static float saturationFloat;
|
|
|
|
private static bool colorizing;
|
|
private static bool maskColorize=true;
|
|
private static bool textureColorize;
|
|
private static bool alphaColorize;
|
|
private static float colorizeFloat=0.5f;
|
|
private static Color colorizeColor = Color.black;
|
|
private static Texture2D colorizeTexture;
|
|
|
|
private static Color originalGUIColor;
|
|
|
|
private static TexEncoding encoding = TexEncoding.SaveAsPNG;
|
|
public enum TexEncoding
|
|
{
|
|
SaveAsPNG,
|
|
SaveAsJPG,
|
|
SaveAsTGA
|
|
}
|
|
|
|
public enum TexRotation
|
|
{
|
|
Clockwise90,
|
|
CClockwise90,
|
|
Rotate180,
|
|
FlipHorizontal,
|
|
FlipVertical
|
|
}
|
|
|
|
public enum SaturationMethodEnum
|
|
{
|
|
Poiyomi,
|
|
Gimp
|
|
}
|
|
|
|
#region Creating Tab Variables
|
|
private static bool creatingCustomSize;
|
|
private static bool creatingReverse;
|
|
private static string creatingPath;
|
|
private static Color solidColor=Color.black;
|
|
private static Gradient gradientColor = new Gradient() { colorKeys = new GradientColorKey[] { new GradientColorKey(Color.white, 0), new GradientColorKey(Color.black, 1) } };
|
|
|
|
private static TextureCreatingMode creatingMode = TextureCreatingMode.SolidColor;
|
|
|
|
private enum TextureCreatingMode
|
|
{
|
|
SolidColor,
|
|
HorizontalGradient,
|
|
VerticalGradient
|
|
}
|
|
#endregion
|
|
|
|
[MenuItem("DreadTools/Utility/Texture Utility")]
|
|
private static void showWindow()
|
|
{
|
|
EditorWindow w = GetWindow<TextureUtility>(false, "Texture Utility", true);
|
|
if (!titleTexture)
|
|
{
|
|
titleTexture = GetColors((Texture2D)EditorGUIUtility.IconContent("Texture2D Icon").image, 16, 16, out _);
|
|
titleTexture.Apply();
|
|
}
|
|
|
|
w.titleContent.image = titleTexture;
|
|
w.minSize = new Vector2(423, 253);
|
|
}
|
|
|
|
private void OnGUI()
|
|
{
|
|
originalGUIColor = GUI.backgroundColor;
|
|
using (new GUILayout.HorizontalScope())
|
|
{
|
|
bool c = editingTab;
|
|
|
|
SetColorIcon(editingTab);
|
|
editingTab = GUILayout.Toggle(editingTab, "Editing", "toolbarbutton");
|
|
if (!c && editingTab)
|
|
{
|
|
packingTab = false;
|
|
creatingTab = false;
|
|
}
|
|
|
|
c = creatingTab;
|
|
|
|
|
|
SetColorIcon(creatingTab);
|
|
creatingTab = GUILayout.Toggle(creatingTab, "Creating", "toolbarbutton");
|
|
if (!c && creatingTab)
|
|
{
|
|
packingTab = false;
|
|
editingTab = false;
|
|
}
|
|
|
|
c = packingTab;
|
|
|
|
SetColorIcon(packingTab);
|
|
packingTab = GUILayout.Toggle(packingTab, "Packing", "toolbarbutton");
|
|
if (!c && packingTab)
|
|
{
|
|
editingTab = false;
|
|
creatingTab = false;
|
|
}
|
|
GUI.backgroundColor = originalGUIColor;
|
|
}
|
|
|
|
if (editingTab)
|
|
DrawEditingTab();
|
|
|
|
|
|
if (creatingTab)
|
|
DrawCreatingTab();
|
|
|
|
if (packingTab)
|
|
DrawPackingTab();
|
|
|
|
Credit();
|
|
}
|
|
|
|
|
|
private void DrawEditingTab()
|
|
{
|
|
using (new GUILayout.HorizontalScope())
|
|
{
|
|
using (new GUILayout.VerticalScope())
|
|
{
|
|
using (new GUILayout.HorizontalScope("box"))
|
|
DrawDimensionsGUI();
|
|
|
|
using (new GUILayout.HorizontalScope("box"))
|
|
{
|
|
encoding = (TexEncoding)EditorGUILayout.EnumPopup(encoding, GUILayout.Width(95));
|
|
|
|
EditorGUI.BeginDisabledGroup(encoding != TexEncoding.SaveAsJPG);
|
|
EditorGUIUtility.labelWidth = 50;
|
|
jpgQuality = EditorGUILayout.IntSlider("Quality", jpgQuality, 1, 100);
|
|
EditorGUIUtility.labelWidth = 0;
|
|
EditorGUI.EndDisabledGroup();
|
|
}
|
|
|
|
using (new GUILayout.HorizontalScope("box"))
|
|
{
|
|
copyImport = EditorGUILayout.Toggle("Copy Import Settings", copyImport);
|
|
pingTexture = EditorGUILayout.Toggle(new GUIContent("Highlight Texture", "Highlight the newly created texture in Assets"), pingTexture);
|
|
}
|
|
|
|
using (new GUILayout.HorizontalScope("box"))
|
|
{
|
|
if (!rotating)
|
|
{
|
|
SetColorIcon(rotating);
|
|
rotating = GUILayout.Toggle(rotating, "Rotate", "toolbarbutton");
|
|
GUI.backgroundColor = originalGUIColor;
|
|
}
|
|
else
|
|
{
|
|
SetColorIcon(rotating);
|
|
rotating = GUILayout.Toggle(rotating, "", "toolbarbutton", GUILayout.Width(17), GUILayout.Height(17));
|
|
GUI.backgroundColor = originalGUIColor;
|
|
|
|
EditorGUI.BeginDisabledGroup(true);
|
|
GUILayout.Toggle(true, "M", EditorStyles.miniButton, GUILayout.Width(21), GUILayout.Height(16));
|
|
EditorGUI.EndDisabledGroup();
|
|
|
|
GUILayout.Label("Rotate");
|
|
rotationType = (TexRotation)EditorGUILayout.EnumPopup(GUIContent.none, rotationType);
|
|
}
|
|
}
|
|
|
|
using (new GUILayout.HorizontalScope("box"))
|
|
{
|
|
if (!inverting)
|
|
{
|
|
SetColorIcon(inverting);
|
|
inverting = GUILayout.Toggle(inverting, "Invert", "toolbarbutton");
|
|
GUI.backgroundColor = originalGUIColor;
|
|
}
|
|
else
|
|
{
|
|
SetColorIcon(inverting);
|
|
inverting = GUILayout.Toggle(inverting, "", "toolbarbutton", GUILayout.Width(17), GUILayout.Height(17));
|
|
GUI.backgroundColor = originalGUIColor;
|
|
|
|
maskInvert = GUILayout.Toggle(maskInvert, new GUIContent("M", "Use Mask"), EditorStyles.miniButton, GUILayout.Width(21), GUILayout.Height(16)); GUILayout.Label("Invert");
|
|
invertRedS = EditorGUILayout.ToggleLeft("R", invertRedS, GUILayout.Width(30));
|
|
invertGreenS = EditorGUILayout.ToggleLeft("G", invertGreenS, GUILayout.Width(30));
|
|
invertBlueS = EditorGUILayout.ToggleLeft("B", invertBlueS, GUILayout.Width(30));
|
|
invertAlphaS = EditorGUILayout.ToggleLeft("A", invertAlphaS, GUILayout.Width(30));
|
|
|
|
}
|
|
}
|
|
|
|
using (new GUILayout.HorizontalScope("box"))
|
|
{
|
|
if (!saturating)
|
|
{
|
|
SetColorIcon(saturating);
|
|
saturating = GUILayout.Toggle(saturating, "Saturate", "toolbarbutton");
|
|
GUI.backgroundColor = originalGUIColor;
|
|
}
|
|
else
|
|
{
|
|
SetColorIcon(saturating);
|
|
saturating = GUILayout.Toggle(saturating, "", "toolbarbutton", GUILayout.Width(17), GUILayout.Height(17));
|
|
GUI.backgroundColor = originalGUIColor;
|
|
maskSaturate = GUILayout.Toggle(maskSaturate, new GUIContent("M", "Use Mask"), EditorStyles.miniButton, GUILayout.Width(21), GUILayout.Height(16));
|
|
EditorGUIUtility.labelWidth = 65;
|
|
saturationFloat = EditorGUILayout.Slider("Saturate", saturationFloat, -1, saturationMethod == SaturationMethodEnum.Poiyomi ? 10 : 1);
|
|
EditorGUIUtility.labelWidth = 0;
|
|
saturationMethod = (SaturationMethodEnum)EditorGUILayout.EnumPopup(GUIContent.none, saturationMethod, GUILayout.Width(70));
|
|
}
|
|
}
|
|
using (new GUILayout.HorizontalScope("box"))
|
|
{
|
|
if (!hueShifting)
|
|
{
|
|
SetColorIcon(hueShifting);
|
|
hueShifting = GUILayout.Toggle(hueShifting, "Hue Shift", "toolbarbutton");
|
|
GUI.backgroundColor = originalGUIColor;
|
|
}
|
|
else
|
|
{
|
|
SetColorIcon(hueShifting);
|
|
hueShifting = GUILayout.Toggle(hueShifting, "", "toolbarbutton", GUILayout.Width(17), GUILayout.Height(17));
|
|
GUI.backgroundColor = originalGUIColor;
|
|
|
|
maskHueShift = GUILayout.Toggle(maskHueShift, new GUIContent("M", "Use Mask"), EditorStyles.miniButton, GUILayout.Width(21), GUILayout.Height(16));
|
|
EditorGUIUtility.labelWidth = 65;
|
|
hueShiftFloat = EditorGUILayout.Slider("Hue Shift", hueShiftFloat, 0, 1);
|
|
EditorGUIUtility.labelWidth = 0;
|
|
}
|
|
}
|
|
|
|
using (new GUILayout.HorizontalScope("box"))
|
|
{
|
|
if (!colorizing)
|
|
{
|
|
SetColorIcon(colorizing);
|
|
colorizing = GUILayout.Toggle(colorizing, "Colorize", "toolbarbutton");
|
|
GUI.backgroundColor = originalGUIColor;
|
|
}
|
|
else
|
|
{
|
|
SetColorIcon(colorizing);
|
|
colorizing = GUILayout.Toggle(colorizing, "", "toolbarbutton", GUILayout.Width(17), GUILayout.Height(17));
|
|
GUI.backgroundColor = originalGUIColor;
|
|
|
|
maskColorize = GUILayout.Toggle(maskColorize, new GUIContent("M", "Use Mask"), EditorStyles.miniButton, GUILayout.Width(21), GUILayout.Height(16));
|
|
EditorGUIUtility.labelWidth = 65;
|
|
colorizeFloat = EditorGUILayout.Slider("Colorize", colorizeFloat, 0, 1);
|
|
EditorGUIUtility.labelWidth = 0;
|
|
if (!textureColorize)
|
|
colorizeColor = EditorGUILayout.ColorField(new GUIContent(""), colorizeColor, true, alphaColorize, false, GUILayout.Width(70), GUILayout.Height(17));
|
|
else
|
|
colorizeTexture = (Texture2D)EditorGUILayout.ObjectField(colorizeTexture, typeof(Texture2D), false, GUILayout.Width(70), GUILayout.Height(17));
|
|
textureColorize = GUILayout.Toggle(textureColorize, new GUIContent("T", "Use Texture"), EditorStyles.miniButton, GUILayout.Width(19), GUILayout.Height(16));
|
|
alphaColorize = GUILayout.Toggle(alphaColorize, new GUIContent("A", "Use Alpha"), EditorStyles.miniButton, GUILayout.Width(19), GUILayout.Height(16));
|
|
}
|
|
}
|
|
|
|
}
|
|
using (new GUILayout.VerticalScope())
|
|
{
|
|
using (new GUILayout.VerticalScope("box"))
|
|
{
|
|
EditorGUIUtility.labelWidth = 1;
|
|
GUILayout.Label("Main", GUILayout.Width(65));
|
|
EditorGUI.BeginChangeCheck();
|
|
mainTexture = (Texture2D)EditorGUILayout.ObjectField("", mainTexture, typeof(Texture2D), false, GUILayout.Width(65));
|
|
if (EditorGUI.EndChangeCheck())
|
|
ResetDimensions();
|
|
EditorGUIUtility.labelWidth = 0;
|
|
}
|
|
EditorGUI.BeginDisabledGroup(!(hueShifting || saturating || inverting || colorizing));
|
|
using (new GUILayout.VerticalScope("box"))
|
|
{
|
|
EditorGUIUtility.labelWidth = 1;
|
|
GUILayout.Label("Mask", GUILayout.Width(65));
|
|
maskTexture = (Texture2D)EditorGUILayout.ObjectField("", maskTexture, typeof(Texture2D), false, GUILayout.Width(65));
|
|
EditorGUIUtility.labelWidth = 0;
|
|
}
|
|
EditorGUI.EndDisabledGroup();
|
|
}
|
|
}
|
|
EditorGUI.BeginDisabledGroup(!mainTexture);
|
|
if (GUILayout.Button("Apply"))
|
|
{
|
|
ApplyTexture();
|
|
}
|
|
EditorGUI.EndDisabledGroup();
|
|
}
|
|
|
|
private void DrawCreatingTab()
|
|
{
|
|
using (new GUILayout.HorizontalScope("box"))
|
|
{
|
|
if (!creatingCustomSize)
|
|
{
|
|
SetColorIcon(creatingCustomSize);
|
|
creatingCustomSize = GUILayout.Toggle(inverting, "Custom Dimensions", "toolbarbutton");
|
|
GUI.backgroundColor = originalGUIColor;
|
|
}
|
|
else
|
|
{
|
|
SetColorIcon(creatingCustomSize);
|
|
creatingCustomSize = GUILayout.Toggle(creatingCustomSize, "", "toolbarbutton", GUILayout.Width(17), GUILayout.Height(17));
|
|
GUI.backgroundColor = originalGUIColor;
|
|
|
|
DrawDimensionsGUI(false);
|
|
}
|
|
}
|
|
|
|
using (new GUILayout.HorizontalScope("box"))
|
|
{
|
|
encoding = (TexEncoding)EditorGUILayout.EnumPopup(encoding);
|
|
|
|
EditorGUI.BeginDisabledGroup(encoding != TexEncoding.SaveAsJPG);
|
|
EditorGUIUtility.labelWidth = 50;
|
|
jpgQuality = EditorGUILayout.IntSlider("Quality", jpgQuality, 1, 100);
|
|
EditorGUIUtility.labelWidth = 0;
|
|
EditorGUI.EndDisabledGroup();
|
|
}
|
|
|
|
using (new GUILayout.HorizontalScope("box"))
|
|
{
|
|
pingTexture = EditorGUILayout.Toggle(new GUIContent("Highlight Texture", "Highlight the newly created texture in Assets"), pingTexture);
|
|
|
|
EditorGUI.BeginDisabledGroup(creatingMode != TextureCreatingMode.HorizontalGradient && creatingMode != TextureCreatingMode.VerticalGradient);
|
|
creatingReverse = EditorGUILayout.Toggle("Reverse Texture", creatingReverse);
|
|
EditorGUI.EndDisabledGroup();
|
|
}
|
|
|
|
using (new GUILayout.HorizontalScope("box"))
|
|
{
|
|
creatingMode = (TextureCreatingMode)EditorGUILayout.EnumPopup("Texture Mode", creatingMode);
|
|
}
|
|
|
|
switch ((int)creatingMode)
|
|
{
|
|
case 0:
|
|
solidColor = EditorGUILayout.ColorField(solidColor);
|
|
break;
|
|
case 1:
|
|
case 2:
|
|
gradientColor = EditorGUILayout.GradientField(gradientColor);
|
|
break;
|
|
}
|
|
if (GUILayout.Button("Create"))
|
|
{
|
|
CreateTexture();
|
|
}
|
|
AssetFolderPath(ref creatingPath, "Save To", "TextureUtilityCreatingPath");
|
|
}
|
|
|
|
private void DrawPackingTab()
|
|
{
|
|
|
|
using (new GUILayout.HorizontalScope("box"))
|
|
{
|
|
encoding = (TexEncoding)EditorGUILayout.EnumPopup(encoding);
|
|
EditorGUI.BeginDisabledGroup(encoding != TexEncoding.SaveAsJPG);
|
|
EditorGUIUtility.labelWidth = 50;
|
|
jpgQuality = EditorGUILayout.IntSlider("Quality", jpgQuality, 1, 100);
|
|
EditorGUIUtility.labelWidth = 0;
|
|
EditorGUI.EndDisabledGroup();
|
|
}
|
|
using (new GUILayout.HorizontalScope("box"))
|
|
{
|
|
copyImport = EditorGUILayout.Toggle("Copy Import Settings", copyImport);
|
|
pingTexture = EditorGUILayout.Toggle(new GUIContent("Highlight Texture", "Highlight the newly created texture in Assets"), pingTexture);
|
|
}
|
|
using (new GUILayout.HorizontalScope())
|
|
{
|
|
bool p = unpacking;
|
|
SetColorIcon(unpacking);
|
|
unpacking = GUILayout.Toggle(unpacking, "Unpack", "toolbarbutton");
|
|
if (!p && unpacking)
|
|
packing = false;
|
|
|
|
p = packing;
|
|
SetColorIcon(packing);
|
|
packing = GUILayout.Toggle(packing, "Pack", "toolbarbutton");
|
|
if (!p && packing)
|
|
unpacking = false;
|
|
|
|
GUI.backgroundColor = originalGUIColor;
|
|
}
|
|
if (packing)
|
|
{
|
|
using (new GUILayout.HorizontalScope())
|
|
{
|
|
EditorGUIUtility.labelWidth = 1;
|
|
redChannel.DrawGUI();
|
|
greenChannel.DrawGUI();
|
|
blueChannel.DrawGUI();
|
|
alphaChannel.DrawGUI();
|
|
EditorGUIUtility.labelWidth = 0;
|
|
}
|
|
EditorGUI.BeginDisabledGroup(!channelTextures.Any(c => c.texture));
|
|
if (GUILayout.Button("Pack"))
|
|
{
|
|
PackTexture(channelTextures);
|
|
}
|
|
}
|
|
if (unpacking)
|
|
{
|
|
|
|
using (new GUILayout.VerticalScope("box"))
|
|
{
|
|
using (new GUILayout.HorizontalScope())
|
|
{
|
|
GUILayout.FlexibleSpace();
|
|
GUILayout.Label("Main Texture");
|
|
GUILayout.FlexibleSpace();
|
|
}
|
|
|
|
using (new GUILayout.HorizontalScope())
|
|
{
|
|
GUILayout.FlexibleSpace();
|
|
EditorGUIUtility.labelWidth = 1;
|
|
mainTexture = (Texture2D)EditorGUILayout.ObjectField("", mainTexture, typeof(Texture2D), false, GUILayout.Width(66));
|
|
EditorGUIUtility.labelWidth = 0;
|
|
GUILayout.FlexibleSpace();
|
|
}
|
|
}
|
|
EditorGUI.BeginDisabledGroup(!mainTexture);
|
|
if (GUILayout.Button("Unpack"))
|
|
{
|
|
UnpackTexture();
|
|
}
|
|
EditorGUI.EndDisabledGroup();
|
|
}
|
|
|
|
|
|
EditorGUI.EndDisabledGroup();
|
|
}
|
|
|
|
private void DrawDimensionsGUI(bool drawReset=true)
|
|
{
|
|
GUIStyle iconStyle = new GUIStyle(GUI.skin.label) { padding = new RectOffset(), margin = new RectOffset(), imagePosition = ImagePosition.ImageOnly };
|
|
|
|
EditorGUI.BeginDisabledGroup(!mainTexture && !creatingTab);
|
|
if (drawReset)
|
|
{
|
|
if (GUILayout.Button(resetIcon, iconStyle, GUILayout.Height(16), GUILayout.Width(16)))
|
|
ResetDimensions();
|
|
}
|
|
EditorGUIUtility.labelWidth = 20;
|
|
texWidth = EditorGUILayout.IntField(new GUIContent("W","Width"), texWidth);
|
|
texHeight = EditorGUILayout.IntField(new GUIContent("H", "Height"), texHeight);
|
|
EditorGUIUtility.labelWidth = 0;
|
|
|
|
int dummy = -1;
|
|
EditorGUI.BeginChangeCheck();
|
|
dummy = EditorGUILayout.Popup(dummy, DimensionPresets,GUILayout.Width(17));
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
string[] dimensions = ((string)DimensionPresets.GetValue(dummy)).Split('x');
|
|
texWidth = int.Parse(dimensions[0]);
|
|
texHeight = int.Parse(dimensions[1]);
|
|
}
|
|
|
|
EditorGUI.EndDisabledGroup();
|
|
|
|
}
|
|
|
|
public static Texture2D GetColors(Texture2D texture, out Color[] Colors, bool unloadTempTexture = false)
|
|
{
|
|
return GetColors(texture, texture.width, texture.height, out Colors, unloadTempTexture);
|
|
}
|
|
|
|
public static Texture2D GetColors(Texture2D texture, int width, int height, out Color[] Colors,bool unloadTempTexture = false)
|
|
{
|
|
//Thanks to
|
|
//https://gamedev.stackexchange.com/questions/92285/unity3d-resize-texture-without-corruption
|
|
texture.filterMode = FilterMode.Point;
|
|
RenderTexture rt = RenderTexture.GetTemporary(width, height);
|
|
|
|
rt.filterMode = FilterMode.Point;
|
|
RenderTexture.active = rt;
|
|
Graphics.Blit(texture, rt);
|
|
Texture2D newTexture = new Texture2D(width, height);
|
|
newTexture.ReadPixels(new Rect(0, 0, width, height), 0, 0);
|
|
Color[] myColors = newTexture.GetPixels();
|
|
RenderTexture.active = null;
|
|
/////////////////////
|
|
Colors = myColors;
|
|
if (unloadTempTexture)
|
|
{
|
|
DestroyImmediate(newTexture);
|
|
return null;
|
|
}
|
|
return newTexture;
|
|
}
|
|
|
|
private static void SaveTexture(byte[] textureEncoding, string path, bool refresh=false, bool ping=false)
|
|
{
|
|
System.IO.FileStream stream = System.IO.File.Create(path);
|
|
stream.Write(textureEncoding, 0, textureEncoding.Length);
|
|
stream.Dispose();
|
|
if (refresh)
|
|
{
|
|
AssetDatabase.Refresh();
|
|
if (ping)
|
|
{
|
|
Ping(path);
|
|
}
|
|
}
|
|
|
|
}
|
|
private static void Ping(string path)
|
|
{
|
|
EditorGUIUtility.PingObject(AssetDatabase.LoadAssetAtPath<Object>(path));
|
|
}
|
|
|
|
private void ApplyTexture()
|
|
{
|
|
if (colorizing && !colorizeTexture && textureColorize)
|
|
{
|
|
Debug.LogError("Cannot Colorize using a texture without a texture!");
|
|
return;
|
|
}
|
|
|
|
string destinationPath = GetDestinationFolder(mainTexture);
|
|
string texPath = AssetDatabase.GetAssetPath(mainTexture);
|
|
|
|
Texture2D newTexture = GetColors(mainTexture, texWidth, texHeight, out Color[] myColors);
|
|
|
|
if (rotating)
|
|
{
|
|
List<Color> rotatedColors = new List<Color>();
|
|
switch (rotationType)
|
|
{
|
|
case TexRotation.Clockwise90:
|
|
for (int i = texWidth-1; i >=0; i--)
|
|
{
|
|
rotatedColors.AddRange(newTexture.GetPixels(i, 0, 1, texHeight));
|
|
}
|
|
myColors = rotatedColors.ToArray();
|
|
newTexture = new Texture2D(texHeight, texWidth);
|
|
break;
|
|
|
|
case TexRotation.CClockwise90:
|
|
for (int i = 0; i < texWidth; i++)
|
|
{
|
|
rotatedColors.AddRange(ReverseArray(newTexture.GetPixels(i, 0, 1, texHeight)));
|
|
}
|
|
myColors = rotatedColors.ToArray();
|
|
newTexture = new Texture2D(texHeight, texWidth);
|
|
break;
|
|
|
|
case TexRotation.Rotate180:
|
|
myColors = ReverseArray(myColors);
|
|
break;
|
|
|
|
case TexRotation.FlipHorizontal:
|
|
for (int i = 0; i < texHeight; i++)
|
|
{
|
|
rotatedColors.AddRange(ReverseArray(newTexture.GetPixels(0, i, texWidth, 1)));
|
|
}
|
|
myColors = rotatedColors.ToArray();
|
|
break;
|
|
|
|
case TexRotation.FlipVertical:
|
|
for (int i = texHeight - 1; i >= 0; i--)
|
|
{
|
|
rotatedColors.AddRange(newTexture.GetPixels(0, i, texWidth, 1));
|
|
}
|
|
myColors = rotatedColors.ToArray();
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
bool colorInverting = (invertRedS || invertGreenS || invertBlueS || invertAlphaS) && inverting;
|
|
bool HSVEditing = hueShifting || saturating;
|
|
bool colorEditing = HSVEditing || colorizing;
|
|
bool editing = colorEditing || colorInverting || unpacking;
|
|
bool masking = ((maskColorize && colorizing) || (maskInvert && colorInverting) || (maskSaturate && saturating) || (maskHueShift && hueShifting)) && maskTexture;
|
|
|
|
Color[] maskColors = null;
|
|
if (masking) GetColors(maskTexture, texWidth, texHeight, out maskColors, true);
|
|
|
|
Color[] colorizeTextureColors;
|
|
if (colorizing && textureColorize)
|
|
{
|
|
GetColors(colorizeTexture, texWidth, texHeight, out colorizeTextureColors, true);
|
|
}
|
|
else
|
|
colorizeTextureColors = null;
|
|
|
|
|
|
Color[] newColors = new Color[myColors.Length];
|
|
if (editing)
|
|
{
|
|
bool hasMaskTexture = maskTexture != null;
|
|
float tempSatValue = saturationMethod == SaturationMethodEnum.Poiyomi ? saturationFloat + 1 : saturationFloat;
|
|
Parallel.For(0, myColors.Length, i =>
|
|
{
|
|
Color currentColor = myColors[i];
|
|
|
|
if (colorEditing)
|
|
{
|
|
if (HSVEditing)
|
|
{
|
|
Color.RGBToHSV(currentColor, out float h, out float s, out float v);
|
|
if (hueShifting)
|
|
h = Mathf.Repeat(h + (hueShiftFloat * (hasMaskTexture && maskHueShift ? maskColors[i].r : 1)), 1);
|
|
if (saturating && saturationMethod == SaturationMethodEnum.Gimp)
|
|
s = Mathf.Clamp01(s * (1 + tempSatValue * (hasMaskTexture && maskSaturate ? maskColors[i].r : 1)));
|
|
currentColor = Color.HSVToRGB(h, s, v);
|
|
|
|
if (saturating && saturationMethod == SaturationMethodEnum.Poiyomi)
|
|
{
|
|
//return lerp(dot(col, float3(0.3, 0.59, 0.11)), col, interpolator);
|
|
//Doesn't seem to replicate the exact effect, but looks close. Thank you Poiyomi!
|
|
var dot = currentColor.r * 0.3f + currentColor.g * 0.59f + currentColor.b * 0.11f;
|
|
var factor = tempSatValue;
|
|
if (hasMaskTexture && maskSaturate)
|
|
factor *= maskColors[i].r;
|
|
|
|
currentColor = new Color(dot + factor * (currentColor.r - dot), dot + factor * (currentColor.g - dot), dot + factor * (currentColor.b - dot), currentColor.a);
|
|
|
|
}
|
|
currentColor.a = myColors[i].a;
|
|
}
|
|
|
|
if (colorizing)
|
|
{
|
|
float oga = currentColor.a;
|
|
currentColor = Color.Lerp(currentColor, textureColorize ? colorizeTextureColors[i] : colorizeColor, colorizeFloat * (maskColorize && hasMaskTexture ? maskColors[i].r : 1));
|
|
|
|
if (!alphaColorize)
|
|
currentColor.a = oga;
|
|
}
|
|
}
|
|
|
|
float r = colorInverting && invertRedS ? currentColor.r - ((currentColor.r - (1 - currentColor.r)) * (maskInvert && hasMaskTexture ? maskColors[i].r : 1)) : currentColor.r;
|
|
float g = colorInverting && invertGreenS ? currentColor.g - ((currentColor.g - (1 - currentColor.g)) * (maskInvert && hasMaskTexture ? maskColors[i].g : 1)) : currentColor.g;
|
|
float b = colorInverting && invertBlueS ? currentColor.b - ((currentColor.b - (1 - currentColor.b)) * (maskInvert && hasMaskTexture ? maskColors[i].b : 1)) : currentColor.b;
|
|
float a = colorInverting && invertAlphaS ? currentColor.a - ((currentColor.a - (1 - currentColor.a)) * (maskInvert && hasMaskTexture ? maskColors[i].a : 1)) : currentColor.a;
|
|
|
|
newColors[i] = new Color(r, g, b, a);
|
|
});
|
|
}
|
|
newTexture.SetPixels(editing ? newColors : myColors);
|
|
newTexture.Apply();
|
|
|
|
GetEncoding(newTexture, encoding, out byte[] data, out string ext);
|
|
|
|
string newTexturePath = AssetDatabase.GenerateUniqueAssetPath(destinationPath + "/" + mainTexture.name
|
|
+ (colorInverting ? " Inverted" : "") + ext);
|
|
|
|
SaveTexture(data, newTexturePath, true, pingTexture);
|
|
|
|
if (copyImport)
|
|
{
|
|
CopyTextureSettings(texPath, newTexturePath);
|
|
}
|
|
}
|
|
|
|
private static void GetEncoding(Texture2D texture, TexEncoding encodingType, out byte[] data, out string ext)
|
|
{
|
|
switch ((int)encodingType)
|
|
{
|
|
default:
|
|
ext = ".png";
|
|
data = texture.EncodeToPNG();
|
|
break;
|
|
case 1:
|
|
ext = ".jpg";
|
|
data = texture.EncodeToJPG(jpgQuality);
|
|
break;
|
|
case 2:
|
|
ext = ".tga";
|
|
data = texture.EncodeToTGA();
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
private void CreateTexture()
|
|
{
|
|
Texture2D newTexture = null;
|
|
int w = creatingCustomSize ? texWidth : 0;
|
|
int h = creatingCustomSize ? texHeight : 0;
|
|
|
|
Color[] myColors = null;
|
|
switch ((int)creatingMode)
|
|
{
|
|
case 0:
|
|
if (!creatingCustomSize)
|
|
{
|
|
w = h = 4;
|
|
}
|
|
newTexture = new Texture2D(w, h);
|
|
|
|
myColors = CreateFilledArray(solidColor, w * h);
|
|
newTexture.SetPixels(0, 0, w, h, myColors);
|
|
break;
|
|
case 1:
|
|
{
|
|
if (!creatingCustomSize)
|
|
{
|
|
w = 256;
|
|
h = 4;
|
|
}
|
|
newTexture = new Texture2D(w, h);
|
|
|
|
int i = creatingReverse ? w - 1 : 0;
|
|
int istep = creatingReverse ? -1 : 1;
|
|
|
|
float xstepValue = (1f / w);
|
|
float xcurrentStep = 0;
|
|
for (; i < w && i >= 0; i += istep)
|
|
{
|
|
newTexture.SetPixels(i, 0, 1, h, CreateFilledArray(gradientColor.Evaluate(xcurrentStep), h));
|
|
xcurrentStep += xstepValue;
|
|
}
|
|
}
|
|
break;
|
|
case 2:
|
|
{
|
|
if (!creatingCustomSize)
|
|
{
|
|
w = 4;
|
|
h = 256;
|
|
}
|
|
newTexture = new Texture2D(w, h);
|
|
|
|
int i = creatingReverse ? h - 1 : 0;
|
|
int istep = creatingReverse ? -1 : 1;
|
|
|
|
float ystepValue = 1f / h;
|
|
float ycurrentStep = 0;
|
|
for (; i < h && i >= 0; i += istep)
|
|
{
|
|
newTexture.SetPixels(0, i, w, 1, CreateFilledArray(gradientColor.Evaluate(ycurrentStep), w));
|
|
ycurrentStep += ystepValue;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
GetEncoding(newTexture, encoding, out byte[] data, out string ext);
|
|
|
|
ReadyFolder(creatingPath);
|
|
SaveTexture(data, AssetDatabase.GenerateUniqueAssetPath(creatingPath +"/Generated Texture"+ext), true, pingTexture);
|
|
}
|
|
|
|
private void UnpackTexture()
|
|
{
|
|
string destinationPath = GetDestinationFolder(mainTexture);
|
|
string texPath = AssetDatabase.GetAssetPath(mainTexture);
|
|
int x = mainTexture.width, y = mainTexture.height;
|
|
Texture2D newTexture = GetColors(mainTexture, x, y, out Color[] myColors);
|
|
List<System.Tuple<string, string>> copyFromTo = new List<System.Tuple<string, string>>();
|
|
|
|
bool isRedPass = true, isGreenPass, isBluePass, isAlphaPass;
|
|
isGreenPass = isBluePass = isAlphaPass = false;
|
|
try
|
|
{
|
|
AssetDatabase.StartAssetEditing();
|
|
|
|
do
|
|
{
|
|
Color[] newColors = new Color[myColors.Length];
|
|
|
|
bool hasAlpha = false;
|
|
for (int i = 0; i < myColors.Length; i++)
|
|
{
|
|
Color currentColor = myColors[i];
|
|
|
|
float r = currentColor.r;
|
|
float g = currentColor.g;
|
|
float b = currentColor.b;
|
|
float a = currentColor.a;
|
|
|
|
if (isRedPass)
|
|
{
|
|
g = b = r;
|
|
a = 1;
|
|
}
|
|
if (isGreenPass)
|
|
{
|
|
r = b = g;
|
|
a = 1;
|
|
}
|
|
if (isBluePass)
|
|
{
|
|
r = g = b;
|
|
a = 1;
|
|
}
|
|
if (isAlphaPass)
|
|
{
|
|
r = g = b = a;
|
|
if (a != 1)
|
|
hasAlpha = true;
|
|
}
|
|
|
|
newColors[i] = new Color(r, g, b, a);
|
|
}
|
|
|
|
if (isAlphaPass && !hasAlpha)
|
|
{
|
|
isAlphaPass = false;
|
|
goto Skip;
|
|
}
|
|
|
|
newTexture.SetPixels(newColors);
|
|
newTexture.Apply();
|
|
|
|
GetEncoding(newTexture, encoding, out byte[] data, out string ext);
|
|
|
|
string newTexturePath = AssetDatabase.GenerateUniqueAssetPath(destinationPath + "/" + mainTexture.name
|
|
+ (isRedPass ? "-Red" : isGreenPass ? "-Green" : isBluePass ? "-Blue" : "-Alpha") + ext);
|
|
|
|
SaveTexture(data, newTexturePath);
|
|
|
|
if (copyImport)
|
|
{
|
|
copyFromTo.Add(new System.Tuple<string, string>(texPath, newTexturePath));
|
|
}
|
|
|
|
if (isAlphaPass)
|
|
isAlphaPass = false;
|
|
if (isBluePass)
|
|
{
|
|
isBluePass = false;
|
|
isAlphaPass = true;
|
|
}
|
|
if (isGreenPass)
|
|
{
|
|
isGreenPass = false;
|
|
isBluePass = true;
|
|
}
|
|
if (isRedPass)
|
|
{
|
|
isRedPass = false;
|
|
isGreenPass = true;
|
|
}
|
|
|
|
if (unpacking)
|
|
newTexture = new Texture2D(x, y);
|
|
|
|
Skip:;
|
|
|
|
} while (isRedPass || isGreenPass || isBluePass || isAlphaPass);
|
|
}
|
|
finally
|
|
{
|
|
AssetDatabase.StopAssetEditing();
|
|
}
|
|
AssetDatabase.Refresh();
|
|
if (copyImport)
|
|
{
|
|
for (int i = 0; i < copyFromTo.Count; i++)
|
|
{
|
|
CopyTextureSettings(copyFromTo[i].Item1, copyFromTo[i].Item2);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void PackTexture(ChannelTexture[] channels)
|
|
{
|
|
int firstIndex = 0;
|
|
for (int i = 3; i >= 0; i--)
|
|
{
|
|
if (channels[i].texture)
|
|
firstIndex = i;
|
|
}
|
|
ChannelTexture firstChannel = channels[firstIndex];
|
|
int w = firstChannel.texture.width;
|
|
int h = firstChannel.texture.height;
|
|
PackTexture(channels, AssetDatabase.GetAssetPath(firstChannel.texture), w, h, encoding);
|
|
}
|
|
|
|
public static string PackTexture(ChannelTexture[] channels, TexEncoding encodingType, bool refresh=true, bool copyImportSettings=true)
|
|
{
|
|
int firstIndex = -1;
|
|
for (int i = 3; i >= 0; i--)
|
|
{
|
|
if (channels[i].texture)
|
|
firstIndex = i;
|
|
}
|
|
if (firstIndex < 0)
|
|
return string.Empty;
|
|
ChannelTexture firstChannel = channels[firstIndex];
|
|
int w = firstChannel.texture.width;
|
|
int h = firstChannel.texture.height;
|
|
return PackTexture(channels, AssetDatabase.GetAssetPath(firstChannel.texture), w, h, encodingType,refresh,false,copyImportSettings);
|
|
}
|
|
|
|
public static string PackTexture(ChannelTexture[] channels, string destination,int width, int height, TexEncoding encodingType, bool refresh=true,bool overwrite=false, bool copyImportSettings=true)
|
|
{
|
|
int firstIndex = -1;
|
|
for (int i = 3; i >= 0; i--)
|
|
{
|
|
if (channels[i].texture)
|
|
firstIndex = i;
|
|
}
|
|
if (firstIndex < 0)
|
|
return string.Empty;
|
|
|
|
ChannelTexture firstChannel = channels[firstIndex];
|
|
|
|
|
|
Texture2D newTexture = new Texture2D(width, height);
|
|
channels[0].GetChannelColors(width, height, out float[] reds, true);
|
|
channels[1].GetChannelColors(width, height, out float[] greens, true);
|
|
channels[2].GetChannelColors(width, height, out float[] blues, true);
|
|
channels[3].GetChannelColors(width, height, out float[] alphas, true);
|
|
Color[] finalColors = new Color[width*height];
|
|
|
|
for (int i=0;i< finalColors.Length;i++)
|
|
{
|
|
finalColors[i].r = (reds!=null) ? reds[i] : 0;
|
|
finalColors[i].g = (greens != null) ? greens[i] : 0;
|
|
finalColors[i].b = (blues != null) ? blues[i] : 0;
|
|
finalColors[i].a = (alphas != null) ? alphas[i] : 1;
|
|
}
|
|
newTexture.SetPixels(finalColors);
|
|
newTexture.Apply();
|
|
|
|
GetEncoding(newTexture, encodingType, out byte[] data, out string ext);
|
|
|
|
string newTexturePath = GetDestinationFolder(destination)+"/"+System.IO.Path.GetFileNameWithoutExtension(destination)+ext;
|
|
if (!overwrite)
|
|
newTexturePath = AssetDatabase.GenerateUniqueAssetPath(newTexturePath);
|
|
SaveTexture(data, newTexturePath);
|
|
DestroyImmediate(newTexture);
|
|
if (refresh)
|
|
AssetDatabase.Refresh();
|
|
|
|
|
|
if (copyImportSettings)
|
|
{
|
|
CopyTextureSettings(AssetDatabase.GetAssetPath(firstChannel.texture), newTexturePath);
|
|
}
|
|
return newTexturePath;
|
|
}
|
|
|
|
private static void CopyTextureSettings(string from, string to)
|
|
{
|
|
TextureImporter source = (TextureImporter)AssetImporter.GetAtPath(from);
|
|
TextureImporterSettings sourceSettings = new TextureImporterSettings();
|
|
source.ReadTextureSettings(sourceSettings);
|
|
|
|
TextureImporter destination = (TextureImporter)AssetImporter.GetAtPath(to);
|
|
destination.SetTextureSettings(sourceSettings);
|
|
destination.maxTextureSize = source.maxTextureSize;
|
|
destination.textureCompression = source.textureCompression;
|
|
destination.crunchedCompression = source.crunchedCompression;
|
|
destination.SaveAndReimport();
|
|
}
|
|
|
|
private static string GetDestinationFolder(Object o)
|
|
{
|
|
string path = AssetDatabase.GetAssetPath(o);
|
|
return GetDestinationFolder(path);
|
|
}
|
|
private static string GetDestinationFolder(string path)
|
|
{
|
|
return path.Substring(0, path.LastIndexOf('/'));
|
|
}
|
|
|
|
private void ResetDimensions()
|
|
{
|
|
if (mainTexture)
|
|
{
|
|
texHeight = mainTexture.height;
|
|
texWidth = mainTexture.width;
|
|
}
|
|
}
|
|
|
|
private void SetColorIcon(bool value)
|
|
{
|
|
if (value)
|
|
GUI.backgroundColor = Color.green;
|
|
else
|
|
GUI.backgroundColor = Color.grey;
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
resetIcon = new GUIContent(EditorGUIUtility.IconContent("d_Refresh")) { tooltip = "Reset Dimensions" };
|
|
creatingPath = PlayerPrefs.GetString("TextureUtilityCreatingPath", "Assets/DreadScripts/Texture Utility/Generated Assets");
|
|
|
|
foreach (var channel in channelTextures)
|
|
{
|
|
channel.SetMode(EditorPrefs.GetInt("TextureUtilityChannel" + channel.name, (int)channel.mode));
|
|
}
|
|
}
|
|
|
|
private static T[] CreateFilledArray<T>(T variable,int length)
|
|
{
|
|
T[] myArray = new T[length];
|
|
for (int i=0;i< myArray.Length;i++)
|
|
{
|
|
myArray[i] = variable;
|
|
}
|
|
return myArray;
|
|
}
|
|
|
|
private static T[] ReverseArray<T>(T[] array)
|
|
{
|
|
T[] reversed = new T[array.Length];
|
|
int index = array.Length - 1;
|
|
for (int i = 0; i < reversed.Length; i++)
|
|
{
|
|
reversed[i] = array[index];
|
|
index--;
|
|
}
|
|
return reversed;
|
|
}
|
|
|
|
public static void AssetFolderPath(ref string variable, string title, string playerpref)
|
|
{
|
|
EditorGUILayout.BeginHorizontal();
|
|
EditorGUI.BeginDisabledGroup(true);
|
|
EditorGUILayout.TextField(title, variable);
|
|
EditorGUI.EndDisabledGroup();
|
|
if (GUILayout.Button("...", GUILayout.Width(30)))
|
|
{
|
|
string dummyPath = EditorUtility.OpenFolderPanel(title, variable, "");
|
|
if (string.IsNullOrEmpty(dummyPath))
|
|
return;
|
|
|
|
if (!dummyPath.Contains("Assets"))
|
|
{
|
|
Debug.LogWarning("New Path must be a folder within Assets!");
|
|
return;
|
|
}
|
|
variable = FileUtil.GetProjectRelativePath(dummyPath);
|
|
PlayerPrefs.SetString(playerpref, variable);
|
|
}
|
|
EditorGUILayout.EndHorizontal();
|
|
}
|
|
|
|
public static void ReadyFolder(string folderPath)
|
|
{
|
|
if (!Directory.Exists(folderPath))
|
|
Directory.CreateDirectory(folderPath);
|
|
}
|
|
|
|
private static void Credit()
|
|
{
|
|
GUIStyle creditLabelStyle = new GUIStyle(GUI.skin.label) { richText = true };
|
|
using (new GUILayout.HorizontalScope())
|
|
{
|
|
GUILayout.FlexibleSpace();
|
|
if (GUILayout.Button("<b>Made by @Dreadrith</b>", creditLabelStyle))
|
|
Application.OpenURL("https://linktr.ee/Dreadrith");
|
|
}
|
|
}
|
|
}
|
|
} |