using UnityEditor;
using UnityEngine;
using System.Reflection;
using System.Collections.Generic;

namespace Mochie {
    
    public class StandardEditor : ShaderGUI, IPostMaterialUpgradeCallback {

        public static Dictionary<Material, Toggles> foldouts = new Dictionary<Material, Toggles>();
        Toggles toggles = new Toggles(new string[] {
            "Shader Variant",
            "Primary Textures",
            "Detail Textures",
            "Specularity",
            "Vertex Manipulation",
            "Subsurface Scattering",
            "Rain",
            "Puddles",
            "Filtering",
            "Extra UVs",
            "AreaLit",
            "LTCGI",
            "Lightmap Settings",
            "Render Settings",
            "Debug"
        }, 3);

        string versionLabel = "v2.5";

        // Variant Settings
        MaterialProperty _BlendMode = null;
        MaterialProperty _SmoothnessToggle = null;
        MaterialProperty _TriplanarCoordSpace = null;
        MaterialProperty _Cutoff = null;
        MaterialProperty _AlphaSource = null;
        MaterialProperty _MipMapRescaling = null;
        MaterialProperty _MipMapScale = null;

        // Primary Textures
        MaterialProperty _PrimaryWorkflow = null;
        MaterialProperty _PrimarySampleMode = null;
        MaterialProperty _PackedHeight = null;
        MaterialProperty _MainTex = null;
        MaterialProperty _Color = null;
        MaterialProperty _NormalMap = null;
        MaterialProperty _NormalStrength = null;
        MaterialProperty _PackedMap = null;
        MaterialProperty _MetallicMap = null;
        MaterialProperty _MetallicStrength = null;
        MaterialProperty _PackedMetallicStrength = null;
        MaterialProperty _MetallicChannel = null;
        MaterialProperty _RoughnessMap = null;
        MaterialProperty _RoughnessStrength = null;
        MaterialProperty _PackedRoughnessStrength = null;
        MaterialProperty _RoughnessChannel = null;
        MaterialProperty _OcclusionMap = null;
        MaterialProperty _OcclusionStrength = null;
        MaterialProperty _PackedOcclusionStrength = null;
        MaterialProperty _OcclusionChannel = null;
        MaterialProperty _HeightMap = null;
        MaterialProperty _HeightStrength = null;
        MaterialProperty _HeightOffset = null;
        MaterialProperty _HeightSteps = null;
        // MaterialProperty _MaxHeightSteps = null;
        // MaterialProperty _MinHeightSteps = null;
        MaterialProperty _HeightChannel = null;
        MaterialProperty _UVMainSet = null;
        MaterialProperty _UVMainSwizzle = null;
        MaterialProperty _UVMainScroll = null;
        MaterialProperty _UVMainRotation = null;

        // Emission/Audiolink
        MaterialProperty _EmissionMap = null;
        MaterialProperty _EmissionStrength = null;
        MaterialProperty _EmissionColor = null;
        MaterialProperty _EmissionPulseWave = null;
        MaterialProperty _EmissionPulseSpeed = null;
        MaterialProperty _EmissionPulseStrength = null;
        MaterialProperty _AudioLinkEmission = null;
        MaterialProperty _AudioLinkEmissionStrength = null;
        MaterialProperty _AudioLinkEmissionMeta = null;
        MaterialProperty _AudioLinkMin = null;
        MaterialProperty _AudioLinkMax = null;

        // Detail Textures
        MaterialProperty _DetailWorkflow = null;
        MaterialProperty _DetailSampleMode = null;
        MaterialProperty _DetailMaskMode = null;
        MaterialProperty _DetailMainTex = null;
        MaterialProperty _DetailMainTexStrength = null;
        MaterialProperty _DetailColor = null;
        MaterialProperty _DetailMainTexBlend = null;
        MaterialProperty _DetailNormalMap = null;
        MaterialProperty _DetailNormalStrength = null;
        MaterialProperty _DetailPackedMap = null;
        MaterialProperty _DetailMetallicMap = null;
        MaterialProperty _DetailMetallicStrength = null;
        MaterialProperty _DetailMetallicBlend = null;
        MaterialProperty _DetailMetallicMultiplier = null;
        MaterialProperty _DetailMetallicChannel = null;
        MaterialProperty _DetailRoughnessMap = null;
        MaterialProperty _DetailRoughnessStrength = null;
        MaterialProperty _DetailRoughnessBlend = null;
        MaterialProperty _DetailRoughnessMultiplier = null;
        MaterialProperty _DetailRoughnessChannel = null;
        MaterialProperty _DetailOcclusionMap = null;
        MaterialProperty _DetailOcclusionStrength = null;
        MaterialProperty _DetailOcclusionBlend = null;
        MaterialProperty _DetailOcclusionMultiplier = null;
        MaterialProperty _DetailOcclusionChannel = null;
        MaterialProperty _UVDetailSet = null;
        MaterialProperty _UVDetailSwizzle = null;
        MaterialProperty _UVDetailScroll = null;
        MaterialProperty _UVDetailRotation = null;

        // Independant Textures
        MaterialProperty _DetailMask = null;
        MaterialProperty _DetailMaskChannel = null;
        MaterialProperty _UVDetailMaskSet = null;
        MaterialProperty _UVDetailMaskSwizzle = null;
        MaterialProperty _UVDetailMaskScroll = null;
        MaterialProperty _UVDetailMaskRotation = null;

        MaterialProperty _HeightMask = null;
        MaterialProperty _HeightMaskChannel = null;
        MaterialProperty _UVHeightMaskSet = null;
        MaterialProperty _UVHeightMaskSwizzle = null;
        MaterialProperty _UVHeightMaskScroll = null;
        MaterialProperty _UVHeightMaskRotation = null;

        MaterialProperty _RainMask = null;
        MaterialProperty _RainMaskChannel = null;
        MaterialProperty _UVRainMaskSet = null;
        MaterialProperty _UVRainMaskSwizzle = null;
        MaterialProperty _UVRainMaskScroll = null;
        MaterialProperty _UVRainMaskRotation = null;

        MaterialProperty _EmissionMask = null;
        MaterialProperty _EmissionMaskChannel = null;
        MaterialProperty _UVEmissionMaskSet = null;
        MaterialProperty _UVEmissionMaskSwizzle = null;
        MaterialProperty _UVEmissionMaskScroll = null;
        MaterialProperty _UVEmissionMaskRotation = null;

        MaterialProperty _AlphaMask = null;
        MaterialProperty _AlphaMaskChannel = null;
        MaterialProperty _UVAlphaMaskSet = null;
        MaterialProperty _UVAlphaMaskSwizzle = null;
        MaterialProperty _UVAlphaMaskScroll = null;
        MaterialProperty _UVAlphaMaskRotation = null;

        MaterialProperty _VertexMask = null;
        MaterialProperty _VertexMaskChannel = null;
        MaterialProperty _UVVertexMaskSet = null;
        MaterialProperty _UVVertexMaskSwizzle = null;
        MaterialProperty _UVVertexMaskScroll = null;
        MaterialProperty _UVVertexMaskRotation = null;

        // Specularity
        MaterialProperty _ShadingModel = null;
        MaterialProperty _ReflectionsToggle = null;
        MaterialProperty _SpecularHighlightsToggle = null;
        MaterialProperty _SpecularOcclusionToggle = null;
        MaterialProperty _SpecularOcclusionStrength = null;
        MaterialProperty _SpecularOcclusionContrast = null;
        MaterialProperty _SpecularOcclusionBrightness = null;
        MaterialProperty _SpecularOcclusionTint = null;
        MaterialProperty _SpecularOcclusionHDR = null;
        MaterialProperty _SpecularHighlightStrength = null;
        MaterialProperty _ReflectionStrength = null;
        MaterialProperty _FresnelToggle = null;
        MaterialProperty _FresnelStrength = null;
        MaterialProperty _SSRToggle = null;
        MaterialProperty _VRSSR = null;
        MaterialProperty _SSRStrength = null;
        MaterialProperty _SSREdgeFade = null;
        MaterialProperty _SSRHeight = null;
        MaterialProperty _ContactHardening = null;
        MaterialProperty _GSAAToggle = null;
        MaterialProperty _GSAAStrength = null;
        MaterialProperty _IndirectSpecularOcclusionStrength = null;
        MaterialProperty _RealtimeSpecularOcclusionStrength = null;
        MaterialProperty _LightVolumeSpecularity = null;
        MaterialProperty _LightVolumeSpecularityStrength = null;

        // Vertex Manipulation
        MaterialProperty _VertexManipulationToggle = null;
        MaterialProperty _VertexRotationStatic = null;
        MaterialProperty _VertexRotationAnimated = null;
        MaterialProperty _VertexOffset = null;
        // MaterialProperty _VertexWave = null;

        // Subsurface Scattering
        MaterialProperty _Subsurface = null;
        MaterialProperty _ThicknessMap = null;
        MaterialProperty _ScatterCol = null;
        MaterialProperty _ThicknessMapPower = null;
        MaterialProperty _ScatterAmbient = null;
        MaterialProperty _ScatterIntensity = null;
        MaterialProperty _ScatterPow = null;
        MaterialProperty _ScatterDist = null; 
        MaterialProperty _WrappingFactor = null;
        MaterialProperty _ScatterBaseColorTint = null;

        // Filtering
        MaterialProperty _Filtering = null;
        MaterialProperty _HueMode = null;
        MaterialProperty _MonoTint = null;
        MaterialProperty _HuePost = null;
        MaterialProperty _SaturationPost = null;
        MaterialProperty _BrightnessPost = null;
        MaterialProperty _ContrastPost = null;
        MaterialProperty _ACES = null;
        // MaterialProperty _ColorGradingLUT = null;
        // MaterialProperty _ColorGradingLUTStrength = null;
        MaterialProperty _Hue = null;
        MaterialProperty _Saturation = null;
        MaterialProperty _Brightness = null;
        MaterialProperty _Contrast = null;
        MaterialProperty _HueDet = null;
        MaterialProperty _SaturationDet = null;
        MaterialProperty _BrightnessDet = null;
        MaterialProperty _ContrastDet = null;
        MaterialProperty _HueEmiss = null;
        MaterialProperty _SaturationEmiss = null;
        MaterialProperty _BrightnessEmiss = null;
        MaterialProperty _ContrastEmiss = null;
        
        // Rain
        MaterialProperty _RainMode = null;
        MaterialProperty _UVRainSet = null;
        MaterialProperty _UVRainSwizzle = null;
        MaterialProperty _UVRainRotation = null;
        MaterialProperty _UVRippleSet = null;
        MaterialProperty _UVRippleSwizzle = null;
        MaterialProperty _UVRippleRotation = null;
        MaterialProperty _RainSheet = null;
        MaterialProperty _RainRows = null;
        MaterialProperty _RainColumns = null;
        MaterialProperty _RainSpeed = null;
        MaterialProperty _RainScale = null;
        MaterialProperty _RainStrength = null;
        MaterialProperty _DropletMask = null;
        MaterialProperty _DynamicDroplets = null;
        MaterialProperty _RainThreshold = null;
        MaterialProperty _RainThresholdSize = null;
        MaterialProperty _RippleScale = null;
        MaterialProperty _RippleSpeed = null;
        MaterialProperty _RippleStrength = null;
        MaterialProperty _RippleDensity = null;
        MaterialProperty _RippleSize = null;
        MaterialProperty _RippleHorizonAdjustment = null;
        MaterialProperty _RippleHorizonAdjustmentDistance = null;
        MaterialProperty _PuddleRippleStrength;
        MaterialProperty _PuddleRippleSpeed;
        MaterialProperty _PuddleRippleSize;
        MaterialProperty _PuddleRippleDensity;

        // Puddles
        MaterialProperty _PuddleToggle = null;
        MaterialProperty _PuddleUseHeightMap = null;
        MaterialProperty _PuddleHeightBasedTint = null;
        MaterialProperty _PuddleTexture = null;
        MaterialProperty _UVPuddleScroll = null;
        MaterialProperty _UVPuddleRotation = null;
        MaterialProperty _UVPuddleSet = null;
        MaterialProperty _UVPuddleSwizzle = null;
        MaterialProperty _PuddleStrength = null;
        MaterialProperty _PuddleMetallic = null;
        MaterialProperty _PuddleOcclusionStrength = null;
        MaterialProperty _PuddleTint = null;
        MaterialProperty _PuddleHeightStrength = null;
        MaterialProperty _PuddleThresholdMin = null;
        MaterialProperty _PuddleThresholdMax = null;

        // Lightmapping Settings
        MaterialProperty _BAKERY_LMSPEC = null;
        MaterialProperty _BakeryLMSpecStrength = null;
        MaterialProperty _BAKERY_SHNONLINEAR = null;
        MaterialProperty _BakeryMode = null;
        MaterialProperty _BicubicSampling = null;
        MaterialProperty _IgnoreRealtimeGI = null;
        MaterialProperty _AdditiveLightVolumesToggle = null;
        MaterialProperty _ApplyHeightOffset = null;
        MaterialProperty _LightVolumeBias = null;

        // AreaLit
        MaterialProperty _AreaLitToggle = null;
        MaterialProperty _AreaLitStrength = null;
        MaterialProperty _AreaLitRoughnessMultiplier = null;
        MaterialProperty _AreaLitSpecularOcclusion = null;
        MaterialProperty _LightMesh = null;
        MaterialProperty _LightTex0 = null;
        MaterialProperty _LightTex1 = null;
        MaterialProperty _LightTex2 = null;
        MaterialProperty _LightTex3 = null;
        MaterialProperty _OpaqueLights = null;
        MaterialProperty _AreaLitOcclusion = null;
        MaterialProperty _AreaLitOcclusionUVSet = null;

        // LTCGI
        MaterialProperty _LTCGI = null;
        MaterialProperty _LTCGIStrength = null;
        MaterialProperty _LTCGIRoughness = null;
        MaterialProperty _LTCGISpecularOcclusion = null;
        MaterialProperty _LTCGI_DiffuseColor = null;
        MaterialProperty _LTCGI_SpecularColor = null;

        // Render Settings
        MaterialProperty _Culling = null;
        MaterialProperty _QueueOffset = null;
        MaterialProperty _UnityFogToggle = null;
        MaterialProperty _VertexBaseColor = null;
        MaterialProperty _MaterialDebugMode = null;
        MaterialProperty _FlipBackfaceNormals = null;

        // Debug
        MaterialProperty _DebugEnable = null;
        MaterialProperty _DebugBaseColor = null;
        MaterialProperty _DebugNormals = null;
        MaterialProperty _DebugRoughness = null;
        MaterialProperty _DebugMetallic = null;
        MaterialProperty _DebugHeight = null;
        MaterialProperty _DebugVertexColors = null;
        MaterialProperty _DebugAtten = null;
        MaterialProperty _DebugReflections = null;
        MaterialProperty _DebugSpecular = null;
        MaterialProperty _DebugOcclusion = null;
        MaterialProperty _DebugAlpha = null;
        MaterialProperty _DebugLighting = null;
        MaterialProperty _NoiseTexSSR = null;
        MaterialProperty _DefaultSampler = null;
        MaterialProperty _SrcBlend = null;
        MaterialProperty _DstBlend = null;
        MaterialProperty _ZWrite = null;
        MaterialProperty _ZTest = null;
        MaterialProperty _DFG = null;

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

        bool emissionEnabled = false;
        bool firstTimeApply = true;
        bool isHeightmapped = false;

        #region OnGUI
        public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] props) {
            me = materialEditor;
            
            if (!me.isVisible)
                return;

            foreach (var property in GetType().GetFields(bindingFlags)){
                if (property.FieldType == typeof(MaterialProperty))
                    property.SetValue(this, FindProperty(property.Name, props));
            }
            Material mat = (Material)me.target;

            bool isMobile = MGUI.IsMobileVersion(mat);
            bool isLite = MGUI.IsNewLiteVersion(mat) || isMobile;

            mat.SetShaderPassEnabled("Always", mat.GetInt("_SSRToggle") == 1 && !isLite);

            if (firstTimeApply){
                SetKeywords(mat);
                SetBlendMode(mat);
                firstTimeApply = false;
            }

            if (mat.GetInt("_MaterialResetCheck") == 0){
                mat.SetInt("_MaterialResetCheck", 1);
                SetKeywords(mat);
                SetBlendMode(mat);
            }

            // Add mat to foldout dictionary if it isn't in there yet
            if (!foldouts.ContainsKey(mat))
                foldouts.Add(mat, toggles);

            isHeightmapped = (_PrimaryWorkflow.floatValue == 1 && _PackedHeight.floatValue == 1) || (_PrimaryWorkflow.floatValue == 0 && _HeightMap.textureValue);

            string headerText = "STANDARD";
            if (MGUI.IsNewLiteVersion(mat)) headerText += " LITE";
            if (MGUI.IsMobileVersion(mat)) headerText += " MOBILE";
            MGUI.DoHeader(headerText);

            EditorGUI.BeginChangeCheck(); {
                DoVariant(mat, isLite, isMobile);
                DoPrimaryTextures(mat, isLite, isMobile);
                if (!isLite)
                    DoDetailTextures(mat);
                else
                    DoDetailTexturesLite(mat);
                DoSpecularity(mat, isLite);
                if (!isLite){
                    DoVertexManipulation(mat);
                    DoSubsurface(mat);
                }
                if (!isMobile){
                    DoRain(mat);
                    DoPuddles(mat);
                }
                DoFiltering(mat);
                DoUVs(mat, isMobile, isLite);
                DoAreaLit(mat);
                DoLTCGI(mat);
                DoLightmapSettings(mat);
                DoRenderSettings(mat);
                DoDebug(mat);
            }
            if (EditorGUI.EndChangeCheck()){
                SetKeywords(mat);
                SetBlendMode(mat);
            }

            MGUI.Space10();
            MGUI.DoFooter(versionLabel);
        }
        #endregion

        #region Variant Settings
        void DoVariant(Material mat, bool isLite, bool isMobile){
            bool variantToggle = Foldouts.DoFoldout(foldouts, mat, "Shader Variant", 1, Foldouts.Style.StandardButton);
            if (Foldouts.DoFoldoutButton(MGUI.collapseLabel, 11)) Toggles.CollapseFoldouts(mat, foldouts, 4);
            if (variantToggle) {
                MGUI.PropertyGroupParent(()=>{
                    MGUI.PropertyGroup(()=>{
                        me.ShaderProperty(_BlendMode, Tips.standBlendMode);
                        if (_BlendMode.floatValue > 0 && !isMobile){
                            me.ShaderProperty(_AlphaSource, Tips.useAlphaMaskLabel);
                        }
                        if (isLite){
                            me.ShaderProperty(_PrimaryWorkflow, Tips.workflowText);
                            if (!isMobile){
                                me.ShaderProperty(_PrimarySampleMode, Tips.samplingMode);
                                if (_PrimaryWorkflow.floatValue == 1){
                                    me.ShaderProperty(_PackedHeight, Tips.packedHeightText);
                                }
                            }
                        }
                        me.ShaderProperty(_SmoothnessToggle, Tips.smoothnessModeText);
                        if (_PrimarySampleMode.floatValue == 3 || (_DetailSampleMode.floatValue == 3 && !isLite))
                            me.ShaderProperty(_TriplanarCoordSpace, "Triplanar Coordinates");
                    });
                    if (_BlendMode.floatValue == 1){
                        MGUI.PropertyGroup(()=>{
                            me.ShaderProperty(_MipMapRescaling, Tips.mipRescalingText);
                            if (_MipMapRescaling.floatValue == 1){
                                me.ShaderProperty(_MipMapScale, "Mip Map Scale");
                            }
                            me.ShaderProperty(_Cutoff, Tips.alphaCutoffText);
                        });
                    }
                    if (_BlendMode.floatValue == 1 && isMobile){
                        MGUI.DisplayWarning("Please note that cutout can be EXTREMELY expensive on mobile platforms, and it is HIGHLY recommended to avoid using it there.");
                        MGUI.Space2();
                    }
                });
            }
        }
        #endregion

        #region Primary Tex
        void DoPrimaryTextures(Material mat, bool isLite, bool isMobile){
            if (Foldouts.DoFoldout(foldouts, mat, "Primary Textures", Foldouts.Style.Standard)) {
                MGUI.PropertyGroupParent(()=>{
                    if (!isLite){
                        MGUI.PropertyGroup(()=>{
                            me.ShaderProperty(_PrimaryWorkflow, Tips.workflowText);
                            me.ShaderProperty(_PrimarySampleMode, Tips.samplingMode);
                            if (_PrimaryWorkflow.floatValue == 1){
                                me.ShaderProperty(_PackedHeight, Tips.packedHeightText);
                            }
                        });
                    }
                    MGUI.PropertyGroup(()=>{
                        me.TexturePropertySingleLine(Tips.baseColorText, _MainTex, _Color);
                        if (_BlendMode.floatValue > 0 && _AlphaSource.floatValue == 1 && !isMobile)
                            me.TexturePropertySingleLine(Tips.alphaMaskLabel, _AlphaMask, _AlphaMask.textureValue ? _AlphaMaskChannel : null);
                        me.TexturePropertySingleLine(Tips.normalMapText, _NormalMap, _NormalMap.textureValue ? _NormalStrength : null);
                        MGUI.NormalWarning(_NormalMap);
                        if (_PrimaryWorkflow.floatValue == 0){
                            me.TexturePropertySingleLine(Tips.metallicText, _MetallicMap, _MetallicStrength);
                            MGUI.sRGBWarning(_MetallicMap);
                            me.TexturePropertySingleLine(_SmoothnessToggle.floatValue == 0 ? Tips.roughnessText : Tips.smoothnessText, _RoughnessMap, _RoughnessStrength);
                            MGUI.sRGBWarning(_RoughnessMap);
                            me.TexturePropertySingleLine(Tips.occlusionText, _OcclusionMap, _OcclusionMap.textureValue ? _OcclusionStrength : null);
                            MGUI.sRGBWarning(_OcclusionMap);
                            if (_PrimarySampleMode.floatValue != 3 && !isMobile){
                                me.TexturePropertySingleLine(Tips.heightMapText, _HeightMap, _HeightMap.textureValue ? _HeightStrength : null);
                                MGUI.sRGBWarning(_HeightMap);
                                if (_HeightMap.textureValue){
                                    me.TexturePropertySingleLine(Tips.heightMaskText, _HeightMask, _HeightMask.textureValue ? _HeightMaskChannel : null);
                                    me.ShaderProperty(_HeightSteps, Tips.heightStepsText);
                                    // me.ShaderProperty(_MinHeightSteps, "Min Height Steps");
                                    // me.ShaderProperty(_MaxHeightSteps, "Max Height Steps");
                                    me.ShaderProperty(_HeightOffset, Tips.heightOffsetText);
                                }
                            }
                            // if (MGUI.PropertyButton("Pack Textures")){
                            // 	PackTextures(_MetallicMap, _RoughnessMap, _OcclusionMap, _HeightMap, _PackedMap);
                            // 	_PrimaryWorkflow.floatValue = 1f;
                            // 	mat.SetInt("_PrimaryWorkflow", 1);
                            // 	MGUI.SetKeyword(mat, "_WORKFLOW_PACKED_ON", true);
                            // }
                        }
                        else {
                            me.TexturePropertySingleLine(Tips.packedMapText, _PackedMap);
                            MGUI.sRGBWarning(_PackedMap);
                            if (_PackedHeight.floatValue == 1 && _PrimarySampleMode.floatValue != 3 && !isMobile){
                                me.TexturePropertySingleLine(Tips.heightMaskText, _HeightMask, _HeightMask.textureValue ? _HeightMaskChannel : null);
                            }
                        }
                        DoEmission(isMobile);
                    });
                    if (_PrimaryWorkflow.floatValue == 1){
                        MGUI.PropertyGroup(()=>{
                            me.ShaderProperty(_MetallicChannel, "Metallic Channel");
                            me.ShaderProperty(_RoughnessChannel, _SmoothnessToggle.floatValue == 0 ? "Roughness Channel" : "Smoothness Channel");
                            me.ShaderProperty(_OcclusionChannel, "Occlusion Channel");
                            if (_PackedHeight.floatValue == 1 && _PrimarySampleMode.floatValue != 3 && !isMobile){
                                me.ShaderProperty(_HeightChannel, "Height Channel");
                            }
                        });
                        MGUI.PropertyGroup(()=>{
                            me.ShaderProperty(_PackedMetallicStrength, Tips.metallicPackedText);
                            me.ShaderProperty(_PackedRoughnessStrength, _SmoothnessToggle.floatValue == 0 ? Tips.roughnessPackedText : Tips.smoothnessPackedText);
                            me.ShaderProperty(_PackedOcclusionStrength, Tips.occlusionPackedText);
                            if (_PackedHeight.floatValue == 1 && !isMobile){
                                me.ShaderProperty(_HeightStrength, Tips.heightMapPackedText);
                                me.ShaderProperty(_HeightSteps, Tips.heightStepsText);
                                me.ShaderProperty(_HeightOffset, Tips.heightOffsetText);
                            }
                        });
                    }
                    MGUI.PropertyGroup(()=>{
                        if (_PrimarySampleMode.floatValue != 3){
                            me.ShaderProperty(_UVMainSet, Tips.uvSetLabel);
                            if (_UVMainSet.floatValue >= 5){
                                me.ShaderProperty(_UVMainSwizzle, Tips.swizzleText);
                            }
                            MGUI.TextureSOScroll(me, _MainTex, _UVMainScroll);
                            me.ShaderProperty(_UVMainRotation, "Rotation");
                        }
                        else {
                            MGUI.TextureSO(me, _MainTex);
                        }
                    });
                });
            }
        }
        #endregion

        #region Emission
        void DoEmission(bool isMobile){
            if (me.EmissionEnabledProperty()){
                emissionEnabled = true;
                bool hadEmissionTexture = _EmissionMap.textureValue != null;
                MGUI.ToggleGroup(!emissionEnabled);
                MGUI.PropertyGroup(()=>{
                    me.LightmapEmissionFlagsProperty(0, true);
                    if (!isMobile){
                        me.ShaderProperty(_EmissionPulseWave, Tips.emissPulseWave);
                        if (_EmissionPulseWave.floatValue > 0){
                            me.ShaderProperty(_EmissionPulseStrength, Tips.emissPulseStrength);
                            me.ShaderProperty(_EmissionPulseSpeed, Tips.emissPulseSpeed);
                        }
                    }
                    me.ShaderProperty(_AudioLinkEmission, Tips.audioLinkEmission);
                    if (_AudioLinkEmission.floatValue > 0){
                        me.ShaderProperty(_AudioLinkEmissionStrength, Tips.audioLinkEmissionStrength);
                        MGUI.SliderMinMax(_AudioLinkMin, _AudioLinkMax, 0f, 2f, "Remap", 0);
                        me.ShaderProperty(_AudioLinkEmissionMeta, Tips.audioLinkEmissionMeta);
                    }
                    MGUI.Space4();
                    
                    me.TexturePropertySingleLine(Tips.emissionText, _EmissionMap, _EmissionColor, _EmissionStrength);
                    if (!isMobile)
                        me.TexturePropertySingleLine(Tips.maskText, _EmissionMask, _EmissionMask.textureValue ? _EmissionMaskChannel : null);
                });
                MGUI.ToggleGroupEnd();
                float brightness = _EmissionColor.colorValue.maxColorComponent;
                if (_EmissionMap.textureValue != null && !hadEmissionTexture && brightness <= 0f)
                    _EmissionColor.colorValue = Color.white;
            }
            else {
                emissionEnabled = false;
            }
        }
        #endregion

        #region Detail Tex
        void DoDetailTextures(Material mat){
            if (Foldouts.DoFoldout(foldouts, mat, "Detail Textures", Foldouts.Style.Standard)) {
                MGUI.PropertyGroupParent(()=>{
                    MGUI.PropertyGroup(()=>{
                        me.ShaderProperty(_DetailWorkflow, Tips.workflowText);
                        me.ShaderProperty(_DetailSampleMode, Tips.samplingMode);
                    });
                    MGUI.PropertyGroup(()=>{
                        if (_DetailMainTex.textureValue){
                            me.ShaderProperty(_DetailColor, "Detail Tint");
                            MGUI.Space4();
                        }
                        me.TexturePropertySingleLine(Tips.detailAlbedoText, _DetailMainTex, _DetailMainTex.textureValue ? _DetailMainTexStrength : null, _DetailMainTex.textureValue ? _DetailMainTexBlend : null);
                        me.TexturePropertySingleLine(Tips.detailNormalMapText, _DetailNormalMap, _DetailNormalMap.textureValue ? _DetailNormalStrength : null);
                        MGUI.NormalWarning(_DetailNormalMap);
                        if (_DetailWorkflow.floatValue == 0){
                            me.TexturePropertySingleLine(Tips.detailMetallicMapText, _DetailMetallicMap, _DetailMetallicMap.textureValue ? _DetailMetallicStrength : null, _DetailMetallicMap.textureValue && _DetailMaskMode.floatValue != 1 ? _DetailMetallicBlend : null);
                            MGUI.sRGBWarning(_DetailMetallicMap);
                            me.TexturePropertySingleLine(_SmoothnessToggle.floatValue == 0 ? Tips.detailRoughnessMapText : Tips.detailSmoothnessMapText, _DetailRoughnessMap, _DetailRoughnessMap.textureValue ? _DetailRoughnessStrength : null, _DetailRoughnessMap.textureValue && _DetailMaskMode.floatValue != 1  ? _DetailRoughnessBlend : null);
                            MGUI.sRGBWarning(_DetailRoughnessMap);
                            me.TexturePropertySingleLine(Tips.detailAOMapText, _DetailOcclusionMap, _DetailOcclusionMap.textureValue ? _DetailOcclusionStrength : null, _DetailOcclusionMap.textureValue && _DetailMaskMode.floatValue != 1 ? _DetailOcclusionBlend : null);
                            MGUI.sRGBWarning(_DetailOcclusionMap);
                        }
                        else {
                            me.TexturePropertySingleLine(Tips.packedMapText, _DetailPackedMap);
                            MGUI.sRGBWarning(_DetailPackedMap);
                        }
                        me.TexturePropertySingleLine(Tips.detailMaskText, _DetailMask, _DetailMask.textureValue ? _DetailMaskChannel : null, _DetailMask.textureValue ? _DetailMaskMode : null);
                    });
                    if (_DetailWorkflow.floatValue == 1){
                        MGUI.PropertyGroup(()=>{
                            me.ShaderProperty(_DetailMetallicChannel, "Metallic Channel");
                            me.ShaderProperty(_DetailRoughnessChannel, _SmoothnessToggle.floatValue == 0 ? "Roughness Channel" : "Smoothness Channel");
                            me.ShaderProperty(_DetailOcclusionChannel, "Occlusion Channel");
                        });
                        if (_DetailMaskMode.floatValue == 0){
                            MGUI.PropertyGroup(()=>{
                                me.ShaderProperty(_DetailMetallicBlend, "Metallic Blend");
                                me.ShaderProperty(_DetailRoughnessBlend, "Roughness Blend");
                                me.ShaderProperty(_DetailOcclusionBlend, "Occlusion Blend");
                            });
                        }
                        MGUI.PropertyGroup(()=>{
                            MGUI.ToggleSlider(me, Tips.metallicPackedText, _DetailMetallicMultiplier, _DetailMetallicStrength);
                            MGUI.ToggleSlider(me, _SmoothnessToggle.floatValue == 0 ? Tips.roughnessPackedText : Tips.smoothnessPackedText, _DetailRoughnessMultiplier, _DetailRoughnessStrength);
                            MGUI.ToggleSlider(me, Tips.occlusionPackedText, _DetailOcclusionMultiplier, _DetailOcclusionStrength);
                        });
                    }
                    if (_DetailMainTex.textureValue || _DetailNormalMap.textureValue || (_DetailWorkflow.floatValue == 0 && (_DetailMetallicMap.textureValue || _DetailRoughnessMap.textureValue || _DetailOcclusionMap.textureValue)) || (_DetailWorkflow.floatValue == 1 && _DetailPackedMap.textureValue)){
                        MGUI.PropertyGroup(()=>{
                            if (_DetailSampleMode.floatValue != 3){
                                me.ShaderProperty(_UVDetailSet, Tips.uvSetLabel);
                                if (_UVDetailSet.floatValue >= 5){
                                    me.ShaderProperty(_UVDetailSwizzle, Tips.swizzleText);
                                }
                                MGUI.TextureSOScroll(me, _DetailMainTex, _UVDetailScroll);
                                me.ShaderProperty(_UVDetailRotation, "Rotation");
                            }
                            else {
                                MGUI.TextureSO(me, _DetailMainTex);
                            }
                        });
                    }
                });
            }
        }
        #endregion

        #region Detail Tex Lite
        void DoDetailTexturesLite(Material mat){
            if (Foldouts.DoFoldout(foldouts, mat, "Detail Textures", Foldouts.Style.Standard)) {
                MGUI.PropertyGroupParent(()=>{
                    MGUI.PropertyGroup(()=>{
                        if (_DetailMainTex.textureValue){
                            me.ShaderProperty(_DetailColor, "Detail Tint");
                            MGUI.Space4();
                        }
                        me.TexturePropertySingleLine(Tips.detailAlbedoText, _DetailMainTex, _DetailMainTex.textureValue ? _DetailMainTexStrength : null, _DetailMainTex.textureValue && _DetailMaskMode.floatValue != 1 ? _DetailMainTexBlend : null);
                        me.TexturePropertySingleLine(Tips.detailNormalMapText, _DetailNormalMap, _DetailNormalMap.textureValue ? _DetailNormalStrength : null);
                        me.TexturePropertySingleLine(Tips.detailMaskText, _DetailMask, _DetailMask.textureValue ? _DetailMaskChannel : null, _DetailMask.textureValue ? _DetailMaskMode : null);
                    });
                    if (_DetailMainTex.textureValue || _DetailNormalMap.textureValue){
                        MGUI.PropertyGroup(()=>{
                            me.ShaderProperty(_UVDetailSet, Tips.uvSetLabel);
                            if (_UVDetailSet.floatValue >= 5){
                                me.ShaderProperty(_UVDetailSwizzle, Tips.swizzleText);
                            }
                            MGUI.TextureSOScroll(me, _DetailMainTex, _UVDetailScroll);
                            me.ShaderProperty(_UVDetailRotation, "Rotation");
                        });
                    }
                });
            }
        }
        #endregion

        #region Specularity
        void DoSpecularity(Material mat, bool isLite){
            if (Foldouts.DoFoldout(foldouts, mat, me, _ShadingModel, "Specularity", Foldouts.Style.StandardToggle)) {
                MGUI.PropertyGroupParent(()=>{
                    MGUI.PropertyGroup(()=>{
                        MGUI.ToggleFloat(me, Tips.specularHighlightsText, _SpecularHighlightsToggle, _SpecularHighlightStrength);
                        MGUI.ToggleFloat(me, Tips.cubemapReflectionsText, _ReflectionsToggle, _ReflectionStrength);
                        MGUI.ToggleFloat(me, Tips.lightVolumeSpecText, _LightVolumeSpecularity, _LightVolumeSpecularityStrength);
                        if (!isLite){
                            MGUI.ToggleFloat(me, Tips.ssrText, _SSRToggle, _SSRStrength);
                            if (_SSRToggle.floatValue == 1){
                                MGUI.PropertyGroup(()=>{
                                    me.ShaderProperty(_SSREdgeFade, Tips.ssrEdgeFadeText);
                                    me.ShaderProperty(_SSRHeight, Tips.ssrDepthText);
                                    me.ShaderProperty(_VRSSR, "Enable in VR");
                                });
                            }
                        }
                        if (_ShadingModel.floatValue == 0)
                            MGUI.ToggleFloat(me, Tips.useFresnel, _FresnelToggle, _FresnelStrength);
                        me.ShaderProperty(_ContactHardening, Tips.contactHardeningText);
                    });
                    MGUI.PropertyGroup(()=>{
                        MGUI.ToggleFloat(me, Tips.gsaa, _GSAAToggle, _GSAAStrength);
                        if (_ShadingModel.floatValue == 0){
                            MGUI.ToggleFloat(me, Tips.reflShadows, _SpecularOcclusionToggle, _SpecularOcclusionStrength);
                            if (_SpecularOcclusionToggle.floatValue == 1){
                                MGUI.PropertyGroup(()=>{
                                    me.ShaderProperty(_SpecularOcclusionTint, "Lightmap Tint");
                                    me.ShaderProperty(_SpecularOcclusionBrightness, "Lightmap Brightness");
                                    me.ShaderProperty(_SpecularOcclusionContrast, "Lightmap Contrast");
                                    me.ShaderProperty(_SpecularOcclusionHDR, "Lightmap HDR");
                                });
                            }
                        }
                        else {
                            me.ShaderProperty(_IndirectSpecularOcclusionStrength, Tips.indirectSpecOccText);
                            me.ShaderProperty(_RealtimeSpecularOcclusionStrength, Tips.realtimeSpecOccText);
                        }
                    });
                    if (_SSRToggle.floatValue == 1 && !isLite){
                        MGUI.DisplayInfo("Screenspace reflections in VRChat require the \"Depth Light\" prefab found in: Assets/Mochie/Unity/Prefabs or at least one directional light with shadows enabled in the scene. \n\nThey can also be expensive, please use them sparingly!");
                    }
                });
            }
        }
        #endregion

        #region Vertex Manip
        void DoVertexManipulation(Material mat){
            if (Foldouts.DoFoldout(foldouts, mat, me, _VertexManipulationToggle, "Vertex Manipulation", Foldouts.Style.ThinLongToggle)){
                MGUI.PropertyGroupParent(()=>{
                    MGUI.ToggleGroup(_VertexManipulationToggle.floatValue == 0);
                    MGUI.PropertyGroup(()=>{
                        me.TexturePropertySingleLine(Tips.maskText, _VertexMask, _VertexMask.textureValue ? _VertexMaskChannel : null);
                        MGUI.Vector3Field(_VertexRotationStatic, "Static Rotation", false);
                        MGUI.Vector3Field(_VertexRotationAnimated, "Animated Rotation", false);
                        MGUI.Vector3Field(_VertexOffset, "Offset", false);
                        // me.ShaderProperty(_VertexWave, "Wave");
                    });
                    MGUI.ToggleGroupEnd();
                });
            }
        }
        #endregion
        
        #region Subsurface
        void DoSubsurface(Material mat){
            if (Foldouts.DoFoldout(foldouts, mat, me, _Subsurface, "Subsurface Scattering", Foldouts.Style.ThinLongToggle)){
                MGUI.PropertyGroupParent(()=>{
                    MGUI.ToggleGroup(_Subsurface.floatValue == 0);
                    MGUI.PropertyGroup(() => {
                        me.TexturePropertySingleLine(Tips.thicknessMapText, _ThicknessMap, _ThicknessMapPower);
                        me.ShaderProperty(_ScatterCol, Tips.scatterCol);
                        me.ShaderProperty(_ScatterBaseColorTint, Tips.scatterAlbedoTint);
                    });
                    MGUI.PropertyGroup(()=>{
                        me.ShaderProperty(_ScatterIntensity, Tips.scatterIntensity);
                        me.ShaderProperty(_ScatterAmbient, Tips.scatterAmbient);
                        me.ShaderProperty(_ScatterPow, Tips.scatterPow);
                        me.ShaderProperty(_ScatterDist, Tips.scatterDist);
                        me.ShaderProperty(_WrappingFactor, Tips.wrappingFactor);
                    });
                    MGUI.ToggleGroupEnd();
                });
            }
        }
        #endregion

        #region Rain
        void DoRain(Material mat){
            if (Foldouts.DoFoldout(foldouts, mat, me, _RainMode, "Rain", Foldouts.Style.ThinLongToggle)){
                MGUI.PropertyGroupParent(()=>{
                    if (_RainMode.floatValue == 0 || _RainMode.floatValue == 1){
                        RainDroplets();
                    }
                    else if (_RainMode.floatValue == 2){
                        RainRipples();
                    }
                    else if (_RainMode.floatValue == 3){
                        MGUI.BoldLabel("Droplets");
                        RainDroplets();
                        MGUI.BoldLabel("Ripples");
                        RainRipples();
                        MGUI.BoldLabel("Both");
                        RainBoth();
                    }
                });
            }
        }

        void RainDroplets(){
            MGUI.ToggleGroup(_RainMode.floatValue == 0);
            MGUI.PropertyGroup(()=>{
                if (_RainMode.floatValue != 3){
                    me.TexturePropertySingleLine(Tips.maskText, _RainMask, _RainMask.textureValue ? _RainMaskChannel : null);
                }
                me.ShaderProperty(_RainStrength, "Strength");
                me.ShaderProperty(_RainSpeed, "Speed");
                me.ShaderProperty(_DynamicDroplets, "Dynamic Droplets");
            });
            MGUI.PropertyGroup(()=>{
                me.ShaderProperty(_UVRainSet, Tips.uvSetLabel.text);
                if (_UVRainSet.floatValue >= 5)
                    me.ShaderProperty(_UVRainSwizzle, Tips.swizzleText);
                MGUI.Vector2Field(_RainScale, "Scale");
                me.ShaderProperty(_UVRainRotation, "Rotation");
            });
            MGUI.ToggleGroupEnd();
        }

        void RainRipples(){
            MGUI.PropertyGroup(()=>{
                if (_RainMode.floatValue != 3){
                    me.TexturePropertySingleLine(Tips.maskText, _RainMask, _RainMask.textureValue ? _RainMaskChannel : null);
                }
                me.ShaderProperty(_RippleStrength, "Strength");
                me.ShaderProperty(_RippleSpeed, "Speed");
                me.ShaderProperty(_RippleDensity, "Density");
                me.ShaderProperty(_RippleSize, "Size");
                me.ShaderProperty(_RippleHorizonAdjustment, "Horizon Adjustment");
                me.ShaderProperty(_RippleHorizonAdjustmentDistance, "Adjustment Distance");
            });
            if (_PuddleToggle.floatValue == 1){
                MGUI.PropertyGroup(()=>{
                    me.ShaderProperty(_PuddleRippleStrength, "Puddle Strength");
                    me.ShaderProperty(_PuddleRippleSpeed, "Puddle Speed");
                    me.ShaderProperty(_PuddleRippleDensity, "Puddle Density");
                    me.ShaderProperty(_PuddleRippleSize, "Puddle Size");
                });
            }
            MGUI.PropertyGroup(()=>{
                me.ShaderProperty(_UVRippleSet, Tips.uvSetLabel.text);
                if (_UVRippleSet.floatValue >= 5)
                    me.ShaderProperty(_UVRippleSwizzle, Tips.swizzleText);
                MGUI.Vector2Field(_RippleScale, "Scale");
                me.ShaderProperty(_UVRippleRotation, "Rotation");
            });
        }

        void RainBoth(){
            MGUI.PropertyGroup(()=>{
                me.TexturePropertySingleLine(Tips.maskText, _RainMask, _RainMask.textureValue ? _RainMaskChannel : null);
                me.ShaderProperty(_RainThreshold, "Angle Threshold");
                me.ShaderProperty(_RainThresholdSize, "Threshold Blend");
            });
        }
        #endregion

        #region Puddles
        void DoPuddles(Material mat){
            if (Foldouts.DoFoldout(foldouts, mat, me, _PuddleToggle, "Puddles", Foldouts.Style.ThinLongToggle)){
                MGUI.PropertyGroupParent(()=>{
                    MGUI.ToggleGroup(_PuddleToggle.floatValue == 0);
                    MGUI.PropertyGroup(()=>{
                        if (_PuddleUseHeightMap.floatValue == 1 && isHeightmapped){
                            me.ShaderProperty(_PuddleTint, "Color");
                        }
                        else {
                            me.TexturePropertySingleLine(new GUIContent("Puddle Map"), _PuddleTexture, _PuddleTint);
                        }
                        MGUI.SliderMinMax01(_PuddleThresholdMin, _PuddleThresholdMax, "Threshold", 0);
                        me.ShaderProperty(_PuddleStrength, "Strength");
                        me.ShaderProperty(_PuddleMetallic, "Metallic");
                        if ((_PrimaryWorkflow.floatValue == 0 && _OcclusionMap.textureValue) || _PrimaryWorkflow.floatValue == 1)
                            me.ShaderProperty(_PuddleOcclusionStrength, "Occlusion Strength");
                        
                    });
                    if (isHeightmapped){
                        MGUI.PropertyGroup(()=>{
                            if (_PuddleUseHeightMap.floatValue == 0)
                                me.ShaderProperty(_PuddleHeightStrength, "Height Strength");
                            me.ShaderProperty(_PuddleUseHeightMap, "Use Height Map");
                            me.ShaderProperty(_PuddleHeightBasedTint, "Height-Based Tinting");
                        });
                    }
                    MGUI.PropertyGroup(()=>{
                        me.ShaderProperty(_UVPuddleSet, Tips.uvSetLabel.text);
                        if (_UVPuddleSet.floatValue >= 5)
                            me.ShaderProperty(_UVPuddleSwizzle, Tips.swizzleText);
                        MGUI.TextureSOScroll(me, _PuddleTexture, _UVPuddleScroll);
                        me.ShaderProperty(_UVPuddleRotation, "Rotation");
                    });
                    MGUI.ToggleGroupEnd();
                });
            }
        }
        #endregion

        #region Filtering
        void DoFiltering(Material mat){
            if (Foldouts.DoFoldout(foldouts, mat, me, _Filtering, "Filtering", Foldouts.Style.ThinLongToggle)){
                MGUI.PropertyGroupParent(()=>{
                    MGUI.ToggleGroup(_Filtering.floatValue == 0);
                    me.ShaderProperty(_HueMode, "Hue Mode");
                    me.ShaderProperty(_MonoTint, Tips.monoTintText);
                    MGUI.Space4();
                    MGUI.BoldLabel("Post Processing");
                    MGUI.PropertyGroup(()=>{
                        // me.TexturePropertySingleLine(Tips.colorGradingLUTText, _ColorGradingLUT, _ColorGradingLUTStrength);
                        me.ShaderProperty(_HuePost, "Hue");
                        me.ShaderProperty(_SaturationPost, "Saturation");
                        me.ShaderProperty(_BrightnessPost, "Brightness");
                        me.ShaderProperty(_ContrastPost, "Contrast");
                        me.ShaderProperty(_ACES, Tips.aces);
                    });
                    MGUI.Space4();
                    MGUI.BoldLabel("Base Color");
                    MGUI.PropertyGroup(()=>{
                        me.ShaderProperty(_Hue, "Hue");
                        me.ShaderProperty(_Saturation, "Saturation");
                        me.ShaderProperty(_Brightness, "Brightness");
                        me.ShaderProperty(_Contrast, "Contrast");
                    });
                    MGUI.Space4();
                    MGUI.BoldLabel("Detail Base Color");
                    MGUI.PropertyGroup(()=>{
                        me.ShaderProperty(_HueDet, "Hue");
                        me.ShaderProperty(_SaturationDet, "Saturation");
                        me.ShaderProperty(_BrightnessDet, "Brightness");
                        me.ShaderProperty(_ContrastDet, "Contrast");
                    });
                    if (emissionEnabled){
                        MGUI.Space4();
                        MGUI.BoldLabel("Emission");
                        MGUI.PropertyGroup(()=>{
                            me.ShaderProperty(_HueEmiss, "Hue");
                            me.ShaderProperty(_SaturationEmiss, "Saturation");
                            me.ShaderProperty(_BrightnessEmiss, "Brightness");
                            me.ShaderProperty(_ContrastEmiss, "Contrast");
                        });
                    }
                    MGUI.ToggleGroupEnd();
                });
            }
        }
        #endregion

        #region UVs
        void DoUVs(Material mat, bool isMobile, bool isLite){

            bool needsHeightMaskUV = isHeightmapped && _HeightMask.textureValue && !isMobile;
            bool needsDetailMaskUV = _DetailMask.textureValue;
            bool needsRainMaskUV = _RainMode.floatValue > 0 && _RainMask.textureValue;
            bool needsEmissionMaskUV = emissionEnabled && _EmissionMask.textureValue && !isMobile;
            bool needsAlphaMaskUV = _AlphaMask.textureValue && _AlphaSource.floatValue == 1 && _BlendMode.floatValue > 0;
            bool needsVertexMaskUV = _VertexManipulationToggle.floatValue == 1 && _VertexMask.textureValue && !isLite;

            if (needsHeightMaskUV || needsDetailMaskUV || needsRainMaskUV || needsEmissionMaskUV || needsAlphaMaskUV || needsVertexMaskUV){
                if (Foldouts.DoFoldout(foldouts, mat, "Extra UVs", Foldouts.Style.ThinLong)){
                    MGUI.PropertyGroupParent(()=>{
                        if (needsDetailMaskUV){
                            MGUI.BoldLabel("Detail Mask");
                            MGUI.PropertyGroup(()=>{
                                me.ShaderProperty(_UVDetailMaskSet, Tips.uvSetLabel.text);
                                if (_UVDetailMaskSet.floatValue >= 5)
                                    me.ShaderProperty(_UVDetailMaskSwizzle, Tips.swizzleText);
                                MGUI.TextureSOScroll(me, _DetailMask, _UVDetailMaskScroll);
                                me.ShaderProperty(_UVDetailMaskRotation, "Rotation");
                            });
                        }
                        else {
                            MGUI.SpaceN4();
                        }

                        if (needsHeightMaskUV){
                            MGUI.Space4();
                            MGUI.BoldLabel("Height Mask");
                            MGUI.PropertyGroup(()=>{
                                me.ShaderProperty(_UVHeightMaskSet, Tips.uvSetLabel.text);
                                if (_UVHeightMaskSet.floatValue >= 5)
                                    me.ShaderProperty(_UVHeightMaskSwizzle, Tips.swizzleText);
                                MGUI.TextureSOScroll(me, _HeightMask, _UVHeightMaskScroll);
                                me.ShaderProperty(_UVHeightMaskRotation, "Rotation");
                            });
                        }

                        if (needsEmissionMaskUV){
                            MGUI.Space4();
                            MGUI.BoldLabel("Emission Mask");
                            MGUI.PropertyGroup(()=>{
                                me.ShaderProperty(_UVEmissionMaskSet, Tips.uvSetLabel.text);
                                if (_UVEmissionMaskSet.floatValue >= 5)
                                    me.ShaderProperty(_UVEmissionMaskSwizzle, Tips.swizzleText);
                                MGUI.TextureSOScroll(me, _EmissionMask, _UVEmissionMaskScroll);
                                me.ShaderProperty(_UVEmissionMaskRotation, "Rotation");
                            });
                        }

                        if (needsRainMaskUV){
                            MGUI.Space4();
                            MGUI.BoldLabel("Rain Mask");
                            MGUI.PropertyGroup(()=>{
                                me.ShaderProperty(_UVRainMaskSet, Tips.uvSetLabel.text);
                                if (_UVRainMaskSet.floatValue >= 5)
                                    me.ShaderProperty(_UVRainMaskSwizzle, Tips.swizzleText);
                                MGUI.TextureSOScroll(me, _RainMask, _UVRainMaskScroll);
                                me.ShaderProperty(_UVRainMaskRotation, "Rotation");
                            });
                        }

                        if (needsAlphaMaskUV){
                            MGUI.Space4();
                            MGUI.BoldLabel("Alpha Mask");
                            MGUI.PropertyGroup(()=>{
                                me.ShaderProperty(_UVAlphaMaskSet, Tips.uvSetLabel.text);
                                if (_UVAlphaMaskSet.floatValue >= 5)
                                    me.ShaderProperty(_UVAlphaMaskSwizzle, Tips.swizzleText);
                                MGUI.TextureSOScroll(me, _AlphaMask, _UVAlphaMaskScroll);
                                me.ShaderProperty(_UVAlphaMaskRotation, "Rotation");
                            });
                        }

                        if (needsVertexMaskUV){
                            MGUI.Space4();
                            MGUI.BoldLabel("Vertex Manipulation Mask");
                            MGUI.PropertyGroup(()=>{
                                me.ShaderProperty(_UVVertexMaskSet, Tips.uvSetLabel.text);
                                if (_UVVertexMaskSet.floatValue >= 5)
                                    me.ShaderProperty(_UVVertexMaskSwizzle, Tips.swizzleText);
                                MGUI.TextureSOScroll(me, _VertexMask, _UVVertexMaskScroll);
                                me.ShaderProperty(_UVVertexMaskRotation, "Rotation");
                            });
                        }
                    });
                }
            }
        }
        #endregion

        #region LTCGI
        void DoLTCGI(Material mat){
            if (Shader.Find("LTCGI/Blur Prefilter") != null){
                LTCGILayout(mat);
            }
            else {
                _LTCGI.floatValue = 0;
                mat.SetInt("_LTCGI", 0);
                mat.DisableKeyword("LTCGI");
            }
        }

        void LTCGILayout(Material mat){
            if (Foldouts.DoFoldout(foldouts, mat, me, _LTCGI, "LTCGI", Foldouts.Style.ThinLongToggle)){
                MGUI.PropertyGroupParent(()=>{
                    MGUI.ToggleGroup(_LTCGI.floatValue == 0);
                    MGUI.PropertyGroup(()=>{
                        me.ShaderProperty(_LTCGIStrength, "Strength");
                        me.ShaderProperty(_LTCGIRoughness, "Roughness Multiplier");
                        if (_ShadingModel.floatValue == 0)
                            me.ShaderProperty(_LTCGISpecularOcclusion, "Specular Occlusion");
                    });
                    MGUI.PropertyGroup(()=>{
                        me.ShaderProperty(_LTCGI_DiffuseColor, "Diffuse Color");
                        me.ShaderProperty(_LTCGI_SpecularColor, "Specular Color");
                    });
                    MGUI.ToggleGroupEnd();
                });
            }
        }
        #endregion

        #region AreaLit
        void DoAreaLit(Material mat){
            if (Shader.Find("AreaLit/Standard") != null){
                AreaLitLayout(mat);
            }
            else {
                _AreaLitToggle.floatValue = 0f;
                mat.SetInt("_AreaLitToggle", 0);
                mat.DisableKeyword("_AREALIT_ON");
            }
        }

        void CheckTrilinear(Texture tex) {
            if(!tex)
                return;
            if(tex.mipmapCount <= 1) {
                me.HelpBoxWithButton(
                    EditorGUIUtility.TrTextContent("Mip maps are required, please enable them in the texture import settings."),
                    EditorGUIUtility.TrTextContent("OK"));
                return;
            }
            if(tex.filterMode != FilterMode.Trilinear) {
                if(me.HelpBoxWithButton(
                    EditorGUIUtility.TrTextContent("Trilinear filtering is required, and aniso is recommended."),
                    EditorGUIUtility.TrTextContent("Fix Now"))) {
                    tex.filterMode = FilterMode.Trilinear;
                    tex.anisoLevel = 1;
                    EditorUtility.SetDirty(tex);
                }
                return;
            }
        }

        void AreaLitLayout(Material mat){
            if (Foldouts.DoFoldout(foldouts, mat, me, _AreaLitToggle, "AreaLit", Foldouts.Style.ThinLongToggle)){
                MGUI.PropertyGroupParent(()=>{
                    MGUI.ToggleGroup(_AreaLitToggle.floatValue == 0);
                    MGUI.PropertyGroup(()=>{
                        me.ShaderProperty(_AreaLitStrength, "Strength");
                        me.ShaderProperty(_AreaLitRoughnessMultiplier, "Roughness Multiplier");
                        if (_ShadingModel.floatValue == 0)
                            me.ShaderProperty(_AreaLitSpecularOcclusion, "Specular Occlusion");
                        me.ShaderProperty(_OpaqueLights, Tips.opaqueLightsText);
                    });
                    MGUI.PropertyGroup(()=>{
                        var lightMeshText = !_LightMesh.textureValue ? Tips.lightMeshText : new GUIContent(
                            Tips.lightMeshText.text + $" (max: {_LightMesh.textureValue.height})", Tips.lightMeshText.tooltip
                        );
                        me.TexturePropertySingleLine(lightMeshText, _LightMesh);
                        me.TexturePropertySingleLine(Tips.lightTex0Text, _LightTex0);
                        CheckTrilinear(_LightTex0.textureValue);
                        me.TexturePropertySingleLine(Tips.lightTex1Text, _LightTex1);
                        CheckTrilinear(_LightTex1.textureValue);
                        me.TexturePropertySingleLine(Tips.lightTex2Text, _LightTex2);
                        CheckTrilinear(_LightTex2.textureValue);
                        me.TexturePropertySingleLine(Tips.lightTex3Text, _LightTex3);
                        CheckTrilinear(_LightTex3.textureValue);
                        me.TexturePropertySingleLine(new GUIContent("Occlusion"), _AreaLitOcclusion);
                        if (_AreaLitOcclusion.textureValue){
                            me.ShaderProperty(_AreaLitOcclusionUVSet, "UV Set");
                        }
                        MGUI.TextureSO(me, _AreaLitOcclusion, _AreaLitOcclusion.textureValue);
                    });
                    MGUI.DisplayInfo("Note that the AreaLit package files MUST be inside a folder named AreaLit (case sensitive) directly in the Assets folder (Assets/AreaLit)");
                    MGUI.ToggleGroupEnd();
                });
            }
        }
        #endregion

        #region Lightmap Settings
        void DoLightmapSettings(Material mat){
            if (Foldouts.DoFoldout(foldouts, mat, "Lightmap Settings", Foldouts.Style.ThinLong)){
                MGUI.PropertyGroupParent(()=>{
                    MGUI.PropertyGroup(()=>{
                        me.ShaderProperty(_BakeryMode, Tips.bakeryMode);
                        MGUI.ToggleFloat(me, "Bakery Specular Highlights", _BAKERY_LMSPEC, _BakeryLMSpecStrength);
                    });
                    MGUI.PropertyGroup(()=>{
                        me.ShaderProperty(_BicubicSampling, Tips.bicubicLightmap);
                        if ((_PrimaryWorkflow.floatValue == 0 && _HeightMap.textureValue) || (_PrimaryWorkflow.floatValue == 1 && _PackedHeight.floatValue == 1))
                            me.ShaderProperty(_ApplyHeightOffset, Tips.heightmapLightmapText);
                        me.ShaderProperty(_BAKERY_SHNONLINEAR, "Non-Linear SH");
                        me.DoubleSidedGIField();
                        me.ShaderProperty(_IgnoreRealtimeGI, Tips.ignoreRealtimeGIText);
                        me.ShaderProperty(_AdditiveLightVolumesToggle, "Additive Light Volumes");
                        me.ShaderProperty(_LightVolumeBias, Tips.lightVolumeBiasText);
                    });
                    if ((_PrimaryWorkflow.floatValue == 0 && _HeightMap.textureValue) || (_PrimaryWorkflow.floatValue == 1 && _PackedHeight.floatValue == 1)){
                        if (_ApplyHeightOffset.floatValue == 1){
                            MGUI.DisplayWarning("Please note that due to lightmaps being atlased, manipulating their uvs often reveals visual artifacts, and is often not recommended. Be sure to check for artifacts if using this option.");
                        }
                    }
                });
            }
        }
        #endregion

        #region Render Settings
        void DoRenderSettings(Material mat){
            if (Foldouts.DoFoldout(foldouts, mat, "Render Settings", Foldouts.Style.ThinLong)){
                MGUI.PropertyGroupParent(()=>{
                    MGUI.PropertyGroup(() => {
                        me.ShaderProperty(_Culling, Tips.culling);
                        _QueueOffset.floatValue = (int)_QueueOffset.floatValue;
                        me.ShaderProperty(_QueueOffset, Tips.queueOffset);
                        MGUI.SpaceN1();
                        MGUI.DummyProperty("Render Queue:", mat.renderQueue.ToString());
                    });
                    MGUI.PropertyGroup(()=>{
                        me.ShaderProperty(_UnityFogToggle, Tips.unityFogToggleText);
                        me.ShaderProperty(_VertexBaseColor, Tips.vertexBaseColorText);
                        me.ShaderProperty(_FlipBackfaceNormals, Tips.flipBackfaceNormalsText);
                        me.EnableInstancingField();
                        me.ShaderProperty(_MaterialDebugMode, "Debug Mode");
                    });
                });
            }
        }
        #endregion

        #region Debug Menu
        void DoDebug(Material mat){
            if (_MaterialDebugMode.floatValue == 1){
                if (Foldouts.DoFoldout(foldouts, mat, "Debug", Foldouts.Style.ThinLong)){
                    MGUI.PropertyGroupParent(()=>{
                        MGUI.ShaderPropertyBold(me, _DebugEnable, "Debug View");
                        MGUI.PropertyGroup(()=>{
                            me.ShaderProperty(_DebugBaseColor, "Base Color");
                            me.ShaderProperty(_DebugAlpha, "Alpha");
                            me.ShaderProperty(_DebugNormals, "Normals");
                            me.ShaderProperty(_DebugRoughness, "Roughness");
                            me.ShaderProperty(_DebugMetallic, "Metallic");
                            me.ShaderProperty(_DebugOcclusion, "Occlusion");
                            me.ShaderProperty(_DebugHeight, "Height");
                            me.ShaderProperty(_DebugLighting, "Lighting");
                            me.ShaderProperty(_DebugAtten, "Realtime Shadows");
                            me.ShaderProperty(_DebugReflections, "Reflections");
                            me.ShaderProperty(_DebugSpecular, "Specular Highlights");
                            me.ShaderProperty(_DebugVertexColors, "Vertex Colors");
                        });		
                        MGUI.BoldLabel("Default Textures");
                        MGUI.PropertyGroup(()=>{
                            me.TexturePropertySingleLine(Tips.defaultSamplerText, _DefaultSampler);
                            me.TexturePropertySingleLine(new GUIContent("LUT for Filament SM"), _DFG);
                            me.TexturePropertySingleLine(new GUIContent("SSR Noise Texture"), _NoiseTexSSR);
                            me.TexturePropertySingleLine(new GUIContent("Droplet Map"), _DropletMask);
                            me.TexturePropertySingleLine(new GUIContent("Rain Texture Sheet"), _RainSheet);
                            me.ShaderProperty(_RainColumns, "Rain Texture Sheet Columns");
                            me.ShaderProperty(_RainRows, "Rain Texture Sheet Rows");
                        });

                        MGUI.BoldLabel("Render Settings");
                        MGUI.PropertyGroup(()=>{
                            me.ShaderProperty(_SrcBlend, "Source Blend Op");
                            me.ShaderProperty(_DstBlend, "Destination Blend Op");
                            me.ShaderProperty(_ZWrite, "ZWrite");
                            me.ShaderProperty(_ZTest, "ZTest");
                        });
                    });
                }
            }
        }
        #endregion

        #region Keywords & Other
        void SetProperties(Material mat){
            mat.SetInt("_SampleMetallic", mat.GetTexture("_MetallicMap") ? 1 : 0);
            mat.SetInt("_SampleRoughness", mat.GetTexture("_RoughnessMap") ? 1 : 0);
            mat.SetInt("_SampleOcclusion", mat.GetTexture("_OcclusionMap") ? 1 : 0);
        }

        void SetKeywords(Material mat){
            
            MGUI.ClearKeywords(mat);
            MaterialEditor.FixupEmissiveFlag(mat);
            bool isEmissive = (mat.globalIlluminationFlags & MaterialGlobalIlluminationFlags.EmissiveIsBlack) == 0;
            bool enableParallax = (mat.GetInt("_PrimaryWorkflow") == 0 ? mat.GetTexture("_HeightMap") : mat.GetInt("_PackedHeight") == 1) && mat.GetInt("_PrimarySampleMode") != 3;

            mat.SetInt("_SampleMetallic", mat.GetTexture("_MetallicMap") ? 1 : 0);
            mat.SetInt("_SampleRoughness", mat.GetTexture("_RoughnessMap") ? 1 : 0);
            mat.SetInt("_SampleOcclusion", mat.GetTexture("_OcclusionMap") ? 1 : 0);
            mat.SetInt("_SampleCustomLUT", mat.GetTexture("_ColorGradingLUT") ? 1 : 0);

            MGUI.SetKeyword(mat, "_EMISSION_ON", isEmissive);
            MGUI.SetKeyword(mat, "_PARALLAX_ON", enableParallax);
            MGUI.SetKeyword(mat, "_REFLECTIONS_ON", mat.GetInt("_ReflectionsToggle") == 1);
            MGUI.SetKeyword(mat, "_SPECULAR_HIGHLIGHTS_ON", mat.GetInt("_SpecularHighlightsToggle") == 1);
            MGUI.SetKeyword(mat, "_WORKFLOW_PACKED_ON", mat.GetInt("_PrimaryWorkflow") == 1);
            MGUI.SetKeyword(mat, "_WORKFLOW_DETAIL_PACKED_ON", mat.GetInt("_DetailWorkflow") == 1);
            MGUI.SetKeyword(mat, "_STOCHASTIC_ON", mat.GetInt("_PrimarySampleMode") == 1);
            MGUI.SetKeyword(mat, "_SUPERSAMPLING_ON", mat.GetInt("_PrimarySampleMode") == 2);
            MGUI.SetKeyword(mat, "_TRIPLANAR_ON", mat.GetInt("_PrimarySampleMode") == 3);
            MGUI.SetKeyword(mat, "_STOCHASTIC_DETAIL_ON", mat.GetInt("_DetailSampleMode") == 1);
            MGUI.SetKeyword(mat, "_SUPERSAMPLING_DETAIL_ON", mat.GetInt("_DetailSampleMode") == 2);
            MGUI.SetKeyword(mat, "_TRIPLANAR_DETAIL_ON", mat.GetInt("_DetailSampleMode") == 3);
            MGUI.SetKeyword(mat, "_NORMALMAP_ON", mat.GetTexture("_NormalMap"));
            MGUI.SetKeyword(mat, "_DETAIL_MAINTEX_ON", mat.GetTexture("_DetailMainTex"));
            MGUI.SetKeyword(mat, "_DETAIL_NORMAL_ON", mat.GetTexture("_DetailNormalMap"));
            MGUI.SetKeyword(mat, "_DETAIL_METALLIC_ON", mat.GetTexture("_DetailMetallicMap"));
            MGUI.SetKeyword(mat, "_DETAIL_ROUGHNESS_ON", mat.GetTexture("_DetailRoughnessMap"));
            MGUI.SetKeyword(mat, "_DETAIL_OCCLUSION_ON", mat.GetTexture("_DetailOcclusionMap"));
            MGUI.SetKeyword(mat, "_SSR_ON", mat.GetInt("_SSRToggle") == 1);
            MGUI.SetKeyword(mat, "_RAIN_DROPLETS_ON", mat.GetInt("_RainMode") == 1);
            MGUI.SetKeyword(mat, "_RAIN_RIPPLES_ON", mat.GetInt("_RainMode") == 2);
            MGUI.SetKeyword(mat, "_RAIN_AUTO_ON", mat.GetInt("_RainMode") == 3);
            MGUI.SetKeyword(mat, "_AUDIOLINK_ON", mat.GetInt("_AudioLinkEmission") > 0 && isEmissive);
            MGUI.SetKeyword(mat, "_AUDIOLINK_META_ON", mat.GetInt("_AudioLinkEmission") > 0 && mat.GetInt("_AudioLinkEmissionMeta") > 0 && isEmissive);
            MGUI.SetKeyword(mat, "BAKERY_SH", mat.GetInt("_BakeryMode") == 1);
            MGUI.SetKeyword(mat, "BAKERY_RNM", mat.GetInt("_BakeryMode") == 2);
            MGUI.SetKeyword(mat, "BAKERY_MONOSH", mat.GetInt("_BakeryMode") == 3);
            MGUI.SetKeyword(mat, "BAKERY_LMSPEC", mat.GetInt("_BAKERY_LMSPEC") == 1);
            MGUI.SetKeyword(mat, "BAKERY_SHNONLINEAR", mat.GetInt("_BAKERY_SHNONLINEAR") == 1);
            MGUI.SetKeyword(mat, "_BICUBIC_SAMPLING_ON", mat.GetInt("_BicubicSampling") == 1);
            MGUI.SetKeyword(mat, "_AREALIT_ON", mat.GetInt("_AreaLitToggle") == 1);
            MGUI.SetKeyword(mat, "LTCGI", mat.GetInt("_LTCGI") == 1);
            MGUI.SetKeyword(mat, "_VERTEX_MANIPULATION_ON", mat.GetInt("_VertexManipulationToggle") == 1);
        }
        #endregion

        #region Blend Mode
        public static void SetBlendMode(Material mat){
            bool ssrToggle = mat.GetInt("_SSRToggle") == 1;
            bool isLite = MGUI.IsNewLiteVersion(mat);
            bool isMobile = MGUI.IsMobileVersion(mat);
            int blendMode = mat.GetInt("_BlendMode");
            mat.SetInt("_AlphaToMask", blendMode == 1 ? 1 : 0);	

            switch (blendMode){
                case 0:
                    mat.SetOverrideTag("RenderType", "Opaque");
                    mat.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                    mat.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
                    mat.SetInt("_ZWrite", 1);
                    mat.DisableKeyword("_ALPHATEST_ON");
                    mat.DisableKeyword("_ALPHABLEND_ON");
                    mat.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                    mat.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Geometry+mat.GetInt("_QueueOffset");
                    if (ssrToggle && !isLite && !isMobile)
                        mat.renderQueue = (int)UnityEngine.Rendering.RenderQueue.AlphaTest+51+mat.GetInt("_QueueOffset");
                    break;
                case 1:
                    mat.SetOverrideTag("RenderType", "TransparentCutout");
                    mat.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                    mat.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
                    mat.SetInt("_ZWrite", 1);
                    mat.EnableKeyword("_ALPHATEST_ON");
                    mat.DisableKeyword("_ALPHABLEND_ON");
                    mat.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                    mat.renderQueue = (int)UnityEngine.Rendering.RenderQueue.AlphaTest+mat.GetInt("_QueueOffset");
                    if (ssrToggle && !isLite && !isMobile)
                        mat.renderQueue = (int)UnityEngine.Rendering.RenderQueue.AlphaTest+51+mat.GetInt("_QueueOffset");
                    break;
                case 2:
                    mat.SetOverrideTag("RenderType", "Transparent");
                    mat.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
                    mat.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
                    mat.SetInt("_ZWrite", 0);
                    mat.DisableKeyword("_ALPHATEST_ON");
                    mat.EnableKeyword("_ALPHABLEND_ON");
                    mat.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                    mat.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent+mat.GetInt("_QueueOffset");
                    break;
                case 3:
                    mat.SetOverrideTag("RenderType", "Transparent");
                    mat.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                    mat.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
                    mat.SetInt("_ZWrite", 0);
                    mat.DisableKeyword("_ALPHATEST_ON");
                    mat.DisableKeyword("_ALPHABLEND_ON");
                    mat.EnableKeyword("_ALPHAPREMULTIPLY_ON");
                    mat.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent+mat.GetInt("_QueueOffset");
                    break;
            }
        }
        #endregion

        #region Utilities
        void TransferStandardTextures(Material mat, Shader oldShader){
            if (oldShader == Shader.Find("Standard") || oldShader == Shader.Find("Autodesk Interactive") || oldShader == Shader.Find("Standard (Specular setup)")){
                mat.SetTexture("_NormalMap", mat.GetTexture("_BumpMap"));
                mat.SetTexture("_MetallicMap", mat.GetTexture("_MetallicGlossMap"));
                mat.SetTexture("_HeightMap", mat.GetTexture("_ParallaxMap"));
                mat.SetTexture("_DetailMainTex", mat.GetTexture("_DetailAlbedoMap"));
            }
            if (oldShader == Shader.Find("Autodesk Interactive") || oldShader == Shader.Find("Standard (Specular setup)")){
                mat.SetTexture("_RoughnessMap", mat.GetTexture("_SpecGlossMap"));
            }
        }

        public override void AssignNewShaderToMaterial(Material mat, Shader oldShader, Shader newShader) {
            base.AssignNewShaderToMaterial(mat, oldShader, newShader);
            TransferStandardTextures(mat, oldShader);
            SetKeywords(mat);
            SetBlendMode(mat);
        }

        public void OnAfterMaterialUpgraded(Material mat){
            SetProperties(mat);
            // SetKeywords(mat); - this spams errors from properties not found when called from here, idk why
        }
        #endregion 
    }
}