diff --git a/dist/post_shaders/Bloom.fx b/dist/post_shaders/Bloom.fx index 396582cc98..afc754ed85 100644 --- a/dist/post_shaders/Bloom.fx +++ b/dist/post_shaders/Bloom.fx @@ -24,15 +24,7 @@ uniform float Amount < void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD) { - uv = float2(0.0, 0.0); - if (id == 2) - { - uv.x = 2.0; - } - if (id == 1) - { - uv.y = 2.0; - } + uv = float2(float(id & 2), float((id & 1) << 1)); pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); } diff --git a/dist/post_shaders/Blur.fx b/dist/post_shaders/Blur.fx index e432ba2619..bb9c48b6d7 100644 --- a/dist/post_shaders/Blur.fx +++ b/dist/post_shaders/Blur.fx @@ -33,37 +33,10 @@ uniform float FocusSoftness < > = 0.4; static const int TAPS = 17; -static const float3 KERNEL[17] = { - float3( 0.171499, 0.000000, 0.942873), - float3(-0.219031, 0.200651, 0.838223), - float3( 0.033526, -0.382014, 0.745189), - float3( 0.276075, 0.360090, 0.662480), - float3(-0.506631, -0.089616, 0.588951), - float3( 0.479925, -0.305289, 0.523583), - float3(-0.160526, 0.597147, 0.465471), - float3(-0.306140, -0.589453, 0.413808), - float3( 0.664200, 0.242565, 0.367879), - float3(-0.690990, 0.285231, 0.327048), - float3( 0.333103, -0.711821, 0.290749), - float3( 0.246154, 0.784779, 0.258479), - float3(-0.741912, -0.429953, 0.229790), - float3( 0.870348, -0.191344, 0.204286), - float3(-0.531160, 0.755520, 0.181612), - float3(-0.122710, -0.946946, 0.161455), - float3( 0.753320, 0.634899, 0.143535) -}; void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD) { - uv = float2(0.0, 0.0); - if (id == 2) - { - uv.x = 2.0; - } - if (id == 1) - { - uv.y = 2.0; - } + uv = float2(float(id & 2), float((id & 1) << 1)); pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); } @@ -79,17 +52,22 @@ float4 PS_Blur(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target float amount = Strength * focus; float angle = frac(sin(dot(pos.xy, float2(12.9898, 78.233))) * 43758.5453) * 6.2831853; - float2 rotation = float2(cos(angle), sin(angle)); + float2 spoke = float2(cos(angle), sin(angle)); + + const float2 turn = float2(cos(2.39996323), sin(2.39996323)); + const float decay = exp(-2.0 / float(TAPS)); + float weight = exp(-1.0 / float(TAPS)); float3 sum = float3(0.0, 0.0, 0.0); float total = 0.0; for (int i = 0; i < TAPS; ++i) { - float3 tap = KERNEL[i]; - float2 spun = float2(tap.x * rotation.x - tap.y * rotation.y, - tap.x * rotation.y + tap.y * rotation.x); - sum += tex2D(BackBuffer, uv + spun * texel * Radius).rgb * tap.z; - total += tap.z; + float reach = sqrt((float(i) + 0.5) / float(TAPS)); + sum += tex2D(BackBuffer, uv + spoke * reach * texel * Radius).rgb * weight; + total += weight; + weight *= decay; + spoke = float2(spoke.x * turn.x - spoke.y * turn.y, + spoke.x * turn.y + spoke.y * turn.x); } float3 blurred = sum / total; diff --git a/dist/post_shaders/CRT.fx b/dist/post_shaders/CRT.fx index ec4b9840c5..030d10b170 100644 --- a/dist/post_shaders/CRT.fx +++ b/dist/post_shaders/CRT.fx @@ -33,15 +33,7 @@ uniform float Bleed < void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD) { - uv = float2(0.0, 0.0); - if (id == 2) - { - uv.x = 2.0; - } - if (id == 1) - { - uv.y = 2.0; - } + uv = float2(float(id & 2), float((id & 1) << 1)); pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); } diff --git a/dist/post_shaders/Cartoon.fx b/dist/post_shaders/Cartoon.fx index f0beba8dcc..a65a5fcbb8 100644 --- a/dist/post_shaders/Cartoon.fx +++ b/dist/post_shaders/Cartoon.fx @@ -25,15 +25,7 @@ uniform float Levels < void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD) { - uv = float2(0.0, 0.0); - if (id == 2) - { - uv.x = 2.0; - } - if (id == 1) - { - uv.y = 2.0; - } + uv = float2(float(id & 2), float((id & 1) << 1)); pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); } diff --git a/dist/post_shaders/CartoonSoft.fx b/dist/post_shaders/CartoonSoft.fx index 7c1a2b481c..bf89c5f6c6 100644 --- a/dist/post_shaders/CartoonSoft.fx +++ b/dist/post_shaders/CartoonSoft.fx @@ -44,15 +44,7 @@ uniform float Saturation < void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD) { - uv = float2(0.0, 0.0); - if (id == 2) - { - uv.x = 2.0; - } - if (id == 1) - { - uv.y = 2.0; - } + uv = float2(float(id & 2), float((id & 1) << 1)); pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); } diff --git a/dist/post_shaders/CelShading.fx b/dist/post_shaders/CelShading.fx index 6a135246ff..fa1cae452c 100644 --- a/dist/post_shaders/CelShading.fx +++ b/dist/post_shaders/CelShading.fx @@ -55,15 +55,7 @@ uniform float Saturation < void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD) { - uv = float2(0.0, 0.0); - if (id == 2) - { - uv.x = 2.0; - } - if (id == 1) - { - uv.y = 2.0; - } + uv = float2(float(id & 2), float((id & 1) << 1)); pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); } diff --git a/dist/post_shaders/ChromaticAberration.fx b/dist/post_shaders/ChromaticAberration.fx index a83cc117ed..12337c7856 100644 --- a/dist/post_shaders/ChromaticAberration.fx +++ b/dist/post_shaders/ChromaticAberration.fx @@ -20,15 +20,7 @@ uniform float Falloff < void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD) { - uv = float2(0.0, 0.0); - if (id == 2) - { - uv.x = 2.0; - } - if (id == 1) - { - uv.y = 2.0; - } + uv = float2(float(id & 2), float((id & 1) << 1)); pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); } diff --git a/dist/post_shaders/ColorGrade.fx b/dist/post_shaders/ColorGrade.fx index fe506fa0ca..c725692d02 100644 --- a/dist/post_shaders/ColorGrade.fx +++ b/dist/post_shaders/ColorGrade.fx @@ -34,15 +34,7 @@ uniform float Gamma < void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD) { - uv = float2(0.0, 0.0); - if (id == 2) - { - uv.x = 2.0; - } - if (id == 1) - { - uv.y = 2.0; - } + uv = float2(float(id & 2), float((id & 1) << 1)); pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); } diff --git a/dist/post_shaders/Deband.fx b/dist/post_shaders/Deband.fx index a3eb04e85f..0841d5c674 100644 --- a/dist/post_shaders/Deband.fx +++ b/dist/post_shaders/Deband.fx @@ -30,15 +30,7 @@ uniform float Grain < void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD) { - uv = float2(0.0, 0.0); - if (id == 2) - { - uv.x = 2.0; - } - if (id == 1) - { - uv.y = 2.0; - } + uv = float2(float(id & 2), float((id & 1) << 1)); pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); } diff --git a/dist/post_shaders/Denoise.fx b/dist/post_shaders/Denoise.fx index ef1fcb1d5e..2765d0682e 100644 --- a/dist/post_shaders/Denoise.fx +++ b/dist/post_shaders/Denoise.fx @@ -27,15 +27,7 @@ uniform float Curve < void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD) { - uv = float2(0.0, 0.0); - if (id == 2) - { - uv.x = 2.0; - } - if (id == 1) - { - uv.y = 2.0; - } + uv = float2(float(id & 2), float((id & 1) << 1)); pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); } diff --git a/dist/post_shaders/FilmGrain.fx b/dist/post_shaders/FilmGrain.fx index 918c48e553..4e21c18b20 100644 --- a/dist/post_shaders/FilmGrain.fx +++ b/dist/post_shaders/FilmGrain.fx @@ -26,15 +26,7 @@ uniform float Colored < void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD) { - uv = float2(0.0, 0.0); - if (id == 2) - { - uv.x = 2.0; - } - if (id == 1) - { - uv.y = 2.0; - } + uv = float2(float(id & 2), float((id & 1) << 1)); pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); } diff --git a/dist/post_shaders/FilmicCurve.fx b/dist/post_shaders/FilmicCurve.fx index 9e5be6cd46..2b1b1e0773 100644 --- a/dist/post_shaders/FilmicCurve.fx +++ b/dist/post_shaders/FilmicCurve.fx @@ -32,15 +32,7 @@ uniform float Amount < void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD) { - uv = float2(0.0, 0.0); - if (id == 2) - { - uv.x = 2.0; - } - if (id == 1) - { - uv.y = 2.0; - } + uv = float2(float(id & 2), float((id & 1) << 1)); pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); } diff --git a/dist/post_shaders/LensDistortion.fx b/dist/post_shaders/LensDistortion.fx index ea1aea7acd..8e0649bfe7 100644 --- a/dist/post_shaders/LensDistortion.fx +++ b/dist/post_shaders/LensDistortion.fx @@ -20,15 +20,7 @@ uniform float Zoom < void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD) { - uv = float2(0.0, 0.0); - if (id == 2) - { - uv.x = 2.0; - } - if (id == 1) - { - uv.y = 2.0; - } + uv = float2(float(id & 2), float((id & 1) << 1)); pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); } diff --git a/dist/post_shaders/Levels.fx b/dist/post_shaders/Levels.fx index 3bf41a62c9..510fd3d070 100644 --- a/dist/post_shaders/Levels.fx +++ b/dist/post_shaders/Levels.fx @@ -38,15 +38,7 @@ uniform float OutputWhite < void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD) { - uv = float2(0.0, 0.0); - if (id == 2) - { - uv.x = 2.0; - } - if (id == 1) - { - uv.y = 2.0; - } + uv = float2(float(id & 2), float((id & 1) << 1)); pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); } diff --git a/dist/post_shaders/MotionBlur.fx b/dist/post_shaders/MotionBlur.fx new file mode 100644 index 0000000000..21c6cde2b3 --- /dev/null +++ b/dist/post_shaders/MotionBlur.fx @@ -0,0 +1,88 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +texture BackBufferTex : COLOR; +sampler BackBuffer { Texture = BackBufferTex; }; + +uniform float Length < + ui_type = "slider"; + ui_label = "Length"; + ui_tooltip = "How far the streaks reach, as a percentage of screen height."; + ui_min = 0.0; ui_max = 20.0; ui_step = 0.5; +> = 5.0; + +uniform float Zoom < + ui_type = "slider"; + ui_label = "Zoom"; + ui_tooltip = "Streaks running out from the centre of the screen, as if rushing forward. The centre stays sharp."; + ui_min = 0.0; ui_max = 1.0; ui_step = 0.05; +> = 1.0; + +uniform float Pan < + ui_type = "slider"; + ui_label = "Pan"; + ui_tooltip = "Streaks running in one fixed direction, as if the camera were sweeping across."; + ui_min = 0.0; ui_max = 1.0; ui_step = 0.05; +> = 0.0; + +uniform float Angle < + ui_type = "slider"; + ui_label = "Pan Angle"; + ui_tooltip = "Direction of the sweep, in degrees."; + ui_min = 0.0; ui_max = 360.0; ui_step = 5.0; +> = 0.0; + +uniform float Spin < + ui_type = "slider"; + ui_label = "Spin"; + ui_tooltip = "Streaks curling around the centre, as if the camera were rolling. Negative turns the other way."; + ui_min = -1.0; ui_max = 1.0; ui_step = 0.05; +> = 0.0; + +static const int TAPS = 24; + +void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD) +{ + uv = float2(float(id & 2), float((id & 1) << 1)); + pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); +} + +float4 PS_MotionBlur(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target +{ + float aspect = BUFFER_WIDTH * BUFFER_RCP_HEIGHT; + float2 to_screen = float2(aspect, 1.0); + + float2 centred = (uv - 0.5) * to_screen * 2.0; + float2 outward = centred; + float2 around = float2(-centred.y, centred.x); + + float radians_angle = Angle * 0.01745329; + float2 sweep = float2(cos(radians_angle), sin(radians_angle)); + + float2 velocity = sweep * Pan + outward * Zoom + around * Spin; + velocity *= Length * 0.01; + velocity /= to_screen; + + float jitter = frac(sin(dot(pos.xy, float2(12.9898, 78.233))) * 43758.5453); + + float3 sum = float3(0.0, 0.0, 0.0); + for (int i = 0; i < TAPS; ++i) + { + float t = (float(i) + jitter) / float(TAPS) - 0.5; + sum += tex2D(BackBuffer, uv + velocity * t).rgb; + } + + return float4(sum / float(TAPS), 1.0); +} + +technique MotionBlur < + ui_label = "Motion Blur"; + ui_tooltip = "Camera style motion blur: streaks the picture outwards, sideways or around, without touching still detail at the centre."; +> +{ + pass + { + VertexShader = VS_PostProcess; + PixelShader = PS_MotionBlur; + } +} diff --git a/dist/post_shaders/NaturalColors.fx b/dist/post_shaders/NaturalColors.fx index a4a32dcdd6..7e53a0f9ab 100644 --- a/dist/post_shaders/NaturalColors.fx +++ b/dist/post_shaders/NaturalColors.fx @@ -24,15 +24,7 @@ uniform float Chroma < void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD) { - uv = float2(0.0, 0.0); - if (id == 2) - { - uv.x = 2.0; - } - if (id == 1) - { - uv.y = 2.0; - } + uv = float2(float(id & 2), float((id & 1) << 1)); pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); } diff --git a/dist/post_shaders/Reflections.fx b/dist/post_shaders/Reflections.fx index 10a8d61d11..1ab193481e 100644 --- a/dist/post_shaders/Reflections.fx +++ b/dist/post_shaders/Reflections.fx @@ -50,15 +50,7 @@ uniform float RippleSpeed < void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD) { - uv = float2(0.0, 0.0); - if (id == 2) - { - uv.x = 2.0; - } - if (id == 1) - { - uv.y = 2.0; - } + uv = float2(float(id & 2), float((id & 1) << 1)); pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); } diff --git a/dist/post_shaders/Scanlines.fx b/dist/post_shaders/Scanlines.fx index 7b2fea31fe..e6f6223576 100644 --- a/dist/post_shaders/Scanlines.fx +++ b/dist/post_shaders/Scanlines.fx @@ -32,15 +32,7 @@ uniform float Tint < void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD) { - uv = float2(0.0, 0.0); - if (id == 2) - { - uv.x = 2.0; - } - if (id == 1) - { - uv.y = 2.0; - } + uv = float2(float(id & 2), float((id & 1) << 1)); pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); } diff --git a/dist/post_shaders/Sharpen.fx b/dist/post_shaders/Sharpen.fx index 7764c9af62..9e757c4199 100644 --- a/dist/post_shaders/Sharpen.fx +++ b/dist/post_shaders/Sharpen.fx @@ -12,15 +12,7 @@ uniform float Amount < void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD) { - uv = float2(0.0, 0.0); - if (id == 2) - { - uv.x = 2.0; - } - if (id == 1) - { - uv.y = 2.0; - } + uv = float2(float(id & 2), float((id & 1) << 1)); pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); } diff --git a/dist/post_shaders/SplitToning.fx b/dist/post_shaders/SplitToning.fx index 69bedc7912..682ee5cf69 100644 --- a/dist/post_shaders/SplitToning.fx +++ b/dist/post_shaders/SplitToning.fx @@ -37,15 +37,7 @@ uniform float Balance < void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD) { - uv = float2(0.0, 0.0); - if (id == 2) - { - uv.x = 2.0; - } - if (id == 1) - { - uv.y = 2.0; - } + uv = float2(float(id & 2), float((id & 1) << 1)); pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); } diff --git a/dist/post_shaders/Vignette.fx b/dist/post_shaders/Vignette.fx index 1c127c64a9..cea8736948 100644 --- a/dist/post_shaders/Vignette.fx +++ b/dist/post_shaders/Vignette.fx @@ -23,15 +23,7 @@ uniform float Aspect < void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD) { - uv = float2(0.0, 0.0); - if (id == 2) - { - uv.x = 2.0; - } - if (id == 1) - { - uv.y = 2.0; - } + uv = float2(float(id & 2), float((id & 1) << 1)); pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); } diff --git a/dist/post_shaders/WhiteBalance.fx b/dist/post_shaders/WhiteBalance.fx index 33ff15ea51..29aea52fc2 100644 --- a/dist/post_shaders/WhiteBalance.fx +++ b/dist/post_shaders/WhiteBalance.fx @@ -20,15 +20,7 @@ uniform float Tint < void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD) { - uv = float2(0.0, 0.0); - if (id == 2) - { - uv.x = 2.0; - } - if (id == 1) - { - uv.y = 2.0; - } + uv = float2(float(id & 2), float((id & 1) << 1)); pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); }