diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index 2ce5a6d0..4c6a447c 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -69,10 +69,12 @@ WindowData=0 ;Uncomment the option to use a hardware shader (requires DX9 graphics mode) ;The shader file .fx must be placed in \\shaders\ and must contain one technique with one or more passes +;You can specify multiple shader files, separated by commas ;GlobalShaderFile=global.fx ;Set to 1 to enable linear texture filtering -TextureFilter=0 +;This can be used in conjunction with GlobalShaderFile +TextureFilter=1 ;Set to 1 to do the palette conversion on the GPU ;Set to 2 to do the palette conversion on the CPU diff --git a/artifacts/example_mods/GlobalShaders/sharpen.fx b/artifacts/example_mods/GlobalShaders/sharpen.fx new file mode 100644 index 00000000..89e59532 --- /dev/null +++ b/artifacts/example_mods/GlobalShaders/sharpen.fx @@ -0,0 +1,113 @@ +/////////////////////////////////////////////////////////////////////////////// +// Sharpen filter setting +// +// min: Sharpen 0.5, EdgeSharpen 1.0 +// mid: Sharpen 1.0, EdgeSharpen -0.25 +// max: Sharpen 1.75, EdgeSharpen -0.5 (1.5, -0.25) +/////////////////////////////////////////////////////////////////////////////// +#define Sharpen 0.5 +#define EdgeSharpen 1.5 + + +texture sharpenTex; +sampler s0; + +sampler SharpenSampler : samplerstate +{ + Texture = sharpenTex; + MinFilter = Linear; + MagFilter = Linear; + AddressU = Clamp; + AddressV = Clamp; +}; + +// Variables that set the width and height of the current game resolution from sfall +float w; +float h; + +static const float CoefBlur = (Sharpen * 0.5); +static const float CoefOrig = (1 + CoefBlur); + +// for the sharpen edge +#define SharpenEdge 0.4 +static const float sharpenVal0 = (Sharpen * (1.5 + EdgeSharpen)); +static const float sharpenVal1 = ((sharpenVal0 - 1) / 8.0); + +// pixel "width" +static const float px = (1.0 / w); +static const float py = (1.0 / h); + +// for the blur filter +#define mean 1.0 +static const float dx = (mean * px); +static const float dy = (mean * py); + +float4 SharpenComplexPS(float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0 +{ + float4 c0 = tex2D(s0, texCoord); // get original pixel + + // edge detection + // Get neighbor points + // [ c1, c2, c3 ] + // [ c4, c0, c5 ] + // [ c6, c7, c8 ] + float4 c1 = tex2D(s0, texCoord + float2(-px, -py)); + float4 c2 = tex2D(s0, texCoord + float2( 0, -py)); + float4 c3 = tex2D(s0, texCoord + float2( px, -py)); + float4 c4 = tex2D(s0, texCoord + float2(-px, 0)); + float4 c5 = tex2D(s0, texCoord + float2( px, 0)); + float4 c6 = tex2D(s0, texCoord + float2(-px, py)); + float4 c7 = tex2D(s0, texCoord + float2( 0, py)); + float4 c8 = tex2D(s0, texCoord + float2( px, py)); + + // using Sobel filter + // horizontal gradient + // [ -1, 0, 1 ] + // [ -2, 0, 2 ] + // [ -1, 0, 1 ] + float delta1 = (c3 + 2 * c5 + c8) - (c1 + 2 * c4 + c6); + + // vertical gradient + // [ -1, - 2, -1 ] + // [ 0, 0, 0 ] + // [ 1, 2, 1 ] + float4 c13 = c1 + c3; + float4 c68 = c6 + c8; + float delta2 = (c68 + 2 * c7) - (c13 + 2 * c2); + + // computation + if (sqrt(mul(delta1, delta1) + mul(delta2, delta2)) > SharpenEdge) { + // if we have an edge, use sharpen + return c0 * sharpenVal0 - (c13 + c2 + c4 + c5 + c68 + c7) * sharpenVal1; + + // Display edges in red... + //return float4( 1.0, 0.0, 0.0, 0.0 ); + } else { + // else return corrected image + + // compute blurred image (gaussian filter) + c1 = tex2D(s0, texCoord + float2(-dx, -dy)); + c2 = tex2D(s0, texCoord + float2( 0, -dy)); + c3 = tex2D(s0, texCoord + float2( dx, -dy)); + c4 = tex2D(s0, texCoord + float2(-dx, 0)); + c5 = tex2D(s0, texCoord + float2( dx, 0)); + c6 = tex2D(s0, texCoord + float2(-dx, dy)); + c7 = tex2D(s0, texCoord + float2( 0, dy)); + c8 = tex2D(s0, texCoord + float2( dx, dy)); + + // gaussian filter + // [ 1, 2, 1 ] + // [ 2, 4, 2 ] + // [ 1, 2, 1 ] + // to normalize the values, we need to divide by the coeff sum + float4 flou = (c1 + c3 + c6 + c8 + 2 * (c2 + c4 + c5 + c7) + 4 * c0) * 0.0625; // 1 / (1+2+1+2+4+2+1+2+1) = 1 / 16 = 0.0625 + + // substract blurred image from original image + return (CoefOrig * c0 - CoefBlur * flou); + } +} + +technique SharpenT +{ + pass P0 { PixelShader = compile ps_2_0 SharpenComplexPS(); } +} diff --git a/sfall/FalloutEngine/Functions.cpp b/sfall/FalloutEngine/Functions.cpp index 02876338..a963d734 100644 --- a/sfall/FalloutEngine/Functions.cpp +++ b/sfall/FalloutEngine/Functions.cpp @@ -162,20 +162,20 @@ GameObject* __fastcall obj_blocking_at_wrapper(GameObject* obj, DWORD tile, DWOR long __stdcall win_register_button(DWORD winRef, long xPos, long yPos, long width, long height, long hoverOn, long hoverOff, long buttonDown, long buttonUp, BYTE* pictureUp, BYTE* pictureDown, long arg12, long buttonType) { __asm { - push buttonType - push arg12 - push pictureDown - push pictureUp - push buttonUp - push buttonDown - push hoverOff - push hoverOn - push height - mov ecx, width - mov ebx, yPos - mov edx, xPos - mov eax, winRef - call fo::funcoffs::win_register_button_ + push buttonType; + push arg12; + push pictureDown; + push pictureUp; + push buttonUp; + push buttonDown; + push hoverOff; + push hoverOn; + push height; + mov ecx, width; + mov ebx, yPos; + mov edx, xPos; + mov eax, winRef; + call fo::funcoffs::win_register_button_; } } diff --git a/sfall/Modules/Graphics.cpp b/sfall/Modules/Graphics.cpp index 6c6b1b74..ecfdf43a 100644 --- a/sfall/Modules/Graphics.cpp +++ b/sfall/Modules/Graphics.cpp @@ -50,7 +50,7 @@ static DWORD yoffset; static bool DeviceLost = false; static bool mainTexLock = false; -static bool textureFilter = false; +static bool textureFilter = true; static DDSURFACEDESC surfaceDesc; static DDSURFACEDESC mveDesc; @@ -886,7 +886,7 @@ public: HRESULT __stdcall SetEntries(DWORD a, DWORD b, DWORD c, LPPALETTEENTRY destPal) { // used to set palette for splash screen, fades, subtitles if (!windowInit || c == 0 || b + c > 256) return DDERR_INVALIDPARAMS; - __movsd(&palette[b], (unsigned long*)destPal, c); //CopyMemory(&palette[b], destPal, c * 4); + __movsd(&palette[b], (unsigned long*)destPal, c); if (Graphics::GPUBlt && gpuPalette) { D3DLOCKED_RECT rect; @@ -912,8 +912,7 @@ public: } }; -class FakeDirectDraw : IDirectDraw -{ +class FakeDirectDraw : IDirectDraw { private: ULONG Refs; public: @@ -1154,7 +1153,7 @@ void Graphics::init() { SafeWrite8(0x50FB6B, '2'); // Set call DirectDrawCreate2 HookCall(0x44260C, game_init_hook); - textureFilter = (GetConfigInt("Graphics", "TextureFilter", 0) != 0); + textureFilter = (GetConfigInt("Graphics", "TextureFilter", 1) != 0); dlogr(" Done", DL_INIT); } diff --git a/sfall/Modules/ScriptShaders.cpp b/sfall/Modules/ScriptShaders.cpp index f74f9534..1b711819 100644 --- a/sfall/Modules/ScriptShaders.cpp +++ b/sfall/Modules/ScriptShaders.cpp @@ -30,9 +30,16 @@ namespace sfall #define SAFERELEASE(a) { if (a) { a->Release(); a = nullptr; } } static size_t shadersSize; +static bool globalShadersActive = false; -static bool globalShaderActive = false; -std::string gShaderFile; +struct GlobalShader { + std::string gShaderFile; + bool badShader = false; + + GlobalShader(std::string file) { + gShaderFile = std::move(file); + } +}; struct sShader { ID3DXEffect* Effect; @@ -44,6 +51,7 @@ struct sShader { sShader() : Effect(0), ehTicks(0), mode(0), mode2(0), Active(false) {} }; +static std::vector gShaderFiles; static std::vector shaders; static std::vector shaderTextures; @@ -98,13 +106,18 @@ int __stdcall LoadShader(const char* file) { } 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); + if (!globalShadersActive) return; + for (auto &shader : gShaderFiles) { + if (shader.badShader) continue; + long index = LoadShader(shader.gShaderFile.c_str()); + if (index != -1) { + shaders[index].Effect->SetInt("w", Graphics::GetGameWidthRes()); + shaders[index].Effect->SetInt("h", Graphics::GetGameHeightRes()); + shaders[index].Active = true; + dlog_f("Global shader file %s is loaded.\n", DL_INIT, shader.gShaderFile.c_str()); + } else { + shader.badShader = true; + } } } @@ -199,7 +212,7 @@ void ScriptShaders::OnLostDevice() { } void ScriptShaders::Release() { - globalShaderActive = false; + globalShadersActive = false; ResetShaders(); for (DWORD d = 0; d < shaderTextures.size(); d++) shaderTextures[d]->Release(); shaderTextures.clear(); @@ -207,8 +220,10 @@ void ScriptShaders::Release() { void ScriptShaders::init() { if (Graphics::mode) { - gShaderFile = GetConfigString("Graphics", "GlobalShaderFile", "", MAX_PATH); - globalShaderActive = (gShaderFile.length() > 3); + for each (const auto& shaderFile in GetConfigList("Graphics", "GlobalShaderFile", "", 1024)) { + if (shaderFile.length() > 3) gShaderFiles.push_back(GlobalShader(shaderFile)); + } + globalShadersActive = !gShaderFiles.empty(); LoadGameHook::OnGameReset() += ResetShaders; }