SAcousticSurfacesController.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894
  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 "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 Acoustic Texture associated with the selected surfaces. When set to None, the texture is completely reflective. If the Surface Reflector component is disabled, the geometry is not used for reflections or diffractions. In this case, Acoustic Textures are used exclusively to measure Environment Decay and HFDamping as part of the Reverb Estimation process."))
  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 selected surfaces. With a Transmission Loss value of 0, all sounds pass through the surface, and the Acoustic Texture has no effect. With a value of 1, 100% Transmission Loss is applied to sounds that pass through the selected surfaces."))
  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("An enabled surface is associated with the selected Acoustic Texture and Transmission Loss value above. A disabled surface is not associated with an Acoustic Texture, and has a Transmission Loss value of 0 (sound passes through the surface). If Surface Reflector Set is disabled, there is no Transmission Loss property to customize. In this case, enabled surfaces do not let sound pass through (equivalent to a Transmission Loss value of 1) and disabled surfaces let sound pass through (equivalent to a Transmission Loss value of 0)."))
  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. FEditorSupportDelegates::RedrawAllViewports.Broadcast();
  257. for (auto elem : ReflectorSetsFacesToEdit)
  258. {
  259. UAkSurfaceReflectorSetComponent* ReflectorSetComponent = elem.Key;
  260. if (ReflectorSetComponent != nullptr)
  261. {
  262. if (reinitVisualizers)
  263. {
  264. ReflectorSetComponent->CacheAcousticProperties();
  265. ReflectorSetComponent->UpdatePolys();
  266. }
  267. else
  268. {
  269. ReflectorSetComponent->SurfacePropertiesChanged();
  270. }
  271. }
  272. }
  273. RefreshLayout();
  274. }
  275. void SAcousticSurfacesController::RefreshLayout() const
  276. {
  277. if (!LayoutBuilder.IsValid())
  278. {
  279. return;
  280. }
  281. IDetailLayoutBuilder* Layout = nullptr;
  282. if (auto LockedLayoutBuilder = LayoutBuilder.Pin())
  283. {
  284. Layout = LockedLayoutBuilder.Get();
  285. }
  286. if (LIKELY(Layout))
  287. {
  288. Layout->ForceRefreshDetails();
  289. }
  290. }
  291. void SAcousticSurfacesController::BeginModify(FText TransactionText)
  292. {
  293. if (GEditor && GEditor->Trans)
  294. {
  295. UTransBuffer* TransBuffer = CastChecked<UTransBuffer>(GEditor->Trans);
  296. if (TransBuffer != nullptr)
  297. TransBuffer->Begin(*FString("AkSurfaceReflectorSet Acoustic Surfaces"), TransactionText);
  298. }
  299. for (auto elem : ReflectorSetsFacesToEdit)
  300. {
  301. UAkSurfaceReflectorSetComponent* ReflectorSetComponent = elem.Key;
  302. if (ReflectorSetComponent != nullptr)
  303. ReflectorSetComponent->Modify();
  304. }
  305. }
  306. void SAcousticSurfacesController::EndModify()
  307. {
  308. if (GEditor && GEditor->Trans)
  309. {
  310. UTransBuffer* TransBuffer = CastChecked<UTransBuffer>(GEditor->Trans);
  311. if (TransBuffer != nullptr)
  312. TransBuffer->End();
  313. }
  314. }
  315. void SAcousticSurfacesController::OnPropertyChanged(UObject* ObjectBeingModified, FPropertyChangedEvent& PropertyChangedEvent)
  316. {
  317. for (auto elem : ReflectorSetsFacesToEdit)
  318. {
  319. UAkSurfaceReflectorSetComponent* ReflectorSetComponent = elem.Key;
  320. if (ObjectBeingModified == ReflectorSetComponent)
  321. {
  322. if (PropertyChangedEvent.MemberProperty == nullptr)
  323. {
  324. // OnPropertyChanged is called with a null MemberProperty when undoing
  325. RefreshLayout();
  326. }
  327. else
  328. {
  329. const FName memberPropertyName = PropertyChangedEvent.MemberProperty->GetFName();
  330. if (memberPropertyName == GET_MEMBER_NAME_CHECKED(UAkSurfaceReflectorSetComponent, AcousticPolys))
  331. {
  332. UpdateCurrentValues();
  333. }
  334. }
  335. return;
  336. }
  337. }
  338. }
  339. void SAcousticSurfacesController::OnEditorModeChanged(const FEditorModeID& InEditorModeID, bool bIsEnteringMode)
  340. {
  341. if (InEditorModeID == FEditorModeID(TEXT("EM_Geometry")))
  342. {
  343. if (bIsEnteringMode)
  344. {
  345. ApplyToAllFaces = false;
  346. InitReflectorSetsFacesToEdit();
  347. Invalidate(EInvalidateWidgetReason::Paint);
  348. }
  349. else
  350. {
  351. ApplyToAllFaces = true;
  352. InitReflectorSetsFacesToEdit();
  353. Invalidate(EInvalidateWidgetReason::Paint);
  354. }
  355. }
  356. }
  357. FText SAcousticSurfacesController::GetSelectionText() const
  358. {
  359. FString selectionInfo = "(All faces)";
  360. if (!ApplyToAllFaces && NumFacesSelected > 0)
  361. {
  362. selectionInfo = "(" + FString::FromInt(NumFacesSelected) + " faces selected)";
  363. }
  364. return FText::FromString(selectionInfo);
  365. }
  366. FText SAcousticSurfacesController::GetSelectionTextTooltip() const
  367. {
  368. if (!ApplyToAllFaces && NumFacesSelected > 0)
  369. {
  370. return FText::FromString(FString("Changes will apply to all selected faces."));
  371. }
  372. 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'.");
  373. }
  374. void SAcousticSurfacesController::UpdateCurrentValues()
  375. {
  376. CurrentTexture = GetCollectiveTexture(TexturesDiffer);
  377. CurrentOcclusion = GetCollectiveOcclusion(OcclusionsDiffer);
  378. CurrentEnablement = GetCollectiveEnableSurface(EnablementsDiffer);
  379. }
  380. void SAcousticSurfacesController::OnTextureAssetChanged(const FAssetData& InAssetData)
  381. {
  382. BeginModify(FText::FromString(FString("Set Textures")));
  383. CurrentTexture = Cast<UAkAcousticTexture>(InAssetData.GetAsset());
  384. for (auto elem : ReflectorSetsFacesToEdit)
  385. {
  386. UAkSurfaceReflectorSetComponent* ReflectorSetComponent = elem.Key;
  387. if (ReflectorSetComponent != nullptr)
  388. {
  389. TSet<int> FacesToEdit = elem.Value;
  390. for (const int& i : FacesToEdit)
  391. {
  392. GetAcousticSurfaceChecked(ReflectorSetComponent, i).Texture = CurrentTexture;
  393. }
  394. }
  395. }
  396. RefreshEditor();
  397. EndModify();
  398. }
  399. FString SAcousticSurfacesController::GetSelectedTextureAssetPath() const
  400. {
  401. if (CurrentTexture == nullptr)
  402. {
  403. return "";
  404. }
  405. FSoftObjectPath path(CurrentTexture);
  406. return path.GetAssetPathString();
  407. }
  408. EVisibility SAcousticSurfacesController::TransmissionLossEnableSurfaceVisibility()
  409. {
  410. for (auto elem : ReflectorSetsFacesToEdit)
  411. {
  412. UAkSurfaceReflectorSetComponent* ReflectorSetComponent = elem.Key;
  413. if (ReflectorSetComponent != nullptr && ReflectorSetComponent->bEnableSurfaceReflectors)
  414. return EVisibility::Visible;
  415. }
  416. return EVisibility::Collapsed;
  417. }
  418. EVisibility SAcousticSurfacesController::OverrideTextureControlsVisibility()
  419. {
  420. if (TexturesDiffer)
  421. return EVisibility::Visible;
  422. return EVisibility::Collapsed;
  423. }
  424. FReply SAcousticSurfacesController::OnOverrideTextureButtonClicked()
  425. {
  426. BeginModify(FText::FromString(FString("Override Textures")));
  427. for (auto elem : ReflectorSetsFacesToEdit)
  428. {
  429. UAkSurfaceReflectorSetComponent* ReflectorSetComponent = elem.Key;
  430. if (ReflectorSetComponent != nullptr)
  431. {
  432. TSet<int> FacesToEdit = elem.Value;
  433. for (const int& i : FacesToEdit)
  434. {
  435. GetAcousticSurfaceChecked(ReflectorSetComponent, i).Texture = nullptr;
  436. }
  437. }
  438. }
  439. RefreshEditor();
  440. EndModify();
  441. return FReply::Handled();
  442. }
  443. UAkAcousticTexture* SAcousticSurfacesController::GetCollectiveTexture(bool& ValuesDiffer)
  444. {
  445. ValuesDiffer = false;
  446. if (ReflectorSetsFacesToEdit.Num() == 0)
  447. return nullptr;
  448. auto it = ReflectorSetsFacesToEdit.CreateIterator();
  449. ensure(it.Key() != nullptr);
  450. int firstIndex = *(it.Value().begin());
  451. UAkAcousticTexture* texture = it.Key()->AcousticPolys[firstIndex].Texture;
  452. for (; it; ++it)
  453. {
  454. UAkSurfaceReflectorSetComponent* ReflectorSetComponent = it.Key();
  455. if (ReflectorSetComponent != nullptr)
  456. {
  457. TSet<int> FacesToEdit = it.Value();
  458. for (const int& i : FacesToEdit)
  459. {
  460. if (GetAcousticSurfaceChecked(ReflectorSetComponent, i).Texture != texture)
  461. {
  462. ValuesDiffer = true;
  463. texture = nullptr;
  464. break;
  465. }
  466. }
  467. }
  468. }
  469. return texture;
  470. }
  471. EVisibility SAcousticSurfacesController::OverrideOcclusionControlsVisibility()
  472. {
  473. return OcclusionsDiffer ? EVisibility::Visible : EVisibility::Collapsed;
  474. }
  475. FReply SAcousticSurfacesController::OnOverrideOcclusionButtonClicked()
  476. {
  477. BeginModify(FText::FromString(FString("Override Transmission Loss Values")));
  478. for (auto elem : ReflectorSetsFacesToEdit)
  479. {
  480. UAkSurfaceReflectorSetComponent* ReflectorSetComponent = elem.Key;
  481. if (ReflectorSetComponent != nullptr)
  482. {
  483. TSet<int> FacesToEdit = elem.Value;
  484. for (const int& i : FacesToEdit)
  485. {
  486. GetAcousticSurfaceChecked(ReflectorSetComponent, i).Occlusion = 0.0f;
  487. }
  488. }
  489. }
  490. RefreshEditor();
  491. EndModify();
  492. return FReply::Handled();
  493. }
  494. float SAcousticSurfacesController::GetCollectiveOcclusion(bool& ValuesDiffer)
  495. {
  496. ValuesDiffer = false;
  497. if (ReflectorSetsFacesToEdit.Num() == 0)
  498. return 0.0f;
  499. auto it = ReflectorSetsFacesToEdit.CreateIterator();
  500. ensure(it.Key() != nullptr);
  501. int firstIndex = *(it.Value().begin());
  502. float occlusion = it.Key()->AcousticPolys[firstIndex].Occlusion;
  503. for (; it; ++it)
  504. {
  505. UAkSurfaceReflectorSetComponent* ReflectorSetComponent = it.Key();
  506. if (ReflectorSetComponent != nullptr)
  507. {
  508. TSet<int> FacesToEdit = it.Value();
  509. for (const int& i : FacesToEdit)
  510. {
  511. if (GetAcousticSurfaceChecked(ReflectorSetComponent, i).Occlusion != occlusion)
  512. {
  513. ValuesDiffer = true;
  514. occlusion = 0.0f;
  515. break;
  516. }
  517. }
  518. }
  519. }
  520. return occlusion;
  521. }
  522. TOptional<float> SAcousticSurfacesController::GetOcclusionSliderValue() const
  523. {
  524. return CurrentOcclusion;
  525. }
  526. void SAcousticSurfacesController::OnOcclusionSliderChanged(float NewValue, ETextCommit::Type Commit)
  527. {
  528. // TODO: Remove this when fixed.
  529. // There is a bug in UE5.1 when modifying numerical properties and pressing Enter.
  530. // This is the case for the occlusion(transmission loss) value of acoustic surfaces.
  531. // This function is getting called a second time with a wrong occlusion value.
  532. // When that happens, LayoutBuilder is invalid, so we check it to make sure the value is valid as well.
  533. if (!LayoutBuilder.IsValid())
  534. {
  535. return;
  536. }
  537. // Only apply valid values
  538. if (NewValue >= 0.0f && NewValue <= 1.0f)
  539. {
  540. BeginModify(FText::FromString(FString("Set Transmission Loss Values")));
  541. for (auto elem : ReflectorSetsFacesToEdit)
  542. {
  543. UAkSurfaceReflectorSetComponent* ReflectorSetComponent = elem.Key;
  544. if (ReflectorSetComponent != nullptr)
  545. {
  546. TSet<int> FacesToEdit = elem.Value;
  547. for (const int& i : FacesToEdit)
  548. {
  549. GetAcousticSurfaceChecked(ReflectorSetComponent, i).Occlusion = NewValue;
  550. }
  551. }
  552. }
  553. RefreshEditor();
  554. EndModify();
  555. }
  556. }
  557. bool SAcousticSurfacesController::GetCollectiveEnableSurface(bool& ValuesDiffer)
  558. {
  559. ValuesDiffer = false;
  560. if (ReflectorSetsFacesToEdit.Num() == 0)
  561. return false;
  562. auto it = ReflectorSetsFacesToEdit.CreateIterator();
  563. ensure(it.Key() != nullptr);
  564. int firstIndex = *(it.Value().begin());
  565. bool enableSurface = it.Key()->AcousticPolys[firstIndex].EnableSurface;
  566. for (; it; ++it)
  567. {
  568. UAkSurfaceReflectorSetComponent* ReflectorSetComponent = it.Key();
  569. if (ReflectorSetComponent != nullptr)
  570. {
  571. TSet<int> FacesToEdit = it.Value();
  572. for (const int& i : FacesToEdit)
  573. {
  574. if (GetAcousticSurfaceChecked(ReflectorSetComponent, i).EnableSurface != enableSurface)
  575. {
  576. ValuesDiffer = true;
  577. enableSurface = false;
  578. break;
  579. }
  580. }
  581. }
  582. }
  583. return enableSurface;
  584. }
  585. ECheckBoxState SAcousticSurfacesController::GetEnableSurfaceCheckBoxState() const
  586. {
  587. return EnablementsDiffer ? ECheckBoxState::Undetermined
  588. : (CurrentEnablement ? ECheckBoxState::Checked : ECheckBoxState::Unchecked);
  589. }
  590. void SAcousticSurfacesController::OnEnableCheckboxChanged(ECheckBoxState NewState)
  591. {
  592. BeginModify(FText::FromString(FString("Set Enable Surfaces")));
  593. for (auto elem : ReflectorSetsFacesToEdit)
  594. {
  595. UAkSurfaceReflectorSetComponent* ReflectorSetComponent = elem.Key;
  596. if (ReflectorSetComponent != nullptr)
  597. {
  598. TSet<int> FacesToEdit = elem.Value;
  599. if (NewState != ECheckBoxState::Undetermined)
  600. {
  601. bool enable = NewState == ECheckBoxState::Checked;
  602. for (const int& i : FacesToEdit)
  603. {
  604. GetAcousticSurfaceChecked(ReflectorSetComponent, i).EnableSurface = enable;
  605. }
  606. }
  607. }
  608. }
  609. RefreshEditor(true);
  610. EndModify();
  611. }
  612. #if AK_SUPPORT_WAAPI
  613. void SAcousticSurfacesController::RegisterTextureDeletedCallback()
  614. {
  615. FAkWaapiClient* waapiClient = FAkWaapiClient::Get();
  616. if (waapiClient != nullptr && waapiClient->IsConnected())
  617. {
  618. auto textureDeletedCallback = WampEventCallback::CreateLambda([this](uint64_t id, TSharedPtr<FJsonObject> jsonObject)
  619. {
  620. const TSharedPtr<FJsonObject> itemObj = jsonObject->GetObjectField(WwiseWaapiHelper::OBJECT);
  621. if (itemObj != nullptr)
  622. {
  623. const FString itemIdString = itemObj->GetStringField(WwiseWaapiHelper::ID);
  624. FGuid itemID = FGuid::NewGuid();
  625. FGuid::ParseExact(itemIdString, EGuidFormats::DigitsWithHyphensInBraces, itemID);
  626. if (CurrentTexture != nullptr && itemID == CurrentTexture->AcousticTextureInfo.WwiseGuid)
  627. {
  628. AsyncTask(ENamedThreads::GameThread, [this, itemID]
  629. {
  630. CurrentTexture = nullptr;
  631. });
  632. }
  633. }
  634. });
  635. TSharedRef<FJsonObject> options = MakeShareable(new FJsonObject());
  636. options->SetArrayField(WwiseWaapiHelper::RETURN, TArray<TSharedPtr<FJsonValue>> { MakeShareable(new FJsonValueString(WwiseWaapiHelper::ID)) });
  637. TSharedPtr<FJsonObject> outJsonResult;
  638. if (!waapiClient->Subscribe(ak::wwise::core::object::preDeleted, options, textureDeletedCallback, TextureDeleteSubscriptionID, outJsonResult))
  639. {
  640. UE_LOG(LogAkAudio, Warning, TEXT("AkSettings: WAAPI: Acoustic texture object preDeleted subscription failed."));
  641. }
  642. }
  643. }
  644. void SAcousticSurfacesController::RemoveTextureDeletedCallback()
  645. {
  646. FAkWaapiClient* waapiClient = FAkWaapiClient::Get();
  647. if (waapiClient != nullptr && waapiClient->IsConnected() && TextureDeleteSubscriptionID != 0)
  648. {
  649. TSharedPtr<FJsonObject> unsubscribeResult;
  650. waapiClient->Unsubscribe(TextureDeleteSubscriptionID, unsubscribeResult);
  651. }
  652. }
  653. #endif
  654. void SAcousticSurfacesController::BuildSlate()
  655. {
  656. FSlateFontInfo SelectionInfoFont = FAkAppStyle::Get().GetFontStyle("TinyText");
  657. if (LayoutBuilder.IsValid())
  658. {
  659. if (auto LockedDetailBuilder = LayoutBuilder.Pin())
  660. {
  661. SelectionInfoFont = LockedDetailBuilder->GetDetailFontItalic();
  662. }
  663. }
  664. ChildSlot
  665. [
  666. SNew(SHorizontalBox)
  667. + SHorizontalBox::Slot() // Acoustic Surface Parameters
  668. .AutoWidth()
  669. [
  670. SNew(SVerticalBox)
  671. + SVerticalBox::Slot() // Texture
  672. .FillHeight(0.33f)
  673. [
  674. SNew(SHorizontalBox)
  675. + SHorizontalBox::Slot() // Control
  676. .HAlign(HAlign_Left)
  677. .VAlign(VAlign_Center)
  678. .AutoWidth()
  679. [
  680. SNew(SOverlay)
  681. + SOverlay::Slot()
  682. [
  683. SNew(SObjectPropertyEntryBox)
  684. .AllowedClass(UAkAcousticTexture::StaticClass())
  685. .OnObjectChanged(this, &SAcousticSurfacesController::OnTextureAssetChanged)
  686. .ObjectPath(this, &SAcousticSurfacesController::GetSelectedTextureAssetPath)
  687. .ToolTipText(this, &SAcousticSurfacesController::GetSelectionTextTooltip)
  688. .Visibility_Lambda([this]() { return (OverrideTextureControlsVisibility() == EVisibility::Collapsed) ? EVisibility::Visible : EVisibility::Collapsed; })
  689. ]
  690. + SOverlay::Slot() // Multiple values controls
  691. [
  692. SNew(SBox)
  693. .Visibility_Lambda([this]() { return OverrideTextureControlsVisibility(); })
  694. [
  695. SNew(SOverrideControls)
  696. .OnButtonClicked(this, &SAcousticSurfacesController::OnOverrideTextureButtonClicked)
  697. .ToolTipText(this, &SAcousticSurfacesController::GetSelectionTextTooltip)
  698. ]
  699. ]
  700. ]
  701. ]
  702. + SVerticalBox::Slot() // Occlusion
  703. .FillHeight(0.33f)
  704. [
  705. SNew(SBox)
  706. .Visibility_Lambda([this]() { return TransmissionLossEnableSurfaceVisibility(); })
  707. [
  708. SNew(SHorizontalBox)
  709. + SHorizontalBox::Slot() // Control
  710. .HAlign(HAlign_Left)
  711. .VAlign(VAlign_Center)
  712. .AutoWidth()
  713. [
  714. SNew(SOverlay)
  715. + SOverlay::Slot()
  716. [
  717. SNew(SBox)
  718. .Visibility_Lambda([this]() { return (OverrideOcclusionControlsVisibility() == EVisibility::Collapsed) ? EVisibility::Visible : EVisibility::Collapsed; })
  719. [
  720. SNew(SNumericEntryBox<float>)
  721. .MinValue(0.0f)
  722. .MaxValue(1.0f)
  723. .MinSliderValue(0.0f)
  724. .MaxSliderValue(1.0f)
  725. .ToolTipText(this, &SAcousticSurfacesController::GetSelectionTextTooltip)
  726. .Value(this, &SAcousticSurfacesController::GetOcclusionSliderValue)
  727. .OnValueCommitted(this, &SAcousticSurfacesController::OnOcclusionSliderChanged)
  728. ]
  729. ]
  730. + SOverlay::Slot() // Multiple values controls
  731. [
  732. SNew(SBox)
  733. .Visibility_Lambda([this]() { return OverrideOcclusionControlsVisibility(); })
  734. [
  735. SNew(SOverrideControls)
  736. .OnButtonClicked(this, &SAcousticSurfacesController::OnOverrideOcclusionButtonClicked)
  737. .ToolTipText(this, &SAcousticSurfacesController::GetSelectionTextTooltip)
  738. ]
  739. ]
  740. ]
  741. ]
  742. ]
  743. + SVerticalBox::Slot() // EnableSurface
  744. .FillHeight(0.33f)
  745. [
  746. SNew(SHorizontalBox)
  747. + SHorizontalBox::Slot() // Control
  748. .HAlign(HAlign_Left)
  749. .VAlign(VAlign_Center)
  750. .AutoWidth()
  751. [
  752. SNew(SCheckBox)
  753. .IsChecked(ECheckBoxState::Undetermined)
  754. .OnCheckStateChanged(this, &SAcousticSurfacesController::OnEnableCheckboxChanged)
  755. .IsChecked(this, &SAcousticSurfacesController::GetEnableSurfaceCheckBoxState)
  756. .ToolTipText(this, &SAcousticSurfacesController::GetSelectionTextTooltip)
  757. ]
  758. ]
  759. ]
  760. + SHorizontalBox::Slot() // Selection Info
  761. .AutoWidth()
  762. [
  763. SNew(SVerticalBox)
  764. + SVerticalBox::Slot() // Texture
  765. .FillHeight(0.33f)
  766. .HAlign(HAlign_Left)
  767. .VAlign(VAlign_Center)
  768. [
  769. SNew(STextBlock)
  770. .Text(this, &SAcousticSurfacesController::GetSelectionText)
  771. .ToolTipText(this, &SAcousticSurfacesController::GetSelectionTextTooltip)
  772. .Font(SelectionInfoFont)
  773. ]
  774. + SVerticalBox::Slot() // Occlusion
  775. .FillHeight(0.33f)
  776. [
  777. SNew(SBox)
  778. .Visibility_Lambda([this]() { return TransmissionLossEnableSurfaceVisibility(); })
  779. .HAlign(HAlign_Left)
  780. .VAlign(VAlign_Center)
  781. [
  782. SNew(STextBlock)
  783. .Text(this, &SAcousticSurfacesController::GetSelectionText)
  784. .ToolTipText(this, &SAcousticSurfacesController::GetSelectionTextTooltip)
  785. .Font(SelectionInfoFont)
  786. ]
  787. ]
  788. + SVerticalBox::Slot() // EnableSurface
  789. .FillHeight(0.33f)
  790. .HAlign(HAlign_Left)
  791. .VAlign(VAlign_Center)
  792. [
  793. SNew(STextBlock)
  794. .Text(this, &SAcousticSurfacesController::GetSelectionText)
  795. .ToolTipText(this, &SAcousticSurfacesController::GetSelectionTextTooltip)
  796. .Font(SelectionInfoFont)
  797. ]
  798. ]
  799. ];
  800. }
  801. #undef LOCTEXT_NAMESPACE