From 4c7d2431cdea7258df0955562d0b4e3249070f8c Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Mon, 29 Jun 2026 19:51:19 -0400 Subject: Broad area shadow res adjustment wip Signed-off-by: Andrew Opalach --- Plugin.cs | 62 ++++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 34 insertions(+), 28 deletions(-) (limited to 'Plugin.cs') diff --git a/Plugin.cs b/Plugin.cs index 70d69ed..dd68fd8 100755 --- a/Plugin.cs +++ b/Plugin.cs @@ -1764,8 +1764,29 @@ namespace WorldTuningTool private static Patch shadowRes1_2; private static Patch shadowRes1_3; private static Patch shadowRes1_4; - private static Patch shadowRes2; - private static Patch shadowRes3; + private static nint broadAreaShadowRes1_Addr; + private static nint broadAreaShadowRes2_Addr; + + private static void setBroadAreaShadowResolution(int multiplier) + { + bool reset = multiplier == 1; + int unused1Value = Math.Clamp(0x1000 * multiplier, 0x1000, 0x4000); + int unused2Value = Math.Clamp(0xC00 * multiplier, 0xC00, 0x4000); + int highValue = Math.Clamp((reset ? 0x800 : 0xC00) * multiplier, reset ? 0x800 : 0xC00, 0x4000); + int midValue = Math.Clamp( (reset ? 0x600 : 0x800) * multiplier, reset ? 0x600 : 0x800, 0x4000); + int lowValue = Math.Clamp( (reset ? 0x400 : 0x600) * multiplier, reset ? 0x400 : 0x600, 0x4000); + new Patch(broadAreaShadowRes1_Addr + 0x45, BitConverter.GetBytes(unused1Value)).Enable(); + new Patch(broadAreaShadowRes1_Addr + 0x45 + 0xB, BitConverter.GetBytes(unused2Value)).Enable(); + new Patch(broadAreaShadowRes1_Addr + 0x45 + 0x16, BitConverter.GetBytes(highValue)).Enable(); + new Patch(broadAreaShadowRes1_Addr + 0x45 + 0x21, BitConverter.GetBytes(midValue)).Enable(); + new Patch(broadAreaShadowRes1_Addr + 0x45 + 0x2C, BitConverter.GetBytes(lowValue)).Enable(); + // Likely unused. + new Patch(broadAreaShadowRes1_Addr + 0x3A, BitConverter.GetBytes(unused1Value)).Enable(); + new Patch(broadAreaShadowRes1_Addr + 0x3A + 0xB, BitConverter.GetBytes(unused2Value)).Enable(); + new Patch(broadAreaShadowRes1_Addr + 0x3A + 0x16, BitConverter.GetBytes(highValue)).Enable(); + new Patch(broadAreaShadowRes1_Addr + 0x3A + 0x21, BitConverter.GetBytes(midValue)).Enable(); + new Patch(broadAreaShadowRes1_Addr + 0x3A + 0x2C, BitConverter.GetBytes(lowValue)).Enable(); + } private static void shadowResEnable(int multiplier) { @@ -1781,8 +1802,6 @@ namespace WorldTuningTool shadowRes1_2.Enable(); shadowRes1_3.Enable(); shadowRes1_4.Enable(); - shadowRes2.Enable(); - shadowRes3.Enable(); break; case 2: shadowRes1_2x.Disable(); @@ -1822,6 +1841,7 @@ namespace WorldTuningTool break; #endif } + setBroadAreaShadowResolution(multiplier); currentShadowResMultiplier = multiplier; setShadowQuality.Invoke(MemoryUtil.Read(sMhScene!.Instance + 0x5530) + 1); } @@ -1856,8 +1876,7 @@ namespace WorldTuningTool shadowRes1_2.Disable(); shadowRes1_3.Disable(); shadowRes1_4.Disable(); - shadowRes2.Disable(); - shadowRes3.Disable(); + setBroadAreaShadowResolution(1); currentShadowResMultiplier = 1; setShadowQuality.Invoke(MemoryUtil.Read(sMhScene!.Instance + 0x5530) + 1); } @@ -2197,28 +2216,6 @@ namespace WorldTuningTool #else shadowRes1_4 = new Patch(new nint(0x142288AAA) + 0x4, [0x9E]); // Limit 4.0 -> 5.0. #endif - - // shadowRes2/3 control the detail of the infrequently updated fallback shadows (Broad Area). - addr = PatternScanner.FindFirst(Pattern.FromString("83 FA FF 74 06 89 91 1C 55 00 00 8B 91 30 55 00 00 83 FA FF 7F 06 8B 91 1C 55 00 00 85 D2 74 4B 83 EA 01 74 3B 83 EA 01 74 2B 83 EA 01 74 1B 83 FA 01 74 0B C7 81 20 55 00 00 01 00 00 00 C3 C7 81 20 55 00 00 00 10 00 00")); - Assert(addr == 0x142287A50); - shadowRes2 = new Patch(addr + 0x3F, [ - 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0xC3, - 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0xC3, - 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0xC3, // High (8192x8192). - 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0xC3, // Mid (6144x6144). - 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0xC3 // Low (4096x4096). - ]); - - addr = PatternScanner.FindFirst(Pattern.FromString("89 91 30 55 00 00 83 FA FF 7F 06 8B 91 1C 55 00 00 85 D2 74 4B 83 EA 01 74 3B 83 EA 01 74 2B 83 EA 01 74 1B 83 FA 01 74 0B C7 81 20 55 00 00 01 00 00 00 C3 C7 81 20 55 00 00 00 10 00 00")); - Assert(addr == 0x142287AD0); - shadowRes3 = new Patch(addr + 0x34, [ - 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0xC3, - 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0xC3, - 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0xC3, - 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0xC3, - 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0xC3 - ]); - addr = PatternScanner.FindFirst(Pattern.FromString("89 91 00 55 00 00 83 FA 05 77 41 48 63 C2 4C 8D 05 ?? ?? ?? ?? 41 8B 94 80 84 8B 28 02 49 03 D0 FF E2 B8 00 08 00 00")); Assert(addr == 0x142288B00); // This value controls the shadow map texture resolution. 16384x16384 is likely the limit for many drivers @@ -2231,6 +2228,15 @@ namespace WorldTuningTool ]); */ + // shadowRes2/3 control the detail of the infrequently updated fallback shadows (Broad Area). + addr = PatternScanner.FindFirst(Pattern.FromString("83 FA FF 74 06 89 91 1C 55 00 00 8B 91 30 55 00 00 83 FA FF 7F 06 8B 91 1C 55 00 00 85 D2 74 4B 83 EA 01 74 3B 83 EA 01 74 2B 83 EA 01 74 1B 83 FA 01 74 0B C7 81 20 55 00 00 01 00 00 00 C3 C7 81 20 55 00 00 00 10 00 00")); + Assert(addr == 0x142287A50); + broadAreaShadowRes1_Addr = addr; + // This function seems to never be used, but is nearly identical to the first one. So might as well adjust it. + addr = PatternScanner.FindFirst(Pattern.FromString("89 91 30 55 00 00 83 FA FF 7F 06 8B 91 1C 55 00 00 85 D2 74 4B 83 EA 01 74 3B 83 EA 01 74 2B 83 EA 01 74 1B 83 FA 01 74 0B C7 81 20 55 00 00 01 00 00 00 C3 C7 81 20 55 00 00 00 10 00 00")); + Assert(addr == 0x142287AD0); + broadAreaShadowRes2_Addr = addr; + // The volume blur filter is created at a different place in the code and happens at a different // time (area change/createLightingObject() vs change of Volume Quality setting). It's also rendered // in a seperate pass that happens after the initial volume rendering. So keep that in mind if inspecting -- cgit v1.2.3-101-g0448