using Dalamud.Game.ClientState.Keys; using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Windowing; using ImGuiNET; using System; using System.Linq; using System.Numerics; namespace CustomResolution.Windows; public class ConfigWindow : Window, IDisposable { private VirtualKey[] _validKeys = new VirtualKey[] { VirtualKey.NO_KEY }.Union(Service.KeyState.GetValidVirtualKeys()).ToArray(); private readonly int[] _displayCurrentWH = new int[2]; private readonly int[] _displayCurrentWindowWH = new int[2]; private readonly int[] _displayCurrentGameWH = new int[2]; private ConfigurationV1 _; public ConfigWindow() : base( "CustomResolution", ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse | ImGuiWindowFlags.AlwaysAutoResize) { UpdateFromConfig(); } public void Dispose() { } public void UpdateFromConfig() { _ = Service.Config._; } public void UpdateToConfig() { Service.Config._ = _; Service.Config.Save(); } public override void Draw() { var save = false; _displayCurrentWH[0] = (int) Service.DisplaySize.CurrentWidth; _displayCurrentWH[1] = (int) Service.DisplaySize.CurrentHeight; _displayCurrentWindowWH[0] = (int) Service.DisplaySize.CurrentWindowWidth; _displayCurrentWindowWH[1] = (int) Service.DisplaySize.CurrentWindowHeight; _displayCurrentGameWH[0] = (int) Service.GameSize.CurrentWidth; _displayCurrentGameWH[1] = (int) Service.GameSize.CurrentHeight; using (ImRaii.Disabled()) { ImGui.InputInt2("Window size", ref _displayCurrentWindowWH[0]); } using (var imTabBar = ImRaii.TabBar("MalfunctionMainTabs")) { DrawDisplayTab(); DrawGameTab(); DrawCommonTab(); } if (ImGui.Button("Save and apply")) { save = true; } if (save) { UpdateToConfig(); } } private void DrawDisplayTab() { using var imTab = ImRaii.TabItem($"Display##DisplayTab"); if (ImGui.IsItemHovered()) { ImGui.SetTooltip(@"The display resolution affects everything, including screenshots taken in-game and via ReShade. This works best with the ""High Resolution UI Settings"" in the system configuration, as it also affects the UI. In general: Use it as a fake fullscreen / window resolution, best suited for screenshots. Changed via /cres"); } if (!imTab.Success) { return; } using (ImRaii.Disabled()) { ImGui.InputInt2("Current size", ref _displayCurrentWH[0]); } DrawSizeTabShared(ref _.Display, "Display"); ImGui.Checkbox("Use scale", ref _.Display.IsScale); if (_.Display.IsScale) { ImGui.InputFloat("Scale", ref _.Display.Scale, 0.01f, 0.1f, "%.3f", ImGuiInputTextFlags.None); } else { unsafe { ImGui.InputInt2("Size in pixels", ref _.Display.WH[0]); } } if (Service.DebugConfig.IsDebug) { ImGui.Text(Service.DisplaySize.DebugInfo); } } private void DrawGameTab() { var unsupportedSysScale = !Service.GameSize.ConfigGraphicsRezoType.IsSupported(); var blinkTime = (DateTime.UtcNow.Ticks % TimeSpan.TicksPerHour) / (float) TimeSpan.TicksPerSecond; var blink = (blinkTime % 2) < 1; if (unsupportedSysScale && blink) { ImGui.PushStyleColor(ImGuiCol.Border, 0xFF00FFFF); } using var imTab = ImRaii.TabItem($"Gameplay{(unsupportedSysScale ? " \uE0C0" : "")}##GameTab"); if (unsupportedSysScale && blink) { ImGui.PopStyleColor(); } if (ImGui.IsItemHovered()) { ImGui.SetTooltip(@"The gameplay resolution affects only the quality of your character and everything around them, leaving the HUD untouched. This also doesn't touch the screenshot resolution. This works as an advanced version of the in-game ""3D Resolution Scaling"" graphics options, allowing you to go smaller than 0.5x for more FPS, or higher than 1x for higher quality. This overrides dynamic resolution! In general: Use it for gameplay, not for screenshots. Changed via /gres"); } if (!imTab.Success) { return; } if (unsupportedSysScale) { using var border = ImRaii.PushColor(ImGuiCol.Border, 0xFF00FFFF); if (ImGui.Button(@$"Your game system configuration is currently stuck on an unsupported graphics upscaling option: {Service.GameSize.ConfigGraphicsRezoType.ToHumanNameString()} This can happen after you've replaced your GPU, or when your graphic driver has encountered problems. Click here to reset to FSR and fix the scaling slider.##FixDLSS")) { Service.GameSize.SetConfigGraphicsRezoType(ResolutionScalingMode.FSR); } } using (ImRaii.Disabled()) { ImGui.InputInt2("Current size", ref _displayCurrentGameWH[0]); } DrawSizeTabShared(ref _.Game, "Game", scaleOnly: true); ImGui.InputFloat("Scale", ref _.Game.Scale, 0.01f, 0.1f, "%.3f", ImGuiInputTextFlags.None); if (ImGui.BeginCombo("Graphics Upscaling", _.ResolutionScalingMode.ToHumanNameString())) { foreach (var mode in Enum.GetValues()) { if (ImGui.Selectable(mode.ToHumanNameString(), _.ResolutionScalingMode == mode, mode.IsBroken() ? ImGuiSelectableFlags.Disabled : ImGuiSelectableFlags.None)) { _.ResolutionScalingMode = mode; } if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled) && mode.ToHumanInfoString() is { } info) { ImGui.SetTooltip(info); } } ImGui.EndCombo(); } if (Service.DebugConfig.IsDebug) { if (ImGui.Button("(DEBUG) Set game config to DLSS")) { Service.GameSize.SetConfigGraphicsRezoType(ResolutionScalingMode.DLSS); } ImGui.Text(Service.GameSize.DebugInfo); } } private void DrawSizeTabShared(ref ConfigurationV1.SizeConfig size, string name, bool scaleOnly = false) { ImGui.Checkbox("Enabled", ref size.IsEnabled); ImGui.SameLine(); ImGui.Dummy(new Vector2(20, 0)); ImGui.SameLine(); ImGui.SetNextItemWidth(80); if (ImGui.BeginCombo($"##_{name}_configHotkeyModifier", size.HotkeyModifier.ToHumanNameString())) { foreach (var key in Enum.GetValues()) { if (ImGui.Selectable(key.ToHumanNameString(), size.HotkeyModifier == key, ImGuiSelectableFlags.None)) { size.HotkeyModifier = key; } if (ImGui.IsItemHovered() && key.ToHumanInfoString() is { } info) { ImGui.SetTooltip(info); } } ImGui.EndCombo(); } ImGui.SameLine(); ImGui.SetNextItemWidth(160); if (ImGui.BeginCombo($"##_{name}_configHotkeyKey", size.HotkeyKey.ToHumanNameString())) { foreach (var key in _validKeys) { if (ImGui.Selectable(key.ToHumanNameString(), size.HotkeyKey == key, ImGuiSelectableFlags.None)) { size.HotkeyKey = key; } if (ImGui.IsItemHovered() && key.ToHumanInfoString() is { } info) { ImGui.SetTooltip(info); } } ImGui.EndCombo(); } ImGui.SameLine(); ImGui.Text("Hotkey"); } private void DrawCommonTab() { using var imTab = ImRaii.TabItem($"Common##CommonTab"); if (ImGui.IsItemHovered()) { ImGui.SetTooltip(@"Smaller tweaks and fixes, f.e. for DXVK on Windows, or to allow making the window smaller than 1024x768."); } if (!imTab.Success) { return; } if (ImGui.BeginCombo("Borderless window workaround", _.DXVKDWMHackMode.ToHumanNameString())) { foreach (var mode in Enum.GetValues()) { if (ImGui.Selectable(mode.ToHumanNameString(), _.DXVKDWMHackMode == mode, ImGuiSelectableFlags.None)) { _.DXVKDWMHackMode = mode; } if (ImGui.IsItemHovered() && mode.ToHumanInfoString() is { } info) { ImGui.SetTooltip(info); } } ImGui.EndCombo(); } if (ImGui.IsItemHovered()) { ImGui.SetTooltip(@"Fixes DXVK borderless window causing black screens when alt-tabbing. This can *possibly* impact performance, depending on your Windows version and GPU. Feel free to experiment with this toggle. Make sure to switch the game to windowed and then back to borderless windowed when changing. Works even with the scaling above disabled. Not intended to be used with proper fullscreen."); } if (ImGui.BeginCombo("Minimum window size", _.MinSizeMode.ToHumanNameString())) { foreach (var mode in Enum.GetValues()) { if (ImGui.Selectable(mode.ToHumanNameString(), _.MinSizeMode == mode, ImGuiSelectableFlags.None)) { _.MinSizeMode = mode; } if (ImGui.IsItemHovered() && mode.ToHumanInfoString() is { } info) { ImGui.SetTooltip(info); } } ImGui.EndCombo(); } ImGui.Checkbox("Disable on lag", ref _.DisableOnHang); if (ImGui.IsItemHovered()) { ImGui.SetTooltip(@$"Automatically disables scaling if FPS goes below 1 FPS. Leave this option enabled if you want this plugin to disable itself as a protection in case the resolution changes unexpectedly, or in case the resolution goes too high. In the absolute worst case, delete the following file to reset your settings: %%AppData%%\XIVLauncher\pluginConfigs\{Service.PluginName}.json"); } #if DEBUG var debug = Service.DebugConfig.IsDebug; ImGui.Checkbox("DEBUG!", ref debug); Service.DebugConfig.IsDebug = debug; #endif if (Service.DebugConfig.IsDebug) { ImGui.Text($"LAG: {Service.Plugin.LagsTotal} {Service.Plugin.Lag}"); } } }