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

namespace Mochie {
    
    public class WaterEditor : ShaderGUI {

        GUIContent texLabel = new GUIContent("Base Color");
        GUIContent normalLabel = new GUIContent("Normal Map");
        GUIContent flowLabel = new GUIContent("Flow Map");
        GUIContent noiseLabel = new GUIContent("Noise Texture");
        GUIContent foamLabel = new GUIContent("Foam Texture");
        GUIContent cubeLabel = new GUIContent("Cubemap");
        GUIContent emissLabel = new GUIContent("Emission Map");

        Dictionary<Action, GUIContent> baseTabButtons = new Dictionary<Action, GUIContent>();
        Dictionary<Action, GUIContent> norm0TabButtons = new Dictionary<Action, GUIContent>();
        Dictionary<Action, GUIContent> norm1TabButtons = new Dictionary<Action, GUIContent>();
        Dictionary<Action, GUIContent> flowTabButtons = new Dictionary<Action, GUIContent>();
        Dictionary<Action, GUIContent> vertTabButtons = new Dictionary<Action, GUIContent>();
        Dictionary<Action, GUIContent> causticsTabButtons = new Dictionary<Action, GUIContent>();
        Dictionary<Action, GUIContent> fogTabButtons = new Dictionary<Action, GUIContent>();
        Dictionary<Action, GUIContent> foamTabButtons = new Dictionary<Action, GUIContent>();
        Dictionary<Action, GUIContent> edgeFadeTabButtons = new Dictionary<Action, GUIContent>();
        Dictionary<Action, GUIContent> reflSpecTabButtons = new Dictionary<Action, GUIContent>();
        Dictionary<Action, GUIContent> rainTabButtons = new Dictionary<Action, GUIContent>();
        Dictionary<Action, GUIContent> tessTabButtons = new Dictionary<Action, GUIContent>();
        Dictionary<Action, GUIContent> emissTabButtons = new Dictionary<Action, GUIContent>();
        Dictionary<Action, GUIContent> areaLitTabButtons = new Dictionary<Action, GUIContent>();
        Dictionary<Action, GUIContent> renderingTabButtons = new Dictionary<Action, GUIContent>();
        Dictionary<Action, GUIContent> ltcgiTabButtons = new Dictionary<Action, GUIContent>();

        static Dictionary<Material, Toggles> foldouts = new Dictionary<Material, Toggles>();
        Toggles toggles = new Toggles(new string[] {
                "BASE", 
                "NORMAL MAPS", 
                "SPECULARITY", 
                "FLOW MAPPING", 
                "VERTEX OFFSET",
                "CAUSTICS",
                "DEPTH FOG",
                "FOAM",
                "EDGE FADE",
                "RAIN",
                "TESSELLATION",
                "EMISSION",
                "LTCGI",
                "AREALIT",
                "RENDER SETTINGS"
        }, 0);

        string header = "WaterHeader_Pro";
        string versionLabel = "v1.23";

        MaterialProperty _Color = null;
        MaterialProperty _NonGrabColor = null;
        MaterialProperty _AngleTint = null;
        MaterialProperty _BackfaceTint = null;
        MaterialProperty _MainTex = null;
        MaterialProperty _MainTexScroll = null;
        MaterialProperty _DistortionStrength = null;
        MaterialProperty _Roughness = null;
        MaterialProperty _Metallic = null;
        MaterialProperty _Opacity = null;
        MaterialProperty _Reflections = null;
        MaterialProperty _ReflStrength = null;
        MaterialProperty _Specular = null;
        MaterialProperty _SpecStrength = null;
        MaterialProperty _CullMode = null;
        MaterialProperty _ZWrite = null;
        MaterialProperty _BaseColorDistortionStrength = null;
        MaterialProperty _NormalMap0 = null;
        MaterialProperty _NormalStr0 = null;
        MaterialProperty _NormalMapScale0 = null;
        MaterialProperty _Rotation0 = null;
        MaterialProperty _NormalMapScroll0 = null;
        MaterialProperty _Normal1Toggle = null;
        MaterialProperty _NormalMap1 = null;
        MaterialProperty _NormalStr1 = null;
        MaterialProperty _NormalMapScale1 = null;
        MaterialProperty _Rotation1 = null;
        MaterialProperty _NormalMapScroll1 = null;
        MaterialProperty _FlowToggle = null;
        MaterialProperty _FlowMap = null;
        MaterialProperty _FlowSpeed = null;
        MaterialProperty _FlowStrength = null;
        MaterialProperty _FlowMapScale = null;
        MaterialProperty _NoiseTex = null;
        MaterialProperty _NoiseTexScale = null;
        MaterialProperty _NoiseTexScroll = null;
        MaterialProperty _NoiseTexBlur = null;
        MaterialProperty _WaveHeight = null;
        MaterialProperty _Offset = null;
        MaterialProperty _VertOffsetMode = null;
        MaterialProperty _WaveSpeedGlobal = null;
        MaterialProperty _WaveStrengthGlobal = null;
        MaterialProperty _WaveScaleGlobal = null;
        MaterialProperty _WaveSpeed0 = null;
        MaterialProperty _WaveSpeed1 = null;
        MaterialProperty _WaveSpeed2 = null;
        MaterialProperty _WaveScale0 = null;
        MaterialProperty _WaveScale1 = null;
        MaterialProperty _WaveScale2 = null;
        MaterialProperty _WaveStrength0 = null;
        MaterialProperty _WaveStrength1 = null;
        MaterialProperty _WaveStrength2 = null;
        MaterialProperty _WaveDirection0 = null;
        MaterialProperty _WaveDirection1 = null;
        MaterialProperty _WaveDirection2 = null;
        // MaterialProperty _Turbulence = null;
        // MaterialProperty _TurbulenceSpeed = null;
        // MaterialProperty _TurbulenceScale = null;
        MaterialProperty _VoronoiScale = null;
        MaterialProperty _VoronoiScroll = null;
        MaterialProperty _VoronoiWaveHeight = null;
        MaterialProperty _VoronoiOffset = null;
        MaterialProperty _VoronoiSpeed = null;
        MaterialProperty _CausticsTex = null;
        MaterialProperty _CausticsToggle = null;
        MaterialProperty _CausticsOpacity = null;
        MaterialProperty _CausticsScale = null;
        MaterialProperty _CausticsSpeed = null;
        MaterialProperty _CausticsFade = null;
        MaterialProperty _CausticsDisp = null;
        MaterialProperty _CausticsShadow = null;
        MaterialProperty _CausticsShadowStrength = null;
        MaterialProperty _CausticsDistortion = null;
        MaterialProperty _CausticsDistortionTex = null;
        MaterialProperty _CausticsDistortionScale = null;
        MaterialProperty _CausticsDistortionSpeed = null;
        MaterialProperty _CausticsRotation = null;
        MaterialProperty _CausticsColor = null;
        MaterialProperty _CausticsPower = null;
        MaterialProperty _FogToggle = null;
        MaterialProperty _FogTint = null;
        MaterialProperty _FogPower = null;
        MaterialProperty _FoamToggle = null;
        MaterialProperty _FoamTex = null;
        MaterialProperty _FoamNoiseTex = null;
        MaterialProperty _FoamTexScale = null;
        MaterialProperty _FoamRoughness = null;
        MaterialProperty _FoamColor = null;
        MaterialProperty _FoamPower = null;
        MaterialProperty _FoamEdgeStrength = null;
        MaterialProperty _FoamCrestStrength = null;
        MaterialProperty _FoamCrestThreshold = null;
        MaterialProperty _FoamNoiseTexScroll = null;
        MaterialProperty _FoamNoiseTexCrestStrength = null;
        MaterialProperty _FoamNoiseTexStrength = null;
        MaterialProperty _FoamNoiseTexScale = null;
        MaterialProperty _EdgeFadeToggle = null;
        MaterialProperty _EdgeFadePower = null;
        MaterialProperty _EdgeFadeOffset = null;
        MaterialProperty _SSRStrength = null;
        MaterialProperty _SSR = null;
        MaterialProperty _EdgeFadeSSR = null;
        MaterialProperty _Normal0StochasticToggle = null;
        MaterialProperty _Normal1StochasticToggle = null;
        MaterialProperty _FoamStochasticToggle = null;
        MaterialProperty _FoamTexScroll = null;
        MaterialProperty _BaseColorStochasticToggle = null;
        // MaterialProperty _NormalMapOffset1 = null;
        // MaterialProperty _FoamOffset = null;
        // MaterialProperty _NormalMapOffset0 = null;
        // MaterialProperty _BaseColorOffset = null;
        MaterialProperty _FoamDistortionStrength = null;
        MaterialProperty _VertRemapMin = null;
        MaterialProperty _VertRemapMax = null;
        MaterialProperty _LightDir = null;
        MaterialProperty _SpecTint = null;
        MaterialProperty _ReflCube = null;
        MaterialProperty _ReflTint = null;
        MaterialProperty _ReflCubeRotation = null;
        MaterialProperty _RainToggle = null;
        MaterialProperty _RippleScale = null;
        MaterialProperty _RippleSpeed = null;
        MaterialProperty _RippleStr = null;
        MaterialProperty _FoamNormalToggle = null;
        MaterialProperty _FoamNormalStrength = null;
        MaterialProperty _DepthEffects = null;
        MaterialProperty _TessMin = null;
        MaterialProperty _TessMax = null;
        MaterialProperty _TessDistMin = null;
        MaterialProperty _TessDistMax = null;
        MaterialProperty _TessellationOffsetMask = null;
        MaterialProperty _BlendNoise = null;
        MaterialProperty _BlendNoiseScale = null;
        MaterialProperty _BlendNoiseSource = null;
        MaterialProperty _FlowMapUV = null;
        MaterialProperty _BackfaceReflections = null;
        MaterialProperty _RoughnessMap = null;
        MaterialProperty _MetallicMap = null;
        MaterialProperty _EmissionMap = null;
        MaterialProperty _EmissionMapStochasticToggle = null;
        MaterialProperty _EmissionColor = null;
        MaterialProperty _EmissionMapScroll = null;
        MaterialProperty _DetailBaseColor = null;
        MaterialProperty _DetailBaseColorTint = null;
        MaterialProperty _AreaLitToggle = null;
        MaterialProperty _AreaLitMask = null;
        MaterialProperty _AreaLitStrength = null;
        MaterialProperty _AreaLitRoughnessMult = null;
        MaterialProperty _LightMesh = null;
        MaterialProperty _LightTex0 = null;
        MaterialProperty _LightTex1 = null;
        MaterialProperty _LightTex2 = null;
        MaterialProperty _LightTex3 = null;
        MaterialProperty _OpaqueLights = null;
        MaterialProperty _TransparencyMode = null;
        MaterialProperty _DetailNormal = null;
        MaterialProperty _DetailNormalStrength = null;
        MaterialProperty _DetailTextureMode = null;
        MaterialProperty _DetailScroll = null;
        MaterialProperty _StencilRef = null;
        MaterialProperty _RecalculateNormals = null;
        MaterialProperty _ShadowStrength = null;
        MaterialProperty _SSRHeight = null;
        MaterialProperty _CausticsTexArray = null;
        MaterialProperty _NormalMapFlipbook = null;
        MaterialProperty _NormalMapFlipbookSpeed = null;
        MaterialProperty _NormalMapFlipbookStrength = null;
        MaterialProperty _NormalMapMode = null;
        MaterialProperty _VertOffsetFlipbook = null;
        MaterialProperty _VertOffsetFlipbookStrength = null;
        MaterialProperty _VertOffsetFlipbookSpeed = null;
        MaterialProperty _VertOffsetFlipbookScale = null;
        MaterialProperty _NormalMapFlipbookScale = null;
        MaterialProperty _CausticsFlipbookSpeed = null;
        MaterialProperty _RippleSize = null;
        MaterialProperty _RippleDensity = null;
        MaterialProperty _OpacityMask = null;
        MaterialProperty _OpacityMaskScroll = null;
        MaterialProperty _NonGrabBackfaceTint = null;
        MaterialProperty _EmissionDistortionStrength = null;
        MaterialProperty _FogBrightness = null;
        MaterialProperty _VertexOffsetMask = null;
        MaterialProperty _VertexOffsetMaskStrength = null;
        MaterialProperty _VertexOffsetMaskChannel = null;
        MaterialProperty _SubsurfaceTint = null;
        MaterialProperty _SubsurfaceThreshold = null;
        MaterialProperty _SubsurfaceBrightness = null;
        MaterialProperty _SubsurfaceStrength = null;
        MaterialProperty _TexCoordSpace = null;
        MaterialProperty _TexCoordSpaceSwizzle = null;
        MaterialProperty _GlobalTexCoordScaleUV = null;
        MaterialProperty _GlobalTexCoordScaleWorld = null;
        MaterialProperty _MirrorNormalOffsetSwizzle = null;
        MaterialProperty _InvertNormals = null;
        MaterialProperty _VisualizeFlowmap = null;
        MaterialProperty _AudioLink = null;
        MaterialProperty _AudioLinkStrength = null;
        MaterialProperty _AudioLinkBand = null;
        MaterialProperty _CausticsFlipbookDisp = null;
        MaterialProperty _RippleMask = null;
        MaterialProperty _QueueOffset = null;
        MaterialProperty _HorizonAdjustment = null;
        MaterialProperty _HorizonAdjustmentDistance = null;
        MaterialProperty _EmissionFlowToggle = null;
        MaterialProperty _FogContribution = null;
        MaterialProperty _LightmapDistortion = null;
        MaterialProperty _IndirectStrength = null;
        MaterialProperty _IndirectSaturation = null;
        MaterialProperty _VRSSR = null;
        // MaterialProperty _WireframeVisualization = null;
        // MaterialProperty _WireframeColor = null;

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

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

        // MaterialProperty _FoamCrestPower = null;
        // MaterialProperty _FogTint2 = null;
        // MaterialProperty _FogPower2 = null;
        // MaterialProperty _FogBrightness2 = null;

        // MaterialProperty _NormalFlipbookStochasticToggle = null;

        // MaterialProperty _Test1 = null;
        // MaterialProperty _Test2 = null;
        
        BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;

        MaterialEditor me;

        public override void OnGUI(MaterialEditor matEditor, MaterialProperty[] props) {

            me = matEditor;

            if (!me.isVisible)
                return;

            ClearDictionaries();

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

            header = "WaterHeader_Pro";
            if (!EditorGUIUtility.isProSkin){
                header = "WaterHeader";
            }

            Texture2D headerTex = (Texture2D)Resources.Load(header, typeof(Texture2D));
            Texture2D collapseIcon = (Texture2D)Resources.Load("CollapseIcon", typeof(Texture2D));

            GUILayout.Label(headerTex);
            MGUI.Space4();

            if (!foldouts.ContainsKey(mat))
                foldouts.Add(mat, toggles);

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

            EditorGUI.BeginChangeCheck(); {
                
                int transMode = mat.GetInt("_TransparencyMode");
                bool isTessellated = MGUI.IsTessellated(mat);

                // Base
                baseTabButtons.Add(()=>{Toggles.CollapseFoldouts(mat, foldouts, 1);}, MGUI.collapseLabel);
                baseTabButtons.Add(()=>{ResetSurface();}, MGUI.resetLabel);
                Action surfaceTabAction = ()=>{
                    MGUI.PropertyGroup(()=>{
                        me.TexturePropertySingleLine(texLabel, _MainTex, _BaseColorStochasticToggle);
                        MGUI.TexPropLabel(Tips.stochasticLabel, 117, false);
                        if (_MainTex.textureValue){
                            MGUI.TextureSOScroll(me, _MainTex, _MainTexScroll);
                            // me.ShaderProperty(_BaseColorOffset, Tips.parallaxOffsetLabel);
                            me.ShaderProperty(_BaseColorDistortionStrength, "Distortion Strength");
                            MGUI.Space4();
                        }
                        if (transMode > 0){
                            me.TexturePropertySingleLine(new GUIContent("Opacity"), _OpacityMask, _Opacity);
                            MGUI.TextureSOScroll(me, _OpacityMask, _OpacityMaskScroll, _OpacityMask.textureValue);
                        }
                        else {
                            me.ShaderProperty(_ShadowStrength, "Shadow Strength");
                        }
                    });
                    MGUI.PropertyGroup(()=>{
                        bool hasDetailBC = _DetailBaseColor.textureValue;
                        bool hasDetailN = _DetailNormal.textureValue;
                        me.TexturePropertySingleLine(new GUIContent("Decal Base Color"), _DetailBaseColor, hasDetailBC ? _DetailBaseColorTint : null);
                        me.TexturePropertySingleLine(new GUIContent("Decal Normal Map"), _DetailNormal, hasDetailN ? _DetailNormalStrength : null);
                        MGUI.TextureSOScroll(me, _DetailBaseColor, _DetailScroll, hasDetailBC || hasDetailN);
                    });
                    MGUI.PropertyGroup(() => {
                        if (transMode == 2)
                            me.ShaderProperty(_Color, "Surface Tint");
                        else
                            me.ShaderProperty(_NonGrabColor, "Surface Tint");
                        me.ShaderProperty(_AngleTint, "Glancing Tint");
                        if (transMode == 2)
                            me.ShaderProperty(_BackfaceTint, "Backface Tint");
                        else
                            me.ShaderProperty(_NonGrabBackfaceTint, "Backface Tint");
                        MGUI.Space2();
                    });
                };
                Foldouts.Foldout("BASE", foldouts, baseTabButtons, mat, me, surfaceTabAction);

                // Normal Maps
                norm0TabButtons.Add(()=>{ResetNormalMaps();}, MGUI.resetLabel);
                Action norm0TabAction = ()=>{
                    MGUI.Space4();
                    me.ShaderProperty(_NormalMapMode, "Mode");
                    me.ShaderProperty(_DistortionStrength, "Refraction Strength");
                    me.ShaderProperty(_HorizonAdjustment, Tips.horizonAdjustmentText);
                    me.ShaderProperty(_HorizonAdjustmentDistance, "Horizon Adjustment Distance");
                    me.ShaderProperty(_InvertNormals, "Invert");
                    MGUI.Space4();
                    if (_NormalMapMode.floatValue == 0){
                        MGUI.BoldLabel("Primary");
                        MGUI.PropertyGroup(() => {
                            me.TexturePropertySingleLine(Tips.normalMapText, _NormalMap0, _Normal0StochasticToggle);
                            MGUI.TexPropLabel(Tips.stochasticLabel, 117, false);
                            me.ShaderProperty(_NormalStr0, "Strength");
                            MGUI.Vector2Field(_NormalMapScale0, "Scale");
                            MGUI.Vector2Field(_NormalMapScroll0, "Scrolling");
                            me.ShaderProperty(_Rotation0, "Rotation");
                        });
                        MGUI.BoldLabel("Secondary");
                        MGUI.SpaceN18();
                        me.ShaderProperty(_Normal1Toggle, " ");
                        MGUI.PropertyGroup(() => {
                            MGUI.ToggleGroup(_Normal1Toggle.floatValue == 0);
                            me.TexturePropertySingleLine(Tips.normalMapText, _NormalMap1, _Normal1StochasticToggle);
                            MGUI.TexPropLabel(Tips.stochasticLabel, 117, false);
                            me.ShaderProperty(_NormalStr1, "Strength");
                            MGUI.Vector2Field(_NormalMapScale1, "Scale");
                            MGUI.Vector2Field(_NormalMapScroll1, "Scrolling");
                            me.ShaderProperty(_Rotation1, "Rotation");
                            MGUI.ToggleGroupEnd();
                        });
                    }
                    else {
                        MGUI.PropertyGroup(()=>{
                            me.TexturePropertySingleLine(new GUIContent("Flipbook"), _NormalMapFlipbook);
                            MGUI.Vector2Field(_NormalMapFlipbookScale, "Scale");
                            me.ShaderProperty(_NormalMapFlipbookStrength, "Strength");
                            me.ShaderProperty(_NormalMapFlipbookSpeed, "Speed");
                        });
                    }
                };
                Foldouts.Foldout("NORMAL MAPS", foldouts, norm0TabButtons, mat, me, norm0TabAction);

                // Specularity
                reflSpecTabButtons.Add(()=>{ResetReflSpec();}, MGUI.resetLabel);
                Action reflSpecTabAction = ()=>{
                    MGUI.Space4();
                    me.TexturePropertySingleLine(Tips.roughnessText, _RoughnessMap, _Roughness);
                    MGUI.TextureSO(me, _RoughnessMap, _RoughnessMap.textureValue && _DetailTextureMode.floatValue != 1);
                    me.TexturePropertySingleLine(Tips.metallicText, _MetallicMap, _Metallic);
                    MGUI.TextureSO(me, _MetallicMap, _MetallicMap.textureValue && _DetailTextureMode.floatValue != 1);
                    me.ShaderProperty(_DetailTextureMode, Tips.detailMode);
                    MGUI.Space8();
                    me.ShaderProperty(_Reflections, "Reflections");
                    MGUI.PropertyGroup(()=>{
                        MGUI.ToggleGroup(_Reflections.floatValue == 0);
                        if (_Reflections.floatValue == 2){
                            me.TexturePropertySingleLine(cubeLabel, _ReflCube, _ReflTint);
                            MGUI.Vector3Field(_ReflCubeRotation, "Rotation", false);
                        }
                        else {
                            if (_Reflections.floatValue == 3)
                                me.ShaderProperty(_MirrorNormalOffsetSwizzle, Tips.mirrorNormalSwizzleText);
                            me.ShaderProperty(_ReflTint, "Tint");
                        }
                        me.ShaderProperty(_ReflStrength, "Strength");
                        if (_DepthEffects.floatValue == 1 && _Reflections.floatValue != 3){
                            MGUI.ToggleFloat(me, "Screenspace Reflections", _SSR, _SSRStrength);
                            if (_SSR.floatValue > 0){
                                me.ShaderProperty(_EdgeFadeSSR, Tips.ssrEdgeFadeText);
                                me.ShaderProperty(_SSRHeight, Tips.ssrDepthText);
                                me.ShaderProperty(_VRSSR, "Enable SSR in VR");
                            }
                        }
                        me.ShaderProperty(_BackfaceReflections, "Apply to Backfaces");
                        MGUI.ToggleGroupEnd();
                    });
                    if (_Reflections.floatValue == 3){
                        MGUI.DisplayWarning("Mirror mode requires a VRChat mirror component with this shader selected in the custom shader field. It also requires the mesh be facing forwards on the local Z axis (see default unity quad for example). Lastly, this incurs the same performance cost as any other VRChat mirror, use it very sparingly.");
                    }
                    MGUI.Space8();
                    me.ShaderProperty(_Specular, "Specular Highlights");
                    MGUI.PropertyGroup( ()=>{
                        MGUI.ToggleGroup(_Specular.floatValue == 0);
                        me.ShaderProperty(_SpecTint, "Tint");
                        me.ShaderProperty(_SpecStrength, "Strength");
                        if (_Specular.floatValue == 2){
                            MGUI.Vector3Field(_LightDir, "Light Direction", false);
                        }
                        MGUI.ToggleGroupEnd();
                    });

                };
                Foldouts.Foldout("SPECULARITY", foldouts, reflSpecTabButtons, mat, me, reflSpecTabAction);

                // Emission
                emissTabButtons.Add(()=>{ResetEmission();}, MGUI.resetLabel);
                Action emissTabAction = ()=>{
                    MGUI.ToggleGroup(!me.EmissionEnabledProperty());
                    me.LightmapEmissionFlagsProperty(0, true);
                    MGUI.Space4();
                    MGUI.PropertyGroup(()=>{
                        me.TexturePropertySingleLine(emissLabel, _EmissionMap, _EmissionMapStochasticToggle);
                        MGUI.TexPropLabel(Tips.stochasticLabel, 117, false);
                        me.ShaderProperty(_EmissionColor, "Tint");
                        MGUI.TextureSOScroll(me, _EmissionMap, _EmissionMapScroll);
                        me.ShaderProperty(_EmissionDistortionStrength, "Distortion Strength");
                        me.ShaderProperty(_EmissionFlowToggle, "Apply Flow Mapping");
                        me.ShaderProperty(_AudioLink, "Audio Link");
                        if (_AudioLink.floatValue == 1){
                            MGUI.PropertyGroupLayer(()=>{
                                MGUI.SpaceN1();
                                me.ShaderProperty(_AudioLinkBand, "Band");
                                me.ShaderProperty(_AudioLinkStrength, "Strength");
                                MGUI.SpaceN1();
                            });
                        }
                    });
                    MGUI.ToggleGroupEnd();

                };
                Foldouts.Foldout("EMISSION", foldouts, emissTabButtons, mat, me, emissTabAction);

                // Flow Mapping
                flowTabButtons.Add(()=>{ResetFlowMapping();}, MGUI.resetLabel);
                Action flowTabAction = ()=>{
                    me.ShaderProperty(_FlowToggle, "Enable");
                    MGUI.Space4();
                    MGUI.PropertyGroup(()=>{
                        MGUI.ToggleGroup(_FlowToggle.floatValue == 0);
                        me.TexturePropertySingleLine(flowLabel, _FlowMap, _FlowMapUV);
                        MGUI.sRGBWarning(_FlowMap);
                        if (_BlendNoiseSource.floatValue == 1){
                            me.TexturePropertySingleLine(Tips.blendNoise, _BlendNoise);
                            MGUI.sRGBWarning(_BlendNoise);
                        }
                        MGUI.Vector2Field(_FlowMapScale, "Flow Map Scale");
                        if (_BlendNoiseSource.floatValue == 1)
                            MGUI.Vector2Field(_BlendNoiseScale, "Blend Noise Scale");
                        me.ShaderProperty(_FlowSpeed, "Speed");
                        me.ShaderProperty(_FlowStrength, "Strength");
                        me.ShaderProperty(_BlendNoiseSource, "Blend Noise Source");
                        me.ShaderProperty(_VisualizeFlowmap, "Visualize");
                        MGUI.ToggleGroupEnd();
                    });
                };
                Foldouts.Foldout("FLOW MAPPING", foldouts, flowTabButtons, mat, me, flowTabAction);

                // Vertex Offset
                vertTabButtons.Add(()=>{ResetVertOffset();}, MGUI.resetLabel);
                Action vertTabAction = ()=>{
                    me.ShaderProperty(_VertOffsetMode, "Mode");
                    MGUI.Space4();
                    MGUI.ToggleGroup(_VertOffsetMode.floatValue == 0);
                    if (_VertOffsetMode.floatValue == 1){
                        MGUI.PropertyGroup(()=>{
                            me.TexturePropertySingleLine(noiseLabel, _NoiseTex);
                            me.ShaderProperty(_NoiseTexBlur, "Precision");
                            MGUI.Vector2Field(_NoiseTexScale, "Scale");
                            MGUI.Vector2Field(_NoiseTexScroll, "Scrolling");
                        });
                        MGUI.PropertyGroup(()=>{
                            MGUI.Vector3Field(_Offset, "Strength", false);
                            me.ShaderProperty(_WaveHeight, "Strength Multiplier");
                            MGUI.SliderMinMax(_VertRemapMin, _VertRemapMax, -1f, 1f, "Remap", 1);
                        });
                    }
                    else if (_VertOffsetMode.floatValue == 2){
                        MGUI.DisplayInfo("For best results ensure your base mesh is a plane of approximately 10m x 10m (before scaling in the scene). Also don't be afraid to use extremely large or small values, these settings vary significantly depending on the scale you're working at.");
                        MGUI.BoldLabel("Global");
                        MGUI.PropertyGroup(() => {
                            me.ShaderProperty(_WaveStrengthGlobal, "Strength");
                            me.ShaderProperty(_WaveScaleGlobal, "Scale");
                            me.ShaderProperty(_WaveSpeedGlobal, "Speed");
                            me.ShaderProperty(_RecalculateNormals, "Recalculate Normals");
                        });
                        MGUI.PropertyGroup(()=>{
                            me.TexturePropertySingleLine(Tips.maskText, _VertexOffsetMask, _VertexOffsetMaskStrength, _VertexOffsetMaskChannel);
                            MGUI.TextureSO(me, _VertexOffsetMask);
                        });
                        MGUI.BoldLabel("Wave 1");
                        MGUI.PropertyGroup(() => {
                            me.ShaderProperty(_WaveStrength0, "Strength");
                            me.ShaderProperty(_WaveScale0, "Scale");
                            me.ShaderProperty(_WaveSpeed0, "Speed");
                            me.ShaderProperty(_WaveDirection0, "Direction");
                        });
                        MGUI.BoldLabel("Wave 2");
                        MGUI.PropertyGroup(() => {
                            me.ShaderProperty(_WaveStrength1, "Strength");
                            me.ShaderProperty(_WaveScale1, "Scale");
                            me.ShaderProperty(_WaveSpeed1, "Speed");
                            me.ShaderProperty(_WaveDirection1, "Direction");
                        });
                        MGUI.BoldLabel("Wave 3");
                        MGUI.PropertyGroup(() => {
                            me.ShaderProperty(_WaveStrength2, "Strength");
                            me.ShaderProperty(_WaveScale2, "Scale");
                            me.ShaderProperty(_WaveSpeed2, "Speed");
                            me.ShaderProperty(_WaveDirection2, "Direction");
                        });
                        // MGUI.BoldLabel("Turbulence");
                        // MGUI.PropertyGroup(() => {
                        // 	me.ShaderProperty(_Turbulence, Tips.turbulence);
                        // 	me.ShaderProperty(_TurbulenceSpeed, "Speed");
                        // 	me.ShaderProperty(_TurbulenceScale, "Scale");
                        // });
                    }
                    else if (_VertOffsetMode.floatValue == 3){
                        MGUI.PropertyGroup(()=>{
                            me.ShaderProperty(_VoronoiSpeed, "Speed");
                            MGUI.Vector2Field(_VoronoiScale, "Scale");
                            MGUI.Vector2Field(_VoronoiScroll, "Scrolling");
                            MGUI.Vector3Field(_VoronoiOffset, "Strength", false);
                            me.ShaderProperty(_VoronoiWaveHeight, "Strength Multiplier");
                        });
                    }
                    else if (_VertOffsetMode.floatValue == 4){
                        MGUI.PropertyGroup(()=>{
                            me.TexturePropertySingleLine(new GUIContent("Vertex Offset Flipbook"), _VertOffsetFlipbook);
                            MGUI.Vector2Field(_NormalMapFlipbookScale, "Scale");
                            me.ShaderProperty(_VertOffsetFlipbookStrength, "Strength");
                            me.ShaderProperty(_VertOffsetFlipbookSpeed, "Speed");
                        });
                    }
                    if (_VertOffsetMode.floatValue > 0 && _VertOffsetMode.floatValue != 2){
                        MGUI.PropertyGroup(()=>{
                            me.TexturePropertySingleLine(Tips.maskText, _VertexOffsetMask, _VertexOffsetMaskStrength, _VertexOffsetMaskChannel);
                            MGUI.TextureSO(me, _VertexOffsetMask);
                        });
                    }
                    if (_VertOffsetMode.floatValue > 0){
                        MGUI.BoldLabel("Subsurface Scattering");
                        MGUI.PropertyGroup(()=>{
                            me.ShaderProperty(_SubsurfaceTint, "Tint");
                            me.ShaderProperty(_SubsurfaceStrength, "Strength");
                            me.ShaderProperty(_SubsurfaceBrightness, "Brightness");
                            me.ShaderProperty(_SubsurfaceThreshold, "Threshold");
                        });
                    }
                    MGUI.ToggleGroupEnd();
                };
                Foldouts.Foldout("VERTEX OFFSET", foldouts, vertTabButtons, mat, me, vertTabAction);

                // Caustics
                if (_DepthEffects.floatValue == 1 && transMode == 2){
                    causticsTabButtons.Add(()=>{ResetCaustics();}, MGUI.resetLabel);
                    Action causticsTabAction = ()=>{
                        me.ShaderProperty(_CausticsToggle, "Mode");
                        MGUI.Space4();
                        if (_CausticsToggle.floatValue > 0){
                            MGUI.PropertyGroup(()=>{
                                if (_CausticsToggle.floatValue == 2){
                                    me.TexturePropertySingleLine(new GUIContent("Caustics Texture"), _CausticsTex);
                                    me.TexturePropertySingleLine(new GUIContent("Shadow Texture"), _CausticsShadow, _CausticsShadowStrength);
                                }
                                else if (_CausticsToggle.floatValue == 3){
                                    me.TexturePropertySingleLine(new GUIContent("Caustics Flipbook"), _CausticsTexArray);
                                }
                                me.ShaderProperty(_CausticsColor, "Color");
                                me.ShaderProperty(_CausticsOpacity, "Strength");
                                
                                if (_CausticsToggle.floatValue == 1){
                                    me.ShaderProperty(_CausticsPower, "Power");
                                    me.ShaderProperty(_CausticsDisp, "Dispersion");
                                }
                                if (_CausticsToggle.floatValue != 3)
                                    me.ShaderProperty(_CausticsSpeed, "Speed");
                                else {
                                    me.ShaderProperty(_CausticsFlipbookSpeed, "Speed");
                                    me.ShaderProperty(_CausticsFlipbookDisp, "Dispersion");
                                }
                                me.ShaderProperty(_CausticsScale, "Scale");
                                me.ShaderProperty(_CausticsFade, Tips.causticsFade);
                                // me.ShaderProperty(_CausticsSurfaceFade, Tips.causticsSurfaceFade);
                                MGUI.Vector3Field(_CausticsRotation, "Rotation", false);
                            });
                            if (_CausticsToggle.floatValue != 3){
                                MGUI.PropertyGroup( ()=>{
                                    me.TexturePropertySingleLine(new GUIContent("Distortion Texture"), _CausticsDistortionTex);
                                    me.ShaderProperty(_CausticsDistortion, "Distortion Strength");
                                    me.ShaderProperty(_CausticsDistortionScale, "Distortion Scale");
                                    MGUI.Vector2Field(_CausticsDistortionSpeed, "Distortion Speed");
                                });
                            }
                        }
                    };
                    Foldouts.Foldout("CAUSTICS", foldouts, causticsTabButtons, mat, me, causticsTabAction);
                }

                // Foam
                foamTabButtons.Add(()=>{ResetFoam();}, MGUI.resetLabel);
                Action foamTabAction = ()=>{
                    me.ShaderProperty(_FoamToggle, "Enable");
                    MGUI.Space4();
                    MGUI.ToggleGroup(_FoamToggle.floatValue == 0);
                    MGUI.PropertyGroup(()=>{
                        me.TexturePropertySingleLine(foamLabel, _FoamTex, _FoamColor, _FoamStochasticToggle);
                        MGUI.TexPropLabel(Tips.stochasticLabel, 117, true);
                        MGUI.Space2();
                        MGUI.Vector2Field(_FoamTexScale, "Scale");
                        MGUI.Vector2Field(_FoamTexScroll, "Scrolling");
                        // me.ShaderProperty(_FoamOffset, Tips.parallaxOffsetLabel);
                        me.ShaderProperty(_FoamDistortionStrength, "Distortion Strength");
                        MGUI.ToggleFloat(me, Tips.foamNormal, _FoamNormalToggle, _FoamNormalStrength);
                    });
                    MGUI.PropertyGroup(()=>{
                        me.TexturePropertySingleLine(noiseLabel, _FoamNoiseTex);
                        MGUI.Vector2Field(_FoamNoiseTexScale, "Scale");
                        MGUI.Vector2Field(_FoamNoiseTexScroll, "Scrolling");
                        me.ShaderProperty(_FoamNoiseTexStrength, Tips.foamNoiseTexStrength);
                        me.ShaderProperty(_FoamNoiseTexCrestStrength, Tips.foamNoiseTexCrestStrength);
                    });
                    MGUI.PropertyGroup(()=>{
                        me.ShaderProperty(_FoamRoughness, Tips.foamRoughness);
                        me.ShaderProperty(_FoamPower, Tips.foamPower);
                        me.ShaderProperty(_FoamEdgeStrength, Tips.foamEdgeStrength);
                        me.ShaderProperty(_FoamCrestStrength, Tips.foamCrestStrength);
                        // me.ShaderProperty(_FoamCrestPower, Tips.foamCrestPower);
                        me.ShaderProperty(_FoamCrestThreshold, Tips.foamCrestThreshold);
                    });
                    MGUI.ToggleGroupEnd();
                };
                Foldouts.Foldout("FOAM", foldouts, foamTabButtons, mat, me, foamTabAction);

                // Depth Fog
                if (_DepthEffects.floatValue == 1 && transMode == 2){
                    fogTabButtons.Add(()=>{ResetFog();}, MGUI.resetLabel);
                    Action fogTabAction = ()=>{
                        me.ShaderProperty(_FogToggle, "Enable");
                        MGUI.Space4();
                        MGUI.ToggleGroup(_FogToggle.floatValue == 0);
                        // MGUI.BoldLabel("Layer 1");
                        MGUI.PropertyGroup(()=>{
                            me.ShaderProperty(_FogTint, "Color");
                            me.ShaderProperty(_FogBrightness, "Brightness");
                            me.ShaderProperty(_FogPower, "Power");
                        });
                        // MGUI.BoldLabel("Layer 2");
                        // MGUI.PropertyGroup(()=>{
                        // 	me.ShaderProperty(_FogTint2, "Color");
                        // 	me.ShaderProperty(_FogBrightness2, "Brightness");
                        // 	me.ShaderProperty(_FogPower2, "Power");
                        // });
                        MGUI.ToggleGroupEnd();
                    };
                    Foldouts.Foldout("DEPTH FOG", foldouts, fogTabButtons, mat, me, fogTabAction);
                }

                // Edge Fade
                if (_DepthEffects.floatValue == 1 && transMode == 2){
                    edgeFadeTabButtons.Add(()=>{ResetEdgeFade();}, MGUI.resetLabel);
                    Action edgeFadeTabAction = ()=>{
                        me.ShaderProperty(_EdgeFadeToggle, "Enable");
                        MGUI.Space4();
                        MGUI.PropertyGroup(()=>{
                            MGUI.ToggleGroup(_EdgeFadeToggle.floatValue == 0);
                            me.ShaderProperty(_EdgeFadePower, "Power");
                            me.ShaderProperty(_EdgeFadeOffset, "Offset");
                            MGUI.ToggleGroupEnd();
                        });
                    };
                    Foldouts.Foldout("EDGE FADE", foldouts, edgeFadeTabButtons, mat, me, edgeFadeTabAction);
                }

                // Rain
                rainTabButtons.Add(()=>{ResetRain();}, MGUI.resetLabel);
                Action rainTabAction = ()=>{
                    me.ShaderProperty(_RainToggle, "Enable");
                    MGUI.Space4();
                    MGUI.ToggleGroup(_RainToggle.floatValue == 0);
                    MGUI.PropertyGroup(()=>{
                        me.TexturePropertySingleLine(Tips.maskText, _RippleMask);
                        MGUI.TextureSO(me, _RippleMask, _RippleMask.textureValue);
                        me.ShaderProperty(_RippleStr, "Strength");
                        me.ShaderProperty(_RippleSpeed, "Speed");
                        me.ShaderProperty(_RippleScale, "Scale");
                    });
                    MGUI.PropertyGroup(()=>{
                        me.ShaderProperty(_RippleDensity, "Ripple Density");
                        me.ShaderProperty(_RippleSize, "Ripple Size");
                    });
                    MGUI.ToggleGroupEnd();
                };
                Foldouts.Foldout("RAIN", foldouts, rainTabButtons, mat, me, rainTabAction);

                // Tessellation
                if (isTessellated){
                    tessTabButtons.Add(()=>{ResetTess();}, MGUI.resetLabel);
                    Action tessTabAction = ()=>{
                        MGUI.DisplayWarning("WARNING: Tessellation is known to cause issues on some hardware, and can be extremely expensive if you turn up the settings too far. Experimentation will likely be required as factors need to be set based on the base triangle count of the mesh.");
                        MGUI.DisplayInfo("Use the 'Shaded Wireframe' scene view for easy visualization.");
                        MGUI.PropertyGroup(()=>{
                            me.ShaderProperty(_TessellationOffsetMask, "Vertex Offset Mask");
                            // me.ShaderProperty(_WireframeVisualization, "Debug Wireframe");
                            // if (_WireframeVisualization.floatValue == 1)
                            //     me.ShaderProperty(_WireframeColor, "Wireframe Color");
                            me.ShaderProperty(_TessMin, "Min Factor");
                            me.ShaderProperty(_TessMax, "Max Factor");
                            me.ShaderProperty(_TessDistMin, "Min Distance");
                            me.ShaderProperty(_TessDistMax, "Max Distance");
                        });
                    };
                    Foldouts.Foldout("TESSELLATION", foldouts, tessTabButtons, mat, me, tessTabAction);
                }

                // LTCGI
                if (Shader.Find("LTCGI/Blur Prefilter") != null){
                    ltcgiTabButtons.Add(()=>{ResetAreaLit();}, MGUI.resetLabel);
                    Action ltcgiTabAction = ()=>{
                        me.ShaderProperty(_LTCGI, "Enable");
                        MGUI.ToggleGroup(_LTCGI.floatValue == 0);
                        MGUI.PropertyGroup(()=>{
                            me.ShaderProperty(_LTCGIStrength, "Strength");
                            me.ShaderProperty(_LTCGIRoughness, "Roughness Multiplier");
                            me.ShaderProperty(_LTCGI_SpecularColor, "Tint");
                        });
                        MGUI.ToggleGroupEnd();
                    };
                    Foldouts.Foldout("LTCGI", foldouts, ltcgiTabButtons, mat, me, ltcgiTabAction);
                }
                else {
                    _LTCGI.floatValue = 0;
                    mat.SetInt("_LTCGI", 0);
                    mat.DisableKeyword("LTCGI");
                }

                // AreaLit
                if (Shader.Find("AreaLit/Standard") != null){
                    areaLitTabButtons.Add(()=>{ResetAreaLit();}, MGUI.resetLabel);
                    Action areaLitTabAction = ()=>{
                        me.ShaderProperty(_AreaLitToggle, "Enable");
                        MGUI.Space4();
                        bool reflDisabled = _AreaLitToggle.floatValue == 1 && _Reflections.floatValue == 0;
                        bool cantInteract = _AreaLitToggle.floatValue == 0 || reflDisabled;
                        if (reflDisabled){
                            MGUI.DisplayError("Reflections are disabled, please enable them to use AreaLit.");
                        }
                        MGUI.ToggleGroup(cantInteract);
                        MGUI.PropertyGroup(()=>{
                            me.TexturePropertySingleLine(Tips.maskText, _AreaLitMask);
                            MGUI.TextureSO(me, _AreaLitMask, _AreaLitMask.textureValue);
                            me.ShaderProperty(_AreaLitStrength, "Strength");
                            me.ShaderProperty(_AreaLitRoughnessMult, "Roughness Multiplier");
                            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);
                            MGUI.CheckTrilinear(_LightTex0.textureValue, me);
                            me.TexturePropertySingleLine(Tips.lightTex1Text, _LightTex1);
                            MGUI.CheckTrilinear(_LightTex1.textureValue, me);
                            me.TexturePropertySingleLine(Tips.lightTex2Text, _LightTex2);
                            MGUI.CheckTrilinear(_LightTex2.textureValue, me);
                            me.TexturePropertySingleLine(Tips.lightTex3Text, _LightTex3);
                            MGUI.CheckTrilinear(_LightTex3.textureValue, me);
                        });
                        MGUI.ToggleGroupEnd();
                        MGUI.DisplayInfo("Note that the AreaLit package files MUST be inside a folder named AreaLit (case sensitive) directly in the Assets folder (Assets/AreaLit)");
                    };
                    Foldouts.Foldout("AREALIT", foldouts, areaLitTabButtons, mat, me, areaLitTabAction);
                }
                else {
                    _AreaLitToggle.floatValue = 0f;
                    mat.SetInt("_AreaLitToggle", 0);
                    mat.DisableKeyword("_AREALIT_ON");
                }

                // Render Settings
                renderingTabButtons.Add(()=>{ResetRendering(mat);}, MGUI.resetLabel);
                Action renderingTabAction = ()=>{
                    MGUI.Space4();
                    MGUI.PropertyGroup(()=>{
                        _QueueOffset.floatValue = (int)_QueueOffset.floatValue;
                        me.ShaderProperty(_QueueOffset, Tips.queueOffset);
                        MGUI.SpaceN1();
                        MGUI.DummyProperty("Render Queue:", mat.renderQueue.ToString());
                        me.ShaderProperty(_StencilRef, "Stencil Reference");
                    });
                    MGUI.PropertyGroup(()=>{
                        EditorGUI.BeginChangeCheck();
                        me.ShaderProperty(_TransparencyMode, "Transparency Mode");
                        if (EditorGUI.EndChangeCheck()){
                            SetBlendMode(mat);
                        }
                        me.ShaderProperty(_CullMode, "Culling Mode");
                        me.ShaderProperty(_ZWrite, "ZWrite");
                        if (transMode == 2){
                            me.ShaderProperty(_DepthEffects, "Depth Effects");
                        }
                    });
                    MGUI.PropertyGroup(()=>{
                        me.ShaderProperty(_TexCoordSpace, "Texture Coordinate Space");
                        if (_TexCoordSpace.floatValue == 1f){
                            me.ShaderProperty(_TexCoordSpaceSwizzle, "Swizzle");
                            me.ShaderProperty(_GlobalTexCoordScaleWorld, "Texture Coordinate Scale");
                        }
                        else {
                            me.ShaderProperty(_GlobalTexCoordScaleUV, "Texture Coordinate Scale");
                        }
                    });
                    MGUI.PropertyGroup(()=>{
                        me.ShaderProperty(_BakeryMode, Tips.bakeryMode);
                        MGUI.ToggleFloat(me, "Bakery Specular Highlights", _BAKERY_LMSPEC, _BakeryLMSpecStrength);
                        me.ShaderProperty(_LightmapDistortion, "Lightmap UV Distortion");
                        me.ShaderProperty(_IndirectStrength, "Lightmap Strength");
                        me.ShaderProperty(_IndirectSaturation, "Lightmap Saturation");
                        me.ShaderProperty(_FogContribution, "Depth Fog Contribution");
                        me.ShaderProperty(_BicubicSampling, Tips.bicubicLightmap);
                        me.ShaderProperty(_IgnoreRealtimeGI, Tips.ignoreRealtimeGIText);
                    });
                    if (_DepthEffects.floatValue == 1 && transMode == 2){
                        MGUI.DisplayInfo("Depth effects require a \"Depth Light\" prefab be present in the scene.\n(Found in: Assets/Mochie/Unity/Prefabs)");
                    }
                };
                Foldouts.Foldout("RENDER SETTINGS", foldouts, renderingTabButtons, mat, me, renderingTabAction);

            }
            if (EditorGUI.EndChangeCheck()){
                SetKeywords(mat);
            }
            
            MGUI.DoFooter(versionLabel);
        }

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

        void SetBlendMode(Material mat){
            int transMode = mat.GetInt("_TransparencyMode");
            switch (transMode){
                
                // Opaque
                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.SetShaderPassEnabled("Always", false);
                    mat.EnableKeyword("_OPAQUE_MODE_ON");
                    mat.DisableKeyword("_PREMUL_MODE_ON");
                    mat.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Geometry+mat.GetInt("_QueueOffset");
                break;

                // Premultiplied
                case 1:
                    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.SetShaderPassEnabled("Always", false);
                    mat.DisableKeyword("_OPAQUE_MODE_ON");
                    mat.EnableKeyword("_PREMUL_MODE_ON");
                    mat.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent+mat.GetInt("_QueueOffset");
                break;

                // Grabpass
                case 2:
                    mat.SetOverrideTag("RenderType", "Transparent");
                    mat.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                    mat.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
                    mat.SetInt("_ZWrite", 0);
                    mat.SetShaderPassEnabled("Always", true);
                    mat.DisableKeyword("_OPAQUE_MODE_ON");
                    mat.DisableKeyword("_PREMUL_MODE_ON");
                    mat.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent+mat.GetInt("_QueueOffset");
                break;

                default: break;
            }
        }

        void SetKeywords(Material mat){
            MaterialEditor.FixupEmissiveFlag(mat);
            bool isEmissive = (mat.globalIlluminationFlags & MaterialGlobalIlluminationFlags.EmissiveIsBlack) == 0;
            int transMode = mat.GetInt("_TransparencyMode");
            int depthFXToggle = mat.GetInt("_DepthEffects");
            int vertMode = mat.GetInt("_VertOffsetMode");
            int reflMode = mat.GetInt("_Reflections");
            int specMode = mat.GetInt("_Specular");
            int causticsMode = mat.GetInt("_CausticsToggle");
            int normalMapMode = mat.GetInt("_NormalMapMode");
            int bicubic = mat.GetInt("_BicubicSampling");
            int ssrToggle = mat.GetInt("_SSR");
            bool ssrEnabled = ssrToggle == 1 && depthFXToggle == 1 && transMode == 2 && (reflMode == 1 || reflMode == 2);

            MGUI.SetKeyword(mat, "_EMISSION_ON", isEmissive);
            MGUI.SetKeyword(mat, "_REFLECTIONS_ON", reflMode > 0);
            MGUI.SetKeyword(mat, "_REFLECTIONS_MANUAL_ON", reflMode == 2);
            MGUI.SetKeyword(mat, "_REFLECTIONS_MIRROR_ON", reflMode == 3);
            MGUI.SetKeyword(mat, "_SPECULAR_ON", specMode > 0);
            MGUI.SetKeyword(mat, "_NOISE_TEXTURE_ON", vertMode == 1);
            MGUI.SetKeyword(mat, "_GERSTNER_WAVES_ON", vertMode == 2);
            MGUI.SetKeyword(mat, "_VORONOI_ON", vertMode == 3);
            MGUI.SetKeyword(mat, "_VERT_FLIPBOOK_ON", vertMode == 4);
            MGUI.SetKeyword(mat, "_DEPTH_EFFECTS_ON", depthFXToggle == 1 && transMode == 2);
            MGUI.SetKeyword(mat, "_DETAIL_BASECOLOR_ON", mat.GetTexture("_DetailBaseColor"));
            MGUI.SetKeyword(mat, "_DETAIL_NORMAL_ON", mat.GetTexture("_DetailNormal"));
            MGUI.SetKeyword(mat, "_CAUSTICS_VORONOI_ON", causticsMode == 1 && depthFXToggle == 1);
            MGUI.SetKeyword(mat, "_CAUSTICS_TEXTURE_ON", causticsMode == 2 && depthFXToggle == 1);
            MGUI.SetKeyword(mat, "_CAUSTICS_FLIPBOOK_ON", causticsMode == 3 && depthFXToggle == 1);
            MGUI.SetKeyword(mat, "_NORMALMAP_FLIPBOOK_ON", normalMapMode == 1);
            MGUI.SetKeyword(mat, "_SCREENSPACE_REFLECTIONS_ON", ssrEnabled);
            MGUI.SetKeyword(mat, "_BICUBIC_LIGHTMAPPING_ON", bicubic == 1);
            MGUI.SetKeyword(mat, "_FOAM_NORMALS_ON", mat.GetInt("_FoamNormalToggle") == 1);
            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, "_EMISSION_FLOW_ON", mat.GetInt("_EmissionFlowToggle") == 1);
            MGUI.SetKeyword(mat, "LTCGI", mat.GetInt("_LTCGI") == 1);
        }

        void ResetSurface(){
            _Color.colorValue = Color.white;
            _NonGrabColor.colorValue = new Color(0f,0f,0f,0f);
            _MainTex.textureValue = null;
            _MainTexScroll.vectorValue = new Vector4(0,0.1f,0,0);
            _DetailBaseColor.textureValue = null;
            _DetailBaseColorTint.colorValue = Color.white;
            _DetailNormal.textureValue = null;
            _DetailNormalStrength.floatValue = 1f;
            _Opacity.floatValue = 1f;
            _BaseColorDistortionStrength.floatValue = 0.1f;
            _AngleTint.colorValue = Color.white;
            _DetailScroll.vectorValue = Vector4.zero;
            _ShadowStrength.floatValue = 0f;
        }

        void ResetNormalMaps(){
            _DistortionStrength.floatValue = 0.5f;
            _InvertNormals.floatValue = 0f;
            _HorizonAdjustment.floatValue = 0f;
            _HorizonAdjustmentDistance.floatValue = 0.7f;
            ResetPrimaryNormal();
            ResetSecondaryNormal();
            ResetFlipbookNormal();
        }

        void ResetPrimaryNormal(){
            _NormalMapScale0.vectorValue = new Vector4(3f,3f,0,0);
            _NormalStr0.floatValue = 0.3f;
            _Rotation0.floatValue = 0f;
            _NormalMapScroll0.vectorValue = new Vector4(0.1f,0.1f,0,0);
        }

        void ResetSecondaryNormal(){
            _NormalStr1.floatValue = 0.3f;
            _NormalMapScale1.vectorValue = new Vector4(4f,4f,0,0);
            _NormalMapScroll1.vectorValue = new Vector4(-0.1f, 0.1f, 0,0);
            _Rotation1.floatValue = 0f;
        }

        void ResetFlipbookNormal(){
            _NormalMapFlipbookSpeed.floatValue = 8f;
            _NormalMapFlipbookStrength.floatValue = 0.2f;
            _NormalMapFlipbookScale.vectorValue = new Vector4(3f,3f,0f,0f);
        }
        
        void ResetFlowMapping(){
            _FlowSpeed.floatValue = 0.25f;
            _FlowStrength.floatValue = 0.3f;
            _FlowMapScale.vectorValue = new Vector4(2f,2f,0,0);
            _BlendNoiseScale.vectorValue = new Vector4(2f,2f,0,0);
            _BlendNoiseSource.floatValue = 0f;
        }

        void ResetVertOffset(){
            _WaveScaleGlobal.floatValue = 1f;
            _WaveSpeedGlobal.floatValue = 2f;
            _WaveStrengthGlobal.floatValue = 1.5f;
            _NoiseTexScale.vectorValue = new Vector4(3,3,0,0);
            _NoiseTexScroll.vectorValue = new Vector4(0f,0.1f,0f,0f);
            _NoiseTexBlur.floatValue = 0.8f;
            _WaveHeight.floatValue = 1f;
            _Offset.vectorValue = new Vector4(0,1,0,0);
            _WaveSpeed0.floatValue = 1f;
            _WaveSpeed1.floatValue = 1.1f;
            _WaveSpeed2.floatValue = 1.2f;
            _WaveStrength0.floatValue = 0.1f;
            _WaveStrength1.floatValue = 0.1f;
            _WaveStrength2.floatValue = 0.1f;
            _WaveScale0.floatValue = 4f;
            _WaveScale1.floatValue = 2f;
            _WaveScale2.floatValue = 1f;
            _WaveDirection0.floatValue = 0f;
            _WaveDirection1.floatValue = 335f;
            _WaveDirection2.floatValue = 13f;
            // _TurbulenceSpeed.floatValue = 0.3f;
            // _Turbulence.floatValue = 1f;
            // _TurbulenceScale.floatValue = 3f;
            _VertRemapMin.floatValue = -1f;
            _VertRemapMax.floatValue = 1f;
            _VoronoiOffset.vectorValue = new Vector4(0f,1f,0f,0f);
            _VoronoiScroll.vectorValue = new Vector4(0f,-0.25f,0f,0f);
            _VoronoiScale.vectorValue = new Vector4(2f,2f,0,0);
            _VoronoiWaveHeight.floatValue = 1f;
            _VoronoiSpeed.floatValue = 1.5f;
            _RecalculateNormals.floatValue = 1f;
            _VertOffsetFlipbookStrength.floatValue = 0.2f;
            _VertOffsetFlipbookSpeed.floatValue = 8f;
            _VertOffsetFlipbookScale.vectorValue = new Vector4(3f,3f,0f,0f);
            _VertexOffsetMaskStrength.floatValue = 1f;
            _VertexOffsetMaskChannel.floatValue = 0f;
            _SubsurfaceTint.colorValue = Color.white;
            _SubsurfaceThreshold.floatValue = 0.4f;
            _SubsurfaceBrightness.floatValue = 10f;
            _SubsurfaceStrength.floatValue = 0f;
        }

        void ResetCaustics(){
            _CausticsShadowStrength.floatValue = 1f;
            _CausticsDisp.floatValue = 0.15f;
            _CausticsFlipbookDisp.floatValue = 0.15f;
            _CausticsDistortion.floatValue = 0.5f;
            _CausticsDistortionScale.floatValue = 0.2f;
            _CausticsDistortionSpeed.vectorValue = new Vector4(0.2f, -0.2f, 0f, 0f);
            _CausticsColor.colorValue = Color.white;
            _CausticsOpacity.floatValue = 1f;
            _CausticsPower.floatValue = 1f;
            _CausticsScale.floatValue = 1f;
            _CausticsFade.floatValue = 5f;
            _CausticsRotation.vectorValue = new Vector4(-20f, 0, 20f, 0);
            _CausticsFlipbookSpeed.floatValue = 16f;
        }

        void ResetFog(){
            _FogTint.colorValue = new Vector4(0.11f,0.26f,0.26f,1f);
            _FogPower.floatValue = 10f;
            _FogBrightness.floatValue = 1f;
        }

        void ResetFoam(){
            _FoamTexScale.vectorValue = new Vector4(6,6,0,0);
            _FoamTexScroll.vectorValue = new Vector4(0.1f,-0.1f,0,0);
            _FoamRoughness.floatValue = 0.5f;
            _FoamColor.colorValue = Color.white;
            _FoamPower.floatValue = 200f;
            _FoamEdgeStrength.floatValue = 1.5f;
            _FoamCrestStrength.floatValue = 1.5f;
            _FoamCrestThreshold.floatValue = 0.5f;
            _FoamNoiseTexScale.vectorValue = new Vector4(3f,3f,0,0);
            _FoamNoiseTexScroll.vectorValue = new Vector4(0f,0.1f,0f,0f);
            _FoamNoiseTexStrength.floatValue = 0f;
            _FoamNoiseTexCrestStrength.floatValue = 1.1f;
            _FoamDistortionStrength.floatValue = 0.1f;
            _FoamNormalStrength.floatValue = 4f;
            _FoamNormalToggle.floatValue = 0f;
        }

        void ResetReflSpec(){
            _Roughness.floatValue = 0f;
            _Metallic.floatValue = 0f;
            _Reflections.floatValue = 1f;
            _ReflStrength.floatValue = 1f;
            _Specular.floatValue = 1f;
            _SpecStrength.floatValue = 1f;
            _SSR.floatValue = 0f;
            _SSRStrength.floatValue = 1f;
            _EdgeFadeSSR.floatValue = 0.1f;
            _ReflTint.colorValue = Color.white;
            _SpecTint.colorValue = Color.white;
            _ReflCube.textureValue = null;
            _LightDir.vectorValue = new Vector4(0f,0.75f,1f,0f);
            _ReflCubeRotation.vectorValue = Vector4.zero;
            _DetailTextureMode.floatValue = 0f;
            _SSRHeight.floatValue = 0.2f;
            _MirrorNormalOffsetSwizzle.floatValue = 1f;
        }

        void ResetRain(){
            _RippleScale.floatValue = 40f;
            _RippleSpeed.floatValue = 10f;
            _RippleStr.floatValue = 1f;
            _RippleSize.floatValue = 6f;
            _RippleDensity.floatValue = 1.57079632679f;
        }

        void ResetEdgeFade(){
            _EdgeFadePower.floatValue = 300f;
            _EdgeFadeOffset.floatValue = 0.5f;
        }

        void ResetTess(){
            _TessMin.floatValue = 1f;
            _TessMax.floatValue = 9f;
            _TessDistMin.floatValue = 25f;
            _TessDistMax.floatValue = 50f;
        }

        void ResetEmission(){
            _EmissionColor.colorValue = Color.white;
            _EmissionMapScroll.vectorValue = Vector4.zero;
            _EmissionDistortionStrength.floatValue = 0f;
            _AudioLink.floatValue = 0f;
            _AudioLinkBand.floatValue = 0f;
            _AudioLinkStrength.floatValue = 1f;
        }

        void ResetAreaLit(){
            _AreaLitMask.textureValue = null;
            _AreaLitStrength.floatValue = 1f;
            _AreaLitRoughnessMult.floatValue = 1f;
            _LightMesh.textureValue = null;
            _LightTex0.textureValue = null;
            _LightTex1.textureValue = null;
            _LightTex2.textureValue = null;
            _LightTex3.textureValue = null;
            _OpaqueLights.floatValue = 1f;
        }

        void ResetRendering(Material mat){
            _TransparencyMode.floatValue = 2f;
            _StencilRef.floatValue = 65f;
            _DepthEffects.floatValue = 1f;
            _ZWrite.floatValue = 0f;
            _CullMode.floatValue = 0f;
            _TexCoordSpace.floatValue = 0f;
            _TexCoordSpaceSwizzle.floatValue = 1f;
            _GlobalTexCoordScaleUV.floatValue = 1f;
            _GlobalTexCoordScaleWorld.floatValue = 0.1f;
            _BicubicSampling.floatValue = 0f;
            _LightmapDistortion.floatValue = 0f;
            _FogContribution.floatValue = 0f;
            _BakeryMode.floatValue = 0f;
            _BAKERY_LMSPEC.floatValue = 0f;
            _BakeryLMSpecStrength.floatValue = 1f;
            _IndirectStrength.floatValue = 0.5f;
            SetBlendMode(mat);
        }

        void ClearDictionaries(){
            baseTabButtons.Clear();
            norm0TabButtons.Clear();
            norm1TabButtons.Clear();
            flowTabButtons.Clear();
            vertTabButtons.Clear();
            causticsTabButtons.Clear();
            fogTabButtons.Clear();
            foamTabButtons.Clear();
            edgeFadeTabButtons.Clear();
            reflSpecTabButtons.Clear();
            rainTabButtons.Clear();
            tessTabButtons.Clear();
            emissTabButtons.Clear();
            areaLitTabButtons.Clear();
            renderingTabButtons.Clear();
            ltcgiTabButtons.Clear();
        }
    }
}