diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index f83d7498..fadd2440 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -80,6 +80,10 @@ Mode=0 GraphicsWidth=0 GraphicsHeight=0 +;Uncomment the option to use a hardware shader (requires DX9 graphics mode 4 or 5) +;The shader file .fx must be placed in data\shaders\ and must contain one technique with one or more passes +;GlobalShaderFile=global.fx + ;Set to 1 to do the palette conversion on the GPU ;Set to 2 to do the palette conversion on the CPU ;Set to 0 to pick automatically diff --git a/artifacts/example_mods/GlobalShaders/global.fx b/artifacts/example_mods/GlobalShaders/global.fx new file mode 100644 index 00000000..9f68917a --- /dev/null +++ b/artifacts/example_mods/GlobalShaders/global.fx @@ -0,0 +1,116 @@ +// Status: WIP + +texture bloomMap; +sampler s0; + +sampler BloomSampler : samplerstate +{ + Texture = bloomMap; + MinFilter = Linear; + MagFilter = Linear; + AddressU = Clamp; + AddressV = Clamp; +}; + +// pseudo gauss blur +static const float2 offsets[12] = { + -0.326212, -0.405805, + -0.840144, -0.073580, + -0.695914, 0.457137, + -0.203345, 0.620716, + 0.962340, -0.194983, + 0.473434, -0.480026, + 0.519456, 0.767022, + 0.185461, -0.893124, + 0.507431, 0.064425, + 0.896420, 0.412458, + -0.321940, -0.932615, + -0.791559, -0.597705, +}; + +float w; +float h; +static const float2 resolution = float2(w, h); + +// blur setting +static const float blurFalloff = 8; +static const float sharpness = 4; + +float4 AdjustSaturation(float4 color, float saturation) { + float grey = dot(color, float3(0.3, 0.59, 0.11)); + + return lerp(grey, color, saturation); +} + +float Brightness(float3 color) +{ + return color.r * color.g - 0.75 * color.b; +} + +float3 BlurFunction(float2 uv, float brightness, inout float totalWeight) +{ + float3 pointColor =(tex2Dlod(s0, float4(uv, 0, 0)).rgb); + float diff = abs(brightness - Brightness(pointColor)); + float weight = exp2(-0.25 * blurFalloff - diff * sharpness); + totalWeight += weight; + + return pointColor * weight; +} + +float4 BlurPS(float2 uv : TEXCOORD0, uniform float2 delta) : COLOR0 +{ + float3 sumColor = (tex2D(s0, uv).rgb); + float totalWeight = 1; + float brightness = Brightness(sumColor); + delta *= (1 / resolution); + float radius = 1; + + float2 pointUV = uv + delta * radius; + sumColor += BlurFunction(pointUV, brightness, totalWeight); + pointUV = uv - delta * radius; + sumColor += BlurFunction(pointUV, brightness, totalWeight); + + return float4((sumColor / totalWeight),1); +// return AdjustSaturation(Color, 0.5); +} + +float4 BloomT(float2 texCoord : TEXCOORD0) : COLOR0 { + float4 c = tex2D(s0, texCoord); + float BloomThreshold = 0.2; + + return saturate((c - BloomThreshold) / (1 - BloomThreshold)); +} + +float4 Bloom(float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0 { + float BaseIntensity = 1.0; + float BaseSaturation = 1; + float BloomIntensity = 1; // 0.4 + float BloomSaturation = 0.5; + float BlurPower = 0.01; + float BloomThreshold = 0.5; + + float4 original = tex2D(s0, texCoord); + + // blur + float4 sum = tex2D(s0, texCoord); + for(int i = 0; i < 12; i++){ + sum += tex2D(s0, texCoord + BlurPower * offsets[i]); + } + sum /= 13; + + original = AdjustSaturation(original, BaseSaturation) * BaseIntensity; + sum = AdjustSaturation(sum, BloomSaturation) * BloomIntensity; + + sum = saturate((sum - BloomThreshold) / (1 - BloomThreshold)); + + return sum + original; +// return sum; +} + +technique Blur +{ +// pass P2 { PixelShader = compile ps_2_0 BloomT(); } +// pass P3 { PixelShader = compile ps_2_0 Bloom(); } + Pass P0 { PixelShader = compile ps_3_0 BlurPS(float2(1, 0)); } + Pass P1 { PixelShader = compile ps_3_0 BlurPS(float2(0, 1)); } +} diff --git a/sfall/Modules/Graphics.cpp b/sfall/Modules/Graphics.cpp index 49ed7a78..ee833211 100644 --- a/sfall/Modules/Graphics.cpp +++ b/sfall/Modules/Graphics.cpp @@ -183,9 +183,11 @@ int _stdcall GetShaderVersion() { return ShaderVersion; } -static void rcpresInit() { +static void WindowInit() { + windowInit = true; rcpres[0] = 1.0f / (float)Graphics::GetGameWidthRes(); rcpres[1] = 1.0f / (float)Graphics::GetGameHeightRes(); + ScriptShaders::LoadGlobalShader(); } const float* Graphics::rcpresGet() { @@ -962,6 +964,9 @@ HRESULT _stdcall FakeDirectDrawCreate2_Init(void*, IDirectDraw** b, void*) { ScrollWindowKey = GetConfigInt("Input", "WindowScrollKey", 0); } else ScrollWindowKey = 0; + rcpres[0] = 1.0f / (float)gWidth; + rcpres[1] = 1.0f / (float)gHeight; + *b = (IDirectDraw*)new FakeDirectDraw2(); dlogr(" Done.", DL_MAIN); @@ -970,7 +975,9 @@ HRESULT _stdcall FakeDirectDrawCreate2_Init(void*, IDirectDraw** b, void*) { static __declspec(naked) void game_init_hook() { __asm { - mov windowInit, 1; + push ecx; + call WindowInit; + pop ecx; jmp fo::funcoffs::palette_init_; } } @@ -1016,10 +1023,6 @@ void Graphics::init() { fadeMulti = ((double)fadeMulti) / 100.0; dlogr(" Done", DL_INIT); } - - if (Graphics::mode) { - LoadGameHook::OnAfterGameInit() += rcpresInit; - } } void Graphics::exit() { diff --git a/sfall/Modules/ScriptShaders.cpp b/sfall/Modules/ScriptShaders.cpp index 37f58554..a8cadba9 100644 --- a/sfall/Modules/ScriptShaders.cpp +++ b/sfall/Modules/ScriptShaders.cpp @@ -29,6 +29,9 @@ namespace sfall static size_t shadersSize; +static bool globalShaderActive = false; +std::string gShaderFile; + struct sShader { ID3DXEffect* Effect; D3DXHANDLE ehTicks; @@ -55,14 +58,17 @@ void _stdcall SetShaderMode(DWORD d, DWORD mode) { } } -int _stdcall LoadShader(const char* path) { - if (!Graphics::mode || strstr(path, "..") || strstr(path, ":")) return -1; +int _stdcall LoadShader(const char* file) { + if (!Graphics::mode || strstr(file, "..") || strstr(file, ":")) return -1; char buf[MAX_PATH]; - sprintf_s(buf, "%s\\shaders\\%s", fo::var::patches, path); + sprintf_s(buf, "%s\\shaders\\%s", fo::var::paths->path, file); // fo::var::patches for (DWORD d = 0; d < shadersSize; d++) { if (!shaders[d].Effect) { - if (FAILED(D3DXCreateEffectFromFile(d3d9Device, buf, 0, 0, 0, 0, &shaders[d].Effect, 0))) return -1; - else return d; + if (FAILED(D3DXCreateEffectFromFile(d3d9Device, buf, 0, 0, 0, 0, &shaders[d].Effect, 0))) { + return -1; + } else { + return d; + } } } sShader shader = sShader(); @@ -89,6 +95,17 @@ int _stdcall LoadShader(const char* path) { return shadersSize - 1; } +void ScriptShaders::LoadGlobalShader() { + if (!globalShaderActive) return; + long index = LoadShader(gShaderFile.c_str()); + if (index != -1) { + shaders[index].Effect->SetInt("w", Graphics::GetGameWidthRes()); + shaders[index].Effect->SetInt("h", Graphics::GetGameHeightRes()); + shaders[index].Active = true; + dlogr("Global shader file loaded.", DL_INIT); + } +} + void _stdcall ActivateShader(DWORD d) { if (d < shadersSize && shaders[d].Effect) shaders[d].Active = true; } @@ -137,10 +154,11 @@ void _stdcall SetShaderTexture(DWORD d, const char* param, DWORD value) { shaders[d].Effect->SetTexture(param, shaderTextures[value]); } -void ResetShaders() { +static void ResetShaders() { for (DWORD d = 0; d < shadersSize; d++) SAFERELEASE(shaders[d].Effect); shaders.clear(); shadersSize = 0; + ScriptShaders::LoadGlobalShader(); } void ScriptShaders::Refresh(IDirect3DSurface9* sSurf1, IDirect3DSurface9* sSurf2, IDirect3DTexture9* sTex2) { @@ -177,6 +195,7 @@ void ScriptShaders::OnLostDevice() { } void ScriptShaders::Release() { + globalShaderActive = false; ResetShaders(); for (DWORD d = 0; d < shaderTextures.size(); d++) shaderTextures[d]->Release(); shaderTextures.clear(); @@ -184,6 +203,9 @@ void ScriptShaders::Release() { void ScriptShaders::init() { if (Graphics::mode) { + gShaderFile = GetConfigString("Graphics", "GlobalShaderFile", "", MAX_PATH); + globalShaderActive = (gShaderFile.length() > 3); + LoadGameHook::OnGameReset() += ResetShaders; } } diff --git a/sfall/Modules/ScriptShaders.h b/sfall/Modules/ScriptShaders.h index a76d0fea..9d0bbfb3 100644 --- a/sfall/Modules/ScriptShaders.h +++ b/sfall/Modules/ScriptShaders.h @@ -18,6 +18,8 @@ public: static void OnResetDevice(); static void OnLostDevice(); static void Release(); + + static void LoadGlobalShader(); }; int _stdcall LoadShader(const char*);