/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/

#include "LmbrCentral_precompiled.h"

#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Math/Quaternion.h>
#include <AzCore/Math/Vector3.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Asset/AssetManager.h>

#include <CryCommon/MathConversion.h>

#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>


#include <Cry_Math.h>
#include <I3DEngine.h>
#include <IStatObj.h>
#include <IEditor.h>
#include <Util/PathUtil.h>

#include "EditorLightComponent.h"
#include "EditorAreaLightComponent.h"
#include "EditorPointLightComponent.h"
#include "EditorEnvProbeComponent.h"
#include "EditorProjectorLightComponent.h"


namespace LmbrCentral
{
    // private statics
    IEditor* EditorLightComponent::m_editor = nullptr;
    IMaterialManager* EditorLightComponent::m_materialManager = nullptr;

    const char* EditorLightComponent::BUTTON_GENERATE = "Generate";
    const char* EditorLightComponent::BUTTON_ADDBOUNCE = "Add Bounce";

    // class converter. Convert EditorLightComponent to one of four above components
    namespace ClassConverters
    {
        static bool ConvertEditorLightComponent(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement)
        {
            // extract light type
            bool isFound = false;
            LightConfiguration::LightType lightType;

            int lightConfigIndex = classElement.FindElement(AZ_CRC("EditorLightConfiguration", 0xe4cf6af9));
            if (lightConfigIndex != -1)
            {
                AZ::SerializeContext::DataElementNode configElement = classElement.GetSubElement(lightConfigIndex);
                int baseClassIndex = configElement.FindElement(AZ_CRC("BaseClass1", 0xd4925735));
                if (baseClassIndex != -1)
                {
                    AZ::SerializeContext::DataElementNode baseConfig = configElement.GetSubElement(baseClassIndex);

                    int lightTypeIndex = baseConfig.FindElement(AZ_CRC("LightType", 0x9884ece8));
                    if (lightTypeIndex != -1)
                    {
                        AZ::SerializeContext::DataElementNode lightTypeNode = baseConfig.GetSubElement(lightTypeIndex);
                        lightTypeNode.GetData< LightConfiguration::LightType>(lightType);
                        isFound = true;
                    }
                }
            }

            if (!isFound)
            {
                return false;
            }

            //save all the sub elements for old EditorLightComponent
            typedef AZStd::vector<AZ::SerializeContext::DataElementNode> NodeArray;
            NodeArray subElements;
            for (int i = 0; i < classElement.GetNumSubElements(); i++)
            {
                subElements.push_back(classElement.GetSubElement(i));
            }

            // Convert to specific editor light component.
            bool result = true;
            switch (lightType)
            {
                case LightConfiguration::LightType::Point:
                    result = classElement.Convert<EditorPointLightComponent>(context);
                    break;
                case LightConfiguration::LightType::Area:
                    result = classElement.Convert<EditorAreaLightComponent>(context);
                    break;
                case LightConfiguration::LightType::Projector:
                    result = classElement.Convert<EditorProjectorLightComponent>(context);
                    break;
                case LightConfiguration::LightType::Probe:
                    result = classElement.Convert<EditorEnvProbeComponent>(context);
                    break;
                default:
                    result = false;
                    break;
            }

            if (result)
            {
                //add base class for the new specific light component
                int baseClass = classElement.AddElement<EditorLightComponent>(context, "BaseClass1");
                AZ::SerializeContext::DataElementNode& baseClassNode = classElement.GetSubElement(baseClass);

                //then add all the sub elements to this base class. it's because we didn't introduce any other new element to specific light components.
                for (int i = 0; i < subElements.size(); i++)
                {
                    baseClassNode.AddElement(subElements[i]);
                }
            }

            return result;
        }
    }

    AZ::ExportedComponent EditorLightComponent::ExportLightComponent(AZ::Component* thisComponent, const AZ::PlatformTagSet& /*platformTags*/)
    {
        EditorLightComponent* editorLightComponent = static_cast<EditorLightComponent*>(thisComponent);

        LightComponent* lightComponent = aznew LightComponent();
        lightComponent->m_configuration = editorLightComponent->m_configuration;

        return AZ::ExportedComponent(lightComponent, true);
    }

    void EditorLightComponent::Reflect(AZ::ReflectContext* context)
    {
        AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);

        EditorLightConfiguration::Reflect(context);

        if (serializeContext)
        {
            //any data using old UUID of EditorLightComponent will be send to converter
            serializeContext->ClassDeprecate("EditorLightComponent", "{33BB1CD4-6A33-46AA-87ED-8BBB40D94B0D}", &ClassConverters::ConvertEditorLightComponent);

            serializeContext->Class<EditorLightComponent, EditorComponentBase>()
                ->Version(2, &EditorLightComponent::VersionConverter)
                ->Field("EditorLightConfiguration", &EditorLightComponent::m_configuration)
                ->Field("CubemapRegen", &EditorLightComponent::m_cubemapRegen)
                ->Field("CubemapClear", &EditorLightComponent::m_cubemapClear)
                ->Field("ViewCubemap", &EditorLightComponent::m_viewCubemap)
                ->Field("UseCustomizedCubemap", &EditorLightComponent::m_useCustomizedCubemap)
            ;

            AZ::EditContext* editContext = serializeContext->GetEditContext();
            if (editContext)
            {
                editContext->Class<EditorLightComponent>(
                    "Light", "Attach lighting to an entity.")
                    ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
                        ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
                        ->Attribute(AZ::Edit::Attributes::NameLabelOverride, &EditorLightComponent::GetLightTypeText)
                    ->DataElement(0, &EditorLightComponent::m_configuration, "Settings", "Light configuration")
                        ->Attribute(AZ::Edit::Attributes::Visibility, AZ_CRC("PropertyVisibility_ShowChildrenOnly", 0xef428f20))

                    ->ClassElement(AZ::Edit::ClassElements::Group, "Cubemap generation")
                        ->Attribute(AZ::Edit::Attributes::Visibility, &EditorLightComponent::IsProbe)
                        ->Attribute(AZ::Edit::Attributes::AutoExpand, true)

                    ->DataElement(AZ::Edit::UIHandlers::CheckBox, &EditorLightComponent::m_useCustomizedCubemap, "Use customized cubemap", "Check to enable usage of customized cubemap")
                        ->Attribute(AZ::Edit::Attributes::Visibility, &EditorLightComponent::IsProbe)
                        ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorLightComponent::OnCustomizedCubemapChanged)

                    ->DataElement("Button", &EditorLightComponent::m_cubemapRegen, "Cubemap", "Generate the associated cubemap")
                        ->Attribute(AZ::Edit::Attributes::ButtonText, &EditorLightComponent::GetGenerateCubemapButtonName)
                        ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorLightComponent::GenerateCubemap)
                        ->Attribute(AZ::Edit::Attributes::Visibility, &EditorLightComponent::CanGenerateCubemap)

                    ->DataElement("Button", &EditorLightComponent::m_cubemapClear, "Cubemap", "Clear the associated cubemap.")
                        ->Attribute(AZ::Edit::Attributes::ButtonText, "Reset")
                        ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorLightComponent::ClearCubemap)
                        ->Attribute(AZ::Edit::Attributes::Visibility, &EditorLightComponent::CanGenerateCubemap)

                    ->DataElement(0, &EditorLightComponent::m_viewCubemap, "View cubemap", "Preview the cubemap in scene")
                        ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorLightComponent::OnViewCubemapChanged)
                        ->Attribute(AZ::Edit::Attributes::Visibility, &EditorLightComponent::IsProbe)
                ;
            }
        }

        AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
        if (behaviorContext)
        {
            // In the editor we reflect a separate EBus per light type (e.g. Point, Area, Projector). At run-time, we only use a single
            // "LightComponentBus" which is the intersection of the separate buses reflected here.

            // Point Light EBus reflection and VirtualProperties
            behaviorContext->EBus<EditorLightComponentRequestBus>("EditorPointLightComponentBus")
                ->Event("GetVisible", &EditorLightComponentRequestBus::Events::GetVisible)
                ->Event("SetVisible", &EditorLightComponentRequestBus::Events::SetVisible)
                ->VirtualProperty("Visible", "GetVisible", "SetVisible")
                ->Event("GetColor", &EditorLightComponentRequestBus::Events::GetColor)
                ->Event("SetColor", &EditorLightComponentRequestBus::Events::SetColor)
                ->VirtualProperty("Color", "GetColor", "SetColor")
                ->Event("GetDiffuseMultiplier", &EditorLightComponentRequestBus::Events::GetDiffuseMultiplier)
                ->Event("SetDiffuseMultiplier", &EditorLightComponentRequestBus::Events::SetDiffuseMultiplier)
                ->VirtualProperty("DiffuseMultiplier", "GetDiffuseMultiplier", "SetDiffuseMultiplier")
                ->Event("GetSpecularMultiplier", &EditorLightComponentRequestBus::Events::GetSpecularMultiplier)
                ->Event("SetSpecularMultiplier", &EditorLightComponentRequestBus::Events::SetSpecularMultiplier)
                ->VirtualProperty("SpecularMultiplier", "GetSpecularMultiplier", "SetSpecularMultiplier")
                ->Event("GetAmbient", &EditorLightComponentRequestBus::Events::GetAmbient)
                ->Event("SetAmbient", &EditorLightComponentRequestBus::Events::SetAmbient)
                ->VirtualProperty("Ambient", "GetAmbient", "SetAmbient")
                ->Event("GetPointMaxDistance", &EditorLightComponentRequestBus::Events::GetPointMaxDistance)
                ->Event("SetPointMaxDistance", &EditorLightComponentRequestBus::Events::SetPointMaxDistance)
                ->VirtualProperty("PointMaxDistance", "GetPointMaxDistance", "SetPointMaxDistance")
                ->Event("GetPointAttenuationBulbSize", &EditorLightComponentRequestBus::Events::GetPointAttenuationBulbSize)
                ->Event("SetPointAttenuationBulbSize", &EditorLightComponentRequestBus::Events::SetPointAttenuationBulbSize)
                ->VirtualProperty("PointAttenuationBulbSize", "GetPointAttenuationBulbSize", "SetPointAttenuationBulbSize")
                ->Event("GetAnimIndex", &EditorLightComponentRequestBus::Events::GetAnimIndex)
                ->Event("SetAnimIndex", &EditorLightComponentRequestBus::Events::SetAnimIndex)
                ->VirtualProperty("AnimIndex", "GetAnimIndex", "SetAnimIndex")
                ->Event("GetAnimSpeed", &EditorLightComponentRequestBus::Events::GetAnimSpeed)
                ->Event("SetAnimSpeed", &EditorLightComponentRequestBus::Events::SetAnimSpeed)
                ->VirtualProperty("AnimSpeed", "GetAnimSpeed", "SetAnimSpeed")
                ->Event("GetAnimPhase", &EditorLightComponentRequestBus::Events::GetAnimPhase)
                ->Event("SetAnimPhase", &EditorLightComponentRequestBus::Events::SetAnimPhase)
                ->VirtualProperty("AnimPhase", "GetAnimPhase", "SetAnimPhase")
                ;

            // Area Light EBus reflection and VirtualProperties
            behaviorContext->EBus<EditorLightComponentRequestBus>("EditorAreaLightComponentBus")
                ->Event("GetVisible", &EditorLightComponentRequestBus::Events::GetVisible)
                ->Event("SetVisible", &EditorLightComponentRequestBus::Events::SetVisible)
                ->VirtualProperty("Visible", "GetVisible", "SetVisible")
                ->Event("GetColor", &EditorLightComponentRequestBus::Events::GetColor)
                ->Event("SetColor", &EditorLightComponentRequestBus::Events::SetColor)
                ->VirtualProperty("Color", "GetColor", "SetColor")
                ->Event("GetDiffuseMultiplier", &EditorLightComponentRequestBus::Events::GetDiffuseMultiplier)
                ->Event("SetDiffuseMultiplier", &EditorLightComponentRequestBus::Events::SetDiffuseMultiplier)
                ->VirtualProperty("DiffuseMultiplier", "GetDiffuseMultiplier", "SetDiffuseMultiplier")
                ->Event("GetSpecularMultiplier", &EditorLightComponentRequestBus::Events::GetSpecularMultiplier)
                ->Event("SetSpecularMultiplier", &EditorLightComponentRequestBus::Events::SetSpecularMultiplier)
                ->VirtualProperty("SpecularMultiplier", "GetSpecularMultiplier", "SetSpecularMultiplier")
                ->Event("GetAmbient", &EditorLightComponentRequestBus::Events::GetAmbient)
                ->Event("SetAmbient", &EditorLightComponentRequestBus::Events::SetAmbient)
                ->VirtualProperty("Ambient", "GetAmbient", "SetAmbient")
                ->Event("GetAreaMaxDistance", &EditorLightComponentRequestBus::Events::GetAreaMaxDistance)
                ->Event("SetAreaMaxDistance", &EditorLightComponentRequestBus::Events::SetAreaMaxDistance)
                ->VirtualProperty("AreaMaxDistance", "GetAreaMaxDistance", "SetAreaMaxDistance")
                ->Event("GetAreaWidth", &EditorLightComponentRequestBus::Events::GetAreaWidth)
                ->Event("SetAreaWidth", &EditorLightComponentRequestBus::Events::SetAreaWidth)
                ->VirtualProperty("AreaWidth", "GetAreaWidth", "SetAreaWidth")
                ->Event("GetAreaHeight", &EditorLightComponentRequestBus::Events::GetAreaHeight)
                ->Event("SetAreaHeight", &EditorLightComponentRequestBus::Events::SetAreaHeight)
                ->VirtualProperty("AreaHeight", "GetAreaHeight", "SetAreaHeight")
                ->Event("GetAreaFOV", &LightComponentEditorRequestBus::Events::GetAreaFOV)
                ->Event("SetAreaFOV", &LightComponentEditorRequestBus::Events::SetAreaFOV)
                ->VirtualProperty("AreaFOV", "GetAreaFOV", "SetAreaFOV")
                ->Event("GetAnimIndex", &EditorLightComponentRequestBus::Events::GetAnimIndex)
                ->Event("SetAnimIndex", &EditorLightComponentRequestBus::Events::SetAnimIndex)
                ->VirtualProperty("AnimIndex", "GetAnimIndex", "SetAnimIndex")
                ->Event("GetAnimSpeed", &EditorLightComponentRequestBus::Events::GetAnimSpeed)
                ->Event("SetAnimSpeed", &EditorLightComponentRequestBus::Events::SetAnimSpeed)
                ->VirtualProperty("AnimSpeed", "GetAnimSpeed", "SetAnimSpeed")
                ->Event("GetAnimPhase", &EditorLightComponentRequestBus::Events::GetAnimPhase)
                ->Event("SetAnimPhase", &EditorLightComponentRequestBus::Events::SetAnimPhase)
                ->VirtualProperty("AnimPhase", "GetAnimPhase", "SetAnimPhase")
                ;

            // Projector Light Ebus reflection and VirtualProperties
            behaviorContext->EBus<EditorLightComponentRequestBus>("EditorProjectorLightComponentBus")
                ->Event("GetVisible", &EditorLightComponentRequestBus::Events::GetVisible)
                ->Event("SetVisible", &EditorLightComponentRequestBus::Events::SetVisible)
                ->VirtualProperty("Visible", "GetVisible", "SetVisible")
                ->Event("GetColor", &EditorLightComponentRequestBus::Events::GetColor)
                ->Event("SetColor", &EditorLightComponentRequestBus::Events::SetColor)
                ->VirtualProperty("Color", "GetColor", "SetColor")
                ->Event("GetDiffuseMultiplier", &EditorLightComponentRequestBus::Events::GetDiffuseMultiplier)
                ->Event("SetDiffuseMultiplier", &EditorLightComponentRequestBus::Events::SetDiffuseMultiplier)
                ->VirtualProperty("DiffuseMultiplier", "GetDiffuseMultiplier", "SetDiffuseMultiplier")
                ->Event("GetSpecularMultiplier", &EditorLightComponentRequestBus::Events::GetSpecularMultiplier)
                ->Event("SetSpecularMultiplier", &EditorLightComponentRequestBus::Events::SetSpecularMultiplier)
                ->VirtualProperty("SpecularMultiplier", "GetSpecularMultiplier", "SetSpecularMultiplier")
                ->Event("GetAmbient", &EditorLightComponentRequestBus::Events::GetAmbient)
                ->Event("SetAmbient", &EditorLightComponentRequestBus::Events::SetAmbient)
                ->VirtualProperty("Ambient", "GetAmbient", "SetAmbient")
                ->Event("GetProjectorMaxDistance", &EditorLightComponentRequestBus::Events::GetProjectorMaxDistance)
                ->Event("SetProjectorMaxDistance", &EditorLightComponentRequestBus::Events::SetProjectorMaxDistance)
                ->VirtualProperty("ProjectorMaxDistance", "GetProjectorMaxDistance", "SetProjectorMaxDistance")
                ->Event("GetProjectorAttenuationBulbSize", &EditorLightComponentRequestBus::Events::GetProjectorAttenuationBulbSize)
                ->Event("SetProjectorAttenuationBulbSize", &EditorLightComponentRequestBus::Events::SetProjectorAttenuationBulbSize)
                ->VirtualProperty("ProjectorAttenuationBulbSize", "GetProjectorAttenuationBulbSize", "SetProjectorAttenuationBulbSize")
                ->Event("GetProjectorFOV", &EditorLightComponentRequestBus::Events::GetProjectorFOV)
                ->Event("SetProjectorFOV", &EditorLightComponentRequestBus::Events::SetProjectorFOV)
                ->VirtualProperty("ProjectorFOV", "GetProjectorFOV", "SetProjectorFOV")
                ->Event("GetProjectorNearPlane", &EditorLightComponentRequestBus::Events::GetProjectorNearPlane)
                ->Event("SetProjectorNearPlane", &EditorLightComponentRequestBus::Events::SetProjectorNearPlane)
                ->VirtualProperty("ProjectorNearPlane", "GetProjectorNearPlane", "SetProjectorNearPlane")
                ->Event("GetAnimIndex", &EditorLightComponentRequestBus::Events::GetAnimIndex)
                ->Event("SetAnimIndex", &EditorLightComponentRequestBus::Events::SetAnimIndex)
                ->VirtualProperty("AnimIndex", "GetAnimIndex", "SetAnimIndex")
                ->Event("GetAnimSpeed", &EditorLightComponentRequestBus::Events::GetAnimSpeed)
                ->Event("SetAnimSpeed", &EditorLightComponentRequestBus::Events::SetAnimSpeed)
                ->VirtualProperty("AnimSpeed", "GetAnimSpeed", "SetAnimSpeed")
                ->Event("GetAnimPhase", &EditorLightComponentRequestBus::Events::GetAnimPhase)
                ->Event("SetAnimPhase", &EditorLightComponentRequestBus::Events::SetAnimPhase)
                ->VirtualProperty("AnimPhase", "GetAnimPhase", "SetAnimPhase")
                ;

            // Environment Probe Light Ebus reflection and VirtualProperties
            behaviorContext->EBus<LightComponentEditorRequestBus>("EditorProbeLightComponentBus")
                ->Event("GetVisible", &LightComponentEditorRequestBus::Events::GetVisible)
                ->Event("SetVisible", &LightComponentEditorRequestBus::Events::SetVisible)
                ->VirtualProperty("Visible", "GetVisible", "SetVisible")
                ->Event("GetColor", &LightComponentEditorRequestBus::Events::GetColor)
                ->Event("SetColor", &LightComponentEditorRequestBus::Events::SetColor)
                ->VirtualProperty("Color", "GetColor", "SetColor")
                ->Event("GetDiffuseMultiplier", &LightComponentEditorRequestBus::Events::GetDiffuseMultiplier)
                ->Event("SetDiffuseMultiplier", &LightComponentEditorRequestBus::Events::SetDiffuseMultiplier)
                ->VirtualProperty("DiffuseMultiplier", "GetDiffuseMultiplier", "SetDiffuseMultiplier")
                ->Event("GetSpecularMultiplier", &LightComponentEditorRequestBus::Events::GetSpecularMultiplier)
                ->Event("SetSpecularMultiplier", &LightComponentEditorRequestBus::Events::SetSpecularMultiplier)
                ->VirtualProperty("SpecularMultiplier", "GetSpecularMultiplier", "SetSpecularMultiplier")
                ->Event("GetProbeAreaDimensions", &LightComponentEditorRequestBus::Events::GetProbeAreaDimensions)
                ->Event("SetProbeAreaDimensions", &LightComponentEditorRequestBus::Events::SetProbeAreaDimensions)
                ->VirtualProperty("ProbeAreaDimensions", "GetProbeAreaDimensions", "SetProbeAreaDimensions")
                ->Event("GetProbeSortPriority", &LightComponentEditorRequestBus::Events::GetProbeSortPriority)
                ->Event("SetProbeSortPriority", &LightComponentEditorRequestBus::Events::SetProbeSortPriority)
                ->VirtualProperty("ProbeSortPriority", "GetProbeSortPriority", "SetProbeSortPriority")
                ->Event("GetProbeBoxProjected", &LightComponentEditorRequestBus::Events::GetProbeBoxProjected)
                ->Event("SetProbeBoxProjected", &LightComponentEditorRequestBus::Events::SetProbeBoxProjected)
                ->VirtualProperty("ProbeBoxProjected", "GetProbeBoxProjected", "SetProbeBoxProjected")
                ->Event("GetProbeBoxHeight", &LightComponentEditorRequestBus::Events::GetProbeBoxHeight)
                ->Event("SetProbeBoxHeight", &LightComponentEditorRequestBus::Events::SetProbeBoxHeight)
                ->VirtualProperty("ProbeBoxHeight", "GetProbeBoxHeight", "SetProbeBoxHeight")
                ->Event("GetProbeBoxLength", &LightComponentEditorRequestBus::Events::GetProbeBoxLength)
                ->Event("SetProbeBoxLength", &LightComponentEditorRequestBus::Events::SetProbeBoxLength)
                ->VirtualProperty("ProbeBoxLength", "GetProbeBoxLength", "SetProbeBoxLength")
                ->Event("GetProbeBoxWidth", &LightComponentEditorRequestBus::Events::GetProbeBoxWidth)
                ->Event("SetProbeBoxWidth", &LightComponentEditorRequestBus::Events::SetProbeBoxWidth)
                ->VirtualProperty("ProbeBoxWidth", "GetProbeBoxWidth", "SetProbeBoxWidth")
                ->Event("GetProbeAttenuationFalloff", &LightComponentEditorRequestBus::Events::GetProbeAttenuationFalloff)
                ->Event("SetProbeAttenuationFalloff", &LightComponentEditorRequestBus::Events::SetProbeAttenuationFalloff)
                ->VirtualProperty("ProbeAttenuationFalloff", "GetProbeAttenuationFalloff", "SetProbeAttenuationFalloff")
                ->Event("GetProbeFade", &LightComponentEditorRequestBus::Events::GetProbeFade)
                ->Event("SetProbeFade", &LightComponentEditorRequestBus::Events::SetProbeFade)
                ->VirtualProperty("ProbeFade", "GetProbeFade", "SetProbeFade")
                ->Event("GetAnimIndex", &EditorLightComponentRequestBus::Events::GetAnimIndex)
                ->Event("SetAnimIndex", &EditorLightComponentRequestBus::Events::SetAnimIndex)
                ->VirtualProperty("AnimIndex", "GetAnimIndex", "SetAnimIndex")
                ->Event("GetAnimSpeed", &EditorLightComponentRequestBus::Events::GetAnimSpeed)
                ->Event("SetAnimSpeed", &EditorLightComponentRequestBus::Events::SetAnimSpeed)
                ->VirtualProperty("AnimSpeed", "GetAnimSpeed", "SetAnimSpeed")
                ->Event("GetAnimPhase", &EditorLightComponentRequestBus::Events::GetAnimPhase)
                ->Event("SetAnimPhase", &EditorLightComponentRequestBus::Events::SetAnimPhase)
                ->VirtualProperty("AnimPhase", "GetAnimPhase", "SetAnimPhase")
                ;
        }
    }

    bool EditorLightComponent::VersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement)
    {
        if (classElement.GetVersion() <= 1)
        {
            if (!classElement.RemoveElementByName(AZ_CRC("cubemapAsset", 0xc10ac43b)))
            {
                return false;
            }
        }

        return true;
    }
    void EditorLightConfiguration::Reflect(AZ::ReflectContext* context)
    {
        AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);

        if (serializeContext)
        {
            serializeContext->Class<EditorLightConfiguration, LightConfiguration>()->
                Version(1);

            AZ::EditContext* editContext = serializeContext->GetEditContext();
            if (editContext)
            {
                editContext->Class<LightConfiguration>(
                    "Configuration", "Light configuration")->

                    ClassElement(AZ::Edit::ClassElements::EditorData, "")->
                      Attribute(AZ::Edit::Attributes::AutoExpand, true)->
                      Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)->

                    ClassElement(AZ::Edit::ClassElements::Group, "General Settings")->
                        Attribute(AZ::Edit::Attributes::AutoExpand, true)->

                    DataElement(AZ::Edit::UIHandlers::CheckBox, &LightConfiguration::m_visible, "Visible", "The current visibility status of this flare")->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MajorPropertyChanged)->

                    DataElement(0, &LightConfiguration::m_onInitially, "On initially", "The light is initially turned on.")->

                    DataElement(AZ::Edit::UIHandlers::Color, &LightConfiguration::m_color, "Color", "Light color")->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->

                    DataElement(0, &LightConfiguration::m_diffuseMultiplier, "Diffuse multiplier", "Diffuse color multiplier")->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->
                        Attribute(AZ::Edit::Attributes::Min, 0.f)->
                        Attribute(AZ::Edit::Attributes::Step, 0.1f)->
                        Attribute(AZ::Edit::Attributes::Suffix, "x")->

                    DataElement(0, &LightConfiguration::m_specMultiplier, "Specular multiplier", "Specular multiplier")->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->
                        Attribute(AZ::Edit::Attributes::Min, 0.f)->
                        Attribute(AZ::Edit::Attributes::Step, 0.1f)->
                        Attribute(AZ::Edit::Attributes::Suffix, "x")->

                    DataElement(0, &LightConfiguration::m_ambient, "Ambient", "Ambient light")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetAmbientLightVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->

                    // Point Light Settings
                    ClassElement(AZ::Edit::ClassElements::Group, "Point Light Settings")->
                        Attribute(AZ::Edit::Attributes::AutoExpand, true)->

                    DataElement(0, &LightConfiguration::m_pointMaxDistance, "Max distance", "Point light radius")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetPointLightVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->
                        Attribute(AZ::Edit::Attributes::Suffix, " m")->
                        Attribute(AZ::Edit::Attributes::Min, 0.1f)->
                        Attribute(AZ::Edit::Attributes::Step, 0.1f)->

                    DataElement(0, &LightConfiguration::m_pointAttenuationBulbSize, "Attenuation bulb size", "Radius of area inside falloff.")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetPointLightVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->
                        Attribute(AZ::Edit::Attributes::Suffix, " m")->
                        Attribute(AZ::Edit::Attributes::Min, 0.f)->
                        Attribute(AZ::Edit::Attributes::Step, 0.1f)->

                    // Area Light Settings
                    ClassElement(AZ::Edit::ClassElements::Group, "Area Light Settings")->
                        Attribute(AZ::Edit::Attributes::AutoExpand, true)->

                    DataElement(0, &LightConfiguration::m_areaWidth, "Area width", "Area light width.")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetAreaSettingVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->
                        Attribute(AZ::Edit::Attributes::Min, 0.1f)->
                        Attribute(AZ::Edit::Attributes::Step, 0.1f)->
                        Attribute(AZ::Edit::Attributes::Suffix, " m")->

                    DataElement(0, &LightConfiguration::m_areaHeight, "Area height", "Area light height.")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetAreaSettingVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->
                        Attribute(AZ::Edit::Attributes::Min, 0.1f)->
                        Attribute(AZ::Edit::Attributes::Step, 0.1f)->
                        Attribute(AZ::Edit::Attributes::Suffix, " m")->

                    DataElement(0, &LightConfiguration::m_areaMaxDistance, "Max distance", "Area light max distance.")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetAreaSettingVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->
                        Attribute(AZ::Edit::Attributes::Min, 0.1f)->
                        Attribute(AZ::Edit::Attributes::Step, 0.1f)->
                        Attribute(AZ::Edit::Attributes::Suffix, " _")->

                    DataElement(0, &LightConfiguration::m_areaFOV, "FOV", "Area light field of view.")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetAreaSettingVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->
                        Attribute(AZ::Edit::Attributes::Min, 0.0f)->
                        Attribute(AZ::Edit::Attributes::Max, 90.0f)->
                        Attribute(AZ::Edit::Attributes::Step, 1.0f)->
                        Attribute(AZ::Edit::Attributes::Suffix, " degrees")->

                    // Projector settings.
                    ClassElement(AZ::Edit::ClassElements::Group, "Projector Light Settings")->
                        Attribute(AZ::Edit::Attributes::AutoExpand, true)->

                    DataElement(0, &LightConfiguration::m_projectorRange, "Max distance", "Projector light range")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetProjectorLightVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->
                        Attribute(AZ::Edit::Attributes::Min, 0.1f)->
                        Attribute(AZ::Edit::Attributes::Step, 0.1f)->
                        Attribute(AZ::Edit::Attributes::Suffix, " m")->

                    DataElement(0, &LightConfiguration::m_projectorAttenuationBulbSize, "Attenuation bulb size", "Radius of area inside falloff.")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetProjectorLightVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->
                        Attribute(AZ::Edit::Attributes::Suffix, " m")->
                        Attribute(AZ::Edit::Attributes::Min, 0.f)->
                        Attribute(AZ::Edit::Attributes::Step, 0.1f)->

                    DataElement(AZ::Edit::UIHandlers::Slider, &LightConfiguration::m_projectorFOV, "FOV", "Projector light FOV")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetProjectorLightVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->
                        Attribute(AZ::Edit::Attributes::Min, 1.f)->
                        Attribute(AZ::Edit::Attributes::Max, 180.0f)->      //Projector will start shrinking if FOV goes above 180 degrees
                        Attribute(AZ::Edit::Attributes::Step, 0.1f)->
                        Attribute(AZ::Edit::Attributes::Suffix, " degrees")->

                    DataElement(0, &LightConfiguration::m_projectorNearPlane, "Near plane", "Projector light near plane")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetProjectorLightVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->
                        Attribute(AZ::Edit::Attributes::Min, 0.f)->
                        Attribute(AZ::Edit::Attributes::Max, 100.f)->
                        Attribute(AZ::Edit::Attributes::Step, 1.f)->
                        Attribute(AZ::Edit::Attributes::Suffix, " m")->

                    DataElement(0, &LightConfiguration::m_projectorTexture, "Texture", "Projector light texture")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetProjectorLightVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MajorPropertyChanged)->

                    DataElement(0, &LightConfiguration::m_material, "Material", "Projector light material")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetProjectorLightVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MajorPropertyChanged)->

                    //environment probe settings
                    ClassElement(AZ::Edit::ClassElements::Group, "Environment Probe Settings")->
                        Attribute(AZ::Edit::Attributes::AutoExpand, true)->

                    DataElement(0, &LightConfiguration::m_probeArea, "Area dimensions", "Probe area")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetProbeLightVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->

                    DataElement(AZ::Edit::UIHandlers::CheckBox, &LightConfiguration::m_isBoxProjected, "Box projected", "Check to enable box projection during runtime")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetProbeLightVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->

                    DataElement(0, &LightConfiguration::m_boxHeight, "Box height", "Height of box projection area")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetProbeLightVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->

                    DataElement(0, &LightConfiguration::m_boxWidth, "Box width", "Width of box projection area")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetProbeLightVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->

                    DataElement(0, &LightConfiguration::m_boxLength, "Box length", "Length of box projection area")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetProbeLightVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->

                    DataElement(0, &LightConfiguration::m_attenFalloffMax, "Attenuation falloff", "Attenuation falloff value.")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetProbeLightVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->
                        Attribute(AZ::Edit::Attributes::Min, 0.f)->
                        Attribute(AZ::Edit::Attributes::Max, 1.0f)->
                        Attribute(AZ::Edit::Attributes::Step, 0.02f)->

                    DataElement(0, &LightConfiguration::m_probeSortPriority, "Sort priority", "Sort priority")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetProbeLightVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->

                    DataElement(AZ::Edit::UIHandlers::ComboBox, &LightConfiguration::m_probeCubemapResolution, "Resolution", "Cubemap resolution")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetProbeLightVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MajorPropertyChanged)->
                        EnumAttribute(ResolutionSetting::ResDefault, "Default (256)")->
                        EnumAttribute(ResolutionSetting::Res32, "32")->
                        EnumAttribute(ResolutionSetting::Res64, "64")->
                        EnumAttribute(ResolutionSetting::Res128, "128")->
                        EnumAttribute(ResolutionSetting::Res256, "256")->
                        EnumAttribute(ResolutionSetting::Res512, "512")->

                    ClassElement(AZ::Edit::ClassElements::Group, "Cubemap Generation")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetProbeLightVisibility)->
                        Attribute(AZ::Edit::Attributes::AutoExpand, true)->

                    DataElement(AZ::Edit::UIHandlers::Default, &LightConfiguration::m_probeCubemap, "Cubemap asset", "Cubemap file path")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetProbeLightVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::OnCubemapAssetChanged)->
                        Attribute(AZ::Edit::Attributes::ReadOnly,&LightConfiguration::CanGenerateCubemap)->

                    ClassElement(AZ::Edit::ClassElements::Group, "Animation")->

                    DataElement(0, &LightConfiguration::m_animIndex, "Style", "Light animation curve ID (\"style\") as it corresponds to values in Light.cfx")->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::OnAnimationSettingChanged)->
                        Attribute(AZ::Edit::Attributes::Max, 255)->

                    DataElement(0, &LightConfiguration::m_animSpeed, "Speed", "Multiple of the base animation rate")->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::OnAnimationSettingChanged)->
                        Attribute(AZ::Edit::Attributes::Min, 0.f)->
                        Attribute(AZ::Edit::Attributes::Step, 0.1f)->
                        Attribute(AZ::Edit::Attributes::Max, 4.f)->
                        Attribute(AZ::Edit::Attributes::Suffix, "x")->

                    DataElement(0, &LightConfiguration::m_animPhase, "Phase", "Animation start offset from 0 to 1.  0.1 would be 10% into the animation")->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::OnAnimationSettingChanged)->
                        Attribute(AZ::Edit::Attributes::Min, 0.f)->
                        Attribute(AZ::Edit::Attributes::Step, 0.1f)->
                        Attribute(AZ::Edit::Attributes::Max, 1.f)->

                    ClassElement(AZ::Edit::ClassElements::Group, "Options")->

                    DataElement(0, &LightConfiguration::m_viewDistMultiplier, "View distance multiplier", "Adjusts max view distance. If 1.0 then default is used. 1.1 would be 10% further than default.")->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->
                        Attribute(AZ::Edit::Attributes::Suffix, "x")->
                        Attribute(AZ::Edit::Attributes::Min, 0.f)->

                    DataElement(AZ::Edit::UIHandlers::ComboBox, &LightConfiguration::m_minSpec, "Minimum spec", "Min spec for light to be active.")->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->
                        EnumAttribute(EngineSpec::Never, "Never")->
                        EnumAttribute(EngineSpec::VeryHigh, "Very high")->
                        EnumAttribute(EngineSpec::High, "High")->
                        EnumAttribute(EngineSpec::Medium, "Medium")->
                        EnumAttribute(EngineSpec::Low, "Low")->

                    DataElement(AZ::Edit::UIHandlers::ComboBox, &LightConfiguration::m_voxelGIMode, "Voxel GI mode", "Mode for light interaction with voxel GI.")->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MajorPropertyChanged)->
                        EnumAttribute(IRenderNode::VM_None, "None")->
                        EnumAttribute(IRenderNode::VM_Static, "Static")->
                        EnumAttribute(IRenderNode::VM_Dynamic, "Dynamic")->

                    DataElement(0, &LightConfiguration::m_useVisAreas, "Use VisAreas", "Light is affected by VisAreas")->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->

                    DataElement(0, &LightConfiguration::m_volumetricFog, "Volumetric fog", "Affects volumetric fog")->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->

                    DataElement(0, &LightConfiguration::m_volumetricFogOnly, "Volumetric fog only", "Only affects volumetric fog")->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->

                    DataElement(0, &LightConfiguration::m_indoorOnly, "Indoor only", "Indoor only")->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->

                    DataElement(0, &LightConfiguration::m_affectsThisAreaOnly, "Affects this area only", "Light only affects this area")->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->

                    DataElement(0, &LightConfiguration::m_clipVolumeEntity, "Clip volume entity", "The entity containing the clip volume to use.")->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->

                    ClassElement(AZ::Edit::ClassElements::Group, "Advanced")->

                    DataElement(0, &LightConfiguration::m_deferred, "Deferred", "Deferred light")->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->
                        Attribute(AZ::Edit::Attributes::Visibility, AZ_CRC("PropertyVisibility_Hide", 0x32ab90f7))->         // Deprecated on non mobile platforms - hidden until we have a platform to use this

                    ClassElement(AZ::Edit::ClassElements::Group, "Shadow Settings")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetShadowSpecVisibility)->
                        Attribute(AZ::Edit::Attributes::AutoExpand, true)->

                    DataElement(AZ::Edit::UIHandlers::ComboBox, &LightConfiguration::m_castShadowsSpec, "Cast shadow spec", "Min spec for shadow casting.")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetShadowSpecVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MajorPropertyChanged)->
                        EnumAttribute(EngineSpec::Never, "Never")->
                        EnumAttribute(EngineSpec::VeryHigh, "Very high")->
                        EnumAttribute(EngineSpec::High, "High")->
                        EnumAttribute(EngineSpec::Medium, "Medium")->
                        EnumAttribute(EngineSpec::Low, "Low")->

                    DataElement(0, &LightConfiguration::m_castTerrainShadows, "Terrain Shadows", "Include the terrain in the shadow casters for this light")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetShadowSettingsVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->


                    DataElement(0, &LightConfiguration::m_shadowBias, "Shadow bias", "Shadow bias")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetShadowSettingsVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->
                        Attribute(AZ::Edit::Attributes::Min, 0.f)->
                        Attribute(AZ::Edit::Attributes::Max, 100.f)->
                        Attribute(AZ::Edit::Attributes::Step, 0.5f)->

                    DataElement(0, &LightConfiguration::m_shadowSlopeBias, "Shadow slope bias", "Shadow slope bias")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetShadowSettingsVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->
                        Attribute(AZ::Edit::Attributes::Min, 0.f)->
                        Attribute(AZ::Edit::Attributes::Max, 100.f)->
                        Attribute(AZ::Edit::Attributes::Step, 0.5f)->

                    DataElement(0, &LightConfiguration::m_shadowResScale, "Shadow resolution scale", "Shadow res scale")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetShadowSettingsVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->
                        Attribute(AZ::Edit::Attributes::Min, 0.f)->
                        Attribute(AZ::Edit::Attributes::Max, 10.f)->
                        Attribute(AZ::Edit::Attributes::Step, 0.1f)->

                    DataElement(0, &LightConfiguration::m_shadowUpdateMinRadius, "Shadow update radius", "Shadow update min radius")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetShadowSettingsVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->
                        Attribute(AZ::Edit::Attributes::Min, 0.f)->
                        Attribute(AZ::Edit::Attributes::Max, 100.f)->
                        Attribute(AZ::Edit::Attributes::Step, 0.5f)->
                        Attribute(AZ::Edit::Attributes::Suffix, " m")->

                    DataElement(0, &LightConfiguration::m_shadowUpdateRatio, "Shadow update ratio", "Shadow update ratio")->
                        Attribute(AZ::Edit::Attributes::Visibility, &LightConfiguration::GetShadowSettingsVisibility)->
                        Attribute(AZ::Edit::Attributes::ChangeNotify, &LightConfiguration::MinorPropertyChanged)->
                        Attribute(AZ::Edit::Attributes::Min, 0.f)->
                        Attribute(AZ::Edit::Attributes::Max, 10.f)->
                        Attribute(AZ::Edit::Attributes::Step, 0.1f)
                ;
            }
        }
    }

    AZ::Crc32 EditorLightConfiguration::GetAmbientLightVisibility() const
    {
        return m_lightType != LightType::Probe ?
                AZ::Edit::PropertyVisibility::Show : AZ::Edit::PropertyVisibility::Hide;
    }

    AZ::Crc32 EditorLightConfiguration::GetPointLightVisibility() const
    {
        return m_lightType == LightType::Point ?
            AZ::Edit::PropertyVisibility::Show : AZ::Edit::PropertyVisibility::Hide;
    }

    AZ::Crc32 EditorLightConfiguration::GetProjectorLightVisibility() const
    {
        return m_lightType == LightType::Projector ?
            AZ::Edit::PropertyVisibility::Show : AZ::Edit::PropertyVisibility::Hide;
    }

    AZ::Crc32 EditorLightConfiguration::GetProbeLightVisibility() const
    {
        return m_lightType == LightType::Probe ?
            AZ::Edit::PropertyVisibility::Show : AZ::Edit::PropertyVisibility::Hide;
    }

    AZ::Crc32 EditorLightConfiguration::GetShadowSpecVisibility() const
    {
        return m_lightType != LightType::Probe ?
            AZ::Edit::PropertyVisibility::Show : AZ::Edit::PropertyVisibility::Hide;
    }

    AZ::Crc32 EditorLightConfiguration::GetShadowSettingsVisibility() const
    {
        return m_castShadowsSpec != EngineSpec::Never ?
            AZ::Edit::PropertyVisibility::Show : AZ::Edit::PropertyVisibility::Hide;
    }

    AZ::Crc32 EditorLightConfiguration::GetAreaSettingVisibility() const
    {
        return m_lightType == LightType::Area ?
            AZ::Edit::PropertyVisibility::Show : AZ::Edit::PropertyVisibility::Hide;
    }

    AZ::Crc32 EditorLightConfiguration::MajorPropertyChanged()
    {
        if (m_editorEntityId.IsValid())
        {
            EditorLightComponentRequestBus::Event(m_editorEntityId, &EditorLightComponentRequests::RefreshLight);
        }

        return AZ::Edit::PropertyRefreshLevels::EntireTree;
    }

    AZ::Crc32 EditorLightConfiguration::MinorPropertyChanged()
    {
        if (m_editorEntityId.IsValid())
        {
            EditorLightComponentRequestBus::Event(m_editorEntityId, &EditorLightComponentRequests::RefreshLight);
        }

        return AZ::Edit::PropertyRefreshLevels::None;
    }

    AZ::Crc32 EditorLightConfiguration::OnAnimationSettingChanged()
    {
        if (m_editorEntityId.IsValid())
        {
            EditorLightComponentRequestBus::Event(m_editorEntityId, &EditorLightComponentRequests::RefreshLight);
            LightSettingsNotificationsBus::Broadcast(&LightSettingsNotifications::AnimationSettingsChanged);
        }

        return AZ_CRC("RefreshNone", 0x98a5045b);
    }

    AZ::Crc32 EditorLightConfiguration::OnCubemapAssetChanged()
    {
        if (!m_component)
        {
            AZ_Error("Lighting", false, "Lighting configuration has a null component, unable to change CubemapAsset");
            return 0;
        }

        return m_component->OnCubemapAssetChanged();
    }

    bool EditorLightConfiguration::CanGenerateCubemap() const
    {
        if (!m_component)
        {
            AZ_Error("Lighting", false, "Lighting configuration has a null component, unable to generate Cubemap");
            return false;
        }

        return m_component->CanGenerateCubemap();
    }

    EditorLightComponent::EditorLightComponent()
        : m_useCustomizedCubemap(false)
        , m_viewCubemap(false)
        , m_cubemapRegen(false)
        , m_cubemapClear(false)
    {
        m_configuration.m_projectorTexture.SetAssetPath("engineassets/textures/defaults/spot_default.dds");
        m_configuration.SetComponent(nullptr);
    }

    EditorLightComponent::~EditorLightComponent()
    {
    }

    void EditorLightComponent::Init()
    {
        Base::Init();
    }

    void EditorLightComponent::Activate()
    {
        Base::Activate();

        m_configuration.SetComponent(this);
        m_configuration.m_editorEntityId = GetEntityId();

        m_light.SetEntity(GetEntityId());
        RefreshLight();

        if (m_configuration.m_lightType == LightConfiguration::LightType::Probe)
        {
            m_cubemapPreview.Setup(m_configuration.m_probeCubemap.GetAssetPath().c_str());

            AZ::Transform transform = AZ::Transform::Identity();
            AZ::TransformBus::EventResult(transform, GetEntityId(), &AZ::TransformInterface::GetWorldTM);
            m_cubemapPreview.SetTransform(AZTransformToLYTransform(transform));

            OnViewCubemapChanged(); // Check to see if it should be displayed now.
        }

        EditorCameraCorrectionRequestBus::Handler::BusConnect(GetEntityId());
        EditorLightComponentRequestBus::Handler::BusConnect(GetEntityId());
        RenderNodeRequestBus::Handler::BusConnect(GetEntityId());
        AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(GetEntityId());
        AzToolsFramework::EditorVisibilityNotificationBus::Handler::BusConnect(GetEntityId());
        AzToolsFramework::EditorEvents::Bus::Handler::BusConnect();
        AZ::TransformNotificationBus::Handler::BusConnect(GetEntityId());
        ClipVolumeComponentNotificationBus::Handler::BusConnect(m_configuration.m_clipVolumeEntity);
    }

    void EditorLightComponent::Deactivate()
    {
        EditorCameraCorrectionRequestBus::Handler::BusDisconnect();
        EditorLightComponentRequestBus::Handler::BusDisconnect();
        RenderNodeRequestBus::Handler::BusDisconnect();
        AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect();
        AzToolsFramework::EditorVisibilityNotificationBus::Handler::BusDisconnect();
        AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect();
        AZ::TransformNotificationBus::Handler::BusDisconnect();
        ClipVolumeComponentNotificationBus::Handler::BusDisconnect();

        gEnv->p3DEngine->FreeRenderNodeState(&m_cubemapPreview);

        m_light.DestroyRenderLight();
        m_light.SetEntity(AZ::EntityId());

        m_configuration.m_editorEntityId.SetInvalid();

        Base::Deactivate();
    }

    void EditorLightComponent::OnEntityVisibilityChanged(bool /*visibility*/)
    {
        RefreshLight();
    }

    void EditorLightComponent::OnEditorSpecChange()
    {
        RefreshLight();
    }

    void EditorLightComponent::RefreshLight()
    {
        EditorLightConfiguration configuration = m_configuration;

        // take the entity's visibility into account
        bool visible = false;
        AzToolsFramework::EditorEntityInfoRequestBus::EventResult(
            visible, GetEntityId(), &AzToolsFramework::EditorEntityInfoRequestBus::Events::IsVisible);

        configuration.m_visible = visible && configuration.m_visible;

        // Reconnect the bus so the newly created internal light instance receives the clip volume
        ClipVolumeComponentNotificationBus::Handler::BusDisconnect();
        m_light.UpdateRenderLight(configuration);
        ClipVolumeComponentNotificationBus::Handler::BusConnect(m_configuration.m_clipVolumeEntity);
    }

    IRenderNode* EditorLightComponent::GetRenderNode()
    {
        return m_light.GetRenderNode();
    }

    float EditorLightComponent::GetRenderNodeRequestBusOrder() const
    {
        return LightComponent::s_renderNodeRequestBusOrder;
    }

    bool EditorLightComponent::IsProbe() const
    {
        return (m_configuration.m_lightType == LightConfiguration::LightType::Probe);
    }

    bool EditorLightComponent::HasCubemap() const
    {
        return !m_configuration.m_probeCubemap.GetAssetPath().empty();
    }

    const char* EditorLightComponent::GetCubemapAssetName() const
    {
        return m_configuration.m_probeCubemap.GetAssetPath().c_str();
    }


    bool EditorLightComponent::CanGenerateCubemap() const
    {
        return (m_configuration.m_lightType == LightConfiguration::LightType::Probe) && (!m_useCustomizedCubemap);
    }

    const char* EditorLightComponent::GetGenerateCubemapButtonName() const
    {
        if (HasCubemap())
        {
            return BUTTON_ADDBOUNCE;
        }
        else
        {
            return BUTTON_GENERATE;
        }
    }

    void EditorLightComponent::GenerateCubemap()
    {
        if (CanGenerateCubemap())
        {
            EBUS_EVENT(AzToolsFramework::EditorRequests::Bus,
                GenerateCubemapWithIDForEntity,
                GetEntityId(),
                GetCubemapId(),
                nullptr,
                false,
                true);
        }
    }

    void EditorLightComponent::ClearCubemap()
    {
        SetCubemap("");
    }

    void EditorLightComponent::OnViewCubemapChanged()
    {
        if (m_viewCubemap)
        {
            gEnv->p3DEngine->RegisterEntity(&m_cubemapPreview);
        }
        else
        {
            gEnv->p3DEngine->FreeRenderNodeState(&m_cubemapPreview);
        }
    }

    void EditorLightComponent::BuildGameEntity(AZ::Entity* gameEntity)
    {
        LightComponent* lightComponent = gameEntity->CreateComponent<LightComponent>();

        if (lightComponent)
        {
            lightComponent->m_configuration = m_configuration;
        }
    }

    void EditorLightComponent::SetCubemap(const AZStd::string& cubemap)
    {
        if (cubemap != m_configuration.m_probeCubemap.GetAssetPath())
        {
            AzToolsFramework::ScopedUndoBatch undo("Cubemap Assignment");

            m_configuration.m_probeCubemap.SetAssetPath(cubemap.c_str());
            m_cubemapPreview.UpdateTexture(m_configuration.m_probeCubemap.GetAssetPath().c_str());

            AzToolsFramework::ToolsApplicationRequestBus::Broadcast(
                &AzToolsFramework::ToolsApplicationRequests::AddDirtyEntity, GetEntityId());
        }

        if (m_configuration.m_probeCubemap.GetAssetPath().empty())
        {
            // Since the cubemap was simply cleared, there is no need to wait for an asset to be processed.
            // Instead, refresh the light now so the output will be cleared immediately.

            if (IsSelected())
            {
                AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
                    &AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_AttributesAndValues);

            }

            if (EditorLightConfiguration::LightType::Probe == m_configuration.m_lightType)
            {
                RefreshLight();
            }
        }
        else
        {
            // Get the notice when the dds is generated by AP. We will only refresh the m_cubemapAsset and the PropertyDisplay when the dds is generated.
            AzFramework::AssetCatalogEventBus::Handler::BusConnect();
        }
    }

    void EditorLightComponent::SetProjectorTexture(const AZStd::string& projectorTexture)
    {
        if (projectorTexture != m_configuration.m_projectorTexture.GetAssetPath())
        {
            m_configuration.m_projectorTexture.SetAssetPath(projectorTexture.c_str());
            RefreshLight();
        }
    }

    void EditorLightComponent::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId)
    {
        AZ::Data::AssetId cmAssetId;
        AZ::Data::AssetCatalogRequestBus::BroadcastResult(
            cmAssetId, &AZ::Data::AssetCatalogRequests::GetAssetIdByPath,
            m_configuration.m_probeCubemap.GetAssetPath().c_str(),
            m_configuration.m_probeCubemap.GetAssetType(), true);

        if (cmAssetId == assetId)
        {
            AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
            //refresh the tree since we don't need to wait for the asset imported
            if (IsSelected())
            {
                AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
                    &AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_AttributesAndValues);
            }

            // We wait to refresh the light until after the new asset has finished loading to avoid showing old data; for example, when you
            // Generate, Clear, and then Generate again.
            if (EditorLightConfiguration::LightType::Probe == m_configuration.m_lightType)
            {
                RefreshLight();
            }
        }
    }

    void EditorLightComponent::OnCatalogAssetChanged(const AZ::Data::AssetId& assetId)
    {
        OnCatalogAssetAdded(assetId);
    }

    AZ::Crc32 EditorLightComponent::OnCubemapAssetChanged()
    {
        //in case user select a "_diff" texture file. remove it and generate specular file name
        static const char* diffExt = "_diff";
        static const int diffStrSize = 5; //string len of "_diff"

        const char* specularCubemap = 0;
        string specularName(m_configuration.m_probeCubemap.GetAssetPath().c_str());

        int strIndex = specularName.find(diffExt);
        if (strIndex >= 0)
        {
            specularName = specularName.substr(0, strIndex) + specularName.substr(strIndex + diffStrSize, specularName.length());
            specularCubemap = specularName.c_str();
            m_configuration.m_probeCubemap.SetAssetPath(specularName);
        }

        m_cubemapPreview.UpdateTexture(m_configuration.m_probeCubemap.GetAssetPath().c_str());

        RefreshLight();

        return AZ::Edit::PropertyRefreshLevels::ValuesOnly;
    }

    void EditorLightConfiguration::SetComponent(EditorLightComponent* component)
    {
        m_component = component;
    }

    AZ::Crc32 EditorLightComponent::OnCustomizedCubemapChanged()
    {
        //clean assets
        m_configuration.m_probeCubemap.SetAssetPath("");
        m_cubemapPreview.UpdateTexture(m_configuration.m_probeCubemap.GetAssetPath().c_str());

        RefreshLight();

        return AZ::Edit::PropertyRefreshLevels::EntireTree;
    }

    AZ::u32 EditorLightComponent::GetCubemapResolution()
    {
        return static_cast<AZ::u32>(m_configuration.m_probeCubemapResolution);
    }
    void EditorLightComponent::SetCubemapResolution(AZ::u32 newResolution)
    {
        AZ_Assert(newResolution > 0, "Invalid resolution");

        LightConfiguration::ResolutionSetting cubemapResolution = static_cast<LightConfiguration::ResolutionSetting>(newResolution);
        if (m_configuration.m_probeCubemapResolution != cubemapResolution)
        {
            m_configuration.m_probeCubemapResolution = cubemapResolution;
            m_configuration.MinorPropertyChanged();
        }
    }

    bool EditorLightComponent::UseCustomizedCubemap() const
    {
        return m_useCustomizedCubemap;
    }

    const LightConfiguration& EditorLightComponent::GetConfiguration() const
    {
        return m_configuration;
    }

    void EditorLightComponent::OnClipVolumeCreated(IClipVolume* clipVolume)
    {
        m_light.SetClipVolume(clipVolume);
    }

    void EditorLightComponent::OnClipVolumeDestroyed(IClipVolume* clipVolume)
    {
        m_light.ClearClipVolume(clipVolume);
    }

    ////////////////////////////////////////////////////////////
    // Modifiers
    void EditorLightComponent::SetVisible(bool isVisible)
    {
        if (m_configuration.m_visible != isVisible)
        {
            m_configuration.m_visible = isVisible;
            m_configuration.MajorPropertyChanged();
        }
    }

    bool EditorLightComponent::GetVisible()
    {
        return m_configuration.m_visible;
    }

    void EditorLightComponent::SetOnInitially(bool onInitially)
    {
        if (m_configuration.m_onInitially != onInitially)
        {
            m_configuration.m_onInitially = onInitially;
            m_configuration.MajorPropertyChanged();
        }
    }
    bool EditorLightComponent::GetOnInitially()
    {
        return m_configuration.m_onInitially;
    }

    void EditorLightComponent::SetColor(const AZ::Color& newColor)
    {
        if (m_configuration.m_color != newColor)
        {
            m_configuration.m_color = newColor;
            m_configuration.MinorPropertyChanged();
        }
    }

    const AZ::Color EditorLightComponent::GetColor()
    {
        return m_configuration.m_color;
    }

    void EditorLightComponent::SetDiffuseMultiplier(float newMultiplier)
    {
        if (newMultiplier != m_configuration.m_diffuseMultiplier)
        {
            m_configuration.m_diffuseMultiplier = newMultiplier;
            m_configuration.MinorPropertyChanged();
        }
    }
    float EditorLightComponent::GetDiffuseMultiplier()
    {
        return m_configuration.m_diffuseMultiplier;
    }

    void EditorLightComponent::SetSpecularMultiplier(float newMultiplier)
    {
        if (newMultiplier != m_configuration.m_specMultiplier)
        {
            m_configuration.m_specMultiplier = newMultiplier;
            m_configuration.MinorPropertyChanged();
        }
    }
    float EditorLightComponent::GetSpecularMultiplier()
    {
        return m_configuration.m_specMultiplier;
    }

    void EditorLightComponent::SetAmbient(bool isAmbient)
    {
        if (isAmbient != m_configuration.m_ambient)
        {
            m_configuration.m_ambient = isAmbient;
            m_configuration.MinorPropertyChanged();
        }
    }
    bool EditorLightComponent::GetAmbient()
    {
        return m_configuration.m_ambient;
    }

    void EditorLightComponent::SetPointMaxDistance(float newMaxDistance)
    {
        if (newMaxDistance != m_configuration.m_pointMaxDistance)
        {
            m_configuration.m_pointMaxDistance = newMaxDistance;
            m_configuration.MinorPropertyChanged();
        }
    }
    float EditorLightComponent::GetPointMaxDistance()
    {
        return m_configuration.m_pointMaxDistance;
    }

    void EditorLightComponent::SetPointAttenuationBulbSize(float newAttenuationBulbSize)
    {
        if (newAttenuationBulbSize != m_configuration.m_pointAttenuationBulbSize)
        {
            m_configuration.m_pointAttenuationBulbSize = newAttenuationBulbSize;
            m_configuration.MinorPropertyChanged();
        }
    }
    float EditorLightComponent::GetPointAttenuationBulbSize()
    {
        return m_configuration.m_pointAttenuationBulbSize;
    }

    void EditorLightComponent::SetAreaMaxDistance(float newMaxDistance)
    {
        if (newMaxDistance != m_configuration.m_areaMaxDistance)
        {
            m_configuration.m_areaMaxDistance = newMaxDistance;
            m_configuration.MinorPropertyChanged();
        }
    }
    float EditorLightComponent::GetAreaMaxDistance()
    {
        return m_configuration.m_areaMaxDistance;
    }

    void EditorLightComponent::SetAreaWidth(float newWidth)
    {
        if (newWidth != m_configuration.m_areaWidth)
        {
            m_configuration.m_areaWidth = newWidth;
            m_configuration.MinorPropertyChanged();
        }
    }
    float EditorLightComponent::GetAreaWidth()
    {
        return m_configuration.m_areaWidth;
    }

    void EditorLightComponent::SetAreaHeight(float newHeight)
    {
        if (newHeight != m_configuration.m_areaHeight)
        {
            m_configuration.m_areaHeight = newHeight;
            m_configuration.MinorPropertyChanged();
        }
    }
    float EditorLightComponent::GetAreaHeight()
    {
        return m_configuration.m_areaHeight;
    }

    void EditorLightComponent::SetAreaFOV(float newFOV)
    {
        if (newFOV != m_configuration.m_areaFOV)
        {
            m_configuration.m_areaFOV = newFOV;
            m_configuration.MinorPropertyChanged();
        }
    }
    float EditorLightComponent::GetAreaFOV()
    {
        return m_configuration.m_areaFOV;
    }

    void EditorLightComponent::SetProjectorMaxDistance(float newMaxDistance)
    {
        if (newMaxDistance != m_configuration.m_projectorRange)
        {
            m_configuration.m_projectorRange = newMaxDistance;
            m_configuration.MinorPropertyChanged();
        }
    }
    float EditorLightComponent::GetProjectorMaxDistance()
    {
        return m_configuration.m_projectorRange;
    }

    void EditorLightComponent::SetProjectorAttenuationBulbSize(float newAttenuationBulbSize)
    {
        if (newAttenuationBulbSize != m_configuration.m_projectorAttenuationBulbSize)
        {
            m_configuration.m_projectorAttenuationBulbSize = newAttenuationBulbSize;
            m_configuration.MinorPropertyChanged();
        }
    }
    float EditorLightComponent::GetProjectorAttenuationBulbSize()
    {
        return m_configuration.m_projectorAttenuationBulbSize;
    }

    void EditorLightComponent::SetProjectorFOV(float newFOV)
    {
        if (newFOV != m_configuration.m_projectorFOV)
        {
            m_configuration.m_projectorFOV = newFOV;
            m_configuration.MinorPropertyChanged();
        }
    }
    float EditorLightComponent::GetProjectorFOV()
    {
        return m_configuration.m_projectorFOV;
    }

    void EditorLightComponent::SetProjectorNearPlane(float newNearPlane)
    {
        if (newNearPlane != m_configuration.m_projectorNearPlane)
        {
            m_configuration.m_projectorNearPlane = newNearPlane;
            m_configuration.MinorPropertyChanged();
        }
    }
    float EditorLightComponent::GetProjectorNearPlane()
    {
        return m_configuration.m_projectorNearPlane;
    }

    void EditorLightComponent::SetProbeAreaDimensions(const AZ::Vector3& newDimensions)
    {
        if (newDimensions != m_configuration.m_probeArea)
        {
            m_configuration.m_probeArea = newDimensions;
            m_configuration.MinorPropertyChanged();
        }
    }
    const AZ::Vector3 EditorLightComponent::GetProbeAreaDimensions()
    {
        return m_configuration.m_probeArea;
    }

    void EditorLightComponent::SetProbeBoxProjected(bool isProbeBoxProjected)
    {
        if (isProbeBoxProjected != m_configuration.m_isBoxProjected)
        {
            m_configuration.m_isBoxProjected = isProbeBoxProjected;
            m_configuration.MinorPropertyChanged();
        }
    }
    bool EditorLightComponent::GetProbeBoxProjected()
    {
        return m_configuration.m_isBoxProjected;
    }

    void EditorLightComponent::SetProbeBoxHeight(float newHeight)
    {
        if (newHeight != m_configuration.m_boxHeight)
        {
            m_configuration.m_boxHeight = newHeight;
            m_configuration.MinorPropertyChanged();
        }
    }
    float EditorLightComponent::GetProbeBoxHeight()
    {
        return m_configuration.m_boxHeight;
    }

    void EditorLightComponent::SetProbeBoxLength(float newLength)
    {
        if (newLength != m_configuration.m_boxLength)
        {
            m_configuration.m_boxLength = newLength;
            m_configuration.MinorPropertyChanged();
        }
    }

    float EditorLightComponent::GetProbeBoxLength()
    {
        return m_configuration.m_boxLength;
    }

    void EditorLightComponent::SetProbeBoxWidth(float newWidth)
    {
        if (newWidth != m_configuration.m_boxWidth)
        {
            m_configuration.m_boxWidth = newWidth;
            m_configuration.MinorPropertyChanged();
        }
    }

    float EditorLightComponent::GetProbeBoxWidth()
    {
        return m_configuration.m_boxWidth;
    }

    void EditorLightComponent::SetProbeAttenuationFalloff(float newAttenuationFalloff)
    {
        if (newAttenuationFalloff != m_configuration.m_attenFalloffMax)
        {
            m_configuration.m_attenFalloffMax = newAttenuationFalloff;
            m_configuration.MinorPropertyChanged();
        }
    }

    float EditorLightComponent::GetProbeAttenuationFalloff()
    {
        return m_configuration.m_attenFalloffMax;
    }

    void EditorLightComponent::SetProbeFade(float fade)
    {
        AZ_Warning("Lighting", 0.0f <= fade && fade <= 1.0f, "SetProbeFade value %f out of range. Clamping to [0,1]", fade);
        fade = AZ::GetClamp(fade, 0.0f, 1.0f);

        if (fade != m_configuration.m_probeFade)
        {
            m_configuration.m_probeFade = fade;
            m_configuration.MinorPropertyChanged();
        }
    }

    float EditorLightComponent::GetProbeFade()
    {
        return m_configuration.m_probeFade;
    }

    void EditorLightComponent::SetIndoorOnly(bool newIndoorOnly)
    {
        if (m_configuration.m_indoorOnly != newIndoorOnly)
        {
            m_configuration.m_indoorOnly = newIndoorOnly;
            m_configuration.MinorPropertyChanged();
        }
    }
    bool EditorLightComponent::GetIndoorOnly()
    {
        return m_configuration.m_indoorOnly;
    }

    void EditorLightComponent::SetCastShadowSpec(AZ::u32 newCastShadowSpec)
    {
        EngineSpec shadowSpec = static_cast<EngineSpec>(newCastShadowSpec);
        if (m_configuration.m_castShadowsSpec != shadowSpec)
        {
            m_configuration.m_castShadowsSpec = shadowSpec;
            m_configuration.MinorPropertyChanged();
        }
    }
    AZ::u32 EditorLightComponent::GetCastShadowSpec()
    {
        return static_cast<AZ::u32>(m_configuration.m_castShadowsSpec);
    }

    void EditorLightComponent::SetViewDistanceMultiplier(float newMultiplier)
    {
        if (m_configuration.m_viewDistMultiplier != newMultiplier)
        {
            m_configuration.m_viewDistMultiplier = newMultiplier;
            m_configuration.MinorPropertyChanged();
        }
    }
    float EditorLightComponent::GetViewDistanceMultiplier()
    {
        return m_configuration.m_viewDistMultiplier;
    }

    void EditorLightComponent::SetProbeArea(const AZ::Vector3& newProbeArea)
    {
        if (m_configuration.m_probeArea != newProbeArea)
        {
            m_configuration.m_probeArea = newProbeArea;
            m_configuration.MinorPropertyChanged();
        }
    }
    AZ::Vector3 EditorLightComponent::GetProbeArea()
    {
        return m_configuration.m_probeArea;
    }

    void EditorLightComponent::SetProbeSortPriority(AZ::u32 newProbeSortPriority)
    {
        if (m_configuration.m_probeSortPriority != newProbeSortPriority)
        {
            m_configuration.m_probeSortPriority = newProbeSortPriority;
            m_configuration.MinorPropertyChanged();
        }
    }
    AZ::u32 EditorLightComponent::GetProbeSortPriority()
    {
        return m_configuration.m_probeSortPriority;
    }

    void EditorLightComponent::SetVolumetricFog(bool newVolumetricFog)
    {
        if (m_configuration.m_volumetricFog != newVolumetricFog)
        {
            m_configuration.m_volumetricFog = newVolumetricFog;
            m_configuration.MinorPropertyChanged();
        }
    }
    bool EditorLightComponent::GetVolumetricFog()
    {
        return m_configuration.m_volumetricFog;
    }

    void EditorLightComponent::SetVolumetricFogOnly(bool newVolumetricFogOnly)
    {
        if (m_configuration.m_volumetricFogOnly != newVolumetricFogOnly)
        {
            m_configuration.m_volumetricFogOnly = newVolumetricFogOnly;
            m_configuration.MinorPropertyChanged();
        }
    }
    bool EditorLightComponent::GetVolumetricFogOnly()
    {
        return m_configuration.m_volumetricFogOnly;
    }

    void EditorLightComponent::SetAttenuationFalloffMax(float newAttenFalloffMax)
    {
        if (m_configuration.m_attenFalloffMax != newAttenFalloffMax)
        {
            m_configuration.m_attenFalloffMax = newAttenFalloffMax;
            m_configuration.MinorPropertyChanged();
        }
    }
    float EditorLightComponent::GetAttenuationFalloffMax()
    {
        return m_configuration.m_attenFalloffMax;
    }

    void EditorLightComponent::SetUseVisAreas(bool useVisAreas)
    {
        if (m_configuration.m_useVisAreas != useVisAreas)
        {
            m_configuration.m_useVisAreas = useVisAreas;
            m_configuration.MinorPropertyChanged();
        }
    }
    bool EditorLightComponent::GetUseVisAreas()
    {
        return m_configuration.m_useVisAreas;
    }

    void EditorLightComponent::SetAffectsThisAreaOnly(bool affectsThisAreaOnly)
    {
        if (m_configuration.m_affectsThisAreaOnly != affectsThisAreaOnly)
        {
            m_configuration.m_affectsThisAreaOnly = affectsThisAreaOnly;
            m_configuration.MinorPropertyChanged();
        }
    }
    bool EditorLightComponent::GetAffectsThisAreaOnly()
    {
        return m_configuration.m_affectsThisAreaOnly;
    }

    void EditorLightComponent::SetBoxHeight(float newBoxHeight)
    {
        if (m_configuration.m_boxHeight != newBoxHeight)
        {
            m_configuration.m_boxHeight = newBoxHeight;
            m_configuration.MinorPropertyChanged();
        }
    }
    float EditorLightComponent::GetBoxHeight()
    {
        return m_configuration.m_boxHeight;
    }

    void EditorLightComponent::SetBoxWidth(float newBoxWidth)
    {
        if (m_configuration.m_boxWidth != newBoxWidth)
        {
            m_configuration.m_boxWidth = newBoxWidth;
            m_configuration.MinorPropertyChanged();
        }
    }
    float EditorLightComponent::GetBoxWidth()
    {
        return m_configuration.m_boxWidth;
    }

    void EditorLightComponent::SetBoxLength(float newBoxLength)
    {
        if (m_configuration.m_boxLength != newBoxLength)
        {
            m_configuration.m_boxLength = newBoxLength;
            m_configuration.MinorPropertyChanged();
        }
    }
    float EditorLightComponent::GetBoxLength()
    {
        return m_configuration.m_boxLength;
    }

    void EditorLightComponent::SetBoxProjected(bool newBoxProjected)
    {
        if (m_configuration.m_isBoxProjected != newBoxProjected)
        {
            m_configuration.m_isBoxProjected = newBoxProjected;
            m_configuration.MinorPropertyChanged();
        }
    }
    bool EditorLightComponent::GetBoxProjected()
    {
        return m_configuration.m_isBoxProjected;
    }
    ///////////////////////////////////////////////////////////////////

    void EditorLightComponent::SetShadowBias(float shadowBias)
    {
        if (m_configuration.m_shadowBias != shadowBias)
        {
            m_configuration.m_shadowBias = shadowBias;
            m_configuration.MinorPropertyChanged();
        }
    }
    float EditorLightComponent::GetShadowBias()
    {
        return m_configuration.m_shadowBias;
    }

    void EditorLightComponent::SetShadowSlopeBias(float shadowSlopeBias)
    {
        if (m_configuration.m_shadowSlopeBias != shadowSlopeBias)
        {
            m_configuration.m_shadowSlopeBias = shadowSlopeBias;
            m_configuration.MinorPropertyChanged();
        }
    }
    float EditorLightComponent::GetShadowSlopeBias()
    {
        return m_configuration.m_shadowSlopeBias;
    }

    void EditorLightComponent::SetShadowResScale(float shadowResScale)
    {
        if (m_configuration.m_shadowResScale != shadowResScale)
        {
            m_configuration.m_shadowResScale = shadowResScale;
            m_configuration.MinorPropertyChanged();
        }
    }
    float EditorLightComponent::GetShadowResScale()
    {
        return m_configuration.m_shadowResScale;
    }

    void EditorLightComponent::SetShadowUpdateMinRadius(float shadowUpdateMinRadius)
    {
        if (m_configuration.m_shadowUpdateMinRadius != shadowUpdateMinRadius)
        {
            m_configuration.m_shadowUpdateMinRadius = shadowUpdateMinRadius;
            m_configuration.MinorPropertyChanged();
        }
    }
    float EditorLightComponent::GetShadowUpdateMinRadius()
    {
        return m_configuration.m_shadowUpdateMinRadius;
    }

    void EditorLightComponent::SetShadowUpdateRatio(float shadowUpdateRatio)
    {
        if (m_configuration.m_shadowUpdateRatio != shadowUpdateRatio)
        {
            m_configuration.m_shadowUpdateRatio = shadowUpdateRatio;
            m_configuration.MinorPropertyChanged();
        }
    }
    float EditorLightComponent::GetShadowUpdateRatio()
    {
        return m_configuration.m_shadowUpdateRatio;
    }

    // Animation parameters
    void EditorLightComponent::SetAnimIndex(AZ::u32 animIndex)
    {
        if (m_configuration.m_animIndex != animIndex)
        {
            m_configuration.m_animIndex = animIndex;
            m_configuration.MinorPropertyChanged();
        }
    }
    AZ::u32 EditorLightComponent::GetAnimIndex()
    {
        return m_configuration.m_animIndex;
    }

    void EditorLightComponent::SetAnimSpeed(float animSpeed)
    {
        if (m_configuration.m_animSpeed != animSpeed)
        {
            m_configuration.m_animSpeed = animSpeed;
            m_configuration.MinorPropertyChanged();
        }
    }
    float EditorLightComponent::GetAnimSpeed()
    {
        return m_configuration.m_animSpeed;
    }

    void EditorLightComponent::OnTransformChanged(const AZ::Transform& /*local*/, const AZ::Transform& world)
    {
        m_cubemapPreview.SetTransform(AZTransformToLYTransform(world));
    }

    void EditorLightComponent::SetAnimPhase(float animPhase)
    {
        if (m_configuration.m_animPhase != animPhase)
        {
            m_configuration.m_animPhase = animPhase;
            m_configuration.MinorPropertyChanged();
        }
    }
    float EditorLightComponent::GetAnimPhase()
    {
        return m_configuration.m_animPhase;
    }

    const char* EditorLightComponent::GetLightTypeText() const
    {
        return "Deprecated Light";
    }

    void EditorLightComponent::DisplayEntityViewport(
        const AzFramework::ViewportInfo& viewportInfo,
        AzFramework::DebugDisplayRequests& debugDisplay)
    {
        // Don't draw extra visualization unless selected.
        if (!IsSelected())
        {
            return;
        }

        AZ::Transform transform = AZ::Transform::CreateIdentity();
        AZ::TransformBus::EventResult(transform, GetEntityId(), &AZ::TransformInterface::GetWorldTM);

        transform.ExtractScaleExact();
        debugDisplay.PushMatrix(transform);
        const AZ::Color& color = m_configuration.m_color;
        debugDisplay.SetColor(AZ::Vector4(color.GetR(), color.GetG(), color.GetB(), 1.f));

        switch (m_configuration.m_lightType)
        {
        case EditorLightConfiguration::LightType::Point:
        {
            debugDisplay.DrawWireSphere(AZ::Vector3::CreateZero(), m_configuration.m_pointMaxDistance);
            debugDisplay.DrawWireSphere(AZ::Vector3::CreateZero(), m_configuration.m_pointAttenuationBulbSize);
            break;
        }
        case EditorLightConfiguration::LightType::Area:
        {
            debugDisplay.SetColor(AZ::Vector4(color.GetR(), color.GetG(), color.GetB(), 0.5f));

            // Some initial calculations for drawing
            AZ::Matrix3x3 rotYMatrix = AZ::Matrix3x3::CreateRotationY(AZ::DegToRad(m_configuration.m_areaFOV));
            AZ::Matrix3x3 rotXMatrix = AZ::Matrix3x3::CreateRotationX(AZ::DegToRad(45));
            AZ::Vector3 AngleRefPoint = AZ::Vector3(m_configuration.m_areaMaxDistance, 0, 0);
            AngleRefPoint *= rotYMatrix;
            const float roundedRectangleOffset = AngleRefPoint.GetZ();
            AngleRefPoint *= rotXMatrix;

            // draw box around light
            AZ::Vector3 points[4];
            points[0] = AZ::Vector3(0, -m_configuration.m_areaWidth * 0.5f, -m_configuration.m_areaHeight * 0.5f);
            points[1] = AZ::Vector3(0,  m_configuration.m_areaWidth * 0.5f, -m_configuration.m_areaHeight * 0.5f);
            points[2] = AZ::Vector3(0,  m_configuration.m_areaWidth * 0.5f,  m_configuration.m_areaHeight * 0.5f);
            points[3] = AZ::Vector3(0, -m_configuration.m_areaWidth * 0.5f,  m_configuration.m_areaHeight * 0.5f);
            debugDisplay.DrawPolyLine(points, 4, true);

            // draw lines from corners of light
            debugDisplay.DrawLine(points[0], points[0] + AZ::Vector3(AngleRefPoint.GetX(), -AngleRefPoint.GetY(), -AngleRefPoint.GetZ()));
            debugDisplay.DrawLine(points[1], points[1] + AZ::Vector3(AngleRefPoint.GetX(),  AngleRefPoint.GetY(), -AngleRefPoint.GetZ()));
            debugDisplay.DrawLine(points[2], points[2] + AZ::Vector3(AngleRefPoint.GetX(),  AngleRefPoint.GetY(),  AngleRefPoint.GetZ()));
            debugDisplay.DrawLine(points[3], points[3] + AZ::Vector3(AngleRefPoint.GetX(), -AngleRefPoint.GetY(),  AngleRefPoint.GetZ()));

            // draw curves to the corners of the max distance box
            const float sqrthalf = sqrt(0.5f);
            debugDisplay.DrawArc(points[0], m_configuration.m_areaMaxDistance, 0, m_configuration.m_areaFOV,  1.0f, AZ::Vector3(0,  sqrthalf, -sqrthalf));
            debugDisplay.DrawArc(points[1], m_configuration.m_areaMaxDistance, -m_configuration.m_areaFOV, m_configuration.m_areaFOV, 1.0f, AZ::Vector3(0, -sqrthalf, -sqrthalf));
            debugDisplay.DrawArc(points[2], m_configuration.m_areaMaxDistance, 0, m_configuration.m_areaFOV,  1.0f, AZ::Vector3(0, -sqrthalf,  sqrthalf));
            debugDisplay.DrawArc(points[3], m_configuration.m_areaMaxDistance, -m_configuration.m_areaFOV, m_configuration.m_areaFOV, 1.0f, AZ::Vector3(0,  sqrthalf,  sqrthalf));

            // Draw middle rounded rect
            debugDisplay.DrawLine(
                AZ::Vector3(AngleRefPoint.GetX(), points[0].GetY(), points[0].GetZ() - roundedRectangleOffset),
                AZ::Vector3(AngleRefPoint.GetX(), points[1].GetY(), points[1].GetZ() - roundedRectangleOffset)
            );
            debugDisplay.DrawLine(
                AZ::Vector3(AngleRefPoint.GetX(), points[1].GetY() + roundedRectangleOffset, points[1].GetZ()),
                AZ::Vector3(AngleRefPoint.GetX(), points[2].GetY() + roundedRectangleOffset, points[2].GetZ())
            );
            debugDisplay.DrawLine(
                AZ::Vector3(AngleRefPoint.GetX(), points[2].GetY(), points[2].GetZ() + roundedRectangleOffset),
                AZ::Vector3(AngleRefPoint.GetX(), points[3].GetY(), points[3].GetZ() + roundedRectangleOffset)
            );
            debugDisplay.DrawLine(
                AZ::Vector3(AngleRefPoint.GetX(), points[3].GetY() - roundedRectangleOffset, points[3].GetZ()),
                AZ::Vector3(AngleRefPoint.GetX(), points[0].GetY() - roundedRectangleOffset, points[0].GetZ())
            );

            debugDisplay.DrawArc(AZ::Vector3(AngleRefPoint.GetX(), points[0].GetY(), points[0].GetZ()), roundedRectangleOffset, 270.0f, 90.0f, 2.0f, AZ::Vector3(1.0f, 0.0f, 0.0f));
            debugDisplay.DrawArc(AZ::Vector3(AngleRefPoint.GetX(), points[1].GetY(), points[1].GetZ()), roundedRectangleOffset,   0.0f, 90.0f, 2.0f, AZ::Vector3(1.0f, 0.0f, 0.0f));
            debugDisplay.DrawArc(AZ::Vector3(AngleRefPoint.GetX(), points[2].GetY(), points[2].GetZ()), roundedRectangleOffset,  90.0f, 90.0f, 2.0f, AZ::Vector3(1.0f, 0.0f, 0.0f));
            debugDisplay.DrawArc(AZ::Vector3(AngleRefPoint.GetX(), points[3].GetY(), points[3].GetZ()), roundedRectangleOffset, 180.0f, 90.0f, 2.0f, AZ::Vector3(1.0f, 0.0f, 0.0f));

            // draw box at max distance in front of light
            points[0] = AZ::Vector3(m_configuration.m_areaMaxDistance, -m_configuration.m_areaWidth * 0.5f, -m_configuration.m_areaHeight * 0.5f);
            points[1] = AZ::Vector3(m_configuration.m_areaMaxDistance,  m_configuration.m_areaWidth * 0.5f, -m_configuration.m_areaHeight * 0.5f);
            points[2] = AZ::Vector3(m_configuration.m_areaMaxDistance,  m_configuration.m_areaWidth * 0.5f,  m_configuration.m_areaHeight * 0.5f);
            points[3] = AZ::Vector3(m_configuration.m_areaMaxDistance, -m_configuration.m_areaWidth * 0.5f,  m_configuration.m_areaHeight * 0.5f);
            debugDisplay.DrawPolyLine(points, 4, true);

            break;
        }
        case EditorLightConfiguration::LightType::Projector:
        {
            debugDisplay.SetColor(AZ::Vector4(color.GetR(), color.GetG(), color.GetB(), 0.5f));

            const float range = m_configuration.m_projectorRange;
            const float attenuation = m_configuration.m_projectorAttenuationBulbSize;
            const float nearPlane = m_configuration.m_projectorNearPlane;

            DrawProjectionGizmo(debugDisplay, range);
            DrawProjectionGizmo(debugDisplay, attenuation);
            DrawPlaneGizmo(debugDisplay, nearPlane);

            break;
        }
        case EditorLightConfiguration::LightType::Probe:
        {
            AZ::Vector3 halfAreaSize = m_configuration.m_probeArea/2;
            debugDisplay.SetColor(1, 1, 0, 0.8f);
            debugDisplay.DrawWireBox( -halfAreaSize, halfAreaSize);
            if (m_configuration.m_isBoxProjected)
            {
                AZ::Vector3 halfBoxSize = AZ::Vector3(m_configuration.m_boxWidth, m_configuration.m_boxLength, m_configuration.m_boxHeight) / 2;
                debugDisplay.SetColor(0, 1, 0, 0.8f);
                debugDisplay.DrawWireBox(-halfBoxSize, halfBoxSize);
            }

            // Note that rendering the cubemap preview is handled by m_cubemapPreview

            break;
        }
        }

        debugDisplay.PopMatrix();
    }

    void EditorLightComponent::DrawProjectionGizmo(
        AzFramework::DebugDisplayRequests& debugDisplay, const float radius) const
    {
        //Don't draw if the radius isn't going to result in anything visible
        if (radius <= 0)
        {
            return;
        }

        const int numPoints = 16;     // per one arc
        const int numArcs = 6;

        AZ::Vector3 points[numPoints * numArcs];
        {
            // Generate 4 arcs on intersection of sphere with pyramid.
            const float fov = DEG2RAD(m_configuration.m_projectorFOV);

            const AZ::Vector3 lightAxis(radius, 0.0f, 0.0f);
            const float tanA = tan_tpl(fov * 0.5f);
            const float fovProj = asin_tpl(1.0f / sqrtf(2.0f + 1.0f / (tanA * tanA))) * 2.0f;

            const float halfFov = 0.5f * fov;
            const float halfFovProj = fovProj * 0.5f;
            const float anglePerSegmentOfFovProj = 1.0f / (numPoints - 1) * fovProj;

            const AZ::Quaternion yRot = AZ::Quaternion::CreateRotationY(halfFov);
            AZ::Vector3* arcPoints = points;
            for (int i = 0; i < numPoints; ++i)
            {
                float angle = i * anglePerSegmentOfFovProj - halfFovProj;
                arcPoints[i] = yRot * AZ::Quaternion::CreateRotationZ(angle) * lightAxis;
            }

            const AZ::Quaternion zRot = AZ::Quaternion::CreateRotationZ(halfFov);
            arcPoints += numPoints;
            for (int i = 0; i < numPoints; ++i)
            {
                float angle = (numPoints - i - 1) * anglePerSegmentOfFovProj - halfFovProj;
                arcPoints[i] = zRot * AZ::Quaternion::CreateRotationY(angle) * lightAxis;
            }

            const AZ::Quaternion nyRot = AZ::Quaternion::CreateRotationY(-halfFov);
            arcPoints += numPoints;
            for (int i = 0; i < numPoints; ++i)
            {
                float angle = (numPoints - i - 1) * anglePerSegmentOfFovProj - halfFovProj;
                arcPoints[i] = nyRot * AZ::Quaternion::CreateRotationZ(angle) * lightAxis;
            }

            const AZ::Quaternion nzRot = AZ::Quaternion::CreateRotationZ(-halfFov);
            arcPoints += numPoints;
            for (int i = 0; i < numPoints; ++i)
            {
                float angle = i * anglePerSegmentOfFovProj - halfFovProj;
                arcPoints[i] = nzRot * AZ::Quaternion::CreateRotationY(angle) * lightAxis;
            }

            arcPoints += numPoints;
            const float anglePerSegmentOfFov = 1.0f / (numPoints - 1) * fov;
            for (int i = 0; i < numPoints; ++i)
            {
                float angle = i * anglePerSegmentOfFov - halfFov;
                arcPoints[i] = AZ::Quaternion::CreateRotationY(angle) * lightAxis;
            }

            arcPoints += numPoints;
            for (int i = 0; i < numPoints; ++i)
            {
                float angle = i * anglePerSegmentOfFov - halfFov;
                arcPoints[i] = AZ::Quaternion::CreateRotationZ(angle) * lightAxis;
            }
        }

        // Draw pyramid and sphere intersection.
        debugDisplay.DrawPolyLine(points, numPoints * 4, false);

        // Draw cross.
        debugDisplay.DrawPolyLine(points + numPoints * 4, numPoints, false);
        debugDisplay.DrawPolyLine(points + numPoints * 5, numPoints, false);
        debugDisplay.DrawLine(AZ::Vector3::CreateZero(), points[numPoints * 0]);
        debugDisplay.DrawLine(AZ::Vector3::CreateZero(), points[numPoints * 1]);
        debugDisplay.DrawLine(AZ::Vector3::CreateZero(), points[numPoints * 2]);
        debugDisplay.DrawLine(AZ::Vector3::CreateZero(), points[numPoints * 3]);
    }

    void EditorLightComponent::DrawPlaneGizmo(AzFramework::DebugDisplayRequests& debugDisplay, const float depth) const
    {
        //Don't draw if depth isn't going to result in anything visible
        if (depth <= 0)
        {
            return;
        }

        const uint32_t numPoints = 8; //8 Points - 4 corners and 4 half widths

        AZ::Vector3 points[numPoints];

        const float fov = DEG2RAD(m_configuration.m_projectorFOV);
        const float halfWidth = tanf(0.5f * fov) * depth;       //Calculate the half width of the frustum at this depth

        //Add corners
        points[0] = AZ::Vector3(depth, +halfWidth, +halfWidth); //Top-Left
        points[1] = AZ::Vector3(depth, -halfWidth, +halfWidth); //Top-Right
        points[2] = AZ::Vector3(depth, -halfWidth, -halfWidth); //Bottom-Right
        points[3] = AZ::Vector3(depth, +halfWidth, -halfWidth); //Bottom-Left

        //Add points halfway between corners
        points[4] = AZ::Vector3(depth, 0, +halfWidth);  //Top-Middle
        points[5] = AZ::Vector3(depth, -halfWidth, 0);  //Right-Middle
        points[6] = AZ::Vector3(depth, 0, -halfWidth);  //Bottom-Middle
        points[7] = AZ::Vector3(depth, +halfWidth, 0);  //Left-Middle


        //Draw Square
        debugDisplay.DrawLine(points[0], points[1]); //TL to TR
        debugDisplay.DrawLine(points[1], points[2]); //TR to BR
        debugDisplay.DrawLine(points[2], points[3]); //BR to BL
        debugDisplay.DrawLine(points[3], points[0]); //BL to TL

        const AZ::Vector3 depthVec(depth, 0, 0);

        // Draw Cross
        debugDisplay.DrawLine(depthVec, points[4]);
        debugDisplay.DrawLine(depthVec, points[5]);
        debugDisplay.DrawLine(depthVec, points[6]);
        debugDisplay.DrawLine(depthVec, points[7]);
    }

    EditorLightComponent::CubemapPreview::CubemapPreview()
        : m_renderTransform(Matrix34::CreateIdentity())
        , m_statObj(nullptr)
    {
        m_dwRndFlags |= ERF_RENDER_ALWAYS;
    }

    void EditorLightComponent::CubemapPreview::Setup(const char* textureName)
    {
        if (!m_editor)
        {
            AzToolsFramework::EditorRequestBus::BroadcastResult(m_editor, &AzToolsFramework::EditorRequests::GetEditor);
        }

        if (!m_materialManager)
        {
            m_materialManager = m_editor->Get3DEngine()->GetMaterialManager();
        }

        _smart_ptr<IMaterial> material = m_materialManager->LoadMaterial("Editor/Objects/envcube", false, true);
        QString matName = Path::GetFileName(textureName);
        if (material)
        {
            SShaderItem& si = material->GetShaderItem();

            // We need to clone the material in order for multiple Environment Probes to not stomp each other's preview materials.
            material = m_materialManager->CreateMaterial(matName.toUtf8().data(), material->GetFlags() | MTL_FLAG_NON_REMOVABLE);
            if (material)
            {
                SInputShaderResources   isr = si.m_pShaderResources;
                // The following operation will create a texture slot entry and copy the name to it.
                isr.m_TexturesResourcesMap[EFTT_ENV].m_Name = textureName;

                SShaderItem siDst = m_editor->GetRenderer()->EF_LoadShaderItem(si.m_pShader->GetName(), true, 0, &isr, si.m_pShader->GetGenerationMask());
                material->AssignShaderItem(siDst);
            }
        }

        m_statObj = m_editor->Get3DEngine()->LoadStatObjAutoRef("Editor/Objects/envcube.cgf", nullptr, nullptr, false);
        if (m_statObj)
        {
            // We need to clone the object in order for multiple Environment Probes to not stomp each other's preview materials.
            m_statObj = m_statObj->Clone(false, false, false);

            m_statObj->SetMaterial(material);
        }
    }

    void EditorLightComponent::CubemapPreview::UpdateTexture(const char* textureName)
    {
        if (m_statObj)
        {
            _smart_ptr<IMaterial> material = m_statObj->GetMaterial();

            if (material)
            {
                SShaderItem& si = material->GetShaderItem();

                SInputShaderResources isr = si.m_pShaderResources;
                // The following operation will create a texture slot entry and copy the name to it.
                isr.m_TexturesResourcesMap[EFTT_ENV].m_Name = textureName;

                SShaderItem siDst = m_editor->GetRenderer()->EF_LoadShaderItem(si.m_pShader->GetName(), true, 0, &isr, si.m_pShader->GetGenerationMask());
                material->AssignShaderItem(siDst);
            }
        }
    }

    void EditorLightComponent::CubemapPreview::SetTransform(const Matrix34& transform)
    {
        m_renderTransform = transform;
    }

    void EditorLightComponent::CubemapPreview::Render(const struct SRendParams& inRenderParams, const struct SRenderingPassInfo& passInfo)
    {
        if (m_statObj)
        {
            SRendParams rp;
            rp.AmbientColor = ColorF(1.0f, 1.0f, 1.0f, 1);
            rp.fAlpha = 1;
            rp.pMatrix = &m_renderTransform;
            rp.pMaterial = m_statObj->GetMaterial();

            m_statObj->Render(rp, passInfo);
        }
    }

    EERType EditorLightComponent::CubemapPreview::GetRenderNodeType()
    {
        return eERType_RenderComponent;
    }

    const char* EditorLightComponent::CubemapPreview::GetName() const
    {
        return "CubemapPreview";
    }

    const char* EditorLightComponent::CubemapPreview::GetEntityClassName() const
    {
        return "CubemapPreview";
    }

    Vec3 EditorLightComponent::CubemapPreview::GetPos(bool bWorldOnly) const
    {
        return m_renderTransform.GetTranslation();
    }

    const AABB EditorLightComponent::CubemapPreview::GetBBox() const
    {
        AABB transformedAABB;
        transformedAABB.Reset();
        if (m_statObj)
        {
            transformedAABB.SetTransformedAABB(QuatT(m_renderTransform), m_statObj->GetAABB());
        }
        return transformedAABB;
    }

    _smart_ptr<IMaterial> EditorLightComponent::CubemapPreview::GetMaterial(Vec3* pHitPos)
    {
        return m_statObj ? m_statObj->GetMaterial() : nullptr;
    }

    _smart_ptr<IMaterial> EditorLightComponent::CubemapPreview::GetMaterialOverride()
    {
        return m_statObj ? m_statObj->GetMaterial() : nullptr;
    }

    IStatObj* EditorLightComponent::CubemapPreview::GetEntityStatObj(unsigned int nPartId, unsigned int nSubPartId, Matrix34A* pMatrix, bool bReturnOnlyVisible)
    {
        if (0 == nPartId)
        {
            if (pMatrix)
            {
                *pMatrix = m_renderTransform;
            }

            return m_statObj;
        }

        return nullptr;
    }

    float EditorLightComponent::CubemapPreview::GetMaxViewDist()
    {
        return FLT_MAX;
    }

    void EditorLightComponent::CubemapPreview::GetMemoryUsage(class ICrySizer* pSizer) const
    {
        pSizer->AddObjectSize(this);
    }



} // namespace LmbrCentral