﻿using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using System.Collections.Generic;
using System.Linq;
using System;
using System.Reflection;

public class MUSEditor : ShaderGUI {

    public enum BlendingMode {FADE, TRANSPARENT}

    static bool showBase = true;
    static bool showShading = false;
    static bool showEmiss = false;
    static bool showRim = false;
    static bool showExtras = false;

    static bool showReflections = false;
    static bool showSpecular = false;
    static bool showSSS = false;
    static bool showFresnel = false;
    static bool showShadows = false;
    static bool showMirrorManip = false;
    static bool showVertRounding = false;
    static bool showEmissFX = false;
    static bool showFilters = false;
    static bool showOutline = false;
    
    static string header = "Header_Pro";
    static string baseFoldout = "BaseFoldout_Pro";
    static string shadingFoldout = "ShadingFoldout_Pro";
    static string emissFoldout = "EmissFoldout_Pro";
    static string rimFoldout = "RimLightingFoldout_Pro";
    static string discordPic = "Discord_Pro";
    static string discordIconPic = "Discord_Icon_Pro";
    static string versionPic = "Version_Pro";
    static string extrasFoldout = "ExtrasFoldout_Pro";
    
    private const float foldoutHeightL = 28.0f;
    private const float foldoutHeightS = 22.0f;
    private const int indent = 2;
    
    private const float kMaxfp16 = 65536f;
    ColorPickerHDRConfig HDRField = new ColorPickerHDRConfig(0f, kMaxfp16, 1 / kMaxfp16, 3f);

    static GUIContent MainTexLabel = new GUIContent("Main Texture", "");
    static GUIContent AlbedoLabel = new GUIContent("Albedo", "");
    static GUIContent EmissTexLabel = new GUIContent("Emission Map", "");
    static GUIContent EmissMaskLabel = new GUIContent("Mask", "");
    static GUIContent NormalTexLabel = new GUIContent("Normal", "");
    static GUIContent MetallicTexLabel = new GUIContent("Metallic", "");
    static GUIContent RoughnessTexLabel = new GUIContent("Roughness", "");
    static GUIContent OcclusionMapLabel = new GUIContent("Occlusion", "");
    static GUIContent HeightTexLabel = new GUIContent("Height", "");
    static GUIContent ReflCubeLabel = new GUIContent("Reflection Cubemap", "");
    static GUIContent TranslucencyLabel = new GUIContent("Translucency", "");
    static GUIContent ShadowRampLabel = new GUIContent("Shadow Ramp", "");
    static GUIContent SpecularTexLabel = new GUIContent("Specular Map", "");
    static GUIContent DetailMaskLabel = new GUIContent("Detail Mask", "");
    static GUIContent ReflectionMaskLabel = new GUIContent("Reflection Mask", "");
    static GUIContent SpecularMaskLabel = new GUIContent("Specular Mask", "");
    static GUIContent ShadowMaskLabel = new GUIContent("Shadow Mask", "");
    static GUIContent PrimaryMapsLabel = new GUIContent("Primary Maps (UV0)", "");
    static GUIContent DetailMapsLabel = new GUIContent("Detail Maps (UV1)", "");
    static GUIContent FilterMaskLabel = new GUIContent("Mask", "");
    static GUIContent SpecIntMaskLabel = new GUIContent("Interpolation Mask", "");

    //----------------------------
    // Global
    //----------------------------
    // Render Settings
    static MaterialProperty _RenderMode = null; 
    static MaterialProperty _CullingMode = null; 
    static MaterialProperty _BlendMode = null;
    static MaterialProperty _ZWrite = null; 
    static MaterialProperty _Cutoff = null; 
    static MaterialProperty _ATM = null;
    static MaterialProperty _PBRWorkflow = null;
    static MaterialProperty _SourceAlpha = null;
    static MaterialProperty _StaticLightDirToggle = null;
    static MaterialProperty _StaticLightDir = null;

    // Outlines
    static MaterialProperty _UnlitOutline = null;
    static MaterialProperty _Outline = null; 
    static MaterialProperty _OutlineThicc = null; 
    static MaterialProperty _OutlineCol = null;

    // Filters
    static MaterialProperty _FilterMask = null;
    static MaterialProperty _FilterMaskStr = null;
    static MaterialProperty _SaturationRGB = null; 
    static MaterialProperty _Contrast = null; 
    static MaterialProperty _RAmt = null;
    static MaterialProperty _GAmt = null;
    static MaterialProperty _BAmt = null;
    static MaterialProperty _Hue = null;
    static MaterialProperty _SaturationHSL = null;
    static MaterialProperty _Luminance = null;
    static MaterialProperty _HSLMin = null;
    static MaterialProperty _HSLMax = null;
    static MaterialProperty _FilterModel = null;
    static MaterialProperty _AutoShift = null;
    static MaterialProperty _AutoShiftSpeed = null;
    static MaterialProperty _Brightness = null;
    static MaterialProperty _HDR = null;
    static MaterialProperty _Noise = null;

    //----------------------------
    // General Texture Maps
    //----------------------------
    static MaterialProperty _Color = null; 
    static MaterialProperty _PreserveCol = null; 
    static MaterialProperty _MainTex = null; 
    static MaterialProperty _BumpScale = null; 
    static MaterialProperty _BumpMap = null; 
    static MaterialProperty _Metallic = null; 
    static MaterialProperty _MetallicGlossMap = null;
    static MaterialProperty _Glossiness = null; 
    static MaterialProperty _GlossMapScale = null;
    static MaterialProperty _InvertRough = null;
    static MaterialProperty _PBRSpecCol = null;
    static MaterialProperty _SpecGlossMap = null;
    static MaterialProperty _OcclusionStrength = null; 
    static MaterialProperty _OcclusionMap = null;
    static MaterialProperty _Parallax = null;
    static MaterialProperty _ParallaxMap = null; 
    static MaterialProperty _March = null; 
    static MaterialProperty _HeightContrast = null;
    static MaterialProperty _UseReflCube = null; 
    static MaterialProperty _ReflCube = null;
    static MaterialProperty _ReflCubeFallback = null;
    static MaterialProperty _DetailMask = null;
    static MaterialProperty _DetailMaskStr = null;

    static MaterialProperty _DetailAlbedoMap = null;
    static MaterialProperty _DetailNormalMapScale = null;
    static MaterialProperty _DetailNormalMap = null;

    //----------------------------
    // Toon
    //----------------------------
    // Reflections
    static MaterialProperty _Reflections = null;
    static MaterialProperty _ReflectionMaskStr = null;
    static MaterialProperty _ReflectionMask = null;

    // Specular
    static MaterialProperty _ToonSpec = null; 
    static MaterialProperty _ToonSpecMode = null;
    static MaterialProperty _SpecularMask = null;
    static MaterialProperty _SpecularMaskStr = null;
    static MaterialProperty _SpecularIntMask = null;
    static MaterialProperty _SpecularIntMaskStr = null;
    static MaterialProperty _SpecStr = null; 
    static MaterialProperty _SpecSmooth = null; 
    static MaterialProperty _SpecCol = null; 
    static MaterialProperty _SpecBias = null;
    static MaterialProperty _AnisoSpecStr = null;
    static MaterialProperty _AnisoSpecSmooth = null;
    static MaterialProperty _AnisoSpecBias = null;

    // Subsurface Scattering
    static MaterialProperty _Subsurface = null;
    static MaterialProperty _TranslucencyMap = null; 
    static MaterialProperty _SColor = null;
    static MaterialProperty _SStrength = null;
    static MaterialProperty _SSharp = null;
    static MaterialProperty _SPen = null;

    // Fresnel
    static MaterialProperty _IOR = null;
    static MaterialProperty _FresnelStr = null;
    static MaterialProperty _FresnelFade = null;
    static MaterialProperty _FresnelSmooth = null;
    static MaterialProperty _FresnelMetallic = null;

    // Shadows
    static MaterialProperty _EnableShadowRamp = null;
    static MaterialProperty _ShadowRamp = null;
    static MaterialProperty _RampWidth = null;
    static MaterialProperty _ShadowMask = null;
    static MaterialProperty _ShadowMaskStr = null;
    static MaterialProperty _ShadowStr = null; 

    //----------------------------
    // Other Tabs
    //----------------------------
    // Emission
    static MaterialProperty _EmissionColor = null; 
    static MaterialProperty _EmissionMap = null; 
    static MaterialProperty _EmissMask = null; 
    static MaterialProperty _UsingMask = null; 
    static MaterialProperty _PulseSpeed = null;
    static MaterialProperty _PulseStr = null;
    static MaterialProperty _XScroll = null; 
    static MaterialProperty _YScroll = null; 
    static MaterialProperty _Crossfade = null; 
    static MaterialProperty _ReactToggle = null; 
    static MaterialProperty _CrossMode = null; 
    static MaterialProperty _ReactThresh = null;
    
    // Rim Lighting
    static MaterialProperty _UnlitRim = null;
    static MaterialProperty _RimBlending = null;
    static MaterialProperty _RimMask = null;
    static MaterialProperty _RimMaskStr = null;
    static MaterialProperty _RimCol = null; 
    static MaterialProperty _RimTex = null;
    static MaterialProperty _RimStrength = null; 
    static MaterialProperty _RimWidth = null; 
    static MaterialProperty _RimEdge = null;
    static MaterialProperty _RimNoise = null;

    // Extras
    static MaterialProperty _MirrorManipulation = null;
    static MaterialProperty _ShowInMirror = null;
    static MaterialProperty _ShowBase = null;
    static MaterialProperty _VertexRounding = null;
    static MaterialProperty _LocalRounding = null;
    static MaterialProperty _VertexRoundingStr = null;
    static MaterialProperty _VertexPrecision = null;

    BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;

    MaterialEditor m_me;
    public override void OnGUI(MaterialEditor me, MaterialProperty[] props) {

        Material material = me.target as Material;
        bool isTransparent = material.shader.name.Contains("Transparent");
        bool isCutout = material.shader.name.Contains("Cutout");
        if (!me.isVisible)
            return;
        foreach (var property in GetType().GetFields(bindingFlags)){
            if (property.FieldType == typeof(MaterialProperty)){
                property.SetValue(this, FindProperty(property.Name, props));
            }
        }

        if (!EditorGUIUtility.isProSkin){
            header = "Header";
            baseFoldout = "BaseFoldout";
            shadingFoldout = "ShadingFoldout";
            emissFoldout = "EmissFoldout";
            rimFoldout = "RimLightingFoldout";
            discordPic = "Discord";
            discordIconPic = "Discord_Icon";
            versionPic = "Version";
            extrasFoldout = "ExtrasFoldout";
        }

        Texture2D headerTex = (Texture2D)Resources.Load(header, typeof(Texture2D));
        Texture2D shadingTex = (Texture2D)Resources.Load(shadingFoldout, typeof(Texture2D));
        ShaderGUIHelper.CenteredTexture(headerTex, 0, 0);
        EditorGUI.BeginChangeCheck(); {

            bool isPBR = _RenderMode.floatValue == 2;
            bool isToon = _RenderMode.floatValue == 1;
            bool isBasic = _RenderMode.floatValue == 0;
            bool usingHeight = _ParallaxMap.textureValue;
            bool usingNormal = _BumpMap.textureValue;
            bool usingDetail = _DetailNormalMap.textureValue;
            bool usingMetallic = _MetallicGlossMap.textureValue;
            bool usingRoughness = _SpecGlossMap.textureValue;
            bool usingRamp = _ShadowRamp.textureValue;
            bool usingMask = _EmissMask.textureValue;
            bool usingEmiss = _EmissionMap.textureValue;
            bool usingRefl = _ReflCube.textureValue;

            if (isToon){
                if (usingRamp) _EnableShadowRamp.floatValue = 1;
                else _EnableShadowRamp.floatValue = 0;
            }
            if (isPBR){
                if (usingHeight) material.EnableKeyword("_PARALLAXMAP");
                else material.DisableKeyword("_PARALLAXMAP");
                if (_PBRWorkflow.floatValue == 0){
                    if (!usingRoughness) 
                        _InvertRough.floatValue = 0;
                }
                else {
                    if (usingRoughness) material.EnableKeyword("_SPECGLOSSMAP");
                    else material.DisableKeyword("_SPECGLOSSMAP");
                }
            }
            else {
                material.DisableKeyword("_SPECGLOSSMAP");
                material.DisableKeyword("_PARALLAXMAP");
            }
            if (isToon || isPBR){
                if (usingMetallic) _Metallic.floatValue = 1;
                if (usingRoughness) _Glossiness.floatValue = 1;
                if (usingRefl) _UseReflCube.floatValue = 1;
                else _UseReflCube.floatValue = 0;
                if (usingDetail) material.EnableKeyword("_DETAIL_MULX2");
                else material.DisableKeyword("_DETAIL_MULX2");
            }
            else material.DisableKeyword("_DETAIL_MULX2");

            Texture2D baseTex = (Texture2D)Resources.Load(baseFoldout, typeof(Texture2D));
            showBase = ShaderGUIHelper.Foldout(baseTex, showBase, foldoutHeightL);
            if (showBase){
                GUILayout.Space(8);
                me.ShaderProperty(_RenderMode, "Shading Style");
                me.ShaderProperty(_CullingMode, "Backface Culling");

                // Cutout and Transparent specific properties
                if (!isPBR && isCutout)
                    me.ShaderProperty(_ATM, "Alpha To Mask");

                if (isTransparent){
                    me.ShaderProperty(_ZWrite, _ZWrite.displayName);
                    EditorGUI.showMixedValue = _BlendMode.hasMixedValue;
                    var mode = (BlendingMode)_BlendMode.floatValue;
                    EditorGUI.BeginChangeCheck();
                    mode = (BlendingMode)EditorGUILayout.Popup("Blending Mode", (int)mode, Enum.GetNames(typeof(BlendingMode)));
                    if (EditorGUI.EndChangeCheck()) {
                        me.RegisterPropertyChangeUndo("Blending Mode");
                        _BlendMode.floatValue = (float)mode;
                        foreach (var obj in _BlendMode.targets){
                            SetBlendMode((Material)obj, (BlendingMode)mode);
                        }
                        EditorGUI.showMixedValue = false;
                    }
                }

                // Outline
                if (!isTransparent){
                    if (_Outline.floatValue != 0){
                        showOutline = ShaderGUIHelper.SimpleFoldout("Outline", showOutline);
                        me.ShaderProperty(_Outline, " ");
                    }
                    else me.ShaderProperty(_Outline, "Outline");
                    if (_Outline.floatValue >= 1 && showOutline){
                        ShaderGUIHelper.ContentBox(64.0f);
                        me.ShaderProperty(_UnlitOutline, "Unlit");
                        me.ShaderProperty(_OutlineCol, "Color");
                        me.ShaderProperty(_OutlineThicc, "Thickness");
                        GUILayout.Space(16);
                    }
                }
                
                // Filters
                if (_FilterModel.floatValue > 0){
                    showFilters = ShaderGUIHelper.SimpleFoldout("Filters", showFilters);
                    me.ShaderProperty(_FilterModel, " ");
                }
                else me.ShaderProperty(_FilterModel, "Filters");
                if (showFilters){
                    if (_FilterModel.floatValue == 1){
                        ShaderGUIHelper.ContentBox(173.0f);
                        me.TexturePropertySingleLine(FilterMaskLabel, _FilterMask, _FilterMask.textureValue ? _FilterMaskStr : null);
                        me.ShaderProperty(_HDR, "HDR");
                        me.ShaderProperty(_Contrast, "Contrast");
                        me.ShaderProperty(_SaturationRGB, "Saturation");
                        me.ShaderProperty(_Brightness, "Brightness");
                        me.ShaderProperty(_RAmt, "Red");
                        me.ShaderProperty(_GAmt, "Green");
                        me.ShaderProperty(_BAmt, "Blue");
                        me.ShaderProperty(_Noise, "Noise");
                        GUILayout.Space(8);
                    }
                    if (_FilterModel.floatValue == 2){
                        ShaderGUIHelper.ContentBox(190.0f);
                        me.TexturePropertySingleLine(FilterMaskLabel, _FilterMask, _FilterMask.textureValue ? _FilterMaskStr : null);
                        me.ShaderProperty(_AutoShift, "Auto Shift");
                        if (_AutoShift.floatValue == 1)
                            me.ShaderProperty(_AutoShiftSpeed, "Speed");
                        else
                            me.ShaderProperty(_Hue, "Hue");
                        me.ShaderProperty(_SaturationHSL, "Saturation");
                        me.ShaderProperty(_Luminance, "Luminance");
                        me.ShaderProperty(_HSLMin, "Min Threshold");
                        me.ShaderProperty(_HSLMax, "Max Threshold");
                        me.ShaderProperty(_HDR, "HDR");
                        me.ShaderProperty(_Contrast, "Contrast");
                        me.ShaderProperty(_Noise, "Noise");
                        GUILayout.Space(8);
                    }
                }
                
                if (isCutout && _ATM.floatValue == 0){
                    GUILayout.Space(8);
                    me.ShaderProperty(_Cutoff, "Cutout Amount");
                }

                GUILayout.Space(16);
                if (isBasic || isToon){
                    me.TexturePropertySingleLine(MainTexLabel, _MainTex, _Color, _PreserveCol);
                    ShaderGUIHelper.ToggleLabel("Preserve Color", 145);
                }
                else {
                    me.TexturePropertySingleLine(AlbedoLabel, _MainTex, _Color);
                }
                me.TextureScaleOffsetProperty(_MainTex);
                GUILayout.Space(8);
            }

            // Toon Shading
            if (isToon){

                // Lighting
                showShading = ShaderGUIHelper.Foldout(shadingTex, showShading, foldoutHeightL);
                
                if (showShading){
                    GUILayout.Label(PrimaryMapsLabel, EditorStyles.boldLabel);
                    me.TexturePropertySingleLine(NormalTexLabel, _BumpMap, usingNormal ? _BumpScale : null);
                    me.TexturePropertySingleLine(OcclusionMapLabel, _OcclusionMap, _OcclusionMap.textureValue ? _OcclusionStrength : null);
                    me.TexturePropertySingleLine(DetailMaskLabel, _DetailMask, _DetailMask.textureValue ? _DetailMaskStr : null);
                    GUILayout.Label(DetailMapsLabel, EditorStyles.boldLabel);
                    me.TexturePropertySingleLine(AlbedoLabel, _DetailAlbedoMap);
                    me.TexturePropertySingleLine(NormalTexLabel, _DetailNormalMap, usingDetail ? _DetailNormalMapScale : null);
                    if (_DetailAlbedoMap.textureValue || usingDetail)
                        me.TextureScaleOffsetProperty(_DetailAlbedoMap);
                    GUILayout.Label(new GUIContent("Lighting"), EditorStyles.boldLabel);
                    ShaderGUIHelper.ToggleVector3("Static Direction", _StaticLightDirToggle, _StaticLightDir);
                    GUILayout.Space(4);

                    // Shadows
                    showShadows = ShaderGUIHelper.SimpleFoldout("Shadows", showShadows);
                    GUILayout.Space(18);
                    if (showShadows){
                        ShaderGUIHelper.ContentBox(86.0f);
                        me.TexturePropertySingleLine(ShadowMaskLabel, _ShadowMask, _ShadowMask.textureValue ? _ShadowMaskStr : null);
                        me.TexturePropertySingleLine(ShadowRampLabel, _ShadowRamp);
                        me.ShaderProperty(_ShadowStr, "Strength");
                        EditorGUI.BeginDisabledGroup(usingRamp);
                        me.ShaderProperty(_RampWidth, "Smoothness");
                        EditorGUI.EndDisabledGroup();
                        GUILayout.Space(8);
                    }

                    // Reflections
                    showReflections = ShaderGUIHelper.SimpleFoldout("Reflections", showReflections);
                    me.ShaderProperty(_Reflections, " ");
                    if (showReflections){
                        EditorGUI.BeginDisabledGroup(_Reflections.floatValue == 0);
                        ShaderGUIHelper.ContentBox(88f);
                        me.TexturePropertySingleLine(ReflectionMaskLabel, _ReflectionMask, _ReflectionMask.textureValue ? _ReflectionMaskStr : null);
                        me.TexturePropertySingleLine(RoughnessTexLabel, _SpecGlossMap, !usingRoughness ? _Glossiness : null);
                        me.TexturePropertySingleLine(MetallicTexLabel, _MetallicGlossMap, !usingMetallic ? _Metallic : null);
                        me.TexturePropertySingleLine(ReflCubeLabel, _ReflCube, _ReflCubeFallback);
                        ShaderGUIHelper.ToggleLabel("Fallback", 105);
                        EditorGUI.EndDisabledGroup();
                        GUILayout.Space(8);
                    }

                    // Specular
                    showSpecular = ShaderGUIHelper.SimpleFoldout("Specular Highlights", showSpecular);
                    me.ShaderProperty(_ToonSpec, " ");
                    if (showSpecular){
                        float specBoxSize = 0f;
                        switch((int)_ToonSpecMode.floatValue){
                            case 0: specBoxSize = 128f; break;
                            case 1: specBoxSize = 128f; break;
                            case 2: specBoxSize = 210f; break;
                            default: break;
                        }
                        EditorGUI.BeginDisabledGroup(_ToonSpec.floatValue == 0);
                        ShaderGUIHelper.ContentBox(specBoxSize);
                        me.ShaderProperty(_ToonSpecMode, "Specular Model");
                        me.TexturePropertySingleLine(SpecularMaskLabel, _SpecularMask, _SpecularMask.textureValue ? _SpecularMaskStr : null);
                        switch((int)_ToonSpecMode.floatValue){
                            case 0:
                                me.ShaderProperty(_SpecCol, "Specular Color");
                                GUILayout.Space(8);
                                me.ShaderProperty(_SpecStr, "Strength");
                                me.ShaderProperty(_SpecSmooth, "Smoothness");
                                me.ShaderProperty(_SpecBias, "Bias");
                                break;
                            case 1:
                                me.ShaderProperty(_SpecCol, "Specular Color");
                                GUILayout.Space(8);
                                me.ShaderProperty(_AnisoSpecStr, "Strength");
                                me.ShaderProperty(_AnisoSpecSmooth, "Smoothness");
                                me.ShaderProperty(_AnisoSpecBias, "Bias");
                                break;
                            case 2: 
                                me.TexturePropertySingleLine(SpecIntMaskLabel, _SpecularIntMask, _SpecularIntMask.textureValue ? _SpecularIntMaskStr : null);
                                me.ShaderProperty(_SpecCol, "Specular Color");
                                GUILayout.Space(8);
                                me.ShaderProperty(_SpecStr, "Blinn Strength");
                                me.ShaderProperty(_SpecSmooth, "Blinn Smoothness");
                                me.ShaderProperty(_SpecBias, "Blinn Bias");
                                GUILayout.Space(8);
                                me.ShaderProperty(_AnisoSpecStr, "Aniso Strength");
                                me.ShaderProperty(_AnisoSpecSmooth, "Aniso Smoothness");
                                me.ShaderProperty(_AnisoSpecBias, "Aniso Bias");
                                break;
                            default: break;
                        }
                        GUILayout.Space(8);
                        EditorGUI.EndDisabledGroup();
                    }

                    // Subsurface Scattering
                    showSSS = ShaderGUIHelper.SimpleFoldout("Subsurface Scattering", showSSS);
                    me.ShaderProperty(_Subsurface, " ");
                    if (showSSS){
                        EditorGUI.BeginDisabledGroup(_Subsurface.floatValue == 0);
                        ShaderGUIHelper.ContentBox(102.0f);
                        me.TexturePropertySingleLine(TranslucencyLabel, _TranslucencyMap);
                        me.ShaderProperty(_SColor, "Color");
                        me.ShaderProperty(_SStrength, "Strength");
                        me.ShaderProperty(_SPen, "Penetration");
                        me.ShaderProperty(_SSharp, "Sharpness");
                        EditorGUI.EndDisabledGroup();
                        GUILayout.Space(8);
                    }

                    // Fresnel
                    showFresnel = ShaderGUIHelper.SimpleFoldout("Fresnel", showFresnel);
                    bool canFresnel = _Reflections.floatValue == 0 && _ToonSpec.floatValue == 0;
                    GUILayout.Space(20);
                    if (showFresnel){
                        if (canFresnel){
                            GUILayout.Space(-4);
                            ShaderGUIHelper.CenteredText("REQUIRES REFLECTIONS OR BLINN SPECULAR HIGHLIGHTS", 10, 0, 0);
                        }
                        EditorGUI.BeginDisabledGroup(canFresnel);
                        ShaderGUIHelper.ContentBox(101.0f);
                        me.ShaderProperty(_FresnelStr, "Strength");
                        me.ShaderProperty(_IOR, "Radius");
                        me.ShaderProperty(_FresnelFade, "Fade");
                        me.ShaderProperty(_FresnelSmooth, "Smoothness");
                        me.ShaderProperty(_FresnelMetallic, "Metallic");
                        EditorGUI.EndDisabledGroup();
                        GUILayout.Space(12);
                    }
                    GUILayout.Space(8);
                }
            }

            // PBR
            if (isPBR){    
                showShading = ShaderGUIHelper.Foldout(shadingTex, showShading, foldoutHeightL);
                if (showShading){
                    GUILayout.Space(8);
                    me.ShaderProperty(_PBRWorkflow, "Workflow");
                    GUILayout.Label(PrimaryMapsLabel, EditorStyles.boldLabel);
                    if (_PBRWorkflow.floatValue == 0){
                        me.TexturePropertySingleLine(MetallicTexLabel, _MetallicGlossMap, !usingMetallic ? _Metallic : null);
                        me.TexturePropertySingleLine(RoughnessTexLabel, _SpecGlossMap, !usingRoughness ? _Glossiness : null, usingRoughness ? _InvertRough : null);
                        if (usingRoughness)
                            ShaderGUIHelper.ToggleLabel("Read as Smoothness", 180);
                    }
                    else {
                        me.TexturePropertySingleLine(SpecularTexLabel, _SpecGlossMap, !usingRoughness ? _PBRSpecCol : null);
                        if (usingRoughness)
                            me.ShaderProperty(_GlossMapScale, "Smoothness", indent);
                        else {
                            if (_SourceAlpha.floatValue == 1)
                                me.ShaderProperty(_GlossMapScale, "Smoothness", indent);
                            else
                                me.ShaderProperty(_Glossiness, "Smoothness", indent);
                        }
                        me.ShaderProperty(_SourceAlpha, "Source Alpha", indent);
                    }
                    me.TexturePropertySingleLine(NormalTexLabel, _BumpMap, usingNormal ? _BumpScale : null);
                    me.TexturePropertySingleLine(OcclusionMapLabel, _OcclusionMap, _OcclusionMap.textureValue != null ? _OcclusionStrength : null);
                    me.TexturePropertySingleLine(HeightTexLabel, _ParallaxMap, usingHeight ? _Parallax : null);
                    if (usingHeight){
                        me.ShaderProperty(_HeightContrast, "Height Contrast", indent);
                        me.ShaderProperty(_March, "High Quality", indent);
                    }
                    me.TexturePropertySingleLine(DetailMaskLabel, _DetailMask, _DetailMask.textureValue ? _DetailMaskStr : null);
                    me.TexturePropertySingleLine(ReflCubeLabel, _ReflCube, _ReflCubeFallback);
                    ShaderGUIHelper.ToggleLabel("Fallback", 105);
                    ShaderGUIHelper.ToggleVector3("Static Direction", _StaticLightDirToggle, _StaticLightDir);
                    GUILayout.Label(DetailMapsLabel, EditorStyles.boldLabel);
                    me.TexturePropertySingleLine(AlbedoLabel, _DetailAlbedoMap);
                    me.TexturePropertySingleLine(NormalTexLabel, _DetailNormalMap, usingDetail ? _DetailNormalMapScale : null);
                    if (_DetailAlbedoMap.textureValue || usingDetail)
                        me.TextureScaleOffsetProperty(_DetailAlbedoMap);
                    GUILayout.Space(8);
                }
            }

            // Emission
            if (usingMask)
                _UsingMask.floatValue = 1;
            Texture2D emissTex = (Texture2D)Resources.Load(emissFoldout, typeof(Texture2D));
            showEmiss = ShaderGUIHelper.Foldout(emissTex, showEmiss, foldoutHeightL);
            if (showEmiss){
                GUILayout.Space(8);
                me.TexturePropertyWithHDRColor(EmissTexLabel, _EmissionMap, _EmissionColor, HDRField, false);
                ShaderGUIHelper.ToggleLabel("Brightness", 120);
                if (usingEmiss){
                    GUILayout.Space(2);
                    me.TextureScaleOffsetProperty(_EmissionMap);
                    GUILayout.Space(8);
                }
                me.TexturePropertySingleLine(EmissMaskLabel, _EmissMask);
                if (usingMask){
                    me.TextureScaleOffsetProperty(_EmissMask);
                }
                GUILayout.Space(4);
                showEmissFX = ShaderGUIHelper.SimpleFoldout("Emission FX", showEmissFX);
                if (showEmissFX){
                    GUILayout.Space(16);
                    ShaderGUIHelper.ContentBox(169.0f);
                    me.ShaderProperty(_PulseStr, "Pulse Strength");
                    me.ShaderProperty(_PulseSpeed, "Pulse Speed");
                    GUILayout.Space(8);
                    me.ShaderProperty(_XScroll, "X Scrolling");
                    me.ShaderProperty(_YScroll, "Y Scrolling");
                    GUILayout.Space(8);
                    me.ShaderProperty(_ReactToggle, "Light Reactivity");
                    EditorGUI.BeginDisabledGroup(_ReactToggle.floatValue == 0);
                    me.ShaderProperty(_CrossMode, "Crossfade Mode");
                    EditorGUI.BeginDisabledGroup(_CrossMode.floatValue == 0);
                        me.ShaderProperty(_ReactThresh, "Threshold");
                        me.ShaderProperty(_Crossfade, "Strength");
                    EditorGUI.EndDisabledGroup();
                    EditorGUI.EndDisabledGroup();
                    GUILayout.Space(-8);
                }
                GUILayout.Space(22);
            }

            // Rim Lighting
            if (!isBasic){
                Texture2D rimTex = (Texture2D)Resources.Load(rimFoldout, typeof(Texture2D));
                showRim = ShaderGUIHelper.Foldout(rimTex, showRim, foldoutHeightL);
                if (showRim){
                    GUILayout.Space(8);
                    me.ShaderProperty(_RimBlending, "Blending");
                    GUILayout.Space(8);
                    me.TexturePropertySingleLine(new GUIContent("Color"), _RimTex, _RimCol, _UnlitRim);
                    ShaderGUIHelper.ToggleLabel("Unlit", 87);
                    if (_RimTex.textureValue != null){
                        me.TextureScaleOffsetProperty(_RimTex);
                        GUILayout.Space(10);
                    }
                    me.TexturePropertySingleLine(new GUIContent("Mask"), _RimMask, _RimMask.textureValue != null ? _RimMaskStr : null);
                    if (_RimMask.textureValue != null){
                        me.TextureScaleOffsetProperty(_RimMask);
                        GUILayout.Space(10);
                    }
                    me.ShaderProperty(_RimStrength, "Strength");
                    me.ShaderProperty(_RimWidth, "Width");
                    me.ShaderProperty(_RimEdge, "Sharpness");
                    me.ShaderProperty(_RimNoise, "Noise");
                    GUILayout.Space(8);
                }
            }

            // Extras
            Texture2D extrasTex = (Texture2D)Resources.Load(extrasFoldout, typeof(Texture2D));
            showExtras = ShaderGUIHelper.Foldout(extrasTex, showExtras, foldoutHeightL);
            if (showExtras){
                GUILayout.Space(8);

                // Mirror manipulation
                showMirrorManip = ShaderGUIHelper.SimpleFoldout("Mirror Manipulation", showMirrorManip);
                me.ShaderProperty(_MirrorManipulation, " ");
                if (showMirrorManip){
                    EditorGUI.BeginDisabledGroup(_MirrorManipulation.floatValue == 0);
                    ShaderGUIHelper.ContentBox(45.0f);
                    me.ShaderProperty(_ShowBase, "Show Original");
                    me.ShaderProperty(_ShowInMirror, "Show Reflection");
                    EditorGUI.EndDisabledGroup();
                    GUILayout.Space(8);
                }

                // Vertex Rounding
                showVertRounding = ShaderGUIHelper.SimpleFoldout("Vertex Rounding", showVertRounding);
                me.ShaderProperty(_VertexRounding, " ");
                if (showVertRounding){
                    EditorGUI.BeginDisabledGroup(_VertexRounding.floatValue == 0);
                    ShaderGUIHelper.ContentBox(64.0f);
                    me.ShaderProperty(_LocalRounding, "Local");
                    me.ShaderProperty(_VertexRoundingStr, "Strength");
                    me.ShaderProperty(_VertexPrecision, "Precision");
                    EditorGUI.EndDisabledGroup();
                }
                GUILayout.Space(15);
            }
            
            Texture2D discord = (Texture2D)Resources.Load(discordPic, typeof(Texture2D));
            Texture2D discordIcon = (Texture2D)Resources.Load(discordIconPic, typeof(Texture2D));
            Texture2D version = (Texture2D)Resources.Load(versionPic, typeof(Texture2D));
            ShaderGUIHelper.CenteredTexture(discordIcon, discord, -20, 0, 0);
            ShaderGUIHelper.CenteredTexture(version, -10, 0);
        }
    }

    public static void SetBlendMode(Material material, BlendingMode mode) {
        EditorGUI.BeginChangeCheck();
        switch (mode) {
             case BlendingMode.FADE:
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
                break;   
            case BlendingMode.TRANSPARENT:
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                break;
            default: break;
        }
    } 
}
