﻿//Script created by Merlin and Xiexe.
using System.Collections;
using System.IO;
using UnityEditor;
using UnityEngine;
namespace XSToonDynamicPenetration {
	public class XSTextureMerger : EditorWindow {

		private enum resolutions {
			Tiny_256x256,
			Small_512x512,
			Medium_1024x1024,
			Large_2048x2048,
			VeryLarge_4096x4096,
			Why_8192x8192
		}

		private enum EChannels {
			None,
			Red,
			Green,
			Blue,
			Alpha
		}

		private enum ETextures {
			None,
			Tex1,
			Tex2,
			Tex3,
			Tex4
		}

		private Texture2D[] textures = new Texture2D[4];
		private EChannels[] texChannels = new EChannels[4];
		private ETextures[] pickTexture = new ETextures[4];
		private bool[] invertChannel = new bool[4];

		private static int srcTex;
		private resolutions res;
		private Vector2 scrollPos;
		private static int resolution;
		private static string finalFilePath;
		private static Color outColor;
		private static Color[] texColors = new Color[4];

		private static float progress;
		[MenuItem("Tools/Xiexe/XSToon/Texture Merger")]
		static public void Init() {
			XSTextureMerger window = EditorWindow.GetWindow<XSTextureMerger>(false, "XSToon: Texture Merger", true);
			window.minSize = new Vector2(500, 300);
			window.maxSize = new Vector2(500, 500);
		}

		public void OnGUI() {
			scrollPos = EditorGUILayout.BeginScrollView(scrollPos);

			GUILayout.BeginHorizontal();
			GUILayout.Space(105);
			XSStyles.doLabel("1");
			GUILayout.Space(105);
			XSStyles.doLabel("2");
			GUILayout.Space(105);
			XSStyles.doLabel("3");
			GUILayout.Space(105);
			XSStyles.doLabel("4");
			GUILayout.EndHorizontal();

			XSStyles.SeparatorThin();
			GUILayout.BeginHorizontal();
			for (int i = 0; i < 4; i++) {
				EditorGUIUtility.labelWidth = 0.01f;
				textures[i] = (Texture2D) EditorGUILayout.ObjectField(new GUIContent("", ""), textures[i], typeof(Texture2D), true);

			}
			GUILayout.EndHorizontal();

			float oldLabelWidth = EditorGUIUtility.labelWidth;
			EditorGUIUtility.labelWidth = 40;
			GUIStyle headerStyle = EditorStyles.boldLabel;
			headerStyle.alignment = TextAnchor.UpperLeft;
			headerStyle.fontStyle = FontStyle.Bold;
			headerStyle.stretchWidth = true;

			XSStyles.SeparatorThin();
			EditorGUILayout.BeginHorizontal();
			GUILayout.Label("Output Channel:", headerStyle);

			GUILayout.Label("R", headerStyle);
			GUILayout.Label("G", headerStyle);
			GUILayout.Label("B", headerStyle);
			GUILayout.Label("A", headerStyle);
			EditorGUILayout.EndHorizontal();

			GUILayout.BeginHorizontal();
			GUILayout.Label("Src Texture:");
			GUILayout.Space(20);
			for (int i = 0; i < 4; i++) {
				pickTexture[i] = (ETextures) EditorGUILayout.EnumPopup("", pickTexture[i]);
			}
			GUILayout.EndHorizontal();

			GUILayout.BeginHorizontal();
			GUILayout.Label("Src Channel:");
			GUILayout.Space(17);
			for (int i = 0; i < 4; i++) {
				texChannels[i] = (EChannels) EditorGUILayout.EnumPopup("", texChannels[i]);
			}
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal();
			GUILayout.Label("Invert Channel:");
			for (int i = 0; i < 4; i++) {
				invertChannel[i] = EditorGUILayout.Toggle("", invertChannel[i]);
			}
			GUILayout.EndHorizontal();

			GUILayout.Space(20);
			EditorGUILayout.EndScrollView();

			//Button and Resolution
			GUILayout.BeginVertical();
			XSStyles.doLabel("Resolution");

			GUILayout.BeginHorizontal();
			GUILayout.Space(175);
			res = (resolutions) EditorGUILayout.EnumPopup("", res);
			GUILayout.Space(175);
			GUILayout.EndHorizontal();

			if (GUILayout.Button("Merge Channels")) {
				if (progress < 2) {
					EditorUtility.DisplayProgressBar("XSToon Texture Merger", "Merging and compressing new texture...", (float) (progress / 2));
				}

				//Set target textures to be ReadWriteable

				for (int i = 0; i < textures.Length; i++) {
					if (textures[i] == null)
						break;

					string texturePath = AssetDatabase.GetAssetPath(textures[i]);
					TextureImporter texture = (TextureImporter) TextureImporter.GetAtPath(texturePath);
					if (texture != null) {
						texture.isReadable = true;
						texture.SaveAndReimport();
					}
				}

				switch (res) {
					case resolutions.Tiny_256x256:
						resolution = 256;
						break;

					case resolutions.Small_512x512:
						resolution = 512;
						break;

					case resolutions.Medium_1024x1024:
						resolution = 1024;
						break;

					case resolutions.Large_2048x2048:
						resolution = 2048;
						break;

					case resolutions.VeryLarge_4096x4096:
						resolution = 4096;
						break;

					case resolutions.Why_8192x8192:
						resolution = 8192;
						break;
				}

				XSStyles.findAssetPath(finalFilePath);
				finalFilePath = EditorUtility.SaveFilePanel("Save Merged Texture", finalFilePath + "/Textures/", "mergedTex.png", "png");

				Texture2D newTexture = new Texture2D(resolution, resolution, TextureFormat.RGBA32, false);

				//Get Colors textures and write them to the proper channel

				for (int y = 0; y < resolution; y++) {
					for (int x = 0; x < resolution; x++) {
						float u = x / (float) resolution;
						float v = y / (float) resolution;

						// Grab out the texture values into an array for later lookup. Could probably just be done at the moment the texture color is needed.
						for (int i = 0; i < textures.Length; i++) {
							if (textures[i] != null) {
								texColors[i] = textures[i].GetPixelBilinear(u, v);
							} else {
								texColors[i] = new Color(0, 0, 0, 1);
							}
						}

						Color outputColor = new Color(0, 0, 0, 1);

						// Iterate the output RGBA channels
						for (int i = 0; i < 4; i++) {
							// Convert the enums to indices we can use. 'None' will turn into -1 which will be discarded as invalid.
							int srcTexIdx = ((int) pickTexture[i]) - 1;
							int srcChannelIdx = ((int) texChannels[i]) - 1;

							// Go through each channel in the output color and assign it
							if (srcTexIdx >= 0 && srcChannelIdx >= 0) {
								outputColor[i] = texColors[srcTexIdx][srcChannelIdx];

								//Allow you to invert specific channels. 
								if (invertChannel[i]) {
									outputColor[i] = 1f - outputColor[i];
								}
							}
						}

						newTexture.SetPixel(x, y, outputColor);
					}
				}
				progress += 1;
				newTexture.Apply();
				ExportTexture(newTexture);
			}

			GUILayout.Space(10);
			GUILayout.EndVertical();

			EditorGUIUtility.labelWidth = oldLabelWidth;
		}

		private static void ExportTexture(Texture2D newTexture) {
			var pngData = newTexture.EncodeToPNG();

			if (pngData != null) {
				File.WriteAllBytes(finalFilePath, pngData);
				AssetDatabase.Refresh();
			}
			progress += 1;
			EditorUtility.ClearProgressBar();
		}
	}
}