From 9db1e8686b1315a83325fb11d58b877ee3df9774 Mon Sep 17 00:00:00 2001 From: Emmanuel AYME Date: Wed, 31 Dec 2025 14:29:36 +0100 Subject: [PATCH] Add cheat time dilation shader OSD --- external/reshade/shaders/TimeDilationOSD.fx | 225 ++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 external/reshade/shaders/TimeDilationOSD.fx diff --git a/external/reshade/shaders/TimeDilationOSD.fx b/external/reshade/shaders/TimeDilationOSD.fx new file mode 100644 index 0000000..9d9f01d --- /dev/null +++ b/external/reshade/shaders/TimeDilationOSD.fx @@ -0,0 +1,225 @@ +#include "ReShade.fxh" + +texture FontTexture < source = "font.png"; > +{ + Width = 512; + Height = 512; + Format = RGBA8; +}; +sampler FontSampler { + Texture = FontTexture; +}; + +uniform bool TD_Show = false; +uniform bool TD_Enabled = false; +uniform float TD_World = 1.0; +uniform float TD_AI = 1.0; + + +// Define caracters for "Time Dilation ON" (size 32) +static const int ON_LENGTH = 17; +static float ON_CHARS[32] = { + 84 - 32, 105 - 32, 109 - 32, 101 - 32, // T, i, m, e + 32 - 32, 100 - 32, 105 - 32, 108 - 32, // , d, i, l + 97 - 32, 116 - 32, 105 - 32, 111 - 32, // a, t, i, o + 110 - 32, 32 - 32, 79 - 32, 78 - 32, // n, , O, N + 32 - 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // ' ' + filling +}; + +// Define caracters for "Time Dilation OFF" (size 32) +static const int OFF_LENGTH = 17; +static float OFF_CHARS[32] = { + 84 - 32, 105 - 32, 109 - 32, 101 - 32, // T, i, m, e + 32 - 32, 100 - 32, 105 - 32, 108 - 32, // , d, i, l + 97 - 32, 116 - 32, 105 - 32, 111 - 32, // a, t, i, o + 110 - 32, 32 - 32, 79 - 32, 70 - 32, // n, , O, F + 70 - 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F + filling +}; + +static const int WORLD_LEN = 7; +static float WORLD_CHARS[32] = { + 87 - 32,111 - 32,114 - 32, 108 - 32, // W, o, r, l + 100 - 32, 58 - 32, 32 - 32, 0, // d, :, , + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static const int AI_LEN = 5; +static float AI_CHARS[32] = { + 32 - 32, 65 - 32, 73 - 32, 58 - 32, // ' ', A, I, : + 32 - 32, 0, 0, 0, // ' ' + filling + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +// Fonction SDF pour le rectangle (inchangée) +float sdRoundRect(float2 p, float2 b, float r) { + float2 q = abs(p) - b + r; + return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r; +} + +// Draw a character +float4 DrawChar(float2 uv, float2 pos, float2 charSize, float charIndex) { + float2 texSize = float2(14.0, 7.0); + float2 fontUV = float2(charIndex % texSize.x, floor(charIndex / texSize.x)) / texSize; + float2 fontUVSize = 1.0 / texSize; + float2 localUV = (uv - pos) / charSize; + float2 finalFontUV = fontUV + fontUVSize * localUV; + return tex2D(FontSampler, finalFontUV); +} + +// Draw a characters array +float4 DrawText(float2 uv, float2 startPos, float2 charSize, float chars[32], int length) { + float4 col = float4(0, 0, 0, 0); + + [unroll] + for (int i = 0; i < 32; i++) + { + if (i >= length) break; + + float2 charPos = startPos + float2(i * charSize.x, 0.0); + + // test si le pixel est dans le quad du caractère + if (uv.x >= charPos.x && uv.x < charPos.x + charSize.x && + uv.y >= charPos.y && uv.y < charPos.y + charSize.y) { + float4 glyph = DrawChar(uv, charPos, charSize, chars[i]); + + // proper alpha-over + col.rgb = lerp(col.rgb, glyph.rgb, glyph.a); + col.a = max(col.a, glyph.a); + } + } + + return col; +} + +float4 DrawFloat(float2 uv, float2 startPos, float2 charSize, float value) { + float4 col = float4(0,0,0,0); + + float v = abs(value); + int iv = (int)(v * 100.0 + 0.5); + int i0 = iv / 100; + int i1 = (iv / 10) % 10; + int i2 = iv % 10; + + float chars[4]; + chars[0] = i0 + 16; // '0' + chars[1] = 14; // '.' + chars[2] = i1 + 16; + chars[3] = i2 + 16; + + [unroll] + for (int i = 0; i < 4; i++) + { + float2 pos = startPos + float2(i * charSize.x, 0); + if (uv.x >= pos.x && uv.x < pos.x + charSize.x && uv.y >= pos.y && uv.y < pos.y + charSize.y) { + float4 g = DrawChar(uv, pos, charSize, chars[i]); + col.rgb = lerp(col.rgb, g.rgb, g.a); + col.a = max(col.a, g.a); + } + } + + return col; +} + +void AlphaBlend(inout float4 dst, float4 src) { + dst.rgb = lerp(dst.rgb, src.rgb, src.a); + dst.a = max(dst.a, src.a); +} + +float4 PS_OSD(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target { + float4 col = tex2D(ReShade::BackBuffer, uv); + + if (TD_Show) { + // ---- Size & position of the frame ---- + float margin_top = 20.0; + + // ---- aspect ratio correction for SDF ---- + float2 screen_size = float2(BUFFER_WIDTH, BUFFER_HEIGHT); + float aspect = screen_size.x / screen_size.y; + + // Pure UV Center (for text) + float2 center_uv = float2(0.5, margin_top / screen_size.y + 0.01); + float2 p = uv - center_uv; + p.x *= aspect; + + // Compute total text length to center it horizontally + float totalLen = (TD_Enabled ? ON_LENGTH + WORLD_LEN + 4 + AI_LEN + 4 : OFF_LENGTH) ; // 4 = 3 chiffres + '.' + float2 charSize = float2(0.003, 0.02); // width, height + float charAdvance = charSize.x; + + // SDF center (for the frame) + float textWidthUV = totalLen * charAdvance; + float padding = charAdvance * 1.0; + float2 size_uv = float2((textWidthUV * 0.5 + padding) * aspect, 20.0 / screen_size.y); + + // ---- Thickness and radius in pixels ---- + float thickness_px = 1.0; + float thickness = thickness_px * ReShade::PixelSize.y; + float radius_px = 2.0; + float radius = radius_px * ReShade::PixelSize.y; + + float d = sdRoundRect(p, size_uv, radius); + + // ---- Border drawing ---- + if (abs(d) < thickness) { + float3 border = TD_Enabled ? float3(0.3, 1.0, 0.3) : float3(1.0, 0.3, 0.3); // green ON , red OFF + col.rgb = lerp(col.rgb, border, 0.85); + } + + // ---- Draw the text (ON/OFF + World + AI) ---- + + float2 pen = center_uv; + pen.x -= totalLen * charAdvance * 0.5; // horizontal centering + pen.y -= charSize.y * 0.5; // vertical centering + + float4 t0, t1, wv, t2, av; + float4 textCol = float4(0,0,0,0); + + if (TD_Enabled) { // "Time Dilation ON" + t0 = DrawText(uv, pen, charSize, ON_CHARS, ON_LENGTH); + pen.x += charAdvance * ON_LENGTH; + + // "World: " + t1 = DrawText(uv, pen, charSize, WORLD_CHARS, WORLD_LEN); + pen.x += charAdvance * WORLD_LEN; + + // World value + wv = DrawFloat(uv, pen, charSize, TD_World); + pen.x += charAdvance * 4; + + // "AI: " + t2 = DrawText(uv, pen, charSize, AI_CHARS, AI_LEN); + pen.x += charAdvance * AI_LEN; + + // AI value + av = DrawFloat(uv, pen, charSize, TD_AI); + } + else // "Time Dilation OFF" + t0 = DrawText(uv, pen, charSize, OFF_CHARS, OFF_LENGTH); + + // ---- Combine all glyphs ---- + float4 combined = t0; + AlphaBlend(combined, t1); + AlphaBlend(combined, wv); + AlphaBlend(combined, t2); + AlphaBlend(combined, av); + + float3 textColor = TD_Enabled ? float3(0.3,1.0,0.3) : float3(1.0,0.3,0.3); + combined.rgb *= textColor; + + // ---- final blend ---- + col.rgb = lerp(col.rgb, combined.rgb, combined.a); + } + + return col; +} + +technique TimeDilationOSD { + pass { + VertexShader = PostProcessVS; + PixelShader = PS_OSD; + } +}