// Copyright Epic Games, Inc. All Rights Reserved. #include "LocalLightComponentDetails.h" #include "LightComponentDetails.h" #include "Components/LocalLightComponent.h" #include "Components/SpotLightComponent.h" #include "DetailLayoutBuilder.h" #include "DetailCategoryBuilder.h" #include "Engine/Scene.h" #define LOCTEXT_NAMESPACE "LocalLightComponentDetails" TSharedRef FLocalLightComponentDetails::MakeInstance() { return MakeShareable( new FLocalLightComponentDetails ); } void FLocalLightComponentDetails::CustomizeDetails( IDetailLayoutBuilder& DetailBuilder ) { TArray> Objects; DetailBuilder.GetObjectsBeingCustomized(Objects); ULocalLightComponent* Component = Cast(Objects[0].Get()); TSharedPtr LightIntensityProperty = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(ULightComponentBase, Intensity), ULightComponentBase::StaticClass()); TSharedPtr IntensityUnitsProperty = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(ULocalLightComponent, IntensityUnits), ULocalLightComponent::StaticClass()); // DetailBuilder.HideProperty(LightIntensityProperty); float ConversionFactor = 1.f; uint8 Value = 0; // Unitless if (IntensityUnitsProperty->GetValue(Value) == FPropertyAccess::Success) { ConversionFactor = ULocalLightComponent::GetUnitsConversionFactor((ELightUnits)0, (ELightUnits)Value); } IntensityUnitsProperty->SetOnPropertyValuePreChange(FSimpleDelegate::CreateSP(this, &FLocalLightComponentDetails::OnIntensityUnitsPreChange, Component)); IntensityUnitsProperty->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FLocalLightComponentDetails::OnIntensityUnitsChanged, Component)); // Inverse squared falloff point lights (the default) are in units of lumens, instead of just being a brightness scale LightIntensityProperty->SetInstanceMetaData("UIMin",TEXT("0.0f")); LightIntensityProperty->SetInstanceMetaData("UIMax", *FString::SanitizeFloat(100000.0f * ConversionFactor)); LightIntensityProperty->SetInstanceMetaData("SliderExponent", TEXT("2.0f")); if (Component->IntensityUnits == ELightUnits::Lumens) { LightIntensityProperty->SetInstanceMetaData("Units", TEXT("lm")); LightIntensityProperty->SetToolTipText(LOCTEXT("LightIntensityInLumensToolTipText", "Luminous power or flux in lumens")); } else if (Component->IntensityUnits == ELightUnits::Candelas) { LightIntensityProperty->SetInstanceMetaData("Units", TEXT("cd")); LightIntensityProperty->SetToolTipText(LOCTEXT("LightIntensityInCandelasToolTipText", "Luminous intensity in candelas")); } // Make these come first IDetailCategoryBuilder& LightCategory = DetailBuilder.EditCategory( "Light", FText::GetEmpty(), ECategoryPriority::TypeSpecific ); LightCategory.AddProperty(IntensityUnitsProperty) .OverrideResetToDefault(FResetToDefaultOverride::Create(FIsResetToDefaultVisible::CreateSP(this, &FLocalLightComponentDetails::IsIntensityUnitsResetToDefaultVisible, Component), FResetToDefaultHandler::CreateSP(this, &FLocalLightComponentDetails::ResetIntensityUnitsToDefault, Component))); LightCategory.AddProperty( DetailBuilder.GetProperty( GET_MEMBER_NAME_CHECKED(ULocalLightComponent, AttenuationRadius), ULocalLightComponent::StaticClass() ) ); } void FLocalLightComponentDetails::CustomizeDetails(const TSharedPtr& DetailBuilder) { CachedDetailBuilder = DetailBuilder; CustomizeDetails(*DetailBuilder); } void FLocalLightComponentDetails::OnIntensityUnitsPreChange(ULocalLightComponent* Component) { if (Component) { LastLightBrigtness = Component->ComputeLightBrightness(); } } void FLocalLightComponentDetails::OnIntensityUnitsChanged(ULocalLightComponent* Component) { // Convert the brightness using the new units. if (Component) { FLightComponentDetails::SetComponentIntensity(Component, LastLightBrigtness); } // Here we can only take the ptr as ForceRefreshDetails() checks that the reference is unique. IDetailLayoutBuilder* DetailBuilder = CachedDetailBuilder.Pin().Get(); if (DetailBuilder) { DetailBuilder->ForceRefreshDetails(); } } namespace { void SetComponentIntensityUnits(ULocalLightComponent* Component, ELightUnits InUnits) { check(Component); FProperty* IntensityUnitsProperty = FindFieldChecked(ULocalLightComponent::StaticClass(), GET_MEMBER_NAME_CHECKED(ULocalLightComponent, IntensityUnits)); FPropertyChangedEvent PropertyChangedEvent(IntensityUnitsProperty); const ELightUnits PreviousUnits = Component->IntensityUnits; Component->IntensityUnits = InUnits; Component->PostEditChangeProperty(PropertyChangedEvent); Component->MarkRenderStateDirty(); // Propagate changes to instances. TArray Instances; Component->GetArchetypeInstances(Instances); for (UObject* Instance : Instances) { ULocalLightComponent* InstanceComponent = Cast(Instance); if (InstanceComponent && InstanceComponent->IntensityUnits == PreviousUnits) { InstanceComponent->IntensityUnits = Component->IntensityUnits; InstanceComponent->PostEditChangeProperty(PropertyChangedEvent); InstanceComponent->MarkRenderStateDirty(); } } } } void FLocalLightComponentDetails::ResetIntensityUnitsToDefault(TSharedPtr PropertyHandle, ULocalLightComponent* Component) { // Actors (and blueprints) spawned from the actor factory inherit the intensity units from the project settings. if (Component && Component->GetArchetype() && !Component->GetArchetype()->IsInBlueprint()) { static const auto CVarDefaultLightUnits = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.DefaultFeature.LightUnits")); const ELightUnits DefaultUnits = (ELightUnits)CVarDefaultLightUnits->GetValueOnGameThread(); if (DefaultUnits != Component->IntensityUnits) { SetComponentIntensityUnits(Component, DefaultUnits); } } else { // Fall back to default handler. PropertyHandle->ResetToDefault(); } } bool FLocalLightComponentDetails::IsIntensityUnitsResetToDefaultVisible(TSharedPtr PropertyHandle, ULocalLightComponent* Component) const { // Actors (and blueprints) spawned from the actor factory inherit the project settings. if (Component && Component->GetArchetype() && !Component->GetArchetype()->IsInBlueprint()) { static const auto CVarDefaultLightUnits = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.DefaultFeature.LightUnits")); const ELightUnits DefaultUnits = (ELightUnits)CVarDefaultLightUnits->GetValueOnGameThread(); return DefaultUnits != Component->IntensityUnits; } else { // Fall back to default handler return PropertyHandle->DiffersFromDefault(); } } #undef LOCTEXT_NAMESPACE