UiSettingsComponent.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0 OR MIT
  5. *
  6. */
  7. #include <Atom/RHI/Factory.h>
  8. #include <Atom/RHI/FactoryManagerBus.h>
  9. #include <AzCore/Interface/Interface.h>
  10. #include <AzCore/Serialization/EditContext.h>
  11. #include <LyShine/Bus/UiButtonBus.h>
  12. #include <LyShine/Bus/UiElementBus.h>
  13. #include <LyShine/Bus/UiTextBus.h>
  14. #include <Source/Components/UI/UiSettingsComponent.h>
  15. #include <Source/UserSettings/MultiplayerSampleUserSettings.h>
  16. namespace MultiplayerSample
  17. {
  18. void UiToggle::Reflect(AZ::ReflectContext* context)
  19. {
  20. if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  21. {
  22. serializeContext->Class<UiToggle>()
  23. ->Version(0)
  24. ->Field("Label", &UiToggle::m_labelEntity)
  25. ->Field("LeftButton", &UiToggle::m_leftButtonEntity)
  26. ->Field("RightButton", &UiToggle::m_rightButtonEntity)
  27. ;
  28. if (AZ::EditContext* editContext = serializeContext->GetEditContext())
  29. {
  30. editContext->Class<UiToggle>("Ui Toggle", "Manages the user settings")
  31. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  32. ->DataElement(AZ::Edit::UIHandlers::Default, &UiToggle::m_labelEntity, "Label", "The toggle's label entity.")
  33. ->DataElement(AZ::Edit::UIHandlers::Default, &UiToggle::m_leftButtonEntity, "Left Button", "The toggle's left button entity.")
  34. ->DataElement(AZ::Edit::UIHandlers::Default, &UiToggle::m_rightButtonEntity, "Right Button", "The toggle's right button entity.")
  35. ;
  36. }
  37. }
  38. }
  39. void UiSettingsComponent::Reflect(AZ::ReflectContext* context)
  40. {
  41. UiToggle::Reflect(context);
  42. if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  43. {
  44. serializeContext->Class<UiSettingsComponent, AZ::Component>()
  45. ->Version(0)
  46. ->Field("GraphicsApi", &UiSettingsComponent::m_graphicsApiToggle)
  47. ->Field("TextureQuality", &UiSettingsComponent::m_textureQualityToggle)
  48. ->Field("Fullscreen", &UiSettingsComponent::m_fullscreenToggle)
  49. ->Field("Resolution", &UiSettingsComponent::m_resolutionToggle)
  50. ->Field("Reflection", &UiSettingsComponent::m_reflectionToggle)
  51. ->Field("MSAA", &UiSettingsComponent::m_msaaToggle)
  52. ->Field("TAA", &UiSettingsComponent::m_taaToggle)
  53. ->Field("MasterVolume", &UiSettingsComponent::m_masterVolumeToggle)
  54. ->Field("MusicVolume", &UiSettingsComponent::m_musicVolumeToggle)
  55. ->Field("SfxVolume", &UiSettingsComponent::m_sfxVolumeToggle)
  56. ;
  57. if (AZ::EditContext* editContext = serializeContext->GetEditContext())
  58. {
  59. editContext->Class<UiSettingsComponent>("Ui Settings", "Manages the user settings")
  60. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  61. ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("CanvasUI"))
  62. ->DataElement(AZ::Edit::UIHandlers::Default, &UiSettingsComponent::m_graphicsApiToggle, "Graphics Api", "The Graphics Api toggle elements.")
  63. ->DataElement(AZ::Edit::UIHandlers::Default, &UiSettingsComponent::m_textureQualityToggle, "Texture Quality", "The Texture Quality toggle elements.")
  64. ->DataElement(AZ::Edit::UIHandlers::Default, &UiSettingsComponent::m_fullscreenToggle, "Fullscreen", "The Fullscreen toggle elements.")
  65. ->DataElement(AZ::Edit::UIHandlers::Default, &UiSettingsComponent::m_resolutionToggle, "Resolution", "The Resolution toggle elements.")
  66. ->DataElement(AZ::Edit::UIHandlers::Default, &UiSettingsComponent::m_reflectionToggle, "Reflection", "The Reflection toggle elements.")
  67. ->DataElement(AZ::Edit::UIHandlers::Default, &UiSettingsComponent::m_msaaToggle, "MSAA", "The MSAA toggle elements.")
  68. ->DataElement(AZ::Edit::UIHandlers::Default, &UiSettingsComponent::m_taaToggle, "TAA", "The TAA toggle elements.")
  69. ->DataElement(AZ::Edit::UIHandlers::Default, &UiSettingsComponent::m_masterVolumeToggle, "Master Volume", "The Master Volume toggle elements.")
  70. ->DataElement(AZ::Edit::UIHandlers::Default, &UiSettingsComponent::m_musicVolumeToggle, "Music Volume", "The Music Volume toggle elements.")
  71. ->DataElement(AZ::Edit::UIHandlers::Default, &UiSettingsComponent::m_sfxVolumeToggle, "SFX Volume", "The SFX Volume toggle elements.")
  72. ;
  73. }
  74. }
  75. }
  76. AzFramework::NativeWindowHandle UiSettingsComponent::GetWindowHandle()
  77. {
  78. AzFramework::NativeWindowHandle windowHandle = nullptr;
  79. AzFramework::WindowSystemRequestBus::BroadcastResult(
  80. windowHandle,
  81. &AzFramework::WindowSystemRequestBus::Events::GetDefaultWindowHandle);
  82. return windowHandle;
  83. }
  84. void UiSettingsComponent::Activate()
  85. {
  86. // Listen for window notifications so that we can detect fullscreen/windowed changes.
  87. AzFramework::WindowNotificationBus::Handler::BusConnect(GetWindowHandle());
  88. // Loads and applies the current user settings when this component activates.
  89. // The user settings should *already* be loaded and applied at Launcher startup, but connecting to the server
  90. // and switching levels can cause some engine settings to reset themselves, so this will reapply the desired
  91. // user settings again.
  92. MultiplayerSampleUserSettingsRequestBus::Broadcast(&MultiplayerSampleUserSettingsRequestBus::Events::Load);
  93. // Initialize the toggles to the current values
  94. InitializeToggle(m_graphicsApiToggle, OnGraphicsApiToggle);
  95. InitializeToggle(m_textureQualityToggle, OnTextureQualityToggle);
  96. InitializeToggle(m_fullscreenToggle, OnFullscreenToggle);
  97. InitializeToggle(m_resolutionToggle, OnResolutionToggle);
  98. InitializeToggle(m_reflectionToggle, OnReflectionToggle);
  99. InitializeToggle(m_msaaToggle, OnMsaaToggle);
  100. InitializeToggle(m_taaToggle, OnTaaToggle);
  101. InitializeToggle(m_masterVolumeToggle, OnMasterVolumeToggle);
  102. InitializeToggle(m_musicVolumeToggle, OnMusicVolumeToggle);
  103. InitializeToggle(m_sfxVolumeToggle, OnSfxVolumeToggle);
  104. }
  105. void UiSettingsComponent::Deactivate()
  106. {
  107. AzFramework::WindowNotificationBus::Handler::BusDisconnect();
  108. }
  109. void UiSettingsComponent::InitializeToggle(UiToggle& toggle, AZStd::function<void(UiToggle&, ToggleDirection)> toggleUpdateFn)
  110. {
  111. toggleUpdateFn(toggle, ToggleDirection::None);
  112. UiButtonBus::Event(toggle.m_leftButtonEntity, &UiButtonInterface::SetOnClickCallback,
  113. [&toggle, toggleUpdateFn]([[maybe_unused]] AZ::EntityId buttonEntityId, [[maybe_unused]] AZ::Vector2 position)
  114. {
  115. toggleUpdateFn(toggle, ToggleDirection::Left);
  116. });
  117. UiButtonBus::Event(toggle.m_rightButtonEntity, &UiButtonInterface::SetOnClickCallback,
  118. [&toggle, toggleUpdateFn]([[maybe_unused]] AZ::EntityId buttonEntityId, [[maybe_unused]] AZ::Vector2 position)
  119. {
  120. toggleUpdateFn(toggle, ToggleDirection::Right);
  121. });
  122. }
  123. template<typename ValueType>
  124. uint32_t UiSettingsComponent::GetRotatedIndex(
  125. const AZStd::span<const AZStd::pair<ValueType, AZStd::string_view>> valuesToLabels,
  126. const ValueType& value, ToggleDirection toggleDirection)
  127. {
  128. const size_t totalValues = valuesToLabels.size();
  129. uint32_t curIndex = 0;
  130. // Loop through and look for the correct value
  131. for (size_t index = 0; index < totalValues; index++)
  132. {
  133. if (value == valuesToLabels[index].first)
  134. {
  135. curIndex = aznumeric_cast<uint32_t>(index);
  136. break;
  137. }
  138. }
  139. switch (toggleDirection)
  140. {
  141. case ToggleDirection::Left:
  142. return aznumeric_cast<uint32_t>((curIndex + (totalValues - 1)) % totalValues);
  143. case ToggleDirection::Right:
  144. return aznumeric_cast<uint32_t>((curIndex + 1) % totalValues);
  145. default:
  146. return curIndex;
  147. }
  148. }
  149. void UiSettingsComponent::OnGraphicsApiToggle(UiToggle& toggle, ToggleDirection toggleDirection)
  150. {
  151. // Build up a list of supported graphics APIs dynamically the first time we're called.
  152. static AZStd::vector<AZStd::pair<AZStd::string_view, AZStd::string_view>> valuesToLabels;
  153. if (valuesToLabels.empty())
  154. {
  155. // Create a list of Graphics APIs supported on this platform.
  156. AZ::RHI::FactoryManagerBus::Broadcast(&AZ::RHI::FactoryManagerRequest::EnumerateFactories,
  157. [](AZ::RHI::Factory* factory) -> bool
  158. {
  159. auto name = factory->GetName().GetStringView();
  160. if (name == "null")
  161. {
  162. // Remove the Null API choice from the list. It's not something end users should want to choose.
  163. }
  164. else if (name == "dx12")
  165. {
  166. valuesToLabels.emplace_back(name, "DirectX 12");
  167. }
  168. else if (name == "vulkan")
  169. {
  170. valuesToLabels.emplace_back(name, "Vulkan");
  171. }
  172. else if (name == "metal")
  173. {
  174. valuesToLabels.emplace_back(name, "Metal");
  175. }
  176. else
  177. {
  178. // This is an unexpected API, use whatever name is provided as the display name.
  179. valuesToLabels.emplace_back(name, name);
  180. }
  181. // Keep enumerating through the full set.
  182. return true;
  183. });
  184. }
  185. // Get the current api selection.
  186. AZStd::string graphicsApi;
  187. MultiplayerSampleUserSettingsRequestBus::BroadcastResult(
  188. graphicsApi, &MultiplayerSampleUserSettingsRequestBus::Events::GetGraphicsApi);
  189. // If there isn't anything stored in the user settings yet, default to the currently-loaded api.
  190. if (graphicsApi.empty())
  191. {
  192. graphicsApi = AZ::RHI::Factory::Get().GetName().GetStringView();
  193. }
  194. // Rotate the index based on toggle direction.
  195. uint32_t graphicsApiIndex = GetRotatedIndex<AZStd::string_view>(valuesToLabels, graphicsApi, toggleDirection);
  196. UiTextBus::Event(toggle.m_labelEntity, &UiTextInterface::SetText, valuesToLabels[graphicsApiIndex].second);
  197. MultiplayerSampleUserSettingsRequestBus::Broadcast(
  198. &MultiplayerSampleUserSettingsRequestBus::Events::SetGraphicsApi, valuesToLabels[graphicsApiIndex].first);
  199. MultiplayerSampleUserSettingsRequestBus::Broadcast(&MultiplayerSampleUserSettingsRequestBus::Events::Save);
  200. }
  201. void UiSettingsComponent::OnTextureQualityToggle(UiToggle& toggle, ToggleDirection toggleDirection)
  202. {
  203. constexpr auto valuesToLabels = AZStd::to_array<AZStd::pair<int16_t, AZStd::string_view>>(
  204. {
  205. { aznumeric_cast<int16_t>(6), "Rock Bottom (64)" },
  206. { aznumeric_cast<int16_t>(5), "Extremely Low (128)" },
  207. { aznumeric_cast<int16_t>(4), "Very Low (256)" },
  208. { aznumeric_cast<int16_t>(3), "Low (512)" },
  209. { aznumeric_cast<int16_t>(2), "Medium (1K)" },
  210. { aznumeric_cast<int16_t>(1), "High (2K)" },
  211. { aznumeric_cast<int16_t>(0), "Ultra (4K)" },
  212. });
  213. // Get the current texture quality value.
  214. int16_t textureQuality = 0;
  215. MultiplayerSampleUserSettingsRequestBus::BroadcastResult(
  216. textureQuality, &MultiplayerSampleUserSettingsRequestBus::Events::GetTextureQuality);
  217. // Rotate the index based on toggle direction.
  218. uint32_t textureQualityIndex = GetRotatedIndex<int16_t>(valuesToLabels, textureQuality, toggleDirection);
  219. UiTextBus::Event(toggle.m_labelEntity, &UiTextInterface::SetText, valuesToLabels[textureQualityIndex].second);
  220. MultiplayerSampleUserSettingsRequestBus::Broadcast(
  221. &MultiplayerSampleUserSettingsRequestBus::Events::SetTextureQuality, valuesToLabels[textureQualityIndex].first);
  222. MultiplayerSampleUserSettingsRequestBus::Broadcast(&MultiplayerSampleUserSettingsRequestBus::Events::Save);
  223. }
  224. void UiSettingsComponent::OnReflectionToggle(UiToggle& toggle, ToggleDirection toggleDirection)
  225. {
  226. constexpr auto valuesToLabels = AZStd::to_array<AZStd::pair<SpecularReflections, AZStd::string_view>>(
  227. {
  228. { SpecularReflections::None, "None" },
  229. { SpecularReflections::ScreenSpace, "Screen Space" },
  230. // This choice can be enabled once raytraced reflections are considered stable.
  231. //{ SpecularReflections::ScreenSpaceAndRaytracing, "Hybrid Raytraced" },
  232. });
  233. // Get the current reflection value.
  234. SpecularReflections reflectionType = SpecularReflections::None;
  235. MultiplayerSampleUserSettingsRequestBus::BroadcastResult(
  236. reflectionType, &MultiplayerSampleUserSettingsRequestBus::Events::GetReflectionSetting);
  237. // Rotate the index based on toggle direction.
  238. uint32_t index = GetRotatedIndex<SpecularReflections>(valuesToLabels, reflectionType, toggleDirection);
  239. UiTextBus::Event(toggle.m_labelEntity, &UiTextInterface::SetText, valuesToLabels[index].second);
  240. MultiplayerSampleUserSettingsRequestBus::Broadcast(
  241. &MultiplayerSampleUserSettingsRequestBus::Events::SetReflectionSetting, valuesToLabels[index].first);
  242. MultiplayerSampleUserSettingsRequestBus::Broadcast(&MultiplayerSampleUserSettingsRequestBus::Events::Save);
  243. }
  244. void UiSettingsComponent::OnMsaaToggle(UiToggle& toggle, ToggleDirection toggleDirection)
  245. {
  246. constexpr auto valuesToLabels = AZStd::to_array<AZStd::pair<Msaa, AZStd::string_view>>(
  247. {
  248. { Msaa::X1, "1x" },
  249. { Msaa::X2, "2x" },
  250. { Msaa::X4, "4x" },
  251. });
  252. // Get the current msaa value.
  253. Msaa msaa = Msaa::X1;
  254. MultiplayerSampleUserSettingsRequestBus::BroadcastResult(
  255. msaa, &MultiplayerSampleUserSettingsRequestBus::Events::GetMsaa);
  256. // Rotate the index based on toggle direction.
  257. uint32_t index = GetRotatedIndex<Msaa>(valuesToLabels, msaa, toggleDirection);
  258. UiTextBus::Event(toggle.m_labelEntity, &UiTextInterface::SetText, valuesToLabels[index].second);
  259. MultiplayerSampleUserSettingsRequestBus::Broadcast(
  260. &MultiplayerSampleUserSettingsRequestBus::Events::SetMsaa, valuesToLabels[index].first);
  261. MultiplayerSampleUserSettingsRequestBus::Broadcast(&MultiplayerSampleUserSettingsRequestBus::Events::Save);
  262. }
  263. void UiSettingsComponent::OnTaaToggle(UiToggle& toggle, ToggleDirection toggleDirection)
  264. {
  265. constexpr auto valuesToLabels = AZStd::to_array<AZStd::pair<bool, AZStd::string_view>>(
  266. {
  267. { false, "Off" },
  268. { true, "On" },
  269. });
  270. // Get the current TAA value.
  271. bool enabled = false;
  272. MultiplayerSampleUserSettingsRequestBus::BroadcastResult(
  273. enabled, &MultiplayerSampleUserSettingsRequestBus::Events::GetTaa);
  274. // Rotate the index based on toggle direction.
  275. uint32_t index = GetRotatedIndex<bool>(valuesToLabels, enabled, toggleDirection);
  276. UiTextBus::Event(toggle.m_labelEntity, &UiTextInterface::SetText, valuesToLabels[index].second);
  277. MultiplayerSampleUserSettingsRequestBus::Broadcast(
  278. &MultiplayerSampleUserSettingsRequestBus::Events::SetTaa, valuesToLabels[index].first);
  279. MultiplayerSampleUserSettingsRequestBus::Broadcast(&MultiplayerSampleUserSettingsRequestBus::Events::Save);
  280. }
  281. void UiSettingsComponent::OnMasterVolumeToggle(UiToggle& toggle, ToggleDirection toggleDirection)
  282. {
  283. OnVolumeToggle(VolumeChannel::MasterVolume, toggle, toggleDirection);
  284. }
  285. void UiSettingsComponent::OnMusicVolumeToggle(UiToggle& toggle, ToggleDirection toggleDirection)
  286. {
  287. OnVolumeToggle(VolumeChannel::MusicVolume, toggle, toggleDirection);
  288. }
  289. void UiSettingsComponent::OnSfxVolumeToggle(UiToggle& toggle, ToggleDirection toggleDirection)
  290. {
  291. OnVolumeToggle(VolumeChannel::SfxVolume, toggle, toggleDirection);
  292. }
  293. void UiSettingsComponent::OnVolumeToggle(VolumeChannel volumeChannel, UiToggle& toggle, ToggleDirection toggleDirection)
  294. {
  295. constexpr auto valuesToLabels = AZStd::to_array<AZStd::pair<uint8_t, AZStd::string_view>>(
  296. {
  297. { aznumeric_cast<uint8_t>(0), "0 (off)" },
  298. { aznumeric_cast<uint8_t>(10), "10" },
  299. { aznumeric_cast<uint8_t>(20), "20" },
  300. { aznumeric_cast<uint8_t>(30), "30" },
  301. { aznumeric_cast<uint8_t>(40), "40" },
  302. { aznumeric_cast<uint8_t>(50), "50" },
  303. { aznumeric_cast<uint8_t>(60), "60" },
  304. { aznumeric_cast<uint8_t>(70), "70" },
  305. { aznumeric_cast<uint8_t>(80), "80" },
  306. { aznumeric_cast<uint8_t>(90), "90" },
  307. { aznumeric_cast<uint8_t>(100), "100 (max)" },
  308. });
  309. // Get the current volume value.
  310. uint8_t volume = 0;
  311. MultiplayerSampleUserSettingsRequestBus::BroadcastResult(
  312. volume, &MultiplayerSampleUserSettingsRequestBus::Events::GetVolume, volumeChannel);
  313. // Make sure our volume is a multiple of 10.
  314. volume = (volume / 10) * 10;
  315. // Rotate the index based on toggle direction.
  316. uint32_t volumeIndex = GetRotatedIndex<uint8_t>(valuesToLabels, volume, toggleDirection);
  317. UiTextBus::Event(toggle.m_labelEntity, &UiTextInterface::SetText, valuesToLabels[volumeIndex].second);
  318. MultiplayerSampleUserSettingsRequestBus::Broadcast(
  319. &MultiplayerSampleUserSettingsRequestBus::Events::SetVolume, volumeChannel, valuesToLabels[volumeIndex].first);
  320. MultiplayerSampleUserSettingsRequestBus::Broadcast(&MultiplayerSampleUserSettingsRequestBus::Events::Save);
  321. }
  322. void UiSettingsComponent::OnFullscreenToggle(UiToggle& toggle, ToggleDirection toggleDirection)
  323. {
  324. constexpr auto valuesToLabels = AZStd::to_array<AZStd::pair<bool, AZStd::string_view>>(
  325. {
  326. { false, "Windowed" },
  327. { true, "Fullscreen" },
  328. });
  329. // Get the current fullscreen state. Unlike the other settings, we'll get this from the current window state so that we
  330. // handle things like Alt-enter that can change our windowing state regardless of what our user settings thinks.
  331. // Start by getting the current user setting as the default state.
  332. bool fullscreen = false;
  333. MultiplayerSampleUserSettingsRequestBus::BroadcastResult(
  334. fullscreen, &MultiplayerSampleUserSettingsRequestBus::Events::GetFullscreen);
  335. // Next, try to get the current state from the window. If it fails to get the state, we'll default to the
  336. // user setting value that we fetched above.
  337. bool currentFullscreenState = fullscreen;
  338. AzFramework::WindowRequestBus::EventResult(currentFullscreenState,
  339. GetWindowHandle(), &AzFramework::WindowRequestBus::Events::GetFullScreenState);
  340. // Rotate the index based on toggle direction.
  341. uint32_t fullscreenIndex = GetRotatedIndex<bool>(valuesToLabels, currentFullscreenState, toggleDirection);
  342. UiTextBus::Event(toggle.m_labelEntity, &UiTextInterface::SetText, valuesToLabels[fullscreenIndex].second);
  343. MultiplayerSampleUserSettingsRequestBus::Broadcast(
  344. &MultiplayerSampleUserSettingsRequestBus::Events::SetFullscreen, valuesToLabels[fullscreenIndex].first);
  345. MultiplayerSampleUserSettingsRequestBus::Broadcast(&MultiplayerSampleUserSettingsRequestBus::Events::Save);
  346. }
  347. void UiSettingsComponent::OnResolutionToggle(UiToggle& toggle, ToggleDirection toggleDirection)
  348. {
  349. constexpr auto valuesToLabels = AZStd::to_array<AZStd::pair<AZStd::pair<uint32_t, uint32_t>, AZStd::string_view>>(
  350. {
  351. // This set of resolutions was selected because they're the set that we offer in O3DE in the IMGUI debug menus.
  352. // Feel free to add, remove or reorder resolution pairs from this list as appropriate.
  353. // There is logic below for filtering out resolutions that are too large that assumes that the smallest
  354. // resolution is the first entry on the list, so just keep that in mind when altering this list.
  355. { { 800, 334}, "800 x 334 (43:18)" },
  356. { { 800, 450}, "800 x 450 (16:9)" },
  357. { { 800, 500}, "800 x 500 (16:10)" },
  358. { { 800, 600}, "800 x 600 (4:3)" },
  359. { {1280, 535}, "1280 x 535 (43:18)" },
  360. { {1280, 720}, "1280 x 720 (16:9)" },
  361. { {1280, 800}, "1280 x 800 (16:10)" },
  362. { {1280, 960}, "1280 x 960 (4:3)" },
  363. { {1600, 669}, "1600 x 669 (43:18)" },
  364. { {1600, 900}, "1600 x 900 (16:9)" },
  365. { {1600, 1000}, "1600 x 1000 (16:10)" },
  366. { {1600, 1200}, "1600 x 1200 (4:3)" },
  367. { {1920, 803}, "1920 x 803 (43:18)" },
  368. { {1920, 1080}, "1920 x 1080 (16:9)" },
  369. { {1920, 1200}, "1920 x 1200 (16:10)" },
  370. { {1920, 1440}, "1920 x 1440 (4:3)" },
  371. { {2560, 1071}, "2560 x 1071 (43:18)" },
  372. { {2560, 1440}, "2560 x 1440 (16:9)" },
  373. { {2560, 1600}, "2560 x 1600 (16:10)" },
  374. { {2560, 1920}, "2560 x 1920 (4:3)" },
  375. { {3440, 1440}, "3440 x 1440 (43:18)" },
  376. { {3440, 1935}, "3440 x 1935 (16:9)" },
  377. { {3440, 2150}, "3440 x 2150 (16:10)" },
  378. { {3440, 2580}, "3440 x 2580 (4:3)" },
  379. { {3840, 1607}, "3840 x 1607 (43:18)" },
  380. { {3840, 2160}, "3840 x 2160 (16:9)" },
  381. { {3840, 2400}, "3840 x 2400 (16:10)" },
  382. { {3840, 2880}, "3840 x 2880 (4:3)" },
  383. });
  384. // Get the max supported resolution for the monitor that the window is currently on.
  385. AzFramework::WindowSize maxWindowSize = { AZStd::numeric_limits<uint32_t>::max(), AZStd::numeric_limits<uint32_t>::max() };
  386. AzFramework::WindowRequestBus::EventResult(maxWindowSize,
  387. GetWindowHandle(), &AzFramework::WindowRequestBus::Events::GetMaximumClientAreaSize);
  388. // Get the current resolution value.
  389. AZStd::pair<uint32_t, uint32_t> resolution = { 1920, 1080 };
  390. MultiplayerSampleUserSettingsRequestBus::BroadcastResult(
  391. resolution, &MultiplayerSampleUserSettingsRequestBus::Events::GetResolution);
  392. // Rotate the index based on toggle direction.
  393. uint32_t resolutionIndex = GetRotatedIndex<AZStd::pair<uint32_t, uint32_t>>(valuesToLabels, resolution, toggleDirection);
  394. // If the resolution is too big for the monitor, keep rotating the index until we find one that fits
  395. // or until we reach the start of the list. The list starts with the smallest resolution, so if that one
  396. // doesn't fit, there's no point in continuing to look for something smaller.
  397. while ((resolutionIndex > 0) && (
  398. (valuesToLabels[resolutionIndex].first.first > maxWindowSize.m_width) ||
  399. (valuesToLabels[resolutionIndex].first.second > maxWindowSize.m_height)))
  400. {
  401. ToggleDirection searchDirection = (toggleDirection == ToggleDirection::None) ? ToggleDirection::Left : toggleDirection;
  402. resolutionIndex = GetRotatedIndex({ valuesToLabels }, valuesToLabels[resolutionIndex].first, searchDirection);
  403. }
  404. UiTextBus::Event(toggle.m_labelEntity, &UiTextInterface::SetText, valuesToLabels[resolutionIndex].second);
  405. MultiplayerSampleUserSettingsRequestBus::Broadcast(
  406. &MultiplayerSampleUserSettingsRequestBus::Events::SetResolution, valuesToLabels[resolutionIndex].first);
  407. MultiplayerSampleUserSettingsRequestBus::Broadcast(&MultiplayerSampleUserSettingsRequestBus::Events::Save);
  408. }
  409. void UiSettingsComponent::OnFullScreenModeChanged([[maybe_unused]] bool fullscreen)
  410. {
  411. // Refresh the windowed / fullscreen setting and toggle in case the user changes the current mode by pressing Alt-Enter.
  412. OnFullscreenToggle(m_fullscreenToggle, ToggleDirection::None);
  413. }
  414. }