diff --git a/UnleashedRecomp/gpu/imgui_common.h b/UnleashedRecomp/gpu/imgui_common.h index 1398110..748d542 100644 --- a/UnleashedRecomp/gpu/imgui_common.h +++ b/UnleashedRecomp/gpu/imgui_common.h @@ -4,6 +4,9 @@ #define IMGUI_SHADER_MODIFIER_SCANLINE 1 #define IMGUI_SHADER_MODIFIER_CHECKERBOARD 2 #define IMGUI_SHADER_MODIFIER_SCANLINE_BUTTON 3 +#define IMGUI_SHADER_MODIFIER_TEXT_SKEW 4 +#define IMGUI_SHADER_MODIFIER_MARQUEE_FADE 5 +#define IMGUI_SHADER_MODIFIER_GRAYSCALE 6 #ifdef __cplusplus @@ -13,14 +16,16 @@ enum class ImGuiCallback : int32_t SetShaderModifier = -2, SetOrigin = -3, SetScale = -4, + SetMarqueeFade = -5, + // -8 is ImDrawCallback_ResetRenderState, don't use! }; union ImGuiCallbackData { struct { - float gradientMin[2]; - float gradientMax[2]; + float boundsMin[2]; + float boundsMax[2]; uint32_t gradientTop; uint32_t gradientBottom; } setGradient; @@ -39,6 +44,12 @@ union ImGuiCallbackData { float scale[2]; } setScale; + + struct + { + float boundsMin[2]; + float boundsMax[2]; + } setMarqueeFade; }; extern ImGuiCallbackData* AddImGuiCallback(ImGuiCallback callback); diff --git a/UnleashedRecomp/gpu/shader/imgui_common.hlsli b/UnleashedRecomp/gpu/shader/imgui_common.hlsli index 85a9ecc..6c79a48 100644 --- a/UnleashedRecomp/gpu/shader/imgui_common.hlsli +++ b/UnleashedRecomp/gpu/shader/imgui_common.hlsli @@ -1,9 +1,11 @@ #pragma once +#include "../imgui_common.h" + struct PushConstants { - float2 GradientMin; - float2 GradientMax; + float2 BoundsMin; + float2 BoundsMax; uint GradientTop; uint GradientBottom; uint ShaderModifier; diff --git a/UnleashedRecomp/gpu/shader/imgui_ps.hlsl b/UnleashedRecomp/gpu/shader/imgui_ps.hlsl index 2207a2b..6888b89 100644 --- a/UnleashedRecomp/gpu/shader/imgui_ps.hlsl +++ b/UnleashedRecomp/gpu/shader/imgui_ps.hlsl @@ -1,5 +1,4 @@ #include "imgui_common.hlsli" -#include "../imgui_common.h" float4 DecodeColor(uint color) { @@ -82,11 +81,22 @@ float4 main(in Interpolators interpolators) : SV_Target if (g_PushConstants.Texture2DDescriptorIndex != 0) color *= g_Texture2DDescriptorHeap[g_PushConstants.Texture2DDescriptorIndex].Sample(g_SamplerDescriptorHeap[0], interpolators.UV); - if (any(g_PushConstants.GradientMin != g_PushConstants.GradientMax)) + if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_MARQUEE_FADE) { - float2 factor = saturate((interpolators.Position.xy - g_PushConstants.GradientMin) / (g_PushConstants.GradientMax - g_PushConstants.GradientMin)); - color *= lerp(DecodeColor(g_PushConstants.GradientTop), DecodeColor(g_PushConstants.GradientBottom), factor.y); + float minAlpha = saturate((interpolators.Position.x - g_PushConstants.BoundsMin.x) / g_PushConstants.Scale.x); + float maxAlpha = saturate((g_PushConstants.BoundsMax.x - interpolators.Position.x) / g_PushConstants.Scale.x); + + color.a *= minAlpha; + color.a *= maxAlpha; + } + else if (any(g_PushConstants.BoundsMin != g_PushConstants.BoundsMax)) + { + float2 factor = saturate((interpolators.Position.xy - g_PushConstants.BoundsMin) / (g_PushConstants.BoundsMax - g_PushConstants.BoundsMin)); + color *= lerp(DecodeColor(g_PushConstants.GradientTop), DecodeColor(g_PushConstants.GradientBottom), smoothstep(0.0, 1.0, factor.y)); } + if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_GRAYSCALE) + color.rgb = dot(color.rgb, float3(0.2126, 0.7152, 0.0722)); + return color; } diff --git a/UnleashedRecomp/gpu/shader/imgui_vs.hlsl b/UnleashedRecomp/gpu/shader/imgui_vs.hlsl index 5b7820d..994be88 100644 --- a/UnleashedRecomp/gpu/shader/imgui_vs.hlsl +++ b/UnleashedRecomp/gpu/shader/imgui_vs.hlsl @@ -1,9 +1,18 @@ #include "imgui_common.hlsli" void main(in float2 position : POSITION, in float2 uv : TEXCOORD, in float4 color : COLOR, out Interpolators interpolators) -{ - float2 correctedPosition = g_PushConstants.Origin + (position - g_PushConstants.Origin) * g_PushConstants.Scale; - interpolators.Position = float4(correctedPosition * g_PushConstants.InverseDisplaySize * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); +{ + if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_TEXT_SKEW) + { + if (position.y < g_PushConstants.Origin.y) + position.x += g_PushConstants.Scale.x; + } + else if (g_PushConstants.ShaderModifier != IMGUI_SHADER_MODIFIER_MARQUEE_FADE) + { + position.xy = g_PushConstants.Origin + (position.xy - g_PushConstants.Origin) * g_PushConstants.Scale; + } + + interpolators.Position = float4(position.xy * g_PushConstants.InverseDisplaySize * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); interpolators.UV = uv; interpolators.Color = color; } diff --git a/UnleashedRecomp/gpu/video.cpp b/UnleashedRecomp/gpu/video.cpp index eabe028..be7ec78 100644 --- a/UnleashedRecomp/gpu/video.cpp +++ b/UnleashedRecomp/gpu/video.cpp @@ -1101,8 +1101,8 @@ static constexpr uint32_t PLACEMENT_ALIGNMENT = 0x200; struct ImGuiPushConstants { - ImVec2 gradientMin{}; - ImVec2 gradientMax{}; + ImVec2 boundsMin{}; + ImVec2 boundsMax{}; ImU32 gradientTop{}; ImU32 gradientBottom{}; uint32_t shaderModifier{}; @@ -1921,7 +1921,7 @@ static void ProcDrawImGui(const RenderCommand& cmd) switch (static_cast(reinterpret_cast(drawCmd.UserCallback))) { case ImGuiCallback::SetGradient: - commandList->setGraphicsPushConstants(0, &callbackData->setGradient, offsetof(ImGuiPushConstants, gradientMin), sizeof(callbackData->setGradient)); + commandList->setGraphicsPushConstants(0, &callbackData->setGradient, offsetof(ImGuiPushConstants, boundsMin), sizeof(callbackData->setGradient)); break; case ImGuiCallback::SetShaderModifier: commandList->setGraphicsPushConstants(0, &callbackData->setShaderModifier, offsetof(ImGuiPushConstants, shaderModifier), sizeof(callbackData->setShaderModifier)); @@ -1931,6 +1931,9 @@ static void ProcDrawImGui(const RenderCommand& cmd) break; case ImGuiCallback::SetScale: commandList->setGraphicsPushConstants(0, &callbackData->setScale, offsetof(ImGuiPushConstants, scale), sizeof(callbackData->setScale)); + break; + case ImGuiCallback::SetMarqueeFade: + commandList->setGraphicsPushConstants(0, &callbackData->setScale, offsetof(ImGuiPushConstants, boundsMin), sizeof(callbackData->setMarqueeFade)); break; } } diff --git a/UnleashedRecomp/kernel/xam.cpp b/UnleashedRecomp/kernel/xam.cpp index 12f61fe..70245e8 100644 --- a/UnleashedRecomp/kernel/xam.cpp +++ b/UnleashedRecomp/kernel/xam.cpp @@ -387,7 +387,9 @@ SWA_API uint32_t XamInputGetState(uint32_t userIndex, uint32_t flags, XAMINPUT_S state->Gamepad.sThumbLX = 32767; if (GetAsyncKeyState(VK_RETURN) & 0x8000) - state->Gamepad.wButtons |= XAMINPUT_GAMEPAD_START; + state->Gamepad.wButtons |= XAMINPUT_GAMEPAD_START; + if (GetAsyncKeyState(VK_BACK) & 0x8000) + state->Gamepad.wButtons |= XAMINPUT_GAMEPAD_BACK; ByteSwap(state->Gamepad.wButtons); ByteSwap(state->Gamepad.sThumbLX); diff --git a/UnleashedRecomp/ui/achievement_menu.cpp b/UnleashedRecomp/ui/achievement_menu.cpp index b2bd492..389eb85 100644 --- a/UnleashedRecomp/ui/achievement_menu.cpp +++ b/UnleashedRecomp/ui/achievement_menu.cpp @@ -138,7 +138,9 @@ static void DrawHeaderContainer(const char* text) DrawPauseHeaderContainer(g_upWindow.get(), min, max, alpha); - // TODO: skew this text and apply bevel. + SetTextSkew((min.y + max.y) / 2.0f, Scale(3.0f)); + + // TODO: Apply bevel. DrawTextWithOutline ( g_fntNewRodinUB, @@ -149,6 +151,8 @@ static void DrawHeaderContainer(const char* text) 3, IM_COL32(0, 0, 0, 255 * alpha) ); + + ResetTextSkew(); } static void DrawAchievement(int rowIndex, float yOffset, Achievement& achievement, bool isUnlocked) @@ -182,8 +186,10 @@ static void DrawAchievement(int rowIndex, float yOffset, Achievement& achievemen auto titleTextY = Scale(20); auto descTextY = Scale(52); + if (!isUnlocked) + SetShaderModifier(IMGUI_SHADER_MODIFIER_GRAYSCALE); + // Draw achievement icon. - // TODO: make icon greyscale if locked? drawList->AddImage ( icon, @@ -194,6 +200,9 @@ static void DrawAchievement(int rowIndex, float yOffset, Achievement& achievemen IM_COL32(255, 255, 255, 255 * (isUnlocked ? 1 : 0.5f)) ); + if (!isUnlocked) + SetShaderModifier(IMGUI_SHADER_MODIFIER_NONE); + drawList->PushClipRect(min, max, true); auto colLockedText = IM_COL32(60, 60, 60, 29); @@ -219,13 +228,16 @@ static void DrawAchievement(int rowIndex, float yOffset, Achievement& achievemen if (isSelected && textX + textSize.x >= max.x - Scale(10)) { + ImVec2 marqueeMin = { textMarqueeX, min.y }; + SetMarqueeFade(marqueeMin, max, Scale(32.0f)); + // Draw achievement description with marquee. DrawTextWithMarqueeShadow ( g_fntSeurat, fontSize, { textX, min.y + descTextY }, - { textMarqueeX, min.y }, + marqueeMin, max, isUnlocked ? IM_COL32(255, 255, 255, 255) : colLockedText, desc, @@ -236,6 +248,8 @@ static void DrawAchievement(int rowIndex, float yOffset, Achievement& achievemen 0.4f, colTextShadow ); + + ResetMarqueeFade(); } else { diff --git a/UnleashedRecomp/ui/imgui_utils.h b/UnleashedRecomp/ui/imgui_utils.h index 4308986..09e1ab6 100644 --- a/UnleashedRecomp/ui/imgui_utils.h +++ b/UnleashedRecomp/ui/imgui_utils.h @@ -16,10 +16,10 @@ static void SetGradient(const ImVec2& min, const ImVec2& max, ImU32 top, ImU32 bottom) { auto callbackData = AddImGuiCallback(ImGuiCallback::SetGradient); - callbackData->setGradient.gradientMin[0] = min.x; - callbackData->setGradient.gradientMin[1] = min.y; - callbackData->setGradient.gradientMax[0] = max.x; - callbackData->setGradient.gradientMax[1] = max.y; + callbackData->setGradient.boundsMin[0] = min.x; + callbackData->setGradient.boundsMin[1] = min.y; + callbackData->setGradient.boundsMax[0] = max.x; + callbackData->setGradient.boundsMax[1] = max.y; callbackData->setGradient.gradientTop = top; callbackData->setGradient.gradientBottom = bottom; } @@ -50,6 +50,39 @@ static void SetScale(ImVec2 scale) callbackData->setScale.scale[1] = scale.y; } +static void SetTextSkew(float yCenter, float skewScale) +{ + SetShaderModifier(IMGUI_SHADER_MODIFIER_TEXT_SKEW); + SetOrigin({ 0.0f, yCenter }); + SetScale({ skewScale, 1.0f }); +} + +static void ResetTextSkew() +{ + SetShaderModifier(IMGUI_SHADER_MODIFIER_NONE); + SetOrigin({ 0.0f, 0.0f }); + SetScale({ 1.0f, 1.0f }); +} + +static void SetMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale) +{ + auto callbackData = AddImGuiCallback(ImGuiCallback::SetMarqueeFade); + callbackData->setMarqueeFade.boundsMin[0] = min.x; + callbackData->setMarqueeFade.boundsMin[1] = min.y; + callbackData->setMarqueeFade.boundsMax[0] = max.x; + callbackData->setMarqueeFade.boundsMax[1] = max.y; + + SetShaderModifier(IMGUI_SHADER_MODIFIER_MARQUEE_FADE); + SetScale({ fadeScale, 1.0f }); +} + +static void ResetMarqueeFade() +{ + ResetGradient(); + SetShaderModifier(IMGUI_SHADER_MODIFIER_NONE); + SetScale({ 1.0f, 1.0f }); +} + // Aspect ratio aware. static float Scale(float size) { @@ -173,7 +206,10 @@ static void DrawTextWithOutline(const ImFont* font, float fontSize, const ImVec2 for (int32_t i = -outlineSize + 1; i < outlineSize; i++) { for (int32_t j = -outlineSize + 1; j < outlineSize; j++) - drawList->AddText(font, fontSize, { pos.x + i, pos.y + j }, outlineColor, text); + { + if (i != 0 && j != 0) + drawList->AddText(font, fontSize, { pos.x + i, pos.y + j }, outlineColor, text); + } } }