diff --git a/artifacts/example_mods/GlobalShaders/global.fx b/artifacts/example_mods/GlobalShaders/global.fx index 9f68917a..fac25d02 100644 --- a/artifacts/example_mods/GlobalShaders/global.fx +++ b/artifacts/example_mods/GlobalShaders/global.fx @@ -1,4 +1,23 @@ -// Status: WIP +/////////////////////////////////////////////////////////////////////////////// +// Blur filter setting +// +// min: blurFalloff 8, sharpness 10/8 +// mid: blurFalloff 6, sharpness 8 +// max: blurFalloff 4, sharpness 6 +/////////////////////////////////////////////////////////////////////////////// +#define blurFalloff 4.0 +#define sharpness 6.0 + +/////////////////////////////////////////////////////////////////////////////// +// 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.0 + texture bloomMap; sampler s0; @@ -12,6 +31,88 @@ sampler BloomSampler : samplerstate AddressV = Clamp; }; +// Variables that set the width and height of the current game resolution from sfall +float w; +float h; + +static const float2 resolution = float2(w, h); +static const float2 wPass = float2(1, 0); +static const float2 hPass = float2(0, 1); + +float Brightness(float3 color) +{ + return 0.299 * color.r + 0.587 * color.g + 0.114 * 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 BlurDeltaPassPS(float2 uv : TEXCOORD0, uniform float2 delta) : COLOR0 +{ + float3 sumColor = (tex2D(s0, uv).rgb); + float brightness = Brightness(sumColor); + + delta *= (1 / resolution); + float totalWeight = 1; + + float2 pointUV = uv + delta; + sumColor += BlurFunction(pointUV, brightness, totalWeight); + + pointUV = uv - delta; + sumColor += BlurFunction(pointUV, brightness, totalWeight); + + return float4((sumColor / totalWeight), 1); +} + +static const float2 wDelta = float2(1, 0) * (1 / resolution); +static const float2 hDelta = float2(0, 1) * (1 / resolution); + +float4 BlurPS(float4 color : COLOR0, float2 uv : TEXCOORD0) : COLOR0 +{ + float totalWeight = 1; + + float3 sumColor = (tex2D(s0, uv).rgb); + float brightness = Brightness(sumColor); + + float2 pointUV = uv + wDelta; + sumColor += BlurFunction(pointUV, brightness, totalWeight); + + pointUV = uv - wDelta; + sumColor += BlurFunction(pointUV, brightness, totalWeight); + + pointUV = uv + hDelta; + sumColor += BlurFunction(pointUV, brightness, totalWeight); + + pointUV = uv - hDelta; + sumColor += BlurFunction(pointUV, brightness, totalWeight); + + return float4((sumColor / totalWeight), 1); +} + +/////////////////////////////////////////////////////////////////////////////// +// Bloom effect setting +// +// min: BloomIntensity .8 +// mid: BloomIntensity .85 +// max: BloomIntensity .9 +/////////////////////////////////////////////////////////////////////////////// +#define BaseIntensity 1.2 +#define BaseSaturation 1.0 + +#define BloomIntensity 0.8 +#define BloomSaturation 0.35 + +#define BloomThreshold 0.35 +#define BlurPower 0.002 + // pseudo gauss blur static const float2 offsets[12] = { -0.326212, -0.405805, @@ -28,89 +129,122 @@ static const float2 offsets[12] = { -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) { +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) +float4 BloomPS(float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0 { - 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; + float sum = (original.r + original.g + original.b) * 0.333; + if (sum >= 0.95) return original; - sum = saturate((sum - BloomThreshold) / (1 - BloomThreshold)); + // bloom blur + float4 bloomBlur = tex2D(s0, texCoord); + for(int i = 0; i < 12; i++) + { + bloomBlur += tex2D(s0, texCoord + BlurPower * offsets[i]); + } + bloomBlur *= 0.085; - return sum + original; -// return sum; + float intensity = BloomIntensity - lerp(0.0, 0.2, sum); + bloomBlur = AdjustSaturation(bloomBlur, BloomSaturation) * intensity; + bloomBlur = saturate((bloomBlur - BloomThreshold) / (1 - BloomThreshold)); + + return bloomBlur + original; } -technique Blur +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 { -// 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)); } + 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 BlurBloom +{ + //pass P0 { PixelShader = compile ps_3_0 BlurDeltaPassPS(wPass); } + //pass P1 { PixelShader = compile ps_3_0 BlurDeltaPassPS(hPass); } + + pass P0 { PixelShader = compile ps_3_0 BlurPS(); } + pass P3 { PixelShader = compile ps_2_0 BloomPS(); } + pass P2 { PixelShader = compile ps_2_0 SharpenComplexPS(); } } diff --git a/artifacts/example_mods/WithinPerception/gl_withinperception.ssl b/artifacts/example_mods/WithinPerception/gl_withinperception.ssl index 36690172..275b4b0d 100644 --- a/artifacts/example_mods/WithinPerception/gl_withinperception.ssl +++ b/artifacts/example_mods/WithinPerception/gl_withinperception.ssl @@ -1,7 +1,5 @@ /* Example implementation of the algorithm of how the game engine checks if one critter sees another critter. - - NOTE: the AllowUnsafeScripting option must be enabled. */ #include "..\headers\define.h" @@ -9,10 +7,8 @@ #include "..\headers\sfall\sfall.h" #include "..\headers\sfall\define_extra.h" -#define can_see_(source, target) call_offset_r2(0x412BEC, source, target) -#define obj_dist_(target, source) call_offset_r2(0x48BBD4, target, source) - procedure start; +procedure can_see(variable obj1, variable obj2); procedure start begin if game_loaded then begin @@ -21,40 +17,50 @@ procedure start begin variable source := get_sfall_arg, target := get_sfall_arg, - original := get_sfall_arg, - hookType := get_sfall_arg, /* new arg */ + engine := get_sfall_arg, + type := get_sfall_arg, /* new arg */ result := 0, - distance; + distance, seeDistance, seeText; if target then begin - distance := get_critter_stat(source, STAT_pe); + seeDistance := get_critter_stat(source, STAT_pe); - if can_see_(source, target) then begin - distance *= 5; - if (get_flags(target) bwand FLAG_TRANSGLASS) then distance /= 2; + if can_see(source, target) then begin + seeDistance *= 5; + if (get_flags(target) bwand FLAG_TRANSGLASS) then seeDistance /= 2; end else if combat_is_initialized then begin - distance *= 2; + seeDistance *= 2; end if (target == dude_obj) then begin if sneak_success then begin - distance /= 4; - if has_skill(target, SKILL_SNEAK) > 120 then distance -= 1; + seeDistance /= 4; + if has_skill(target, SKILL_SNEAK) > 120 then seeDistance -= 1; end else if dude_is_sneaking then begin - distance := distance * 2 / 3; + seeDistance := (seeDistance * 2) / 3; // distance div 1.5 end end - if obj_dist_(target, source) <= distance then result := 1; + distance := tile_distance_objs(source, target); + if (get_flags(source) bwand FLAG_MULTIHEX) then distance--; + if (get_flags(target) bwand FLAG_MULTIHEX) then distance--; - // example - if (result) then begin - display_msg("hs_withinperception: " + obj_name(source) + " sees " + obj_name(target) + " [original: " + original + " script: " + result + "]"); - end else begin - display_msg("hs_withinperception: " + obj_name(source) + " does not see " + obj_name(target) + " [original: " + original + " script: " + result + "]"); - end + if (distance <= seeDistance) then result := 1; + + seeText = " does not see > "; + if (result) then seeText = " sees > "; + + // Example + display_msg("hs_withinperception: " + obj_name(source) + seeText + obj_name(target) + " [engine: " + engine + ", script: " + result + "]"); + + /* override engine result */ + //set_sfall_return(result); end - - //set_sfall_return(result); end end + +procedure can_see(variable obj1, variable obj2) begin + variable dir = obj_get_rot(obj1) - rotation_to_tile(tile_num(obj1), tile_num(obj2)); + if (dir < 0) then dir = -dir; + return (dir <= 1) or (dir == 5); +end diff --git a/sfall/BugFixes.cpp b/sfall/BugFixes.cpp index d061e8e1..cd66abce 100644 --- a/sfall/BugFixes.cpp +++ b/sfall/BugFixes.cpp @@ -3542,6 +3542,6 @@ void BugFixesInit() MakeCall(0x41094B, show_damage_to_object_hack, 1); MakeCall(0x48A6CB, obj_move_to_tile_hack_ondeath, 1); - // Fix to limit the maximum distance for knockback animation + // Fix to limit the maximum distance for the knockback animation MakeCall(0x4104D5, action_knockback_hack); } diff --git a/sfall/InputFuncs.cpp b/sfall/InputFuncs.cpp index 50177498..5a31d5d4 100644 --- a/sfall/InputFuncs.cpp +++ b/sfall/InputFuncs.cpp @@ -100,16 +100,14 @@ DWORD __stdcall KeyDown(DWORD key) { } key = key & 0xFFFF; // combined use of DINPUT states + confirmation from GetAsyncKeyState() - if (key > MAX_KEYS) { - return 0; - } else { - DWORD keyVK = 0; + if (key < MAX_KEYS) { if (keysDown[key]) { // confirm pressed state - keyVK = MapVirtualKeyEx(key, MAPVK_VSC_TO_VK, keyboardLayout); + DWORD keyVK = MapVirtualKeyEx(key, MAPVK_VSC_TO_VK, keyboardLayout); if (keyVK) keysDown[key] = (GetAsyncKeyState(keyVK) & 0x8000); } return (keysDown[key] > 0); } + return 0; } void __stdcall TapKey(DWORD key) { diff --git a/sfall/LoadGameHook.h b/sfall/LoadGameHook.h index 4f75ec8e..73f98a10 100644 --- a/sfall/LoadGameHook.h +++ b/sfall/LoadGameHook.h @@ -27,7 +27,7 @@ DWORD InWorldMap(); DWORD InCombat(); DWORD InDialog(); -enum LoopFlag : long { +enum LoopFlag : unsigned long { WORLDMAP = 1 << 0, // 0x1 // RESERVED = 1 << 1, // 0x2 (unused) DIALOG = 1 << 2, // 0x4 @@ -50,7 +50,7 @@ enum LoopFlag : long { DIALOGVIEW = 1 << 19, // 0x80000 COUNTERWIN = 1 << 20, // 0x100000 Counter window for moving multiple items or setting a timer -// SPECIAL = 1 << 31 // 0x80000000 Additional special flag for all modes +// SPECIAL = 1UL << 31 // 0x80000000 Additional special flag for all modes }; DWORD GetLoopFlags(); diff --git a/sfall/MiscPatches.cpp b/sfall/MiscPatches.cpp index 662bf3c3..ccf8e29d 100644 --- a/sfall/MiscPatches.cpp +++ b/sfall/MiscPatches.cpp @@ -694,10 +694,11 @@ void MiscPatchesInit() { HookCall(0x483726, map_check_state_hook); // Corrects the height of the black background for the subtitles on death screens - if (hrpVersionValid) { - SafeWrite8(HRPAddress(0x10011738), 10); + if (hrpIsEnabled == false || hrpVersionValid) { + SafeWrite32(0x48134D, -602 - (640 * 2)); // main_death_scene_ (shift y-offset 2px up, w/o HRP) SafeWrite8(0x481345, 4); // main_death_scene_ } + if (hrpVersionValid) SafeWrite8(HRPAddress(0x10011738), 10); F1EngineBehaviorPatch(); DialogueFix(); diff --git a/sfall/ScriptOps/InterfaceOps.hpp b/sfall/ScriptOps/InterfaceOps.hpp index 7e72b578..f531a950 100644 --- a/sfall/ScriptOps/InterfaceOps.hpp +++ b/sfall/ScriptOps/InterfaceOps.hpp @@ -693,7 +693,7 @@ static void mf_unwield_slot() { } bool isDude = (critter == *ptr_obj_dude); bool update = false; - if (slot && (GetLoopFlags() && (INVENTORY | INTFACEUSE | INTFACELOOT | BARTER)) == false) { + if (slot && (GetLoopFlags() & (INVENTORY | INTFACEUSE | INTFACELOOT | BARTER)) == false) { if (InvenUnwield(critter, (slot == INVEN_TYPE_LEFT_HAND) ? 0 : 1) == 0) { update = isDude; }