diff --git a/UnleashedRecomp/gpu/imgui/imgui_common.h b/UnleashedRecomp/gpu/imgui/imgui_common.h index 91d5b4ee..861e72cc 100644 --- a/UnleashedRecomp/gpu/imgui/imgui_common.h +++ b/UnleashedRecomp/gpu/imgui/imgui_common.h @@ -20,6 +20,7 @@ enum class ImGuiCallback : int32_t SetScale = -4, SetMarqueeFade = -5, SetOutline = -6, + SetProceduralOrigin = -7, // -8 is ImDrawCallback_ResetRenderState, don't use! }; @@ -58,6 +59,11 @@ union ImGuiCallbackData { float outline; } setOutline; + + struct + { + float proceduralOrigin[2]; + } setProceduralOrigin; }; extern ImGuiCallbackData* AddImGuiCallback(ImGuiCallback callback); diff --git a/UnleashedRecomp/gpu/shader/imgui_common.hlsli b/UnleashedRecomp/gpu/shader/imgui_common.hlsli index dbc812ec..9f96d553 100644 --- a/UnleashedRecomp/gpu/shader/imgui_common.hlsli +++ b/UnleashedRecomp/gpu/shader/imgui_common.hlsli @@ -13,6 +13,7 @@ struct PushConstants float2 InverseDisplaySize; float2 Origin; float2 Scale; + float2 ProceduralOrigin; float Outline; }; diff --git a/UnleashedRecomp/gpu/shader/imgui_ps.hlsl b/UnleashedRecomp/gpu/shader/imgui_ps.hlsl index 18928e0f..a1a5d59a 100644 --- a/UnleashedRecomp/gpu/shader/imgui_ps.hlsl +++ b/UnleashedRecomp/gpu/shader/imgui_ps.hlsl @@ -81,7 +81,7 @@ float median(float r, float g, float b) float4 main(in Interpolators interpolators) : SV_Target { float4 color = interpolators.Color; - color *= PixelAntialiasing(interpolators.Position.xy - 0.5); + color *= PixelAntialiasing(interpolators.Position.xy - (g_PushConstants.ProceduralOrigin + 0.5)); if (g_PushConstants.Texture2DDescriptorIndex != 0) { diff --git a/UnleashedRecomp/gpu/video.cpp b/UnleashedRecomp/gpu/video.cpp index 46e4411d..64f0d94f 100644 --- a/UnleashedRecomp/gpu/video.cpp +++ b/UnleashedRecomp/gpu/video.cpp @@ -1168,6 +1168,7 @@ struct ImGuiPushConstants ImVec2 inverseDisplaySize{}; ImVec2 origin{ 0.0f, 0.0f }; ImVec2 scale{ 1.0f, 1.0f }; + ImVec2 proceduralOrigin{ 0.0f, 0.0f }; float outline{}; }; @@ -2171,6 +2172,9 @@ static void ProcDrawImGui(const RenderCommand& cmd) case ImGuiCallback::SetOutline: setPushConstants(&pushConstants.outline, &callbackData->setOutline, sizeof(callbackData->setOutline)); break; + case ImGuiCallback::SetProceduralOrigin: + setPushConstants(&pushConstants.proceduralOrigin, &callbackData->setProceduralOrigin, sizeof(callbackData->setProceduralOrigin)); + break; default: assert(false && "Unknown ImGui callback type."); break; @@ -4813,6 +4817,8 @@ static bool LoadTexture(GuestTexture& texture, const uint8_t* data, size_t dataS texture.descriptorIndex = g_textureDescriptorAllocator.allocate(); g_textureDescriptorSet->setTexture(texture.descriptorIndex, texture.texture, RenderTextureLayout::SHADER_READ, texture.textureView.get()); + texture.width = ddsDesc.width; + texture.height = ddsDesc.height; texture.viewDimension = viewDesc.dimension; struct Slice diff --git a/UnleashedRecomp/locale/config_locale.cpp b/UnleashedRecomp/locale/config_locale.cpp index ff08e571..cf0d4dbe 100644 --- a/UnleashedRecomp/locale/config_locale.cpp +++ b/UnleashedRecomp/locale/config_locale.cpp @@ -61,7 +61,7 @@ CONFIG_DEFINE_LOCALE(ControlTutorial) CONFIG_DEFINE_LOCALE(AchievementNotifications) { - { ELanguage::English, { "Achievement Notifications", "Show notifications for unlocking achievements.\n\nAchievements will still\nbe rewarded with notifications disabled." } } + { ELanguage::English, { "Achievement Notifications", "Show notifications for unlocking achievements.\n\nAchievements will still be rewarded with notifications disabled." } } }; CONFIG_DEFINE_LOCALE(TimeOfDayTransition) @@ -90,7 +90,7 @@ CONFIG_DEFINE_ENUM_LOCALE(EControllerIcons) { ELanguage::English, { - { EControllerIcons::Auto, { "AUTO", "Auto: the game will determine which icons\nto use based on the current input device." } }, + { EControllerIcons::Auto, { "AUTO", "Auto: the game will determine which icons to use based on the current input device." } }, { EControllerIcons::Xbox, { "XBOX", "" } }, { EControllerIcons::PlayStation, { "PLAYSTATION", "" } } } @@ -206,7 +206,7 @@ CONFIG_DEFINE_LOCALE(Fullscreen) CONFIG_DEFINE_LOCALE(VSync) { - { ELanguage::English, { "V-Sync", "Synchronize the game\nto the refresh rate of\nthe display to prevent screen tearing." } } + { ELanguage::English, { "V-Sync", "Synchronize the game to the refresh rate of the display to prevent screen tearing." } } }; CONFIG_DEFINE_LOCALE(FPS) @@ -284,7 +284,7 @@ CONFIG_DEFINE_ENUM_LOCALE(EMotionBlur) { { EMotionBlur::Off, { "OFF", "" } }, { EMotionBlur::Original, { "ORIGINAL", "" } }, - { EMotionBlur::Enhanced, { "ENHANCED", "Enhanced: uses more samples for smoother motion blur at the cost\nof performance." } } + { EMotionBlur::Enhanced, { "ENHANCED", "Enhanced: uses more samples for smoother motion blur at the cost of performance." } } } } }; diff --git a/UnleashedRecomp/ui/imgui_utils.h b/UnleashedRecomp/ui/imgui_utils.h index 48f0caed..d5d5afce 100644 --- a/UnleashedRecomp/ui/imgui_utils.h +++ b/UnleashedRecomp/ui/imgui_utils.h @@ -96,6 +96,18 @@ inline void ResetOutline() SetOutline(0.0f); } +inline void SetProceduralOrigin(ImVec2 proceduralOrigin) +{ + auto callbackData = AddImGuiCallback(ImGuiCallback::SetProceduralOrigin); + callbackData->setProceduralOrigin.proceduralOrigin[0] = proceduralOrigin.x; + callbackData->setProceduralOrigin.proceduralOrigin[1] = proceduralOrigin.y; +} + +inline void ResetProceduralOrigin() +{ + SetProceduralOrigin({ 0.0f, 0.0f }); +} + inline float Scale(float size) { auto& io = ImGui::GetIO(); diff --git a/UnleashedRecomp/ui/options_menu.cpp b/UnleashedRecomp/ui/options_menu.cpp index 793d0c48..49998d2c 100644 --- a/UnleashedRecomp/ui/options_menu.cpp +++ b/UnleashedRecomp/ui/options_menu.cpp @@ -42,9 +42,15 @@ static constexpr double CONTAINER_FULL_DURATION = CONTAINER_BACKGROUND_TIME + CO static constexpr double CONTAINER_CATEGORY_TIME = (CONTAINER_INNER_TIME + CONTAINER_BACKGROUND_TIME) / 2.0; static constexpr double CONTAINER_CATEGORY_DURATION = 12.0; -constexpr float COMMON_PADDING_POS_Y = 118.0f; -constexpr float COMMON_PADDING_POS_X = 30.0f; -constexpr float INFO_CONTAINER_POS_X = 870.0f; +static constexpr float CONTAINER_POS_Y = 118.0f; + +static constexpr float SETTINGS_WIDE_GRID_COUNT = 90.0f; +static constexpr float INFO_WIDE_GRID_COUNT = 42.0f; +static constexpr float PADDING_WIDE_GRID_COUNT = 3.0f; + +static constexpr float SETTINGS_NARROW_GRID_COUNT = 70.0f; +static constexpr float INFO_NARROW_GRID_COUNT = 34.0f; +static constexpr float PADDING_NARROW_GRID_COUNT = 1.0f; static constexpr int32_t g_categoryCount = 4; static int32_t g_categoryIndex; @@ -187,7 +193,7 @@ static void DrawScanlineBars() static float AlignToNextGrid(float value) { - return floor(value / GRID_SIZE) * GRID_SIZE; + return round(value / GRID_SIZE) * GRID_SIZE; } static void DrawContainer(ImVec2 min, ImVec2 max) @@ -306,8 +312,11 @@ static bool DrawCategories() auto clipRectMin = drawList->GetClipRectMin(); auto clipRectMax = drawList->GetClipRectMax(); + constexpr float NARROW_PADDING_GRID_COUNT = 1.5f; + constexpr float WIDE_PADDING_GRID_COUNT = 3.0f; + float gridSize = Scale(GRID_SIZE); - float textPadding = gridSize * 3.0f; + float textPadding = gridSize * Lerp(NARROW_PADDING_GRID_COUNT, WIDE_PADDING_GRID_COUNT, g_narrowOffsetScale); float tabPadding = gridSize; float size = Scale(32.0f); @@ -449,8 +458,11 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef* conf auto clipRectMax = drawList->GetClipRectMax(); auto& padState = SWA::CInputState::GetInstance()->GetPadState(); + constexpr float OPTION_NARROW_GRID_COUNT = 36.0f; + constexpr float OPTION_WIDE_GRID_COUNT = 54.0f; + auto gridSize = Scale(GRID_SIZE); - auto optionWidth = gridSize * 54.0f; + auto optionWidth = gridSize * floor(Lerp(OPTION_NARROW_GRID_COUNT, OPTION_WIDE_GRID_COUNT, g_narrowOffsetScale)); auto optionHeight = gridSize * 5.5f; auto optionPadding = gridSize * 0.5f; auto valueWidth = Scale(192.0f); @@ -999,13 +1011,11 @@ static void DrawConfigOptions() } } -static void DrawSettingsPanel() +static void DrawSettingsPanel(ImVec2 settingsMin, ImVec2 settingsMax) { auto drawList = ImGui::GetForegroundDrawList(); - ImVec2 settingsMin = { Scale(AlignToNextGrid(COMMON_PADDING_POS_X)), Scale(AlignToNextGrid(COMMON_PADDING_POS_Y)) }; - ImVec2 settingsMax = { Scale(AlignToNextGrid(INFO_CONTAINER_POS_X - COMMON_PADDING_POS_X)), Scale(AlignToNextGrid(720.0f - COMMON_PADDING_POS_Y)) }; - + SetProceduralOrigin(settingsMin); DrawContainer(settingsMin, settingsMax); if (DrawCategories()) @@ -1019,31 +1029,34 @@ static void DrawSettingsPanel() ResetSelection(); } + ResetProceduralOrigin(); + // Pop clip rect from DrawContainer drawList->PopClipRect(); } -static void DrawInfoPanel() +static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax) { auto drawList = ImGui::GetForegroundDrawList(); - ImVec2 infoMin = { Scale(AlignToNextGrid(INFO_CONTAINER_POS_X)), Scale(AlignToNextGrid(COMMON_PADDING_POS_Y)) }; - ImVec2 infoMax = { Scale(AlignToNextGrid(1280.0f - COMMON_PADDING_POS_X)), Scale(AlignToNextGrid(720.0f - COMMON_PADDING_POS_Y)) }; - + SetProceduralOrigin(infoMin); DrawContainer(infoMin, infoMax); auto clipRectMin = drawList->GetClipRectMin(); auto clipRectMax = drawList->GetClipRectMax(); - ImVec2 thumbnailMax = { clipRectMax.x, clipRectMin.y + Scale(198.0f) }; - if (g_selectedItem) { auto desc = g_selectedItem->GetDescription(Config::Language); auto thumbnail = GetThumbnail(g_selectedItem); - if (thumbnail) - drawList->AddImage(thumbnail, clipRectMin, thumbnailMax); + float aspectRatio = float(thumbnail->width) / thumbnail->height; + float thumbnailHeight = (clipRectMax.x - clipRectMin.x) / aspectRatio; + + ImVec2 thumbnailMin = { clipRectMin.x, clipRectMin.y + Scale(GRID_SIZE / 2.0f) }; + ImVec2 thumbnailMax = { clipRectMax.x, thumbnailMin.y + thumbnailHeight }; + + drawList->AddImage(thumbnail, thumbnailMin, thumbnailMax); if (g_inaccessibleReason) { @@ -1081,6 +1094,8 @@ static void DrawInfoPanel() ); } + ResetProceduralOrigin(); + // Pop clip rect from DrawContainer drawList->PopClipRect(); } @@ -1198,8 +1213,25 @@ void OptionsMenu::Draw() drawList->AddRectFilled({ 0.0f, 0.0f }, res, IM_COL32(0, 0, 0, 223)); DrawScanlineBars(); - DrawSettingsPanel(); - DrawInfoPanel(); + + float settingsGridCount = floor(Lerp(SETTINGS_NARROW_GRID_COUNT, SETTINGS_WIDE_GRID_COUNT, g_narrowOffsetScale)); + float paddingGridCount = Lerp(PADDING_NARROW_GRID_COUNT, PADDING_WIDE_GRID_COUNT, g_narrowOffsetScale); + float infoGridCount = floor(Lerp(INFO_NARROW_GRID_COUNT, INFO_WIDE_GRID_COUNT, g_narrowOffsetScale)); + float totalGrindCount = settingsGridCount + paddingGridCount + infoGridCount; + + float offsetX = g_aspectRatioOffsetX + (1280.0f - ((GRID_SIZE * totalGrindCount) - 1)) / 2.0f; + float minY = Scale(g_aspectRatioOffsetY + CONTAINER_POS_Y); + float maxY = Scale(g_aspectRatioOffsetY + (720.0f - CONTAINER_POS_Y + 1.0f)); + + DrawSettingsPanel( + { Scale(offsetX), minY }, + { Scale(offsetX + settingsGridCount * GRID_SIZE), maxY } + ); + + DrawInfoPanel( + { Scale(offsetX + (settingsGridCount + paddingGridCount) * GRID_SIZE), minY }, + { Scale(offsetX + totalGrindCount * GRID_SIZE), maxY } + ); if (g_isStage) DrawFadeTransition();