123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356 |
- /*******************************************************************************
- The content of this file includes portions of the proprietary AUDIOKINETIC Wwise
- Technology released in source code form as part of the game integration package.
- The content of this file may not be used without valid licenses to the
- AUDIOKINETIC Wwise Technology.
- Note that the use of the game engine is subject to the Unreal(R) Engine End User
- License Agreement at https://www.unrealengine.com/en-US/eula/unreal
-
- License Usage
-
- Licensees holding valid licenses to the AUDIOKINETIC Wwise Technology may use
- this file in accordance with the end user license agreement provided with the
- software or, alternatively, in accordance with the terms contained
- in a written agreement between you and Audiokinetic Inc.
- Copyright (c) 2023 Audiokinetic Inc.
- *******************************************************************************/
- #include "AkSurfaceReflectorSetDetailsCustomization.h"
- #include "AkComponent.h"
- #include "AkSurfaceReflectorSetComponent.h"
- #include "DetailCategoryBuilder.h"
- #include "DetailLayoutBuilder.h"
- #include "DetailWidgetRow.h"
- #include "EditorModeManager.h"
- #include "EditorSupportDelegates.h"
- #include "IPropertyUtilities.h"
- #include "LevelEditorActions.h"
- #include "Model.h"
- #include "GameFramework/Volume.h"
- #include "UI/SAcousticSurfacesController.h"
- #include "Widgets/Input/SButton.h"
- #include "Widgets/Layout/SBox.h"
- #include "Widgets/Text/STextBlock.h"
- #include "Builders/ConeBuilder.h"
- #include "Builders/CubeBuilder.h"
- #include "Builders/CurvedStairBuilder.h"
- #include "Builders/CylinderBuilder.h"
- #include "Builders/LinearStairBuilder.h"
- #include "Builders/SpiralStairBuilder.h"
- #include "Builders/TetrahedronBuilder.h"
- #define LOCTEXT_NAMESPACE "AudiokineticTools"
- //////////////////////////////////////////////////////////////////////////
- // FAkSurfaceReflectorSetDetailsCustomization
- FAkSurfaceReflectorSetDetailsCustomization::FAkSurfaceReflectorSetDetailsCustomization()
- {
- ReflectorSetBeingCustomized = nullptr;
- FCoreUObjectDelegates::OnObjectModified.AddRaw(this, &FAkSurfaceReflectorSetDetailsCustomization::OnObjectModified);
- FEditorSupportDelegates::RedrawAllViewports.AddRaw(this, &FAkSurfaceReflectorSetDetailsCustomization::OnRedrawViewports);
- }
- FAkSurfaceReflectorSetDetailsCustomization::~FAkSurfaceReflectorSetDetailsCustomization()
- {
- FCoreUObjectDelegates::OnObjectModified.RemoveAll(this);
- FEditorSupportDelegates::RedrawAllViewports.RemoveAll(this);
- if (ReflectorSetBeingCustomized.IsValid() && ReflectorSetBeingCustomized->GetOnRefreshDetails())
- {
- if (ReflectorSetBeingCustomized->GetOnRefreshDetails()->IsBoundToObject(this))
- {
- ReflectorSetBeingCustomized->ClearOnRefreshDetails();
- }
- }
- ReflectorSetBeingCustomized.Reset();
- }
- FReply FAkSurfaceReflectorSetDetailsCustomization::OnEnableEditModeClicked()
- {
- FLevelEditorActionCallbacks::OnShowOnlySelectedActors();
- GLevelEditorModeTools().ActivateMode(FEditorModeID(TEXT("EM_Geometry")), false);
- return FReply::Handled();
- }
- FReply FAkSurfaceReflectorSetDetailsCustomization::OnDisableEditModeClicked()
- {
- GLevelEditorModeTools().DeactivateMode(FEditorModeID(TEXT("EM_Geometry")));
- FLevelEditorActionCallbacks::ExecuteExecCommand(FString(TEXT("ACTOR UNHIDE ALL")));
- return FReply::Handled();
- }
- void FAkSurfaceReflectorSetDetailsCustomization::OnObjectModified(UObject* Object)
- {
- if (!SelectedObjectModifiedThisFrame)
- {
- for (TWeakObjectPtr<UObject> UObjectPtr : ObjectsBeingCustomized)
- {
- if (Object == UObjectPtr.Get())
- {
- SelectedObjectModifiedThisFrame = true;
- return;
- }
- }
- }
- }
- void FAkSurfaceReflectorSetDetailsCustomization::OnRedrawViewports()
- {
- if (SelectedObjectModifiedThisFrame && DetailBuilder.IsValid())
- {
- // If there is any user interaction going on, we don't want to refresh the details panel.
- // (This would interupt the interaction and make sliders unusable)
- for (TWeakObjectPtr<UObject> UObjectPtr : ObjectsBeingCustomized)
- {
- if (UAkSurfaceReflectorSetComponent* reflectorSet = Cast<UAkSurfaceReflectorSetComponent>(UObjectPtr.Get()))
- {
- if (reflectorSet->UserInteractionInProgress)
- {
- return;
- }
- }
- }
- IDetailLayoutBuilder* Layout = nullptr;
- if (auto LockedDetailBuilder = DetailBuilder.Pin())
- {
- Layout = LockedDetailBuilder.Get();
- }
- if (LIKELY(Layout))
- {
- Layout->ForceRefreshDetails();
- }
- SelectedObjectModifiedThisFrame = false;
- }
- }
- TSharedRef<IDetailCustomization> FAkSurfaceReflectorSetDetailsCustomization::MakeInstance()
- {
- return MakeShareable(new FAkSurfaceReflectorSetDetailsCustomization());
- }
- void FAkSurfaceReflectorSetDetailsCustomization::CustomizeDetails(const TSharedPtr<IDetailLayoutBuilder>& InDetailBuilder)
- {
- InDetailBuilder->EditCategory("Toggle", FText::GetEmpty(), ECategoryPriority::Important);
- InDetailBuilder->EditCategory("Geometry Settings", FText::GetEmpty(), ECategoryPriority::TypeSpecific);
- InDetailBuilder->EditCategory("Fit To Geometry", FText::GetEmpty(), ECategoryPriority::TypeSpecific);
- DetailBuilder = InDetailBuilder;
- CustomizeDetails(*InDetailBuilder);
- }
- void FAkSurfaceReflectorSetDetailsCustomization::CustomizeDetails(IDetailLayoutBuilder& InDetailBuilder)
- {
- InDetailBuilder.GetObjectsBeingCustomized(ObjectsBeingCustomized);
- auto AcousticPolysPropHandle = InDetailBuilder.GetProperty("AcousticPolys");
- InDetailBuilder.HideProperty("AcousticPolys");
-
- bool showGeometrySettings = false;
- for (int i = 0; i < ObjectsBeingCustomized.Num(); ++i)
- {
- auto Component = Cast<UAkSurfaceReflectorSetComponent>(ObjectsBeingCustomized[i].Get());
- if (Component)
- {
- ReflectorSetBeingCustomized = TWeakObjectPtr<UAkSurfaceReflectorSetComponent>(Component);
- if (ReflectorSetBeingCustomized->bEnableSurfaceReflectors)
- {
- showGeometrySettings = true;
- break;
- }
- }
- }
- if (!showGeometrySettings)
- InDetailBuilder.HideCategory("Geometry Settings");
- IDetailCategoryBuilder& CategoryBuilder = InDetailBuilder.EditCategory("Geometry Surfaces", FText::GetEmpty(), ECategoryPriority::TypeSpecific);
- FString enableEditSurfacesTooltip(FString("Enable ") + GEOMETRY_EDIT_DISPLAY_NAME + " and show only selected actors");
- FString disableEditSurfacesTooltip(FString("Disable ") + GEOMETRY_EDIT_DISPLAY_NAME + " and show all actors");
- CategoryBuilder.HeaderContent
- (
- SNew(SHorizontalBox)
- + SHorizontalBox::Slot()
- .HAlign(HAlign_Left)
- .VAlign(VAlign_Center)
- .AutoWidth()
- [
- SAssignNew(SelectionInfoLabel, STextBlock)
- // SelectionInfoLabel is passed in to a SAcousticSurfacesController below, and the selection text is set during its construction.
- .Text(FText::FromString(""))
- ]
- + SHorizontalBox::Slot()
- .AutoWidth()
- .HAlign(HAlign_Left)
- .VAlign(VAlign_Center)
- [
- SNew(SButton)
- .Text(FText::FromString("Enable Edit Surfaces "))
- .ToolTipText(FText::FromString(enableEditSurfacesTooltip))
- .OnClicked(this, &FAkSurfaceReflectorSetDetailsCustomization::OnEnableEditModeClicked)
- ]
- + SHorizontalBox::Slot()
- .AutoWidth()
- .HAlign(HAlign_Left)
- .VAlign(VAlign_Center)
- [
- SNew(SButton)
- .Text(FText::FromString("Disable Edit Surfaces"))
- .ToolTipText(FText::FromString(disableEditSurfacesTooltip))
- .OnClicked(this, &FAkSurfaceReflectorSetDetailsCustomization::OnDisableEditModeClicked)
- ]
- );
- // Assume Transmission Loss controls will be hidden
- int surfacePropertiesControlsHeight = 48;
- for (TWeakObjectPtr<UObject> ObjectBeingCustomized : ObjectsBeingCustomized)
- {
- UAkSurfaceReflectorSetComponent* reflectorSetComponent = Cast<UAkSurfaceReflectorSetComponent>(ObjectBeingCustomized.Get());
- if (reflectorSetComponent && reflectorSetComponent->bEnableSurfaceReflectors)
- {
- // There is a surface reflector set with bEnableSurfaceReflectors enabled - add room for Transmission Loss controls.
- surfacePropertiesControlsHeight = 72;
- break;
- }
- }
- if (auto LockedDetailBuilder = DetailBuilder.Pin())
- {
- FDetailWidgetRow& acousticSurfacesRow = CategoryBuilder.AddCustomRow(AcousticPolysPropHandle->GetPropertyDisplayName());
- acousticSurfacesRow.NameContent()
- [
- SNew(SBox)
- .HeightOverride(surfacePropertiesControlsHeight)
- [
- SNew(SAcousticSurfacesLabels, ObjectsBeingCustomized)
- ]
- ];
- acousticSurfacesRow.ValueContent()
- [
- SNew(SBox)
- .HeightOverride(surfacePropertiesControlsHeight)
- [
- SNew(SAcousticSurfacesController, ObjectsBeingCustomized, LockedDetailBuilder)
- ]
- ];
- }
- if (ObjectsBeingCustomized.Num() == 1)
- {
- auto Component = Cast<UAkSurfaceReflectorSetComponent>(ObjectsBeingCustomized[0].Get());
- if (Component)
- {
- ReflectorSetBeingCustomized = TWeakObjectPtr<UAkSurfaceReflectorSetComponent>(Component);
- SetupGeometryModificationHandlers();
- }
- else
- {
- ReflectorSetBeingCustomized.Reset();
- UE_LOG(LogAkAudio, Log, TEXT("FAkSurfaceReflectorSetDetailsCustomization::CustomizeDetails: Could not get ObjectsBeingCustomized."));
- }
- }
- }
- #define REGISTER_PROPERTY_CHANGED(Class, Property, LockedDetailBuilder) \
- auto Property ## Handle = LockedDetailBuilder->GetProperty(GET_MEMBER_NAME_CHECKED(Class, Property), Class::StaticClass(), BrushBuilderName); \
- if (Property ## Handle->IsValidHandle()) Property ## Handle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FAkSurfaceReflectorSetDetailsCustomization::OnGeometryChanged))
- void FAkSurfaceReflectorSetDetailsCustomization::SetupGeometryModificationHandlers()
- {
- if (!ReflectorSetBeingCustomized.IsValid())
- {
- return;
- }
- static const FName BrushBuilderName(TEXT("BrushBuilder"));
- auto ParentBrush = ReflectorSetBeingCustomized->ParentBrush;
- if(!ParentBrush)
- return;
- if (auto LockedDetailBuilder = DetailBuilder.Pin())
- {
- auto EnableHandle = LockedDetailBuilder->GetProperty("bEnableSurfaceReflectors");
- EnableHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FAkSurfaceReflectorSetDetailsCustomization::OnEnableValueChanged));
- // This is to detect if the BrushBuilder changed.
- if (ReflectorSetBeingCustomized->AcousticPolys.Num() != ParentBrush->Nodes.Num())
- LockedDetailBuilder->GetPropertyUtilities()->EnqueueDeferredAction(FSimpleDelegate::CreateSP(this, &FAkSurfaceReflectorSetDetailsCustomization::OnGeometryChanged));
- }
- // Need to register to a LOT of different properties, because some change the geometry but don't force a refresh of the details panel
- AVolume* ParentVolume = Cast<AVolume>(ReflectorSetBeingCustomized->GetOwner());
- UClass* BrushBuilderClass = nullptr;
- if (ParentVolume && ParentVolume->BrushBuilder)
- {
- BrushBuilderClass = ParentVolume->BrushBuilder->GetClass();
- if (BrushBuilderClass == nullptr)
- {
- return;
- }
- }
- if (auto LockedDetailBuilder = DetailBuilder.Pin())
- {
- if (BrushBuilderClass == UConeBuilder::StaticClass())
- {
- REGISTER_PROPERTY_CHANGED(UConeBuilder, Sides, LockedDetailBuilder);
- REGISTER_PROPERTY_CHANGED(UConeBuilder, Hollow, LockedDetailBuilder);
- }
- else if (BrushBuilderClass == UCubeBuilder::StaticClass())
- {
- REGISTER_PROPERTY_CHANGED(UCubeBuilder, Hollow, LockedDetailBuilder);
- REGISTER_PROPERTY_CHANGED(UCubeBuilder, Tessellated, LockedDetailBuilder);
- }
- else if (BrushBuilderClass == UCurvedStairBuilder::StaticClass())
- {
- REGISTER_PROPERTY_CHANGED(UCurvedStairBuilder, NumSteps, LockedDetailBuilder);
- }
- else if (BrushBuilderClass == UCylinderBuilder::StaticClass())
- {
- REGISTER_PROPERTY_CHANGED(UCylinderBuilder, Sides, LockedDetailBuilder);
- REGISTER_PROPERTY_CHANGED(UCylinderBuilder, Hollow, LockedDetailBuilder);
- }
- else if (BrushBuilderClass == ULinearStairBuilder::StaticClass())
- {
- REGISTER_PROPERTY_CHANGED(ULinearStairBuilder, NumSteps, LockedDetailBuilder);
- }
- else if (BrushBuilderClass == USpiralStairBuilder::StaticClass())
- {
- REGISTER_PROPERTY_CHANGED(USpiralStairBuilder, NumSteps, LockedDetailBuilder);
- }
- else if (BrushBuilderClass == UTetrahedronBuilder::StaticClass())
- {
- REGISTER_PROPERTY_CHANGED(UTetrahedronBuilder, SphereExtrapolation, LockedDetailBuilder);
- }
- }
- FOnRefreshDetails DetailsChanged = FOnRefreshDetails::CreateRaw(this, &FAkSurfaceReflectorSetDetailsCustomization::OnEnableValueChanged);
- ReflectorSetBeingCustomized->SetOnRefreshDetails(DetailsChanged);
- }
- void FAkSurfaceReflectorSetDetailsCustomization::OnEnableValueChanged()
- {
- if (ReflectorSetBeingCustomized.IsValid())
- {
- ReflectorSetBeingCustomized->ClearOnRefreshDetails();
- }
- }
- void FAkSurfaceReflectorSetDetailsCustomization::OnGeometryChanged()
- {
- if (ReflectorSetBeingCustomized.IsValid())
- {
- ReflectorSetBeingCustomized->UpdatePolys();
- ReflectorSetBeingCustomized->ClearOnRefreshDetails();
- }
- }
- //////////////////////////////////////////////////////////////////////////
- #undef LOCTEXT_NAMESPACE
|