using System;
using System.IO;
using UnityEditor;
using UnityEngine;

public class MapCreator : EditorWindow
{
    private Material mat;
    private int maptype = 0,_maptype;
    private string[] maptypes = new string[] {"Mask Map", "Detail Map", "Custom"};
    private Texture2D metallic, occlusion, detailmask, smoothness, deAbedo, deNormal, deSmoothness;
    private bool useRoughness;
    //用以记录输入是否更新
    private bool changed;
    private Texture2D _metallic, _occlusion, _detailmask, _smoothness, _deAbedo, _deNormal, _deSmoothness;
    private bool _useRoughness;
    
    //创建菜单栏
    [MenuItem("Window/Tools/MapCreator")]
    //创建窗口
    static void OpenMapCreator()
    {
        MapCreator mapCreator = GetWindow<MapCreator>("Map Creator");
        mapCreator.Init();
    }
    //初始化材质
    private void Init()
    {
        if (mat == null)
        {
            mat = new Material(Shader.Find("Hidden/MapCreator"));//create material
            mat.hideFlags = HideFlags.HideAndDontSave;
        }
    }
    //窗口界面
    public void OnGUI()
    {
        //选择生成贴图类型
        GUILayout.Space(10);
        maptype = EditorGUILayout.Popup("Map Type", maptype, maptypes);
        GUILayout.Space(10);
        //绘制贴图盒
        if (maptype == 0 )//mask map
        {
            useRoughness = EditorGUILayout.Toggle("use Roughness?", useRoughness);
            MaskMapInput();
        }
        else if (maptype == 1) //detail map
        {
            useRoughness = EditorGUILayout.Toggle("use Roughness?", useRoughness);
            DetailMapInput();
        }
        else//custom map
        {
            EditorGUILayout.Space(20);
            CustomInput();
        }
        if (maptype != _maptype || useRoughness!=_useRoughness)
        {
            changed = true;
            _maptype = maptype;
            _useRoughness = useRoughness;
        }
        //绘制预览贴图
        Preview();
        //绘制创建按钮
        CreateMask();
    }

    private void MaskMapInput()
    {
        EditorGUILayout.BeginHorizontal("Box");
        _metallic = TextureField("Metallic", metallic);
        if (_metallic != metallic)
        {
            metallic = _metallic;
            changed = true;
        }
        _occlusion = TextureField("Occlusion", occlusion);
        if (_occlusion != occlusion)
        {
            occlusion = _occlusion;
            changed = true;
        }

        _detailmask = TextureField("Detailmask", detailmask);
        if (_detailmask != detailmask)
        {
            detailmask = _detailmask;
            changed = true;
        }

        if (!useRoughness)
        {
            _smoothness = TextureField("Smoothness", smoothness);
        }
        else
        {
            _smoothness = TextureField("Roughness", smoothness);
        }
        if (_smoothness != smoothness)
        {
            smoothness = _smoothness;
            changed = true;
        }
        EditorGUILayout.EndHorizontal();
    }

    private void DetailMapInput()
    {
        EditorGUILayout.BeginHorizontal("Box");
        _deAbedo = TextureField("Abedo", deAbedo);
        if (_deAbedo != deAbedo)
        {
            deAbedo = _deAbedo;
            changed = true;
        }
        _deNormal = TextureField("Normal", deNormal);
        if (_deNormal != deNormal)
        {
            deNormal = _deNormal;
            changed = true;
        }
        if (!useRoughness)
        {
            _deSmoothness = TextureField("Smoothness", deSmoothness);
        }
        else
        {
            _deSmoothness = TextureField("Roughness", deSmoothness);
        }
        if (_deSmoothness != deSmoothness)
        {
            deSmoothness = _deSmoothness;
            changed = true;
        }
        EditorGUILayout.EndHorizontal();
    }
    private void CustomInput()
    {
        EditorGUILayout.BeginHorizontal("Box");
        _metallic = TextureField("R", metallic);
        if (_metallic != metallic)
        {
            metallic = _metallic;
            changed = true;
        }
        _occlusion = TextureField("G", occlusion);
        if (_occlusion != occlusion)
        {
            occlusion = _occlusion;
            changed = true;
        }
        _detailmask = TextureField("B", detailmask);
        if (_detailmask != detailmask)
        {
            detailmask = _detailmask;
            changed = true;
        }
        _smoothness = TextureField("A", smoothness);
        if (_smoothness != smoothness)
        {
            smoothness = _smoothness;
            changed = true;
        }
        EditorGUILayout.EndHorizontal();
    }
    private Texture2D TextureField(string name, Texture2D texture)
    {
        EditorGUILayout.BeginVertical();
        var style = new GUIStyle(GUI.skin.label);
        style.alignment = TextAnchor.MiddleCenter;
        style.fixedWidth = 80;
        GUILayout.Label(name,style);
        Texture2D result = EditorGUILayout.ObjectField(texture, typeof(Texture2D), false, GUILayout.Width(80),GUILayout.Height(80)) as Texture2D;
        EditorGUILayout.EndVertical();
        return result;
    }

    
    private Texture2D preview = null;
    private void Preview()
    {
        EditorGUILayout.BeginHorizontal();
        GUILayout.Label("Preview Output");
        EditorGUILayout.EndHorizontal();
        //居中绘制贴图框
        EditorGUILayout.BeginHorizontal();
        Rect previewRect = new Rect(this.position.width / 2 - 75, 200, 150, 150);
        //初始绘制默认纹理
        if (preview == null)
        {
            preview = Texture2D.blackTexture;
        }
        //每当输入参数改变时，刷新材质
        if (changed)
        {
            //path只用于自动更名保存，这里其实不需要
            string path = "";
            preview = GetTexture(ref path);
            changed = false;
        }
        //在贴图框中绘制贴图
        EditorGUI.DrawPreviewTexture(previewRect,preview);
        EditorGUILayout.Space(170);
        EditorGUILayout.EndHorizontal();
    }
    
    private void CreateMask()
    {
        EditorGUILayout.BeginHorizontal();
        if (GUILayout.Button("Create Map"))
        {
            GenPictureAuto();
        }

        if (GUILayout.Button("...", GUILayout.Width(40)))
        {
            GenPictureCustom();
        }
        EditorGUILayout.EndHorizontal();
    }
    //根据其他贴图的路径自动保存贴图
    private void GenPictureAuto()
    {
        string savepath = "";
        Texture2D output = GetTexture(ref savepath);
        if(maptype == 0) savepath += "_mask";
        else if (maptype == 1) savepath += "_detailmap";
        byte[] bytes = output.EncodeToPNG();
        FileStream file = File.Open(savepath + ".png", FileMode.Create);
        BinaryWriter writer = new BinaryWriter(file);
        writer.Write(bytes);
        file.Close();
        Texture2D.DestroyImmediate(output);
        output = null;

        AssetDatabase.Refresh();
    }
    //手动保存贴图
    private void GenPictureCustom()
    {
        string savepath = "";
        Texture2D output = GetTexture(ref savepath);
        string savePath = EditorUtility.SaveFilePanel("Save", Application.dataPath, "Texture.png", "png");
        File.WriteAllBytes(savePath,output.EncodeToPNG());
        AssetDatabase.Refresh();
    }
    //KEY FUNCTION 渲染贴图至RT
    private Texture2D GetTexture(ref string path)
    {   //保持新创建的贴图与原贴图尺寸相同
        Vector2 rtSize = new Vector2(2048, 2048);
        //用于路径更名
        char[] splitor = {'_'};

        //传入shader所需参数
        Shader.SetGlobalInt("maptype", maptype);
        if (!useRoughness) Shader.SetGlobalInt("useRoughness", 0);
        else Shader.SetGlobalInt("useRoughness", 1);
        //传入shader所需贴图
        if (maptype == 1)
        {
            if (deAbedo != null)
            {
                mat.SetTexture("_deAbedo", deAbedo);
                rtSize.x = deAbedo.width;
                rtSize.y = deAbedo.height;
                path = AssetDatabase.GetAssetPath(deAbedo);
                path = Reverse(path);
                path = path.Split(splitor, 2)[1];
                path = Reverse(path);
            }
            if (deNormal != null)
            {
                mat.SetTexture("_deNormal", deNormal);
                rtSize.x = deNormal.width;
                rtSize.y = deNormal.height;
                path = AssetDatabase.GetAssetPath(deNormal);
                path = Reverse(path);
                path = path.Split(splitor, 2)[1];
                path = Reverse(path);
            }
            if (deSmoothness != null)
            {
                mat.SetTexture("_deSmoothness", deSmoothness);
                rtSize.x = deSmoothness.width;
                rtSize.y = deSmoothness.height;
                path = AssetDatabase.GetAssetPath(deSmoothness);
                path = Reverse(path);
                path = path.Split(splitor, 2)[1];
                path = Reverse(path);
            }
        }
        else
        {
            if (metallic != null)
            {
                mat.SetTexture("_Metallic", metallic);
                rtSize.x = metallic.width;
                rtSize.y = metallic.height;
                path = AssetDatabase.GetAssetPath(metallic);
                path = Reverse(path);
                path = path.Split(splitor, 2)[1];
                path = Reverse(path);
            }
            if (occlusion != null)
            {
                mat.SetTexture("_Occlusion", occlusion);
                rtSize.x = occlusion.width;
                rtSize.y = occlusion.height;
                path = AssetDatabase.GetAssetPath(occlusion);
                path = Reverse(path);
                path = path.Split(splitor, 2)[1];
                path = Reverse(path);
            }
            if (detailmask != null)
            {
                mat.SetTexture("_DetailMask", detailmask);
                rtSize.x = detailmask.width;
                rtSize.y = detailmask.height;
                path = AssetDatabase.GetAssetPath(detailmask);
                path = Reverse(path);
                path = path.Split(splitor, 2)[1];
                path = Reverse(path);
            }
            if (smoothness != null)
            {
                mat.SetTexture("_Smoothness", smoothness);
                rtSize.x = smoothness.width;
                rtSize.y = smoothness.height;
                path = AssetDatabase.GetAssetPath(smoothness);
                path = Reverse(path);
                path = path.Split(splitor, 2)[1];
                path = Reverse(path);
            }
        }
        
        //创建RT作为Blit()的渲染目标target
        RenderTexture tempRT = new RenderTexture((int)rtSize.x, (int)rtSize.y, 16, RenderTextureFormat.ARGB32);
        tempRT.Create();
        //创建texture作为Blit()的源材质source
        Texture2D temp2 = new Texture2D(tempRT.width, tempRT.height, TextureFormat.ARGB32, false);
        //计算贴图
        Graphics.Blit(temp2,tempRT,mat);
        
        //暂存当前激活的RT
        RenderTexture preview = RenderTexture.active;
        //激活渲染结果RT并从中读取数据
        RenderTexture.active = tempRT;
        Texture2D output = new Texture2D(tempRT.width, tempRT.height, TextureFormat.ARGB32, false);
        output.ReadPixels(new Rect(0,0,tempRT.width,tempRT.height),0,0);
        output.Apply();
        //还原激活的RT
        RenderTexture.active = preview;

        return output;
    }
    public string Reverse(string text)
    {
        char[] cArray = text.ToCharArray();
        string reverse = String.Empty;
        for (int i = cArray.Length - 1; i > -1; i--)
        {
            reverse += cArray[i];
        }
        return reverse;
    }
}

//by Erin.Z erinz.xyz
//published on 26/4/2022
