AkSurfaceReflectorSetDetailsCustomization.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  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 "AkSurfaceReflectorSetDetailsCustomization.h"
  16. #include "AkComponent.h"
  17. #include "AkSurfaceReflectorSetComponent.h"
  18. #include "DetailCategoryBuilder.h"
  19. #include "DetailLayoutBuilder.h"
  20. #include "DetailWidgetRow.h"
  21. #include "EditorModeManager.h"
  22. #include "EditorSupportDelegates.h"
  23. #include "IPropertyUtilities.h"
  24. #include "LevelEditorActions.h"
  25. #include "Model.h"
  26. #include "GameFramework/Volume.h"
  27. #include "UI/SAcousticSurfacesController.h"
  28. #include "Widgets/Input/SButton.h"
  29. #include "Widgets/Layout/SBox.h"
  30. #include "Widgets/Text/STextBlock.h"
  31. #include "Builders/ConeBuilder.h"
  32. #include "Builders/CubeBuilder.h"
  33. #include "Builders/CurvedStairBuilder.h"
  34. #include "Builders/CylinderBuilder.h"
  35. #include "Builders/LinearStairBuilder.h"
  36. #include "Builders/SpiralStairBuilder.h"
  37. #include "Builders/TetrahedronBuilder.h"
  38. #define LOCTEXT_NAMESPACE "AudiokineticTools"
  39. //////////////////////////////////////////////////////////////////////////
  40. // FAkSurfaceReflectorSetDetailsCustomization
  41. FAkSurfaceReflectorSetDetailsCustomization::FAkSurfaceReflectorSetDetailsCustomization()
  42. {
  43. ReflectorSetBeingCustomized = nullptr;
  44. FCoreUObjectDelegates::OnObjectModified.AddRaw(this, &FAkSurfaceReflectorSetDetailsCustomization::OnObjectModified);
  45. FEditorSupportDelegates::RedrawAllViewports.AddRaw(this, &FAkSurfaceReflectorSetDetailsCustomization::OnRedrawViewports);
  46. }
  47. FAkSurfaceReflectorSetDetailsCustomization::~FAkSurfaceReflectorSetDetailsCustomization()
  48. {
  49. FCoreUObjectDelegates::OnObjectModified.RemoveAll(this);
  50. FEditorSupportDelegates::RedrawAllViewports.RemoveAll(this);
  51. if (ReflectorSetBeingCustomized.IsValid() && ReflectorSetBeingCustomized->GetOnRefreshDetails())
  52. {
  53. if (ReflectorSetBeingCustomized->GetOnRefreshDetails()->IsBoundToObject(this))
  54. {
  55. ReflectorSetBeingCustomized->ClearOnRefreshDetails();
  56. }
  57. }
  58. ReflectorSetBeingCustomized.Reset();
  59. }
  60. FReply FAkSurfaceReflectorSetDetailsCustomization::OnEnableEditModeClicked()
  61. {
  62. FLevelEditorActionCallbacks::OnShowOnlySelectedActors();
  63. GLevelEditorModeTools().ActivateMode(FEditorModeID(TEXT("EM_Geometry")), false);
  64. return FReply::Handled();
  65. }
  66. FReply FAkSurfaceReflectorSetDetailsCustomization::OnDisableEditModeClicked()
  67. {
  68. GLevelEditorModeTools().DeactivateMode(FEditorModeID(TEXT("EM_Geometry")));
  69. FLevelEditorActionCallbacks::ExecuteExecCommand(FString(TEXT("ACTOR UNHIDE ALL")));
  70. return FReply::Handled();
  71. }
  72. void FAkSurfaceReflectorSetDetailsCustomization::OnObjectModified(UObject* Object)
  73. {
  74. if (!SelectedObjectModifiedThisFrame)
  75. {
  76. for (TWeakObjectPtr<UObject> UObjectPtr : ObjectsBeingCustomized)
  77. {
  78. if (Object == UObjectPtr.Get())
  79. {
  80. SelectedObjectModifiedThisFrame = true;
  81. return;
  82. }
  83. }
  84. }
  85. }
  86. void FAkSurfaceReflectorSetDetailsCustomization::OnRedrawViewports()
  87. {
  88. if (SelectedObjectModifiedThisFrame && DetailBuilder.IsValid())
  89. {
  90. // If there is any user interaction going on, we don't want to refresh the details panel.
  91. // (This would interupt the interaction and make sliders unusable)
  92. for (TWeakObjectPtr<UObject> UObjectPtr : ObjectsBeingCustomized)
  93. {
  94. if (UAkSurfaceReflectorSetComponent* reflectorSet = Cast<UAkSurfaceReflectorSetComponent>(UObjectPtr.Get()))
  95. {
  96. if (reflectorSet->UserInteractionInProgress)
  97. {
  98. return;
  99. }
  100. }
  101. }
  102. IDetailLayoutBuilder* Layout = nullptr;
  103. if (auto LockedDetailBuilder = DetailBuilder.Pin())
  104. {
  105. Layout = LockedDetailBuilder.Get();
  106. }
  107. if (LIKELY(Layout))
  108. {
  109. Layout->ForceRefreshDetails();
  110. }
  111. SelectedObjectModifiedThisFrame = false;
  112. }
  113. }
  114. TSharedRef<IDetailCustomization> FAkSurfaceReflectorSetDetailsCustomization::MakeInstance()
  115. {
  116. return MakeShareable(new FAkSurfaceReflectorSetDetailsCustomization());
  117. }
  118. void FAkSurfaceReflectorSetDetailsCustomization::CustomizeDetails(const TSharedPtr<IDetailLayoutBuilder>& InDetailBuilder)
  119. {
  120. InDetailBuilder->EditCategory("Toggle", FText::GetEmpty(), ECategoryPriority::Important);
  121. InDetailBuilder->EditCategory("Geometry Settings", FText::GetEmpty(), ECategoryPriority::TypeSpecific);
  122. InDetailBuilder->EditCategory("Fit To Geometry", FText::GetEmpty(), ECategoryPriority::TypeSpecific);
  123. DetailBuilder = InDetailBuilder;
  124. CustomizeDetails(*InDetailBuilder);
  125. }
  126. void FAkSurfaceReflectorSetDetailsCustomization::CustomizeDetails(IDetailLayoutBuilder& InDetailBuilder)
  127. {
  128. InDetailBuilder.GetObjectsBeingCustomized(ObjectsBeingCustomized);
  129. auto AcousticPolysPropHandle = InDetailBuilder.GetProperty("AcousticPolys");
  130. InDetailBuilder.HideProperty("AcousticPolys");
  131. bool showGeometrySettings = false;
  132. for (int i = 0; i < ObjectsBeingCustomized.Num(); ++i)
  133. {
  134. auto Component = Cast<UAkSurfaceReflectorSetComponent>(ObjectsBeingCustomized[i].Get());
  135. if (Component)
  136. {
  137. ReflectorSetBeingCustomized = TWeakObjectPtr<UAkSurfaceReflectorSetComponent>(Component);
  138. if (ReflectorSetBeingCustomized->bEnableSurfaceReflectors)
  139. {
  140. showGeometrySettings = true;
  141. break;
  142. }
  143. }
  144. }
  145. if (!showGeometrySettings)
  146. InDetailBuilder.HideCategory("Geometry Settings");
  147. IDetailCategoryBuilder& CategoryBuilder = InDetailBuilder.EditCategory("Geometry Surfaces", FText::GetEmpty(), ECategoryPriority::TypeSpecific);
  148. FString enableEditSurfacesTooltip(FString("Enable ") + GEOMETRY_EDIT_DISPLAY_NAME + " and show only selected actors");
  149. FString disableEditSurfacesTooltip(FString("Disable ") + GEOMETRY_EDIT_DISPLAY_NAME + " and show all actors");
  150. CategoryBuilder.HeaderContent
  151. (
  152. SNew(SHorizontalBox)
  153. + SHorizontalBox::Slot()
  154. .HAlign(HAlign_Left)
  155. .VAlign(VAlign_Center)
  156. .AutoWidth()
  157. [
  158. SAssignNew(SelectionInfoLabel, STextBlock)
  159. // SelectionInfoLabel is passed in to a SAcousticSurfacesController below, and the selection text is set during its construction.
  160. .Text(FText::FromString(""))
  161. ]
  162. + SHorizontalBox::Slot()
  163. .AutoWidth()
  164. .HAlign(HAlign_Left)
  165. .VAlign(VAlign_Center)
  166. [
  167. SNew(SButton)
  168. .Text(FText::FromString("Enable Edit Surfaces "))
  169. .ToolTipText(FText::FromString(enableEditSurfacesTooltip))
  170. .OnClicked(this, &FAkSurfaceReflectorSetDetailsCustomization::OnEnableEditModeClicked)
  171. ]
  172. + SHorizontalBox::Slot()
  173. .AutoWidth()
  174. .HAlign(HAlign_Left)
  175. .VAlign(VAlign_Center)
  176. [
  177. SNew(SButton)
  178. .Text(FText::FromString("Disable Edit Surfaces"))
  179. .ToolTipText(FText::FromString(disableEditSurfacesTooltip))
  180. .OnClicked(this, &FAkSurfaceReflectorSetDetailsCustomization::OnDisableEditModeClicked)
  181. ]
  182. );
  183. // Assume Transmission Loss controls will be hidden
  184. int surfacePropertiesControlsHeight = 48;
  185. for (TWeakObjectPtr<UObject> ObjectBeingCustomized : ObjectsBeingCustomized)
  186. {
  187. UAkSurfaceReflectorSetComponent* reflectorSetComponent = Cast<UAkSurfaceReflectorSetComponent>(ObjectBeingCustomized.Get());
  188. if (reflectorSetComponent && reflectorSetComponent->bEnableSurfaceReflectors)
  189. {
  190. // There is a surface reflector set with bEnableSurfaceReflectors enabled - add room for Transmission Loss controls.
  191. surfacePropertiesControlsHeight = 72;
  192. break;
  193. }
  194. }
  195. if (auto LockedDetailBuilder = DetailBuilder.Pin())
  196. {
  197. FDetailWidgetRow& acousticSurfacesRow = CategoryBuilder.AddCustomRow(AcousticPolysPropHandle->GetPropertyDisplayName());
  198. acousticSurfacesRow.NameContent()
  199. [
  200. SNew(SBox)
  201. .HeightOverride(surfacePropertiesControlsHeight)
  202. [
  203. SNew(SAcousticSurfacesLabels, ObjectsBeingCustomized)
  204. ]
  205. ];
  206. acousticSurfacesRow.ValueContent()
  207. [
  208. SNew(SBox)
  209. .HeightOverride(surfacePropertiesControlsHeight)
  210. [
  211. SNew(SAcousticSurfacesController, ObjectsBeingCustomized, LockedDetailBuilder)
  212. ]
  213. ];
  214. }
  215. if (ObjectsBeingCustomized.Num() == 1)
  216. {
  217. auto Component = Cast<UAkSurfaceReflectorSetComponent>(ObjectsBeingCustomized[0].Get());
  218. if (Component)
  219. {
  220. ReflectorSetBeingCustomized = TWeakObjectPtr<UAkSurfaceReflectorSetComponent>(Component);
  221. SetupGeometryModificationHandlers();
  222. }
  223. else
  224. {
  225. ReflectorSetBeingCustomized.Reset();
  226. UE_LOG(LogAkAudio, Log, TEXT("FAkSurfaceReflectorSetDetailsCustomization::CustomizeDetails: Could not get ObjectsBeingCustomized."));
  227. }
  228. }
  229. }
  230. #define REGISTER_PROPERTY_CHANGED(Class, Property, LockedDetailBuilder) \
  231. auto Property ## Handle = LockedDetailBuilder->GetProperty(GET_MEMBER_NAME_CHECKED(Class, Property), Class::StaticClass(), BrushBuilderName); \
  232. if (Property ## Handle->IsValidHandle()) Property ## Handle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FAkSurfaceReflectorSetDetailsCustomization::OnGeometryChanged))
  233. void FAkSurfaceReflectorSetDetailsCustomization::SetupGeometryModificationHandlers()
  234. {
  235. if (!ReflectorSetBeingCustomized.IsValid())
  236. {
  237. return;
  238. }
  239. static const FName BrushBuilderName(TEXT("BrushBuilder"));
  240. auto ParentBrush = ReflectorSetBeingCustomized->ParentBrush;
  241. if(!ParentBrush)
  242. return;
  243. if (auto LockedDetailBuilder = DetailBuilder.Pin())
  244. {
  245. auto EnableHandle = LockedDetailBuilder->GetProperty("bEnableSurfaceReflectors");
  246. EnableHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FAkSurfaceReflectorSetDetailsCustomization::OnEnableValueChanged));
  247. // This is to detect if the BrushBuilder changed.
  248. if (ReflectorSetBeingCustomized->AcousticPolys.Num() != ParentBrush->Nodes.Num())
  249. LockedDetailBuilder->GetPropertyUtilities()->EnqueueDeferredAction(FSimpleDelegate::CreateSP(this, &FAkSurfaceReflectorSetDetailsCustomization::OnGeometryChanged));
  250. }
  251. // Need to register to a LOT of different properties, because some change the geometry but don't force a refresh of the details panel
  252. AVolume* ParentVolume = Cast<AVolume>(ReflectorSetBeingCustomized->GetOwner());
  253. UClass* BrushBuilderClass = nullptr;
  254. if (ParentVolume && ParentVolume->BrushBuilder)
  255. {
  256. BrushBuilderClass = ParentVolume->BrushBuilder->GetClass();
  257. if (BrushBuilderClass == nullptr)
  258. {
  259. return;
  260. }
  261. }
  262. if (auto LockedDetailBuilder = DetailBuilder.Pin())
  263. {
  264. if (BrushBuilderClass == UConeBuilder::StaticClass())
  265. {
  266. REGISTER_PROPERTY_CHANGED(UConeBuilder, Sides, LockedDetailBuilder);
  267. REGISTER_PROPERTY_CHANGED(UConeBuilder, Hollow, LockedDetailBuilder);
  268. }
  269. else if (BrushBuilderClass == UCubeBuilder::StaticClass())
  270. {
  271. REGISTER_PROPERTY_CHANGED(UCubeBuilder, Hollow, LockedDetailBuilder);
  272. REGISTER_PROPERTY_CHANGED(UCubeBuilder, Tessellated, LockedDetailBuilder);
  273. }
  274. else if (BrushBuilderClass == UCurvedStairBuilder::StaticClass())
  275. {
  276. REGISTER_PROPERTY_CHANGED(UCurvedStairBuilder, NumSteps, LockedDetailBuilder);
  277. }
  278. else if (BrushBuilderClass == UCylinderBuilder::StaticClass())
  279. {
  280. REGISTER_PROPERTY_CHANGED(UCylinderBuilder, Sides, LockedDetailBuilder);
  281. REGISTER_PROPERTY_CHANGED(UCylinderBuilder, Hollow, LockedDetailBuilder);
  282. }
  283. else if (BrushBuilderClass == ULinearStairBuilder::StaticClass())
  284. {
  285. REGISTER_PROPERTY_CHANGED(ULinearStairBuilder, NumSteps, LockedDetailBuilder);
  286. }
  287. else if (BrushBuilderClass == USpiralStairBuilder::StaticClass())
  288. {
  289. REGISTER_PROPERTY_CHANGED(USpiralStairBuilder, NumSteps, LockedDetailBuilder);
  290. }
  291. else if (BrushBuilderClass == UTetrahedronBuilder::StaticClass())
  292. {
  293. REGISTER_PROPERTY_CHANGED(UTetrahedronBuilder, SphereExtrapolation, LockedDetailBuilder);
  294. }
  295. }
  296. FOnRefreshDetails DetailsChanged = FOnRefreshDetails::CreateRaw(this, &FAkSurfaceReflectorSetDetailsCustomization::OnEnableValueChanged);
  297. ReflectorSetBeingCustomized->SetOnRefreshDetails(DetailsChanged);
  298. }
  299. void FAkSurfaceReflectorSetDetailsCustomization::OnEnableValueChanged()
  300. {
  301. if (ReflectorSetBeingCustomized.IsValid())
  302. {
  303. ReflectorSetBeingCustomized->ClearOnRefreshDetails();
  304. }
  305. }
  306. void FAkSurfaceReflectorSetDetailsCustomization::OnGeometryChanged()
  307. {
  308. if (ReflectorSetBeingCustomized.IsValid())
  309. {
  310. ReflectorSetBeingCustomized->UpdatePolys();
  311. ReflectorSetBeingCustomized->ClearOnRefreshDetails();
  312. }
  313. }
  314. //////////////////////////////////////////////////////////////////////////
  315. #undef LOCTEXT_NAMESPACE