Skip to content

Commit

Permalink
Fix stretched FMVs for Resident Evil Revelations 2. (#1695)
Browse files Browse the repository at this point in the history
* Fix stretched FMVs for Resident Evil Revelations 2.
Explanation:
FMV rendering uses a YUV decoding pixel shader with a crc of 0x9D190FC7 and a generic screenspace vertex shader with a crc of 0x1287841D.
We hook D3DDevice9::DrawPrimitive, and if both of these shaders are active, we instead activate our own vertex shader (injected earlier) which resizes the verts according to 16:9 aspect.

* refactor and fixes

* subtitles fix

---------

Co-authored-by: ThirteenAG <[email protected]>
  • Loading branch information
noorus and ThirteenAG authored Jan 14, 2025
1 parent 6e1f39e commit cf84aa4
Showing 1 changed file with 113 additions and 13 deletions.
126 changes: 113 additions & 13 deletions source/ResidentEvilRevelations2.FusionFix/dllmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ enum GUI
VirtualScreen = 0x141AC10
};

static IDirect3DVertexShader9* g_screenVertexShader = nullptr;
static IDirect3DPixelShader9* g_wmvYuvDecodePixelShader = nullptr;
static IDirect3DVertexShader9* g_myScreenVertexShader = nullptr;

bool IsSplitScreenActive()
{
auto ptr = *(uint32_t*)0x157AE00;
Expand Down Expand Up @@ -256,7 +260,8 @@ enum
{
RESCALE = 0xAAAAEEEE,
STRETCH = 0xBBBBFFFF,
OFFSET = 0xCCCCDDDD
OFFSET = 0xCCCCDDDD,
SUBTITLES = 0xDDDDDDDD,
};

void __fastcall sub_E18040(int _this, int edx, int a2)
Expand Down Expand Up @@ -361,6 +366,7 @@ void __fastcall sub_E18040(int _this, int edx, int a2)

switch (edx)
{
case SUBTITLES:
case RESCALE:
{
if (IsSplitScreenActive())
Expand All @@ -369,7 +375,7 @@ void __fastcall sub_E18040(int _this, int edx, int a2)
{
v14 = 2.0 / (float)(v28 - v19);
v15 = -2.0 / (float)(v21 - v29);
v13[0] = v14 * v4;
v13[0] = v14 * v4 * ((edx == SUBTITLES) ? (1.0f / GetDiff()) : 1.0f);
v13[1] = v15 * v5;
v13[2] = (float)(v14 * v6) - (1.0f / GetDiff());
v13[3] = (float)(v15 * v7) + 1.0;
Expand All @@ -378,7 +384,7 @@ void __fastcall sub_E18040(int _this, int edx, int a2)
{
v14 = 2.0 / (float)(v28 - v19);
v15 = -2.0 / (float)(v21 - v29);
v13[0] = v14 * v4;
v13[0] = v14 * v4 * ((edx == SUBTITLES) ? (1.0f / GetDiff()) : 1.0f);
v13[1] = v15 * v5;
v13[2] = (float)(v14 * v6) - (1.0f / (GetAspectRatio() / defaultAspectRatio));
v13[3] = (float)(v15 * v7) + 1.0;
Expand All @@ -388,7 +394,7 @@ void __fastcall sub_E18040(int _this, int edx, int a2)
{
v14 = 2.0 / (float)(v28 - v19);
v15 = -2.0 / (float)(v21 - v29);
v13[0] = v14 * v4;
v13[0] = v14 * v4 * ((edx == SUBTITLES) ? (1.0f / GetDiff()) : 1.0f);
v13[1] = v15 * v5;
v13[2] = (float)(v14 * v6) - (1.0f / GetDiff());
v13[3] = (float)(v15 * v7) + 1.0;
Expand Down Expand Up @@ -493,6 +499,11 @@ void __fastcall sub_E18040_nop(int _this, int edx, int a2)

void __fastcall sub_E18040_rescale(int _this, int edx, int a2)
{
auto uBioGUISubtitles = (const char*)(*(uintptr_t*)_this + 0x1B8);

if (!IsBadReadPtr(uBioGUISubtitles, sizeof(char*)) && std::string_view(uBioGUISubtitles) == "uBioGUISubtitles")
return sub_E18040(_this, SUBTITLES, a2);

return sub_E18040(_this, RESCALE, a2);
}

Expand Down Expand Up @@ -521,6 +532,7 @@ IDirect3DVertexShader9* __stdcall CreateVertexShaderHook(const DWORD** a1)
return nullptr;

auto pDevice = (IDirect3DDevice9*)*((uint32_t*)*(uint32_t*)0x15E0388 + 0x26);

IDirect3DVertexShader9* pShader = nullptr;
pDevice->CreateVertexShader(a1[2], &pShader);

Expand All @@ -534,7 +546,6 @@ IDirect3DVertexShader9* __stdcall CreateVertexShaderHook(const DWORD** a1)

pShader->GetFunction(pbFunc.data(), &len);

uint32_t crc32(uint32_t crc, const void* buf, size_t size);
auto crc = crc32(0, pbFunc.data(), len);

// various overlays (low health, waiting for partner, pause text, maybe more)
Expand Down Expand Up @@ -596,17 +607,84 @@ IDirect3DVertexShader9* __stdcall CreateVertexShaderHook(const DWORD** a1)
{
pShaderData = (DWORD*)pCode->GetBufferPointer();
IDirect3DVertexShader9* shader = nullptr;
result = pDevice->CreateVertexShader(pShaderData, &shader);
if (FAILED(result)) {
return pShader;
}
else
if (pDevice->CreateVertexShader(pShaderData, &shader) == D3D_OK)
{
pShader->Release();
return shader;
}
}
}
else if (crc == 0x1287841D)
{
g_screenVertexShader = pShader;

// inject additional, alternative screenspace shader for FMV fixups
constexpr auto src = R"(
struct VS_INPUT {
float4 position : POSITION;
};
struct VS_OUTPUT {
float4 position : POSITION;
float4 uv : TEXCOORD;
};
float2 fScreenHalfPixelOffset : register(c1);
float fHorizontalAspectScale : register(c20);
VS_OUTPUT main(VS_INPUT input)
{
VS_OUTPUT output;
output.position = float4(
-fScreenHalfPixelOffset.x + input.position.x * fHorizontalAspectScale,
fScreenHalfPixelOffset.y + input.position.y,
0.0,
1.0);
output.uv = float4(
1.0 * input.position.z,
1.0 * input.position.w,
0.0, 0.0
);
return output;
})";

LPD3DXBUFFER code;
if (SUCCEEDED(D3DXCompileShader(src, strlen(src), nullptr, nullptr, "main", "vs_3_0", NULL, &code, nullptr, nullptr)))
{
pDevice->CreateVertexShader(reinterpret_cast<const DWORD*>(code->GetBufferPointer()), &g_myScreenVertexShader);
}
}
}

return pShader;
}

IDirect3DPixelShader9* __stdcall CreatePixelShaderHook(const DWORD** a1)
{
if (!a1)
return nullptr;

auto pDevice = (IDirect3DDevice9*)*((uint32_t*)*(uint32_t*)0x15E0388 + 0x26);

IDirect3DPixelShader9* pShader = nullptr;
pDevice->CreatePixelShader(a1[2], &pShader);

if (pShader != nullptr)
{
UINT len;
pShader->GetFunction(nullptr, &len);
std::vector<uint8_t> pbFunc(len, 0);

pShader->GetFunction(pbFunc.data(), &len);

auto crc = crc32(0, pbFunc.data(), len);

if (crc == 0x9D190FC7)
{
g_wmvYuvDecodePixelShader = pShader;
}
}

return pShader;
Expand Down Expand Up @@ -755,7 +833,28 @@ void Init()
});

// movies fix for ultra wide
// ?
{
static auto DrawPrimitiveHook = safetyhook::create_mid(0xCC8788, [](SafetyHookContext& regs)
{
auto g_device = (IDirect3DDevice9*)regs.edi;

// switch to a x-scaling vertex shader if drawing FMVs
IDirect3DPixelShader9* frag;
g_device->GetPixelShader(&frag);
if (frag != g_wmvYuvDecodePixelShader)
return;

IDirect3DVertexShader9* vert;
g_device->GetVertexShader(&vert);
if (vert != g_screenVertexShader)
return;

g_device->SetVertexShader(g_myScreenVertexShader);
const float horzScaleFactor = (defaultAspectRatio / GetAspectRatio());
const std::array<float, 4> shaderConsts = { horzScaleFactor, 0.0f, 0.0f, 0.0f };
g_device->SetVertexShaderConstantF(20, shaderConsts.data(), 1);
});
}

// split screen windows dimensions
injector::MakeCALL(0x4AE6E8, SplitScreenSetupTop, true);
Expand Down Expand Up @@ -805,7 +904,8 @@ void Init()

//disable shader overlays (don't scale to fullscreen)
{
injector::MakeCALL(0xFFB9E2, CreateVertexShaderHook, true);
injector::MakeCALL(0xFFB9E2, CreateVertexShaderHook, true);
injector::MakeCALL(0xFFBA31, CreatePixelShaderHook, true);

//struct SetVertexShaderHook
//{
Expand Down Expand Up @@ -974,7 +1074,7 @@ CEXP void InitializeASI()
{
std::call_once(CallbackHandler::flag, []()
{
CallbackHandler::RegisterCallback(Init, hook::pattern("F3 0F 5C 15 ? ? ? ? F3 0F 59 E5"));
CallbackHandler::RegisterCallbackAtGetSystemTimeAsFileTime(Init, hook::pattern("F3 0F 5C 15 ? ? ? ? F3 0F 59 E5"));
});
}

Expand Down

0 comments on commit cf84aa4

Please sign in to comment.