From 04043989c69e048b0047b7716b229e5ee484aca3 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Sat, 14 Dec 2019 11:05:12 +0800 Subject: [PATCH] Restored loading global shaders at game start from pre-3.0 Added GlobalShaderFile option to ddraw.ini. Added an example global shader file to modderspack. Minor edits to HeroAppearance.cpp. --- artifacts/ddraw.ini | 4 + .../example_mods/GlobalShaders/global.fx | 116 ++++++++++++++++++ sfall/FalloutEngine.cpp | 2 +- sfall/FalloutEngine.h | 2 +- sfall/FalloutStructs.h | 10 ++ sfall/Graphics.cpp | 54 ++++++-- sfall/Graphics.h | 1 - sfall/HeroAppearance.cpp | 26 ++-- sfall/LoadGameHook.cpp | 1 - 9 files changed, 183 insertions(+), 33 deletions(-) create mode 100644 artifacts/example_mods/GlobalShaders/global.fx diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index 34dc04f2..ce87de8b 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -64,6 +64,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/FalloutEngine.cpp b/sfall/FalloutEngine.cpp index 3c241df3..cd5986ae 100644 --- a/sfall/FalloutEngine.cpp +++ b/sfall/FalloutEngine.cpp @@ -157,7 +157,7 @@ DWORD** ptr_partyMemberList = reinterpret_cast(_partyMemberLi DWORD* ptr_partyMemberMaxCount = reinterpret_cast(_partyMemberMaxCount); DWORD** ptr_partyMemberPidList = reinterpret_cast(_partyMemberPidList); DWORD* ptr_patches = reinterpret_cast(_patches); -DWORD* ptr_paths = reinterpret_cast(_paths); +PathNode** ptr_paths = reinterpret_cast(_paths); // array DWORD* ptr_pc_crit_succ_eff = reinterpret_cast(_pc_crit_succ_eff); DWORD* ptr_pc_kill_counts = reinterpret_cast(_pc_kill_counts); char* ptr_pc_name = reinterpret_cast(_pc_name); diff --git a/sfall/FalloutEngine.h b/sfall/FalloutEngine.h index c3be0225..ece8f47f 100644 --- a/sfall/FalloutEngine.h +++ b/sfall/FalloutEngine.h @@ -411,7 +411,7 @@ extern DWORD** ptr_partyMemberList; // each struct - 4 integers, first integer - extern DWORD* ptr_partyMemberMaxCount; extern DWORD** ptr_partyMemberPidList; extern DWORD* ptr_patches; -extern DWORD* ptr_paths; +extern PathNode** ptr_paths; extern DWORD* ptr_pc_crit_succ_eff; extern DWORD* ptr_pc_kill_counts; extern char* ptr_pc_name; diff --git a/sfall/FalloutStructs.h b/sfall/FalloutStructs.h index fafd9b26..3afb0e80 100644 --- a/sfall/FalloutStructs.h +++ b/sfall/FalloutStructs.h @@ -236,6 +236,16 @@ public: } FrmHeaderData; #pragma pack(pop) +//fallout2 path node structure +#pragma pack(push, 1) +struct PathNode { + char* path; + void* pDat; + long isDat; + PathNode* next; +}; +#pragma pack(pop) + //for holding window info #pragma pack(push, 1) struct WINinfo { diff --git a/sfall/Graphics.cpp b/sfall/Graphics.cpp index 9cb9d7c8..4b6b8ad2 100644 --- a/sfall/Graphics.cpp +++ b/sfall/Graphics.cpp @@ -138,6 +138,9 @@ static float rcpres[2]; static size_t shadersSize; +static bool globalShaderActive = false; +std::string gShaderFile; + struct sShader { ID3DXEffect* Effect; D3DXHANDLE ehTicks; @@ -181,11 +184,6 @@ int _stdcall GetShaderVersion() { return ShaderVersion; } -void rcpresInit() { - rcpres[0] = 1.0f / (float)Gfx_GetGameWidthRes(); - rcpres[1] = 1.0f / (float)Gfx_GetGameHeightRes(); -} - void _stdcall SetShaderMode(DWORD d, DWORD mode) { if (d >= shadersSize || !shaders[d].Effect) return; if (mode & 0x80000000) { @@ -195,14 +193,18 @@ void _stdcall SetShaderMode(DWORD d, DWORD mode) { } } -int _stdcall LoadShader(const char* path) { - if (!GraphicsMode || strstr(path, "..") || strstr(path, ":")) return -1; +int _stdcall LoadShader(const char* file) { + if (!GraphicsMode || strstr(file, "..") || strstr(file, ":")) return -1; char buf[MAX_PATH]; - sprintf_s(buf, "%s\\shaders\\%s", *(char**)_patches, path); + PathNode* pathsPtr = *ptr_paths; + sprintf_s(buf, "%s\\shaders\\%s", pathsPtr->path, file); 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(); @@ -229,6 +231,17 @@ int _stdcall LoadShader(const char* path) { return shadersSize - 1; } +static void LoadGlobalShader() { + if (!globalShaderActive) return; + long index = LoadShader(gShaderFile.c_str()); + if (index != -1) { + shaders[index].Effect->SetInt("w", Gfx_GetGameWidthRes()); + shaders[index].Effect->SetInt("h", Gfx_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; } @@ -277,6 +290,13 @@ void _stdcall SetShaderTexture(DWORD d, const char* param, DWORD value) { shaders[d].Effect->SetTexture(param, shaderTextures[value]); } +static void WindowInit() { + windowInit = true; + rcpres[0] = 1.0f / (float)Gfx_GetGameWidthRes(); + rcpres[1] = 1.0f / (float)Gfx_GetGameHeightRes(); + LoadGlobalShader(); +} + static void ResetDevice(bool CreateNew) { D3DPRESENT_PARAMETERS params; ZeroMemory(¶ms, sizeof(params)); @@ -594,6 +614,7 @@ void GraphicsResetOnGameLoad() { for (DWORD d = 0; d < shadersSize; d++) SAFERELEASE(shaders[d].Effect); shaders.clear(); shadersSize = 0; + LoadGlobalShader(); } class FakePalette2 : IDirectDrawPalette { @@ -927,6 +948,7 @@ public: ULONG _stdcall Release() { if (!--Refs) { + globalShaderActive = false; GraphicsResetOnGameLoad(); for (DWORD d = 0; d < shaderTextures.size(); d++) shaderTextures[d]->Release(); shaderTextures.clear(); @@ -1055,6 +1077,9 @@ HRESULT _stdcall FakeDirectDrawCreate2(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); @@ -1063,7 +1088,9 @@ HRESULT _stdcall FakeDirectDrawCreate2(void*, IDirectDraw** b, void*) { static __declspec(naked) void game_init_hook() { __asm { - mov windowInit, 1; + push ecx; + call WindowInit; + pop ecx; jmp palette_init_; } } @@ -1085,7 +1112,7 @@ void GraphicsInit() { if (GraphicsMode != 4 && GraphicsMode != 5) { GraphicsMode = 0; } - if (GraphicsMode == 4 || GraphicsMode == 5) { + if (GraphicsMode) { dlog("Applying DX9 graphics patch.", DL_INIT); #ifdef WIN2K #define _DLL_NAME "d3dx9_42.dll" @@ -1104,6 +1131,9 @@ void GraphicsInit() { SafeWrite8(0x50FB6B, '2'); // Set call DirectDrawCreate2 HookCall(0x44260C, game_init_hook); dlogr(" Done", DL_INIT); + + gShaderFile = GetConfigString("Graphics", "GlobalShaderFile", "", MAX_PATH); + globalShaderActive = (gShaderFile.length() > 3); } fadeMulti = GetConfigInt("Graphics", "FadeMultiplier", 100); diff --git a/sfall/Graphics.h b/sfall/Graphics.h index a7be9a29..3d08d250 100644 --- a/sfall/Graphics.h +++ b/sfall/Graphics.h @@ -39,7 +39,6 @@ long Gfx_GetGameHeightRes(); void Gfx_SetHeadTex(IDirect3DTexture9* tex, int width, int height, int xoff, int yoff); void Gfx_SetHeadTechnique(); void Gfx_SetDefaultTechnique(); -void rcpresInit(); int _stdcall GetShaderVersion(); int _stdcall LoadShader(const char*); diff --git a/sfall/HeroAppearance.cpp b/sfall/HeroAppearance.cpp index b8568fdb..32215f17 100644 --- a/sfall/HeroAppearance.cpp +++ b/sfall/HeroAppearance.cpp @@ -43,18 +43,10 @@ bool raceButtons = false, styleButtons = false; int currentRaceVal = 0, currentStyleVal = 0; // holds Appearance values to restore after global reset in NewGame2 function in LoadGameHooks.cpp DWORD critterListSize = 0, critterArraySize = 0; // Critter art list size -// fallout2 path node structure -struct sPath { - char* path; - void* pDat; - DWORD isDat; - sPath* next; -}; - -sPath **heroAppPaths = (sPath**)_paths; +PathNode **heroAppPaths = ptr_paths; // index: 0 - only folder (w/o extension .dat), 1 - file or folder .dat -sPath *heroPathPtr[2] = {nullptr, nullptr}; -sPath *racePathPtr[2] = {nullptr, nullptr}; +PathNode *heroPathPtr[2] = {nullptr, nullptr}; +PathNode *racePathPtr[2] = {nullptr, nullptr}; // for word wrapping typedef struct LineNode { @@ -757,7 +749,7 @@ static __declspec(noinline) int _stdcall LoadHeroDat(unsigned int race, unsigned } heroAppPaths = &heroPathPtr[1 - folderIsExist]; // set path for selected appearance - heroPathPtr[0 + heroDatIsExist]->next = *(sPath**)_paths; // heroPathPtr[] >> foPaths + heroPathPtr[0 + heroDatIsExist]->next = ptr_paths[0]; // heroPathPtr[] >> foPaths if (style != 0) { bool raceDatIsExist = false, folderIsExist = false; @@ -781,7 +773,7 @@ static __declspec(noinline) int _stdcall LoadHeroDat(unsigned int race, unsigned } heroPathPtr[0 + heroDatIsExist]->next = racePathPtr[1 - folderIsExist]; // set path for selected race base appearance - racePathPtr[0 + raceDatIsExist]->next = *(sPath**)_paths; // insert racePathPtr in chain path: heroPathPtr[] >> racePathPtr[] >> foPaths + racePathPtr[0 + raceDatIsExist]->next = ptr_paths[0]; // insert racePathPtr in chain path: heroPathPtr[] >> racePathPtr[] >> foPaths } return 0; } @@ -1995,13 +1987,13 @@ static void EnableHeroAppearanceMod() { appModEnabled = true; // setup paths - heroPathPtr[0] = new sPath(); - racePathPtr[0] = new sPath(); + heroPathPtr[0] = new PathNode(); + racePathPtr[0] = new PathNode(); heroPathPtr[0]->path = new char[64]; racePathPtr[0]->path = new char[64]; - heroPathPtr[1] = new sPath(); - racePathPtr[1] = new sPath(); + heroPathPtr[1] = new PathNode(); + racePathPtr[1] = new PathNode(); heroPathPtr[1]->path = new char[64]; racePathPtr[1]->path = new char[64]; diff --git a/sfall/LoadGameHook.cpp b/sfall/LoadGameHook.cpp index 50bbe1d5..8162e78e 100644 --- a/sfall/LoadGameHook.cpp +++ b/sfall/LoadGameHook.cpp @@ -291,7 +291,6 @@ static void __stdcall game_init_hook() { // OnGameInit } static void __stdcall GameInitialized() { // OnAfterGameInit - if (GraphicsMode) rcpresInit(); RemoveSavFiles(); SetBoxMaxSlots(); if (Use32BitTalkingHeads) TalkingHeadsSetup();