using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.SceneManagement;

namespace X2Engine
{
    public class SkyEnvComponent : EnvironmentComponent
    {
        float timeline;
        float sunDirection;
        float sunEquator;
        float moonDirection;
        float moonEquator;
        //Color sunColor;
        //float sunIntensity;
        //Color charactorLightColor0;
        //float charactorLightIntensity0;
        //Color charactorLightColor1;
        //float charactorLightIntensity1;
        Vector4 sunDirSize;
        Vector4 moonDirSize;

        float[] nightFlags = new float[] {0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f };

        static readonly int sp_NightFlags = Shader.PropertyToID("_NightFlags");
        static readonly int sp_cameraLightColor = Shader.PropertyToID("_CameraLightColor");
        static readonly int sp_charLightColor = Shader.PropertyToID("_CharLightColor");
        static readonly int sp_x2m_SunDirSize = Shader.PropertyToID("x2m_SunDirSize");
        static readonly int sp_x2m_MoonDirSize = Shader.PropertyToID("x2m_MoonDirSize");
        static readonly int sp_cubeHDRInstruct = Shader.PropertyToID("_CubeSpecHDR");
        static readonly int sp_bakedLighterIntensity = Shader.PropertyToID("LighterGIStrength");
        static readonly int sp_bakedEnvGIIntensity = Shader.PropertyToID("EnvGIStrength");
        static readonly int sp_shadowStrength = Shader.PropertyToID("_ShadowStrength");
        static readonly int sp_GiantEnviromentLight = Shader.PropertyToID("_GiantEnviromentLight");

        //static readonly int sp_FrontColor = Shader.PropertyToID("_FrontColor");
        //static readonly int sp_BackColor = Shader.PropertyToID("_BackColor");
        //static readonly int sp_LeftColor= Shader.PropertyToID("_LeftColor");
        //static readonly int sp_RightColor = Shader.PropertyToID("_RightColor");
        //static readonly int sp_UpColor = Shader.PropertyToID("_UpColor");
        //static readonly int sp_DownColor = Shader.PropertyToID("_DownColor");

        //Material m_CubeSkyMat = null;

        //Material m_OldSkyBoxMat = null;

        //UnityEngine.Rendering.AmbientMode m_OldAmbientMode;

        //UnityEngine.Rendering.SphericalHarmonicsL2 m_OldAmbientProbe;

        //UnityEngine.Rendering.SphericalHarmonicsL2 m_AibientProbe;

        UnityEngine.Rendering.SphericalHarmonicsL2 m_TempAmbientProbe;

        static Vector4 m_CubeHDRInstruct = new Vector4(1, 1, 0, 0);

        //SkyLight m_SkyLight = new SkyLight();
        public override void OnInit()
        {
            InitCubeSkyMat();

            SetShaderUniform();

            SetShadowLighting();
        }

        public override void UpdateData()
        {
            if(Parent.profile && Parent.profile.sun.enable == true)
            {
                var sunProfile = Parent.profile.sun;
                bool dirDirty = false;
                if(timeline != sunProfile.timeline)
                { dirDirty = true; timeline = sunProfile.timeline; }

                if (sunDirection != sunProfile.sunDirection)
                { dirDirty = true; sunDirection = sunProfile.sunDirection; }
                if (sunEquator != sunProfile.sunEquator)
                { dirDirty = true; sunEquator = sunProfile.sunEquator; }

                if (moonDirection != sunProfile.moonDirection)
                { dirDirty = true; moonDirection = sunProfile.moonDirection; }
                if (moonEquator != sunProfile.moonEquator)
                { dirDirty = true; moonEquator = sunProfile.moonEquator; }

                SetShaderUniform();

                if (dirDirty)
                    Broadcast(EnvironmentEvent.EnvLightDirDirty);
  
                ResetMapSunDir();

            }
            else
            {
                Shader.SetGlobalVector(sp_GiantEnviromentLight, new Vector4(1, 1, 1, 1));
                Shader.SetGlobalFloat(sp_bakedEnvGIIntensity, 1.0f);
            }
        }
        // lock the mainLighting dir, only when in sceneEditor baking scene
        private void  ResetMapSunDir()
        {
            //Scene scene = SceneManager.GetActiveScene();
            //if(scene != null)
            //{
            //    if(scene.name.IndexOf("world_baked") >= 0 || scene.name.IndexOf("World_JZ") >= 0 )
            //    {
            //        //todo @horatio
            //        //sunDirection = 267.0f;
            //        //sunEquator = 148.0f;
            //        if(Parent && Parent.m_sun)
            //        {
            //            Parent.m_sun.transform.rotation = Quaternion.Euler(30.0f, 301.2f, 107.4f);
            //        }
            //        return ;
            //    }
            //}
            //if (MainLightShadowProxy.Instance && MainLightShadowProxy.Instance.IsLockSunDir)
            //{
            //    Parent.m_sun.transform.rotation = MainLightShadowProxy.Instance.mainLightShadowLighting.transform.rotation;
            //}
        }

        private void SetShadowLighting()
        {
            if (Parent && Parent.m_sun)
            {
                //if (MainLightShadowProxy.Instance)
                //{
                //    MainLightShadowProxy.Instance.sun = Parent.m_sun;
                //}
            }
        }

#if !SCENE_EDITOR
        private float m_lastUpdateTime = 0;
#endif
        void UpdateNightFlags(float timeline)
        {
#if SCENE_EDITOR
            bool daytime = timeline >= 6 && timeline < 18;
            for (int i = 0; i < nightFlags.Length; i++)
                nightFlags[i] = daytime ? 0 : 1;
#else
            float fTime = Time.time;
            if (fTime - m_lastUpdateTime < 0.3)
                return;
            m_lastUpdateTime = fTime;

            for (int i = nightFlags.Length - 1; i > 0; i--)
                nightFlags[i] = nightFlags[i - 1];
            bool daytime = timeline >= 6 && timeline < 18;
            nightFlags[0] = daytime ? 0 : 1;
#endif
        }

        void SetShaderUniform()
        {
            if(!Parent.profile)
                return;
            var sunProfile = Parent.profile.sun;
            float flashLighting = Parent.GetFlashLightIntensity();
            Color flashLightingClr = new Color(flashLighting, flashLighting, flashLighting, 0);

            Shader.SetGlobalColor(sp_charLightColor, sunProfile.charactorLightColor0 * (sunProfile.charactorLightIntensity0 + flashLighting));
            Shader.SetGlobalColor(sp_cameraLightColor, sunProfile.charactorLightColor1 * sunProfile.charactorLightIntensity1);
            Shader.SetGlobalFloat(sp_bakedLighterIntensity, sunProfile.bakedLighterStength);
            Shader.SetGlobalFloat(sp_bakedEnvGIIntensity, sunProfile.bakedEnvGIStrength);
            Shader.SetGlobalFloat(sp_shadowStrength, sunProfile.shadowStrength);

            UpdateNightFlags(sunProfile.timeline);
            Shader.SetGlobalFloatArray(sp_NightFlags, nightFlags);

            float t = sunProfile.timeline * 360.0f / 24.0f - 90.0f;
            float sunDirection = sunProfile.sunDirection - 90.0f;
            float sunEquator = sunProfile.sunEquator - 90.0f;
            Quaternion sunRot = Quaternion.Euler(0f, sunDirection, sunEquator) * Quaternion.Euler(t, 0f, 0f);
            // 太阳方位角度是否固定
            //bool lockSunDirectionDir = MainLightShadowProxy.Instance != null && MainLightShadowProxy.Instance.mainLightShadowLighting != null;
            //if (lockSunDirectionDir)
            //{
            //    Quaternion shadowDir = MainLightShadowProxy.Instance.mainLightShadowLighting.transform.rotation;
            //    sunRot = Quaternion.Euler(t, t < 90 ? shadowDir.eulerAngles.y : 180f+shadowDir.eulerAngles.y, 0);
            //}

            //Quaternion moonRot = Quaternion.Euler(90f - Parent.profile.nightSky.moonZenithAngle, Parent.profile.nightSky.moonDir, 0);
            float t2 = sunProfile.timeline * 360.0f / 24.0f + 90.0f;
            Quaternion moonRot = Quaternion.Euler(0f, sunProfile.moonDirection - 90.0f, sunProfile.moonEquator - 90.0f) * Quaternion.Euler(t2, 0f, 0f);
            var sun = Parent.m_sun;
            //var charLight = Parent.m_charLight;
            //var lensFlareLight = Parent.m_lensFlareLight;
            if (sun/* && charLight*/)
            {
                if (!Parent.m_customLightDir)
                {
                    // 太阳光角度限定sp_mainLightDir
                    Quaternion lightRot;
                    if (t >= 0 && t <= 180)
                        lightRot = sunRot;
                    else
                    {
                        //if (lockSunDirectionDir)
                        //    lightRot = MainLightShadowProxy.Instance.mainLightShadowLighting.transform.rotation;
                        //else
                            lightRot = moonRot;
                    }

                    //Vector3 lightDir = lightRot * Vector3.back;
                    //Shader.SetGlobalVector(sp_mainLightDir, lightDir);
                    //if (lensFlareLight)
                    //    lensFlareLight.transform.rotation = lightRot;

                    // 太阳光角度限定sp_mainLightDir
                    //Quaternion fakeLightRot = lightRot;
                    //Vector3 eulerAngles = fakeLightRot.eulerAngles;
                    //eulerAngles.x = Mathf.Clamp(eulerAngles.x, 30f, 150f);
                    //fakeLightRot.eulerAngles = eulerAngles;

                    //charLight.transform.rotation = sun.transform.rotation = fakeLightRot;
                    sun.transform.rotation = lightRot;
                }
                


                sun.color = sunProfile.sunColor;
                sun.bounceIntensity = sunProfile.sunInDirectionIntensity;
                sun.intensity = sunProfile.sunIntensity + flashLighting;
                sun.shadowStrength = sunProfile.shadowStrength;

            }
  			//if (Parent.m_fakeSun)
            //{
            //    Parent.m_fakeSun.transform.rotation = fakeSunRot;
            //}
 
            //var lensFlare = Parent.m_lensFlare;
            //if (lensFlare)
            //{
            //    //if (flare != sunProfile.flare)
            //    //{
            //    //    flare = sunProfile.flare;
            //    //    lensFlare.flare = flare;
            //    //}
            //    lensFlare.flare = sunProfile.flare;
            //    lensFlare.color = sunProfile.flareColor;
            //    lensFlare.brightness = sunProfile.flareBrightness;
            //    lensFlare.fadeSpeed = sunProfile.flareFadeSpeed;
            //}

            Vector3 sunDir = sunRot * Vector3.back;
            Parent.SunDirection = sunDir;
            sunDirSize = new Vector4(sunDir.x, sunDir.y, sunDir.z, /*skyProfile.sunSize*/1);
            Shader.SetGlobalVector(sp_x2m_SunDirSize, sunDirSize);
            Vector3 moonDir = moonRot * Vector3.back;
            Parent.MoonDirection = moonDir;
            moonDirSize = new Vector4(moonDir.x, moonDir.y, moonDir.z, /*8 / Mathf.Max(0.0001f, nightSkyProfile.moonSize)*/1);
            Shader.SetGlobalVector(sp_x2m_MoonDirSize, moonDirSize);

            Shader.SetGlobalVector(sp_GiantEnviromentLight, sun.color);

            // AmbientSettings
            var ambientProfile = Parent.profile.ambient;
            //UnityEngine.RenderSettings.ambientMode = ambientProfile.source;
            var ambientProfileOfCharacter = Parent.profile.ambientCharacter;
            //CorrectEnvColor(ref ambientProfile);
            //CorrectEnvColor(ref ambientProfileOfCharacter);

            if (!ambientProfileOfCharacter.bUseThisSH)
                ResetTempCharacterAmbient(ref ambientProfileOfCharacter, ref ambientProfile);

            UnityEngine.RenderSettings.ambientSkyColor = ambientProfile.skyColor + flashLightingClr;
            UnityEngine.RenderSettings.ambientEquatorColor = ambientProfile.equatorColor + flashLightingClr;
            UnityEngine.RenderSettings.ambientGroundColor = ambientProfile.groundColor + flashLightingClr;
            UnityEngine.RenderSettings.ambientIntensity = ambientProfile.intensity + flashLighting;
            UnityEngine.RenderSettings.reflectionIntensity = ambientProfile.reflectionIntensity;
            switch (ambientProfile.source)
            {
                case AmbientSettings.kAmbientSourceType.Skybox:
                    UnityEngine.RenderSettings.ambientMode = UnityEngine.Rendering.AmbientMode.Skybox;
                    break;
                case AmbientSettings.kAmbientSourceType.Trilight:
                    UnityEngine.RenderSettings.ambientMode = UnityEngine.Rendering.AmbientMode.Trilight;
                    break;
                case AmbientSettings.kAmbientSourceType.Flat:
                    UnityEngine.RenderSettings.ambientMode = UnityEngine.Rendering.AmbientMode.Flat;
                    break;
                case AmbientSettings.kAmbientSourceType.CubeSkyColor:
                    UnityEngine.RenderSettings.ambientMode = UnityEngine.Rendering.AmbientMode.Custom;
                    break;
                default:
                    break;
            }

            ResetAmbientSettting(ref ambientProfile, flashLightingClr);

            ResetAmbientSetttingOfCharacter(ref ambientProfileOfCharacter, flashLightingClr);
        }

        void CorrectEnvColor(ref AmbientSettings ambientProfile)
        {
            //saterate the sh ot 0 ~1
            if (ambientProfile.source == AmbientSettings.kAmbientSourceType.Flat)
            {
                ambientProfile.skyColor.r = ambientProfile.skyColor.r > 1.0 ? 1.0f : ambientProfile.skyColor.r;
                ambientProfile.skyColor.b = ambientProfile.skyColor.b > 1.0 ? 1.0f : ambientProfile.skyColor.b;
                ambientProfile.skyColor.g = ambientProfile.skyColor.g > 1.0 ? 1.0f : ambientProfile.skyColor.g;
                ambientProfile.skyColor.a = ambientProfile.skyColor.a > 1.0 ? 1.0f : ambientProfile.skyColor.a;
            }
        }

        void SetLightSettings(ref SunSettings sunProfile)
        {

        }

        private void ResetTempCharacterAmbient(ref AmbientSettings characterAmbient, ref AmbientSettings ambientProfiler)
        {
            characterAmbient.source = ambientProfiler.source;
            characterAmbient.skyColor = ambientProfiler.skyColor;
            characterAmbient.equatorColor = ambientProfiler.equatorColor;
            characterAmbient.groundColor = ambientProfiler.groundColor;
            characterAmbient.leftColor = ambientProfiler.leftColor;
            characterAmbient.rightColor = ambientProfiler.rightColor;
            characterAmbient.frontColor = ambientProfiler.frontColor;
            characterAmbient.backColor = ambientProfiler.backColor;
            if(ambientProfiler.bCubeSkyDirty)
                characterAmbient.bCubeSkyDirty = ambientProfiler.bCubeSkyDirty;
        }

        private void ResetAmbientSettting(ref AmbientSettings ambientProfile, Color flashLightingClr)
        {
#if UNITY_ANDROID || UNITY_IOS
            //linear color and DLDR decode
           m_CubeHDRInstruct.x = Mathf.Pow(ambientProfile.reflectionIntensity * 2.0f, 2.2f);
            Shader.SetGlobalVector(sp_cubeHDRInstruct, m_CubeHDRInstruct);
#else
            //linear color and RGBM decode
            m_CubeHDRInstruct.x = Mathf.Pow(ambientProfile.reflectionIntensity, 2.2f);
            Shader.SetGlobalVector(sp_cubeHDRInstruct, m_CubeHDRInstruct);
#endif

//#if SCENE_EDITOR
            if (ambientProfile.bakeSkyMat != null)
                RenderSettings.skybox = ambientProfile.bakeSkyMat;
//#endif

            if (ambientProfile.source == AmbientSettings.kAmbientSourceType.Skybox)
                {
                //#if SCENE_EDITOR
                //SetSHToAmbientCharacter();
                UpdateAmbientSHOfSceneFromSky(flashLightingClr);
//#else
//                    if (EnvironmentSystem.instance.editorMode)
//                    {
//                        //SetSHToAmbientCharacter();
//                        UpdateAmbientSHOfSceneFromSky(flashLightingClr);
//                    }
//                    else
//                    {
//                    // UpdateAmbientSHOfCharacter(ref ambientProfile, flashLightingClr);
//                        UpdateAmbientSHOfSceneFromSky(flashLightingClr);
//                    }

                //#endif
            }
                else
                {
                    if (ambientProfile.source == AmbientSettings.kAmbientSourceType.Trilight)
                    {
                        ambientProfile.rightColor = ambientProfile.leftColor = ambientProfile.frontColor = ambientProfile.backColor = ambientProfile.equatorColor;
                    }
                    else if (ambientProfile.source == AmbientSettings.kAmbientSourceType.Flat)
                    {
                        ambientProfile.rightColor = ambientProfile.leftColor = ambientProfile.frontColor = ambientProfile.backColor = ambientProfile.equatorColor
                            = ambientProfile.groundColor = ambientProfile.skyColor;
                    }
                //#if SCENE_EDITOR
                //UnityEngine.RenderSettings.ambientMode = UnityEngine.Rendering.AmbientMode.Custom;
                BakeCubeSkyMatSHOfScene(ref ambientProfile, flashLightingClr);
                //#else
                //                if (EnvironmentSystem.instance.editorMode)
                //                    {
                //                        //UnityEngine.RenderSettings.ambientMode = UnityEngine.Rendering.AmbientMode.Custom;

                //                        BakeCubeSkyMatSHOfScene(ref ambientProfile, flashLightingClr);
                //                    }
                //                    else
                //                    {
                //                        UpdateAmbientSHOfScene(ref ambientProfile, flashLightingClr);
                //                    }

                //#endif
            }

        }

        private void ResetAmbientSetttingOfCharacter(ref AmbientSettings ambientProfile, Color flashLightingClr)
        {
            if(ambientProfile.source == AmbientSettings.kAmbientSourceType.Skybox)
            {
//#if SCENE_EDITOR
                //SetSHToAmbientCharacter();
                UpdateAmbientSHOfCharacterFromSky(flashLightingClr);

//#else
//                if (EnvironmentSystem.instance.editorMode)
//                {
//                    //SetSHToAmbientCharacter();
//                   UpdateAmbientSHOfCharacterFromSky(flashLightingClr);
//                }
//                else
//                {
//                   // UpdateAmbientSHOfCharacter(ref ambientProfile, flashLightingClr);
//                     UpdateAmbientSHOfCharacterFromSky(flashLightingClr);
//                }

//#endif
            }
            else
            {
                if(ambientProfile.source == AmbientSettings.kAmbientSourceType.Trilight)
                {
                    ambientProfile.rightColor = ambientProfile.leftColor = ambientProfile.frontColor = ambientProfile.backColor = ambientProfile.equatorColor;
                }
                else if (ambientProfile.source == AmbientSettings.kAmbientSourceType.Flat)
                {
                    ambientProfile.rightColor = ambientProfile.leftColor = ambientProfile.frontColor = ambientProfile.backColor = ambientProfile.equatorColor
                        = ambientProfile.groundColor = ambientProfile.skyColor;
                }
//#if SCENE_EDITOR
                 //UnityEngine.RenderSettings.ambientMode = UnityEngine.Rendering.AmbientMode.Custom;

                 BakeCubeSkyMatSHOfCharacter(ref ambientProfile, flashLightingClr);

//#else
//                if (EnvironmentSystem.instance.editorMode)
//                {
//                    //UnityEngine.RenderSettings.ambientMode = UnityEngine.Rendering.AmbientMode.Custom;

//                    BakeCubeSkyMatSHOfCharacter(ref ambientProfile, flashLightingClr);

//                }
//                else
//                {
//                    UpdateAmbientSHOfCharacter(ref ambientProfile, flashLightingClr);
//                }

//#endif
            }

        }

        public static Color GammaToLinear(Color sRGB)
        {
            return new Color(Mathf.GammaToLinearSpace(sRGB.r), Mathf.GammaToLinearSpace(sRGB.g), Mathf.GammaToLinearSpace(sRGB.b), Mathf.GammaToLinearSpace(sRGB.a));
        }

        private void UpdateAmbientSH(ref AmbientSettings ambientProfile, Color flashLightingClr)
        {
            if (ambientProfile.interLightProbe != null)
            {
                RenderSettings.ambientMode = UnityEngine.Rendering.AmbientMode.Custom;

                m_TempAmbientProbe = ambientProfile.interLightProbe.SHL2;
               // m_TempAmbientProbe.AddAmbientLight(flashLightingClr);
                RenderSettings.ambientProbe = m_TempAmbientProbe;
            }
        }
        /// <summary>
        /// Init SkyBox material of 6 side for cubemap ambient
        /// </summary>
        /// <returns></returns>
        private void InitCubeSkyMat()
        {
            //if(m_CubeSkyMat == null)
            //{
            //    Shader skyBoxShader = X2Interface.ResourceHelper.LoadShaderSync("Assets/Asset/shaders/Sky&Fog/", "AmbientSkyBox") as Shader;
            //    m_CubeSkyMat = new Material(skyBoxShader);
            //    if (Parent != null && Parent.profile != null)
            //        Parent.profile.ambient.bCubeSkyDirty = true;
            //}
            if (Parent != null && Parent.profile != null)
                Parent.profile.ambient.bCubeSkyDirty = true;

        }

        //private void BakeCubeSkyMatSH(ref AmbientSettings ambientProfile, Color flashLightingClr)
        //{
        //    if (!ambientProfile.bCubeSkyDirty)
        //        return;

        //    ambientProfile.bCubeSkyDirty = false;         
        //   // X2Interface.LogHelper.Log("x2m: BakeCubeSkyMatSH !!");

        //    if (m_CubeSkyMat != null)
        //    {
        //        UpdateCubeSkyBox(ref ambientProfile);

        //        //we need to call updateAmbientSH of unity
        //        DynamicGI.UpdateEnvironment();

        //        GiveBackAmbientSky();

        //        Parent.sharedProfile.ambient.ambientSH.InitData();
        //        Parent.sharedProfile.ambient.ambientSH.SetData(RenderSettings.ambientProbe);
        //        Parent.sharedProfile.ambient.SetLightProbeFromData();
        //    }
        //}

        private void SetSHToAmbientCharacter(ref UnityEngine.Rendering.SphericalHarmonicsL2 sh)
        {
            Parent.sharedProfile.ambientCharacter.ambientSH.InitData();
            Parent.sharedProfile.ambientCharacter.ambientSH.SetData(sh);
            Parent.sharedProfile.ambientCharacter.SetLightProbeFromData();

          
            SkyLight.Instance.SetupToShader(ref sh);
        }

        private void SetSHToAmbientScene(ref UnityEngine.Rendering.SphericalHarmonicsL2 sh, bool bCorrectSH = false)
        {
            if (bCorrectSH)
                sh *= 0.6f;
            Parent.sharedProfile.ambient.ambientSH.InitData();
            Parent.sharedProfile.ambient.ambientSH.SetData(sh);
            Parent.sharedProfile.ambient.SetLightProbeFromData();


            SkyLight.Instance.SetupToShader(ref sh, false);
        }

        //private void UpdateCubeSkyBox(ref AmbientSettings ambientProfile)
        //{
        //    m_OldAmbientMode = UnityEngine.RenderSettings.ambientMode;
        //    m_OldAmbientProbe = RenderSettings.ambientProbe;
        //    UnityEngine.RenderSettings.ambientMode = UnityEngine.Rendering.AmbientMode.Skybox;
        //    if (m_CubeSkyMat != null)
        //    {
        //        m_CubeSkyMat.SetColor(sp_FrontColor, ambientProfile.frontColor  );
        //        m_CubeSkyMat.SetColor(sp_BackColor, ambientProfile.backColor);
        //        m_CubeSkyMat.SetColor(sp_LeftColor, ambientProfile.leftColor);
        //        m_CubeSkyMat.SetColor(sp_RightColor, ambientProfile.rightColor);
        //        m_CubeSkyMat.SetColor(sp_UpColor, ambientProfile.skyColor);
        //        m_CubeSkyMat.SetColor(sp_DownColor, ambientProfile.groundColor);

        //        m_OldSkyBoxMat = RenderSettings.skybox;
        //        RenderSettings.skybox = m_CubeSkyMat;
        //        //we need to call updateAmbientSH of unity
        //        //m_AibientProbe = RenderSettings.ambientProbe;
        //    }
        //}

        //to bake enlighten GI
        //        private void BakeCubeSkyGI(ref AmbientSettings ambientProfile, Color flashLightingClr)
        //        {
        //            if (!ambientProfile.bToBakeGI)
        //                return;

        //            ambientProfile.bToBakeGI = false;

        //#if UNITY_EDITOR
        //            //X2Interface.LogHelper.Log("x2m: BakeCubeSkyGI !!");

        //            if (m_CubeSkyMat != null)
        //            {
        //                //UpdateCubeSkyBox(ref ambientProfile, flashLightingClr);

        //                m_AibientProbe = RenderSettings.ambientProbe;
        //                UnityEditor.Lightmapping.bakeCompleted += OnBakGIEnd;
        //                UnityEditor.Lightmapping.BakeAsync();
        //            }
        //#endif
        //        }

        private void BakeCubeSkyMatSHOfCharacter(ref AmbientSettings ambientProfile, Color flashLightingClr)
        {
            if (!ambientProfile.bCubeSkyDirty)
                return;

            ambientProfile.bCubeSkyDirty = false;

            // X2Interface.LogHelper.Log("x2m: BakeCubeSkyMatSH !!");

            SkyLight.Instance.BakeSkyColorTOSH(ref ambientProfile, out m_TempAmbientProbe);

            SetSHToAmbientCharacter(ref m_TempAmbientProbe);

            //if (m_CubeSkyMat != null)
            //{
            //    UpdateCubeSkyBox(ref ambientProfile);

            //    //we need to call updateAmbientSH of unity
            //    DynamicGI.UpdateEnvironment();
            
            //    SetSHToAmbientCharacter(ref m_TempAmbientProbe);

            //    GiveBackAmbientSky();
            //}
        }

        private void BakeCubeSkyMatSHOfScene(ref AmbientSettings ambientProfile, Color flashLightingClr)
        {
            if (!ambientProfile.bCubeSkyDirty)
                return;

            ambientProfile.bCubeSkyDirty = false;

            // X2Interface.LogHelper.Log("x2m: BakeCubeSkyMatSH !!");
            SkyLight.Instance.BakeSkyColorTOSH(ref ambientProfile, out m_TempAmbientProbe);

            bool bCorrectSH = false;
            if (ambientProfile.source == AmbientSettings.kAmbientSourceType.Flat)
            {
                if (ambientProfile.skyColor.maxColorComponent > 1.8f)
                    bCorrectSH = true;
            }
            SetSHToAmbientScene(ref m_TempAmbientProbe, bCorrectSH);

            //if (m_CubeSkyMat != null)
            //{
            //    UpdateCubeSkyBox(ref ambientProfile);

            //    //we need to call updateAmbientSH of unity
            //    DynamicGI.UpdateEnvironment();

            //    bool bCorrectSH = false;
            //    if(ambientProfile.source == AmbientSettings.kAmbientSourceType.Flat)
            //    {
            //        if (ambientProfile.skyColor.maxColorComponent > 1.8f)
            //            bCorrectSH = true;
            //    }
            //    SetSHToAmbientScene(bCorrectSH);

            //    GiveBackAmbientSky();
            //}
        }

        private void UpdateAmbientSHOfCharacter(ref AmbientSettings ambientProfile, Color flashLightingClr)
        {
           
            if (ambientProfile.interLightProbe != null)
            {
                //RenderSettings.ambientMode = UnityEngine.Rendering.AmbientMode.Custom;

                m_TempAmbientProbe = ambientProfile.interLightProbe.SHL2;
                //m_TempAmbientProbe.AddAmbientLight(flashLightingClr);

                SkyLight.Instance.SetupToShader(ref m_TempAmbientProbe);
            }
        }

        private void UpdateAmbientSHOfScene(ref AmbientSettings ambientProfile, Color flashLightingClr)
        {

            if (ambientProfile.interLightProbe != null)
            {
                //RenderSettings.ambientMode = UnityEngine.Rendering.AmbientMode.Custom;

                m_TempAmbientProbe = ambientProfile.interLightProbe.SHL2;
                //m_TempAmbientProbe.AddAmbientLight(flashLightingClr);

                SkyLight.Instance.SetupToShader(ref m_TempAmbientProbe, false);
            }
        }

        private void UpdateAmbientSHOfCharacterFromSky( Color flashLightingClr)
        {

            m_TempAmbientProbe = RenderSettings.ambientProbe;
            //m_TempAmbientProbe.AddAmbientLight(flashLightingClr);

            m_TempAmbientProbe *= RenderSettings.ambientIntensity;

            SkyLight.Instance.SetupToShader(ref m_TempAmbientProbe);
        }



        private void UpdateAmbientSHOfSceneFromSky(Color flashLightingClr)
        {
            m_TempAmbientProbe = RenderSettings.ambientProbe;
            //m_TempAmbientProbe.AddAmbientLight(flashLightingClr);

            m_TempAmbientProbe *= RenderSettings.ambientIntensity;

            SkyLight.Instance.SetupToShader(ref m_TempAmbientProbe, false);
        }

//#if UNITY_EDITOR
//        public void OnBakGIEnd()
//        {
//            RenderSettings.ambientProbe = m_AibientProbe;
//            UnityEditor.Lightmapping.bakeCompleted -= OnBakGIEnd;

//            //GiveBackAmbientSky();
//            //GiveBackAmbientSky();

//        }
//#endif


        //private void GiveBackAmbientSky()
        //{
        //    //we must set the custom mode first,otherwise the SH will be overwrited by unity
        //    RenderSettings.ambientMode = m_OldAmbientMode;
        //    RenderSettings.skybox = m_OldSkyBoxMat;
        //    m_OldSkyBoxMat = null;
        //    RenderSettings.ambientProbe = m_OldAmbientProbe;

        //    //RenderSettings.ambientProbe = m_AibientProbe;
        //}

        float NightFade()
        {
            return Mathf.Pow(NightTimeBrightness(), 4);
        }

        public float MoonFade()
        {
            return (moonDirSize.y > 0.0) ? Mathf.Max(Mathf.Clamp01((moonDirSize.y - 0.1f) * Mathf.PI) * NightTimeBrightness() - DayTimeBrightness(), 0f) : 0f;
        }

        float NightTimeBrightness()
        {
            return 1 - DayTimeBrightness();
        }

        public float DayTimeBrightness()
        {
            // DayTime : Based on Bruneton's uMuS Linear function ( modified : calculate at ground/sea level only)
            return Mathf.Clamp01(Mathf.Max(sunDirSize.y + 0.2f, 0.0f) / 1.2f);
        }

    }

    public class SkyboxComponent : EnvironmentComponent
    {
        Material m_skyboxMat;
        static readonly int m_sp_Exposure = Shader.PropertyToID("_Exposure");
        static readonly int m_sp_Rotation = Shader.PropertyToID("_Rotation");
        static readonly int m_sp_Blend = Shader.PropertyToID("_Blend");
        static readonly int m_sp_Tex = Shader.PropertyToID("_MainTex");
        static readonly int m_sp_PrevTex = Shader.PropertyToID("_PrevTex");
        static readonly int m_sp_PrevRotation = Shader.PropertyToID("_PrevRotation");
        static readonly int m_sp_isFog = Shader.PropertyToID("_isFog");

        public override void OnInit()
        {
            m_skyboxMat = new Material( Parent.m_skyMaterial);

        }

        public override void UpdateData()
        {
            if(Parent.profile)
            {
                var profile = Parent.profile.skybox;
                var prevProfile = Parent.profile.prevSkybox;

                var cam = CameraCache.main;
                if(cam)
                {
                    if(profile.enable)
                        cam.clearFlags = CameraClearFlags.Skybox;
                    else
                        cam.clearFlags = CameraClearFlags.SolidColor;
                }

                if(profile.enable)
                {

                    if (Parent.m_skyMaterial != null)
                    {
                        if(m_skyboxMat == null)
                            m_skyboxMat = new Material(Parent.m_skyMaterial);
# if UNITY_EDITOR
                        UnityEngine.Profiling.Profiler.BeginSample("Editor_Code_CopyMaterial");
                        if (m_skyboxMat.shader.name != Parent.m_skyMaterial.shader.name)
                        {
                            m_skyboxMat = new Material(Parent.m_skyMaterial);
                        }

                        m_skyboxMat.CopyPropertiesFromMaterial(Parent.m_skyMaterial);
                        UnityEngine.Profiling.Profiler.EndSample();
#endif
                    }

                    if (m_skyboxMat != null)
                    {
                        m_skyboxMat.SetFloat(m_sp_Exposure, profile.exposure);
                        m_skyboxMat.SetFloat(m_sp_Rotation, profile.rotation);
                        m_skyboxMat.SetFloat(m_sp_Blend, profile.Blend);
                        //m_skyboxMat.SetTexture(m_sp_Tex, profile.texture);
                        m_skyboxMat.SetTexture(m_sp_Tex, Parent.profile.skybox.SkyTexture.Texture);
                        m_skyboxMat.SetTexture(m_sp_PrevTex, Parent.profile.prevSkybox.SkyTexture.Texture);
                        m_skyboxMat.SetFloat(m_sp_PrevRotation, prevProfile.rotation);
                        m_skyboxMat.SetFloat(m_sp_isFog, profile.isFog ? 1 : 0);
                        RenderSettings.skybox = m_skyboxMat;
                    }
// #if UNITY_EDITOR
//                     UnityEngine.Profiling.Profiler.BeginSample("Editor_Code_DynamicGI.UpdateEnvironment()");
//                     DynamicGI.UpdateEnvironment();
//                     UnityEngine.Profiling.Profiler.EndSample();
// #endif
                }
            }
            
        }

    }

    public class VolumetricFogEnvComponent : EnvironmentComponent
    {
        static readonly int sp_USE_VOLUMETRIC_FOG = Shader.PropertyToID("USE_VOLUMETRIC_FOG");

        public override void OnInit()
        {
        }

        public override void OnDestory()
        {
            Shader.SetGlobalFloat(sp_USE_VOLUMETRIC_FOG, 0);
            
        }


        public override void UpdateData()
        {
            if (Parent == null || Parent.profile == null)
            {
                Shader.SetGlobalFloat(sp_USE_VOLUMETRIC_FOG, 0);
                return;
            }

            //var forwardRender = UniversalRenderPipeline.asset.scriptableRenderer as ForwardRenderer;
            //if (forwardRender == null)
            //    return;
            
        }

        void SetShaderUniform()
        {
            //Shader.SetGlobalTexture("_g_volumetric_fog_texture", m_integratedTexture);
        }

    }


    public class Cloud2dEnvComponent : EnvironmentComponent
    {
        private static Mesh m_SkyDome;

        static readonly int m_sp_Attenuation = Shader.PropertyToID("_Attenuation");
        static readonly int m_sp_StepSize = Shader.PropertyToID("_StepSize");
        static readonly int m_sp_AlphaSaturation = Shader.PropertyToID("_AlphaSaturation");
        static readonly int m_sp_LightColorMultiplier = Shader.PropertyToID("_LightColorMultiplier");
        static readonly int m_sp_CloudAmbient = Shader.PropertyToID("_CloudAmbient");
        static readonly int m_sp_Mask = Shader.PropertyToID("_Mask");
        static readonly int m_sp_ScatterMultiplier = Shader.PropertyToID("_ScatterMultiplier");
        static readonly int m_sp_Mapping = Shader.PropertyToID("_Mapping");
        static readonly int m_sp_RotateSpeed = Shader.PropertyToID("_RotateSpeed");
        static readonly int m_sp_RotateAngle = Shader.PropertyToID("_RotateAngle");
        static readonly int m_sp_HeightOffset = Shader.PropertyToID("_HeightOffset");

        private float m_angle = 0;  // 0 - 180;
        Material m_material = null;

        public override void OnInit()
        {
            //var fogProfile = Parent.profile.fog;
            SetCloud2dShaderUniform();
        }

        void SetCloud2dShaderUniform()
        {
            if(Parent.profile)
            {
                var cloudProfile = Parent.profile.cloud2d;
                if (cloudProfile.cloudMaterial == null)
                    return;
                if(m_material == null)
                {
                    m_material = new Material(cloudProfile.cloudMaterial);
                }

#if UNITY_EDITOR
                UnityEngine.Profiling.Profiler.BeginSample("Editor_Code_CopyMaterial");
                if (m_material != null && string.Compare(m_material.shader.name, cloudProfile.cloudMaterial.shader.name) != 0)
                {
                    m_material = new Material(cloudProfile.cloudMaterial);
                }
                m_material.CopyPropertiesFromMaterial(cloudProfile.cloudMaterial);
                UnityEngine.Profiling.Profiler.EndSample();
#endif
      
                var material = m_material;
                PrepareCloudResource();

                //material.SetInt(m_sp_AmbientSource, (int)cloudProfile.ambientSource);
                material.SetFloat(m_sp_Attenuation, cloudProfile.attenuation);
                material.SetFloat(m_sp_StepSize, cloudProfile.stepSize);
                material.SetFloat(m_sp_AlphaSaturation, cloudProfile.alphaSaturation);
                material.SetFloat(m_sp_LightColorMultiplier, cloudProfile.lightColorMultiplier);
                material.SetColor(m_sp_CloudAmbient, cloudProfile.skyColor * cloudProfile.skyColorMultiplier);
                //material.SetFloat(m_sp_SkyColorMultiplier, cloudProfile.skyColorMultiplier);
                material.SetFloat(m_sp_Mask, cloudProfile.cloudsDensity);
                material.SetFloat(m_sp_ScatterMultiplier, cloudProfile.scatterMultiplier);
                material.SetInt(m_sp_Mapping, (int)cloudProfile.mappingMode);
                material.SetFloat(m_sp_RotateSpeed, cloudProfile.rotateSpeed);
                material.SetFloat(m_sp_HeightOffset, cloudProfile.heightOffset);

                m_angle += (cloudProfile.rotateSpeed * Time.deltaTime);
                material.SetFloat(m_sp_RotateAngle, m_angle);
         
            }
            
        }

        void PrepareCloudResource()
        {
            if (m_SkyDome)
                return;

            SkyDomeData uSD = new SkyDomeData();

            // Read the baked mesh data from "SkyDomeData.cs"
            m_SkyDome = new Mesh();
            m_SkyDome.name = "Generated SkyDome";
            m_SkyDome.vertices = uSD.vertices;
            m_SkyDome.triangles = uSD.triangles;
            m_SkyDome.uv = uSD.UV0;
            m_SkyDome.uv2 = uSD.UV2;
            m_SkyDome.normals = uSD.normals;
            m_SkyDome.tangents = uSD.tangents;
            m_SkyDome.bounds = new Bounds(Vector3.zero, Vector3.one * 1e7f);
            m_SkyDome.hideFlags = HideFlags.DontSave;

            //Parent.AddCloud2DGameObject(m_SkyDome, Parent.profile.cloud2d.cloudMaterial);
        }

        public override void UpdateData()
        {
            if(Parent.profile)
            {
                if(Parent.profile.cloud2d.enable == true)
                {

                
                    SetCloud2dShaderUniform();

                    var Clouds2DMaterial = m_material;// Parent.profile.cloud2d.cloudMaterial;
                    if(m_SkyDome == null || Clouds2DMaterial == null)
                        return;

                    Parent.SetCloud2DMeshAndMaterial(m_SkyDome, Clouds2DMaterial);

                    //Graphics.DrawMesh(m_SkyDome, Vector3.zero, Quaternion.identity, Clouds2DMaterial, (int)X2Interface.UserLayer.Layer_Default);
                }
                else
                {
                    Parent.SetCloud2DMeshAndMaterial(m_SkyDome, null);
                }
            }
          
        }
    }


    public class BlackHoleEnvComponent : EnvironmentComponent
    {
        static readonly int m_sp_Black_Hole_Enable = Shader.PropertyToID("_G_Black_Hole_Enable");
        static readonly int m_sp_Black_Hole_Center = Shader.PropertyToID("_G_Black_Hole_Center");
        static readonly int m_sp_Black_Hole_ScaleCoef = Shader.PropertyToID("_G_Black_Hole_ScaleCoef");
        static readonly int m_sp_Black_Hole_Intensity = Shader.PropertyToID("_G_Black_Hole_Intensity");
        static readonly int m_sp_Black_Hole_DarkIntensity = Shader.PropertyToID("_G_Black_Hole_DarkIntensity");

        public override void OnInit()
        {
            SetShaderUniform();
        }

        void SetShaderUniform()
        {
            if (Parent.profile)
            {
                var blackHoleSetting = Parent.profile.blackHoleSetting;
				if(CameraCache.main)
				{
					Vector3 pos = CameraCache.main.transform.position + CameraCache.main.transform.forward * blackHoleSetting.offsetDistance;
					Shader.SetGlobalVector(m_sp_Black_Hole_Center, new Vector4(pos.x, pos.y, pos.z, blackHoleSetting.radius));
				}
                Shader.SetGlobalFloat(m_sp_Black_Hole_ScaleCoef, blackHoleSetting.scaleCoef);
                Shader.SetGlobalFloat(m_sp_Black_Hole_Intensity, blackHoleSetting.intensity);
                Shader.SetGlobalFloat(m_sp_Black_Hole_DarkIntensity, blackHoleSetting.darkIntensity);
                Shader.SetGlobalInt(m_sp_Black_Hole_Enable, blackHoleSetting.enable ? 1 : 0);
            }

        }

      
        public override void UpdateData()
        {
            if (Parent.profile)
            {
                SetShaderUniform();

             
            }

        }
    }
}

