SAcousticSurfacesController.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881
  1. /*******************************************************************************
  2. The content of this file includes portions of the proprietary AUDIOKINETIC Wwise
  3. Technology released in source code form as part of the game integration package.
  4. The content of this file may not be used without valid licenses to the
  5. AUDIOKINETIC Wwise Technology.
  6. Note that the use of the game engine is subject to the Unreal(R) Engine End User
  7. License Agreement at https://www.unrealengine.com/en-US/eula/unreal
  8. License Usage
  9. Licensees holding valid licenses to the AUDIOKINETIC Wwise Technology may use
  10. this file in accordance with the end user license agreement provided with the
  11. software or, alternatively, in accordance with the terms contained
  12. in a written agreement between you and Audiokinetic Inc.
  13. Copyright (c) 2023 Audiokinetic Inc.
  14. *******************************************************************************/
  15. #include "SAcousticSurfacesController.h"
  16. #include "AkSurfaceReflectorSetComponent.h"
  17. #include "DetailCategoryBuilder.h"
  18. #include "DetailLayoutBuilder.h"
  19. #include "EditorModeManager.h"
  20. #include "EditorModes.h"
  21. #include "Engine/Selection.h"
  22. #include "Editor/TransBuffer.h"
  23. #include "EditorSupportDelegates.h"
  24. #include "PropertyCustomizationHelpers.h"
  25. #include "SlateCore/Public/Widgets/SBoxPanel.h"
  26. #include "Widgets/Input/SButton.h"
  27. #include "Widgets/Input/SCheckBox.h"
  28. #include "Widgets/Input/SNumericEntryBox.h"
  29. #include "Widgets/Input/SSlider.h"
  30. #include "Widgets/Layout/SBox.h"
  31. #include "Widgets/SOverlay.h"
  32. #include "Widgets/Text/STextBlock.h"
  33. #if AK_SUPPORT_WAAPI
  34. #include "AkWaapiClient.h"
  35. #include "AkWaapiUtils.h"
  36. #include "Async/Async.h"
  37. #endif
  38. #define LOCTEXT_NAMESPACE "AkAudio"
  39. namespace AkAcousticSurfacesUI
  40. {
  41. static FText OverrideButtonText = FText::FromString(FString("Override"));
  42. static int OverrideButtonPadding = 5;
  43. static int LabelWidth = 102;
  44. }
  45. class SOverrideControls : public SCompoundWidget
  46. {
  47. public:
  48. SLATE_BEGIN_ARGS(SOverrideControls) {}
  49. /** Called when the button is clicked */
  50. SLATE_EVENT(FOnClicked, OnButtonClicked)
  51. SLATE_END_ARGS()
  52. void Construct(const FArguments& InArgs)
  53. {
  54. OnButtonClicked = InArgs._OnButtonClicked;
  55. ChildSlot
  56. [
  57. SNew(SHorizontalBox)
  58. + SHorizontalBox::Slot() // Label
  59. .AutoWidth()
  60. .HAlign(HAlign_Left)
  61. .VAlign(VAlign_Center)
  62. [
  63. SNew(STextBlock)
  64. .Text(FText::FromString(FString(TEXT("Multiple Values"))))
  65. ]
  66. + SHorizontalBox::Slot() // Button
  67. .AutoWidth()
  68. .HAlign(HAlign_Left)
  69. .VAlign(VAlign_Center)
  70. .Padding(AkAcousticSurfacesUI::OverrideButtonPadding, 0)
  71. [
  72. SNew(SButton)
  73. .Text(AkAcousticSurfacesUI::OverrideButtonText)
  74. .HAlign(HAlign_Left)
  75. .VAlign(VAlign_Center)
  76. .OnClicked(this, &SOverrideControls::CallClicked)
  77. ]
  78. ];
  79. }
  80. private:
  81. FOnClicked OnButtonClicked;
  82. FReply CallClicked() { return OnButtonClicked.Execute(); }
  83. };
  84. // ==================================================
  85. // SAcousticSurfacesLabels
  86. // ==================================================
  87. void SAcousticSurfacesLabels::Construct(const FArguments& InArgs, TArray<TWeakObjectPtr<UObject>> ObjectsBeingCustomized)
  88. {
  89. ComponentsBeingCustomized = ObjectsBeingCustomized;
  90. ChildSlot
  91. [
  92. SNew(SVerticalBox)
  93. + SVerticalBox::Slot() // Acoustic Surface Parameters
  94. .FillHeight(1.0f)
  95. [
  96. SNew(SVerticalBox)
  97. + SVerticalBox::Slot() // Texture
  98. .FillHeight(0.33f)
  99. [
  100. SNew(SHorizontalBox)
  101. + SHorizontalBox::Slot() // Label
  102. .HAlign(HAlign_Left)
  103. .VAlign(VAlign_Center)
  104. .AutoWidth()
  105. [
  106. SNew(SBox)
  107. .WidthOverride(AkAcousticSurfacesUI::LabelWidth)
  108. [
  109. SNew(STextBlock)
  110. .ToolTipText(FText::FromString("The Audiokinetic Texture associated with the selected faces."))
  111. .Text(FText::FromString(FString(TEXT("AkAcousticTexture"))))
  112. .Font(IDetailLayoutBuilder::GetDetailFont())
  113. ]
  114. ]
  115. ]
  116. + SVerticalBox::Slot() // Occlusion
  117. .FillHeight(0.33f)
  118. [
  119. SNew(SBox)
  120. .Visibility_Lambda([this]() { return TransmissionLossEnableSurfaceVisibility(); })
  121. [
  122. SNew(SHorizontalBox)
  123. + SHorizontalBox::Slot() // Label
  124. .HAlign(HAlign_Left)
  125. .VAlign(VAlign_Center)
  126. .AutoWidth()
  127. [
  128. SNew(SBox)
  129. .WidthOverride(AkAcousticSurfacesUI::LabelWidth)
  130. [
  131. SNew(STextBlock)
  132. .ToolTipText(FText::FromString("Indicates how much sound is transmitted through the surface."))
  133. .Text(FText::FromString(FString(TEXT("Transmission Loss"))))
  134. .Font(IDetailLayoutBuilder::GetDetailFont())
  135. ]
  136. ]
  137. ]
  138. ]
  139. + SVerticalBox::Slot() // EnableSurface
  140. .FillHeight(0.33f)
  141. [
  142. SNew(SHorizontalBox)
  143. + SHorizontalBox::Slot() // Label
  144. .HAlign(HAlign_Left)
  145. .VAlign(VAlign_Center)
  146. .AutoWidth()
  147. [
  148. SNew(SBox)
  149. .WidthOverride(AkAcousticSurfacesUI::LabelWidth)
  150. [
  151. SNew(STextBlock)
  152. .ToolTipText(FText::FromString("Indicates whether the selected faces are sent to the Spatial Audio engine."))
  153. .Text(FText::FromString(FString(TEXT("Enable Surface"))))
  154. .Font(IDetailLayoutBuilder::GetDetailFont())
  155. ]
  156. ]
  157. ]
  158. ]
  159. ];
  160. }
  161. EVisibility SAcousticSurfacesLabels::TransmissionLossEnableSurfaceVisibility()
  162. {
  163. for (TWeakObjectPtr<UObject> ObjectBeingCustomized : ComponentsBeingCustomized)
  164. {
  165. UAkSurfaceReflectorSetComponent* reflectorSetComponent = Cast<UAkSurfaceReflectorSetComponent>(ObjectBeingCustomized.Get());
  166. if (reflectorSetComponent && reflectorSetComponent->bEnableSurfaceReflectors)
  167. {
  168. return EVisibility::Visible;
  169. }
  170. }
  171. return EVisibility::Collapsed;
  172. }
  173. // ==================================================
  174. // SAcousticSurfacesController
  175. // ==================================================
  176. void SAcousticSurfacesController::Construct(const FArguments& InArgs, TArray<TWeakObjectPtr<UObject>> ObjectsBeingCustomized, const TSharedPtr<IDetailLayoutBuilder>& InLayoutBuilder)
  177. {
  178. ensure(ObjectsBeingCustomized.Num() > 0);
  179. LayoutBuilder = InLayoutBuilder;
  180. FCoreUObjectDelegates::FOnObjectPropertyChanged::FDelegate OnPropertyChangedDelegate = FCoreUObjectDelegates::FOnObjectPropertyChanged::FDelegate::CreateRaw(this, &SAcousticSurfacesController::OnPropertyChanged);
  181. OnPropertyChangedHandle = FCoreUObjectDelegates::OnObjectPropertyChanged.Add(OnPropertyChangedDelegate);
  182. GLevelEditorModeTools().OnEditorModeIDChanged().AddRaw(this, &SAcousticSurfacesController::OnEditorModeChanged);
  183. ComponentsToEdit = ObjectsBeingCustomized;
  184. if (GLevelEditorModeTools().IsModeActive(FEditorModeID(TEXT("EM_Geometry"))))
  185. {
  186. // In geometry edit mode, we only want to apply to all faces when no individual faces are selected.
  187. bool individualSelection = false;
  188. // Loop through all selected components to check if any indivdual faces are selected.
  189. // If no individual faces are selected, we'll just apply the changes to every face on each component.
  190. for (TWeakObjectPtr<UObject> ObjectBeingCustomized : ComponentsToEdit)
  191. {
  192. UAkSurfaceReflectorSetComponent* reflectorSetComponent = Cast<UAkSurfaceReflectorSetComponent>(ObjectBeingCustomized.Get());
  193. if (reflectorSetComponent)
  194. {
  195. TSet<int> FacesToEdit = reflectorSetComponent->GetSelectedFaceIndices();
  196. if (FacesToEdit.Num() > 0)
  197. {
  198. individualSelection = true;
  199. break;
  200. }
  201. }
  202. }
  203. ApplyToAllFaces = !individualSelection;
  204. }
  205. else
  206. {
  207. ApplyToAllFaces = true;
  208. }
  209. InitReflectorSetsFacesToEdit();
  210. UpdateCurrentValues();
  211. #if AK_SUPPORT_WAAPI
  212. RegisterTextureDeletedCallback();
  213. #endif
  214. BuildSlate();
  215. }
  216. SAcousticSurfacesController::~SAcousticSurfacesController()
  217. {
  218. #if AK_SUPPORT_WAAPI
  219. RemoveTextureDeletedCallback();
  220. #endif
  221. FCoreUObjectDelegates::OnObjectPropertyChanged.Remove(OnPropertyChangedHandle);
  222. GLevelEditorModeTools().OnEditorModeIDChanged().RemoveAll(this);
  223. }
  224. void SAcousticSurfacesController::InitReflectorSetsFacesToEdit()
  225. {
  226. NumFacesSelected = 0;
  227. for (TWeakObjectPtr<UObject> ObjectBeingCustomized : ComponentsToEdit)
  228. {
  229. UAkSurfaceReflectorSetComponent* reflectorSetComponent = Cast<UAkSurfaceReflectorSetComponent>(ObjectBeingCustomized.Get());
  230. if (reflectorSetComponent)
  231. {
  232. TSet<int> FacesToEdit;
  233. if (ApplyToAllFaces)
  234. {
  235. for (int i = 0; i < reflectorSetComponent->AcousticPolys.Num(); ++i)
  236. FacesToEdit.Add(i);
  237. }
  238. else
  239. {
  240. FacesToEdit = reflectorSetComponent->GetSelectedFaceIndices();
  241. }
  242. NumFacesSelected += FacesToEdit.Num();
  243. if (FacesToEdit.Num() > 0)
  244. ReflectorSetsFacesToEdit.Add(reflectorSetComponent, FacesToEdit);
  245. }
  246. }
  247. UpdateCurrentValues();
  248. }
  249. FAkSurfacePoly& SAcousticSurfacesController::GetAcousticSurfaceChecked(UAkSurfaceReflectorSetComponent* reflectorSet, int faceIndex)
  250. {
  251. ensure(faceIndex <= reflectorSet->AcousticPolys.Num());
  252. return reflectorSet->AcousticPolys[faceIndex];
  253. }
  254. void SAcousticSurfacesController::RefreshEditor(bool reinitVisualizers /*= false*/) const
  255. {
  256. if (!LayoutBuilder.IsValid())
  257. {
  258. return;
  259. }
  260. FEditorSupportDelegates::RedrawAllViewports.Broadcast();
  261. for (auto elem : ReflectorSetsFacesToEdit)
  262. {
  263. UAkSurfaceReflectorSetComponent* ReflectorSetComponent = elem.Key;
  264. if (ReflectorSetComponent != nullptr)
  265. {
  266. if (reinitVisualizers)
  267. {
  268. ReflectorSetComponent->CacheAcousticProperties();
  269. ReflectorSetComponent->UpdatePolys();
  270. }
  271. else
  272. {
  273. ReflectorSetComponent->SurfacePropertiesChanged();
  274. }
  275. }
  276. }
  277. IDetailLayoutBuilder* Layout = nullptr;
  278. if (auto LockedLayoutBuilder = LayoutBuilder.Pin())
  279. {
  280. Layout = LockedLayoutBuilder.Get();
  281. }
  282. if (LIKELY(Layout))
  283. {
  284. Layout->ForceRefreshDetails();
  285. }
  286. }
  287. void SAcousticSurfacesController::BeginModify(FText TransactionText)
  288. {
  289. if (GEditor && GEditor->Trans)
  290. {
  291. UTransBuffer* TransBuffer = CastChecked<UTransBuffer>(GEditor->Trans);
  292. if (TransBuffer != nullptr)
  293. TransBuffer->Begin(*FString("AkSurfaceReflectorSet Acoustic Surfaces"), TransactionText);
  294. }
  295. for (auto elem : ReflectorSetsFacesToEdit)
  296. {
  297. UAkSurfaceReflectorSetComponent* ReflectorSetComponent = elem.Key;
  298. if (ReflectorSetComponent != nullptr)
  299. ReflectorSetComponent->Modify();
  300. }
  301. }
  302. void SAcousticSurfacesController::EndModify()
  303. {
  304. if (GEditor && GEditor->Trans)
  305. {
  306. UTransBuffer* TransBuffer = CastChecked<UTransBuffer>(GEditor->Trans);
  307. if (TransBuffer != nullptr)
  308. TransBuffer->End();
  309. }
  310. }
  311. void SAcousticSurfacesController::OnPropertyChanged(UObject* ObjectBeingModified, FPropertyChangedEvent& PropertyChangedEvent)
  312. {
  313. for (auto elem : ReflectorSetsFacesToEdit)
  314. {
  315. UAkSurfaceReflectorSetComponent* ReflectorSetComponent = elem.Key;
  316. if (ObjectBeingModified == ReflectorSetComponent)
  317. {
  318. const FName memberPropertyName = (PropertyChangedEvent.MemberProperty != nullptr) ? PropertyChangedEvent.MemberProperty->GetFName() : NAME_None;
  319. if (memberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSurfaceReflectorSetComponent, AcousticPolys))
  320. {
  321. UpdateCurrentValues();
  322. }
  323. return;
  324. }
  325. }
  326. }
  327. void SAcousticSurfacesController::OnEditorModeChanged(const FEditorModeID& InEditorModeID, bool bIsEnteringMode)
  328. {
  329. if (InEditorModeID == FEditorModeID(TEXT("EM_Geometry")))
  330. {
  331. if (bIsEnteringMode)
  332. {
  333. ApplyToAllFaces = false;
  334. InitReflectorSetsFacesToEdit();
  335. Invalidate(EInvalidateWidgetReason::Paint);
  336. }
  337. else
  338. {
  339. ApplyToAllFaces = true;
  340. InitReflectorSetsFacesToEdit();
  341. Invalidate(EInvalidateWidgetReason::Paint);
  342. }
  343. }
  344. }
  345. FText SAcousticSurfacesController::GetSelectionText() const
  346. {
  347. FString selectionInfo = "(All faces)";
  348. if (!ApplyToAllFaces && NumFacesSelected > 0)
  349. {
  350. selectionInfo = "(" + FString::FromInt(NumFacesSelected) + " faces selected)";
  351. }
  352. return FText::FromString(selectionInfo);
  353. }
  354. FText SAcousticSurfacesController::GetSelectionTextTooltip() const
  355. {
  356. if (!ApplyToAllFaces && NumFacesSelected > 0)
  357. {
  358. return FText::FromString(FString("Changes will apply to all selected faces."));
  359. }
  360. return FText::FromString(FString("Changes will apply to all faces. Use ") + GEOMETRY_EDIT_DISPLAY_NAME + " to select individual faces. You can enable " GEOMETRY_EDIT_DISPLAY_NAME " by clicking 'Enable Edit Surfaces'.");
  361. }
  362. void SAcousticSurfacesController::UpdateCurrentValues()
  363. {
  364. CurrentTexture = GetCollectiveTexture(TexturesDiffer);
  365. CurrentOcclusion = GetCollectiveOcclusion(OcclusionsDiffer);
  366. CurrentEnablement = GetCollectiveEnableSurface(EnablementsDiffer);
  367. }
  368. void SAcousticSurfacesController::OnTextureAssetChanged(const FAssetData& InAssetData)
  369. {
  370. BeginModify(FText::FromString(FString("Set Textures")));
  371. CurrentTexture = Cast<UAkAcousticTexture>(InAssetData.GetAsset());
  372. for (auto elem : ReflectorSetsFacesToEdit)
  373. {
  374. UAkSurfaceReflectorSetComponent* ReflectorSetComponent = elem.Key;
  375. if (ReflectorSetComponent != nullptr)
  376. {
  377. TSet<int> FacesToEdit = elem.Value;
  378. for (const int& i : FacesToEdit)
  379. {
  380. GetAcousticSurfaceChecked(ReflectorSetComponent, i).Texture = CurrentTexture;
  381. }
  382. }
  383. }
  384. RefreshEditor();
  385. EndModify();
  386. }
  387. FString SAcousticSurfacesController::GetSelectedTextureAssetPath() const
  388. {
  389. if (CurrentTexture == nullptr)
  390. {
  391. return "";
  392. }
  393. FSoftObjectPath path(CurrentTexture);
  394. return path.GetAssetPathString();
  395. }
  396. EVisibility SAcousticSurfacesController::TransmissionLossEnableSurfaceVisibility()
  397. {
  398. for (auto elem : ReflectorSetsFacesToEdit)
  399. {
  400. UAkSurfaceReflectorSetComponent* ReflectorSetComponent = elem.Key;
  401. if (ReflectorSetComponent != nullptr && ReflectorSetComponent->bEnableSurfaceReflectors)
  402. return EVisibility::Visible;
  403. }
  404. return EVisibility::Collapsed;
  405. }
  406. EVisibility SAcousticSurfacesController::OverrideTextureControlsVisibility()
  407. {
  408. if (TexturesDiffer)
  409. return EVisibility::Visible;
  410. return EVisibility::Collapsed;
  411. }
  412. FReply SAcousticSurfacesController::OnOverrideTextureButtonClicked()
  413. {
  414. BeginModify(FText::FromString(FString("Override Textures")));
  415. for (auto elem : ReflectorSetsFacesToEdit)
  416. {
  417. UAkSurfaceReflectorSetComponent* ReflectorSetComponent = elem.Key;
  418. if (ReflectorSetComponent != nullptr)
  419. {
  420. TSet<int> FacesToEdit = elem.Value;
  421. for (const int& i : FacesToEdit)
  422. {
  423. GetAcousticSurfaceChecked(ReflectorSetComponent, i).Texture = nullptr;
  424. }
  425. }
  426. }
  427. RefreshEditor();
  428. EndModify();
  429. return FReply::Handled();
  430. }
  431. UAkAcousticTexture* SAcousticSurfacesController::GetCollectiveTexture(bool& ValuesDiffer)
  432. {
  433. ValuesDiffer = false;
  434. if (ReflectorSetsFacesToEdit.Num() == 0)
  435. return nullptr;
  436. auto it = ReflectorSetsFacesToEdit.CreateIterator();
  437. ensure(it.Key() != nullptr);
  438. int firstIndex = *(it.Value().begin());
  439. UAkAcousticTexture* texture = it.Key()->AcousticPolys[firstIndex].Texture;
  440. for (; it; ++it)
  441. {
  442. UAkSurfaceReflectorSetComponent* ReflectorSetComponent = it.Key();
  443. if (ReflectorSetComponent != nullptr)
  444. {
  445. TSet<int> FacesToEdit = it.Value();
  446. for (const int& i : FacesToEdit)
  447. {
  448. if (GetAcousticSurfaceChecked(ReflectorSetComponent, i).Texture != texture)
  449. {
  450. ValuesDiffer = true;
  451. texture = nullptr;
  452. break;
  453. }
  454. }
  455. }
  456. }
  457. return texture;
  458. }
  459. EVisibility SAcousticSurfacesController::OverrideOcclusionControlsVisibility()
  460. {
  461. return OcclusionsDiffer ? EVisibility::Visible : EVisibility::Collapsed;
  462. }
  463. FReply SAcousticSurfacesController::OnOverrideOcclusionButtonClicked()
  464. {
  465. BeginModify(FText::FromString(FString("Override Transmission Loss Values")));
  466. for (auto elem : ReflectorSetsFacesToEdit)
  467. {
  468. UAkSurfaceReflectorSetComponent* ReflectorSetComponent = elem.Key;
  469. if (ReflectorSetComponent != nullptr)
  470. {
  471. TSet<int> FacesToEdit = elem.Value;
  472. for (const int& i : FacesToEdit)
  473. {
  474. GetAcousticSurfaceChecked(ReflectorSetComponent, i).Occlusion = 0.0f;
  475. }
  476. }
  477. }
  478. RefreshEditor();
  479. EndModify();
  480. return FReply::Handled();
  481. }
  482. float SAcousticSurfacesController::GetCollectiveOcclusion(bool& ValuesDiffer)
  483. {
  484. ValuesDiffer = false;
  485. if (ReflectorSetsFacesToEdit.Num() == 0)
  486. return 0.0f;
  487. auto it = ReflectorSetsFacesToEdit.CreateIterator();
  488. ensure(it.Key() != nullptr);
  489. int firstIndex = *(it.Value().begin());
  490. float occlusion = it.Key()->AcousticPolys[firstIndex].Occlusion;
  491. for (; it; ++it)
  492. {
  493. UAkSurfaceReflectorSetComponent* ReflectorSetComponent = it.Key();
  494. if (ReflectorSetComponent != nullptr)
  495. {
  496. TSet<int> FacesToEdit = it.Value();
  497. for (const int& i : FacesToEdit)
  498. {
  499. if (GetAcousticSurfaceChecked(ReflectorSetComponent, i).Occlusion != occlusion)
  500. {
  501. ValuesDiffer = true;
  502. occlusion = 0.0f;
  503. break;
  504. }
  505. }
  506. }
  507. }
  508. return occlusion;
  509. }
  510. TOptional<float> SAcousticSurfacesController::GetOcclusionSliderValue() const
  511. {
  512. return CurrentOcclusion;
  513. }
  514. void SAcousticSurfacesController::OnOcclusionSliderChanged(float NewValue, ETextCommit::Type Commit)
  515. {
  516. // TODO: Remove this when fixed.
  517. // There is a bug in UE5.1 when modifying numerical properties and pressing Enter.
  518. // This is the case for the occlusion(transmission loss) value of acoustic surfaces.
  519. // This function is getting called a second time with a wrong occlusion value.
  520. // When that happens, LayoutBuilder is invalid, so we check it to make sure the value is valid as well.
  521. if (!LayoutBuilder.IsValid())
  522. {
  523. return;
  524. }
  525. // Only apply valid values
  526. if (NewValue >= 0.0f && NewValue <= 1.0f)
  527. {
  528. BeginModify(FText::FromString(FString("Set Transmission Loss Values")));
  529. for (auto elem : ReflectorSetsFacesToEdit)
  530. {
  531. UAkSurfaceReflectorSetComponent* ReflectorSetComponent = elem.Key;
  532. if (ReflectorSetComponent != nullptr)
  533. {
  534. TSet<int> FacesToEdit = elem.Value;
  535. for (const int& i : FacesToEdit)
  536. {
  537. GetAcousticSurfaceChecked(ReflectorSetComponent, i).Occlusion = NewValue;
  538. }
  539. }
  540. }
  541. RefreshEditor();
  542. EndModify();
  543. }
  544. }
  545. bool SAcousticSurfacesController::GetCollectiveEnableSurface(bool& ValuesDiffer)
  546. {
  547. ValuesDiffer = false;
  548. if (ReflectorSetsFacesToEdit.Num() == 0)
  549. return false;
  550. auto it = ReflectorSetsFacesToEdit.CreateIterator();
  551. ensure(it.Key() != nullptr);
  552. int firstIndex = *(it.Value().begin());
  553. bool enableSurface = it.Key()->AcousticPolys[firstIndex].EnableSurface;
  554. for (; it; ++it)
  555. {
  556. UAkSurfaceReflectorSetComponent* ReflectorSetComponent = it.Key();
  557. if (ReflectorSetComponent != nullptr)
  558. {
  559. TSet<int> FacesToEdit = it.Value();
  560. for (const int& i : FacesToEdit)
  561. {
  562. if (GetAcousticSurfaceChecked(ReflectorSetComponent, i).EnableSurface != enableSurface)
  563. {
  564. ValuesDiffer = true;
  565. enableSurface = false;
  566. break;
  567. }
  568. }
  569. }
  570. }
  571. return enableSurface;
  572. }
  573. ECheckBoxState SAcousticSurfacesController::GetEnableSurfaceCheckBoxState() const
  574. {
  575. return EnablementsDiffer ? ECheckBoxState::Undetermined
  576. : (CurrentEnablement ? ECheckBoxState::Checked : ECheckBoxState::Unchecked);
  577. }
  578. void SAcousticSurfacesController::OnEnableCheckboxChanged(ECheckBoxState NewState)
  579. {
  580. BeginModify(FText::FromString(FString("Set Enable Surfaces")));
  581. for (auto elem : ReflectorSetsFacesToEdit)
  582. {
  583. UAkSurfaceReflectorSetComponent* ReflectorSetComponent = elem.Key;
  584. if (ReflectorSetComponent != nullptr)
  585. {
  586. TSet<int> FacesToEdit = elem.Value;
  587. if (NewState != ECheckBoxState::Undetermined)
  588. {
  589. bool enable = NewState == ECheckBoxState::Checked;
  590. for (const int& i : FacesToEdit)
  591. {
  592. GetAcousticSurfaceChecked(ReflectorSetComponent, i).EnableSurface = enable;
  593. }
  594. }
  595. }
  596. }
  597. RefreshEditor(true);
  598. EndModify();
  599. }
  600. #if AK_SUPPORT_WAAPI
  601. void SAcousticSurfacesController::RegisterTextureDeletedCallback()
  602. {
  603. FAkWaapiClient* waapiClient = FAkWaapiClient::Get();
  604. if (waapiClient != nullptr && waapiClient->IsConnected())
  605. {
  606. auto textureDeletedCallback = WampEventCallback::CreateLambda([this](uint64_t id, TSharedPtr<FJsonObject> jsonObject)
  607. {
  608. const TSharedPtr<FJsonObject> itemObj = jsonObject->GetObjectField(WwiseWaapiHelper::OBJECT);
  609. if (itemObj != nullptr)
  610. {
  611. const FString itemIdString = itemObj->GetStringField(WwiseWaapiHelper::ID);
  612. FGuid itemID = FGuid::NewGuid();
  613. FGuid::ParseExact(itemIdString, EGuidFormats::DigitsWithHyphensInBraces, itemID);
  614. if (CurrentTexture != nullptr && itemID == CurrentTexture->AcousticTextureInfo.WwiseGuid)
  615. {
  616. AsyncTask(ENamedThreads::GameThread, [this, itemID]
  617. {
  618. CurrentTexture = nullptr;
  619. });
  620. }
  621. }
  622. });
  623. TSharedRef<FJsonObject> options = MakeShareable(new FJsonObject());
  624. options->SetArrayField(WwiseWaapiHelper::RETURN, TArray<TSharedPtr<FJsonValue>> { MakeShareable(new FJsonValueString(WwiseWaapiHelper::ID)) });
  625. TSharedPtr<FJsonObject> outJsonResult;
  626. if (!waapiClient->Subscribe(ak::wwise::core::object::preDeleted, options, textureDeletedCallback, TextureDeleteSubscriptionID, outJsonResult))
  627. {
  628. UE_LOG(LogAkAudio, Warning, TEXT("AkSettings: WAAPI: Acoustic texture object preDeleted subscription failed."));
  629. }
  630. }
  631. }
  632. void SAcousticSurfacesController::RemoveTextureDeletedCallback()
  633. {
  634. FAkWaapiClient* waapiClient = FAkWaapiClient::Get();
  635. if (waapiClient != nullptr && waapiClient->IsConnected() && TextureDeleteSubscriptionID != 0)
  636. {
  637. TSharedPtr<FJsonObject> unsubscribeResult;
  638. waapiClient->Unsubscribe(TextureDeleteSubscriptionID, unsubscribeResult);
  639. }
  640. }
  641. #endif
  642. void SAcousticSurfacesController::BuildSlate()
  643. {
  644. FSlateFontInfo SelectionInfoFont = FAkAppStyle::Get().GetFontStyle("TinyText");
  645. if (LayoutBuilder.IsValid())
  646. {
  647. if (auto LockedDetailBuilder = LayoutBuilder.Pin())
  648. {
  649. SelectionInfoFont = LockedDetailBuilder->GetDetailFontItalic();
  650. }
  651. }
  652. ChildSlot
  653. [
  654. SNew(SHorizontalBox)
  655. + SHorizontalBox::Slot() // Acoustic Surface Parameters
  656. .AutoWidth()
  657. [
  658. SNew(SVerticalBox)
  659. + SVerticalBox::Slot() // Texture
  660. .FillHeight(0.33f)
  661. [
  662. SNew(SHorizontalBox)
  663. + SHorizontalBox::Slot() // Control
  664. .HAlign(HAlign_Left)
  665. .VAlign(VAlign_Center)
  666. .AutoWidth()
  667. [
  668. SNew(SOverlay)
  669. + SOverlay::Slot()
  670. [
  671. SNew(SObjectPropertyEntryBox)
  672. .AllowedClass(UAkAcousticTexture::StaticClass())
  673. .OnObjectChanged(this, &SAcousticSurfacesController::OnTextureAssetChanged)
  674. .ObjectPath(this, &SAcousticSurfacesController::GetSelectedTextureAssetPath)
  675. .ToolTipText(this, &SAcousticSurfacesController::GetSelectionTextTooltip)
  676. .Visibility_Lambda([this]() { return (OverrideTextureControlsVisibility() == EVisibility::Collapsed) ? EVisibility::Visible : EVisibility::Collapsed; })
  677. ]
  678. + SOverlay::Slot() // Multiple values controls
  679. [
  680. SNew(SBox)
  681. .Visibility_Lambda([this]() { return OverrideTextureControlsVisibility(); })
  682. [
  683. SNew(SOverrideControls)
  684. .OnButtonClicked(this, &SAcousticSurfacesController::OnOverrideTextureButtonClicked)
  685. .ToolTipText(this, &SAcousticSurfacesController::GetSelectionTextTooltip)
  686. ]
  687. ]
  688. ]
  689. ]
  690. + SVerticalBox::Slot() // Occlusion
  691. .FillHeight(0.33f)
  692. [
  693. SNew(SBox)
  694. .Visibility_Lambda([this]() { return TransmissionLossEnableSurfaceVisibility(); })
  695. [
  696. SNew(SHorizontalBox)
  697. + SHorizontalBox::Slot() // Control
  698. .HAlign(HAlign_Left)
  699. .VAlign(VAlign_Center)
  700. .AutoWidth()
  701. [
  702. SNew(SOverlay)
  703. + SOverlay::Slot()
  704. [
  705. SNew(SBox)
  706. .Visibility_Lambda([this]() { return (OverrideOcclusionControlsVisibility() == EVisibility::Collapsed) ? EVisibility::Visible : EVisibility::Collapsed; })
  707. [
  708. SNew(SNumericEntryBox<float>)
  709. .MinValue(0.0f)
  710. .MaxValue(1.0f)
  711. .MinSliderValue(0.0f)
  712. .MaxSliderValue(1.0f)
  713. .ToolTipText(this, &SAcousticSurfacesController::GetSelectionTextTooltip)
  714. .Value(this, &SAcousticSurfacesController::GetOcclusionSliderValue)
  715. .OnValueCommitted(this, &SAcousticSurfacesController::OnOcclusionSliderChanged)
  716. ]
  717. ]
  718. + SOverlay::Slot() // Multiple values controls
  719. [
  720. SNew(SBox)
  721. .Visibility_Lambda([this]() { return OverrideOcclusionControlsVisibility(); })
  722. [
  723. SNew(SOverrideControls)
  724. .OnButtonClicked(this, &SAcousticSurfacesController::OnOverrideOcclusionButtonClicked)
  725. .ToolTipText(this, &SAcousticSurfacesController::GetSelectionTextTooltip)
  726. ]
  727. ]
  728. ]
  729. ]
  730. ]
  731. + SVerticalBox::Slot() // EnableSurface
  732. .FillHeight(0.33f)
  733. [
  734. SNew(SHorizontalBox)
  735. + SHorizontalBox::Slot() // Control
  736. .HAlign(HAlign_Left)
  737. .VAlign(VAlign_Center)
  738. .AutoWidth()
  739. [
  740. SNew(SCheckBox)
  741. .IsChecked(ECheckBoxState::Undetermined)
  742. .OnCheckStateChanged(this, &SAcousticSurfacesController::OnEnableCheckboxChanged)
  743. .IsChecked(this, &SAcousticSurfacesController::GetEnableSurfaceCheckBoxState)
  744. .ToolTipText(this, &SAcousticSurfacesController::GetSelectionTextTooltip)
  745. ]
  746. ]
  747. ]
  748. + SHorizontalBox::Slot() // Selection Info
  749. .AutoWidth()
  750. [
  751. SNew(SVerticalBox)
  752. + SVerticalBox::Slot() // Texture
  753. .FillHeight(0.33f)
  754. .HAlign(HAlign_Left)
  755. .VAlign(VAlign_Center)
  756. [
  757. SNew(STextBlock)
  758. .Text(this, &SAcousticSurfacesController::GetSelectionText)
  759. .ToolTipText(this, &SAcousticSurfacesController::GetSelectionTextTooltip)
  760. .Font(SelectionInfoFont)
  761. ]
  762. + SVerticalBox::Slot() // Occlusion
  763. .FillHeight(0.33f)
  764. [
  765. SNew(SBox)
  766. .Visibility_Lambda([this]() { return TransmissionLossEnableSurfaceVisibility(); })
  767. .HAlign(HAlign_Left)
  768. .VAlign(VAlign_Center)
  769. [
  770. SNew(STextBlock)
  771. .Text(this, &SAcousticSurfacesController::GetSelectionText)
  772. .ToolTipText(this, &SAcousticSurfacesController::GetSelectionTextTooltip)
  773. .Font(SelectionInfoFont)
  774. ]
  775. ]
  776. + SVerticalBox::Slot() // EnableSurface
  777. .FillHeight(0.33f)
  778. .HAlign(HAlign_Left)
  779. .VAlign(VAlign_Center)
  780. [
  781. SNew(STextBlock)
  782. .Text(this, &SAcousticSurfacesController::GetSelectionText)
  783. .ToolTipText(this, &SAcousticSurfacesController::GetSelectionTextTooltip)
  784. .Font(SelectionInfoFont)
  785. ]
  786. ]
  787. ];
  788. }
  789. #undef LOCTEXT_NAMESPACE