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(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(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 rotatedColors = new List(); 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> copyFromTo = new List>(); 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(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 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[] 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("Made by @Dreadrith", creditLabelStyle)) Application.OpenURL("https://linktr.ee/Dreadrith"); } } } }