diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index f8f228f5..c20662a1 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -85,6 +85,7 @@ GPUBlt=0 Use32BitHeadGraphics=0 ;Set to 1 to automatically search for alternative avi video files when Fallout tries to play the game movies +;Set to 2 to force avi videos to fit the screen width ;Requires DX9 graphics mode AllowDShowMovies=0 diff --git a/sfall/FalloutEngine/EngineUtils.cpp b/sfall/FalloutEngine/EngineUtils.cpp index 0939ed38..eccff6df 100644 --- a/sfall/FalloutEngine/EngineUtils.cpp +++ b/sfall/FalloutEngine/EngineUtils.cpp @@ -405,7 +405,7 @@ void ClearWindow(DWORD winID, bool refresh) { call fo::funcoffs::win_width_; mov ecx, eax; mov edx, ebx; - mov eax, winID; //dword ptr ds:[FO_VAR_GNWWin]; + mov eax, winID; call fo::funcoffs::win_fill_; } if (refresh) fo::func::win_draw(winID); diff --git a/sfall/Modules/Graphics.cpp b/sfall/Modules/Graphics.cpp index 3bb12b70..4d00d752 100644 --- a/sfall/Modules/Graphics.cpp +++ b/sfall/Modules/Graphics.cpp @@ -55,6 +55,7 @@ DWORD Graphics::GPUBlt; DWORD Graphics::mode; bool Graphics::PlayAviMovie = false; +bool Graphics::AviMovieWidthFit = false; static BYTE* titlesBuffer = nullptr; @@ -449,8 +450,8 @@ void Graphics::SetMovieTexture(IDirect3DTexture9* tex) { D3DSURFACE_DESC desc; movieTex->GetLevelDesc(0, &desc); - float aspect = (float)desc.Width / (float)desc.Height; - float winaspect = (float)gWidth / (float)gHeight; + float aviAspect = (float)desc.Width / (float)desc.Height; + float winAspect = (float)gWidth / (float)gHeight; VertexFormat ShaderVertices2[4] = { ShaderVertices[0], @@ -464,25 +465,35 @@ void Graphics::SetMovieTexture(IDirect3DTexture9* tex) { ShaderVertices2[3].y = (float)gHeight - 0.5f; ShaderVertices2[3].x = (float)gWidth - 0.5f; - DWORD gap; - if (aspect > winaspect) { - aspect = (float)desc.Width / (float)gWidth; - desc.Height = (int)(desc.Height / aspect); - gap = (gHeight - desc.Height) / 2; + long offset; + if (aviAspect > winAspect) { + // scales height proportionally and places the movie surface at the center of the window along the Y-axis + aviAspect = (float)desc.Width / (float)gWidth; + desc.Height = (int)(desc.Height / aviAspect); - ShaderVertices2[0].y += gap; - ShaderVertices2[2].y += gap; - ShaderVertices2[1].y -= gap; - ShaderVertices2[3].y -= gap; - } else if (aspect < winaspect) { - aspect = (float)desc.Height / (float)gHeight; - desc.Width = (int)(desc.Width / aspect); - gap = (gWidth - desc.Width) / 2; + offset = (gHeight - desc.Height) / 2; - ShaderVertices2[0].x += gap; - ShaderVertices2[2].x -= gap; - ShaderVertices2[3].x -= gap; - ShaderVertices2[1].x += gap; + ShaderVertices2[0].y += offset; + ShaderVertices2[2].y += offset; + ShaderVertices2[1].y -= offset; + ShaderVertices2[3].y -= offset; + } else if (aviAspect < winAspect) { + if (Graphics::AviMovieWidthFit || (hrpIsEnabled && *(DWORD*)HRPAddress(0x1006EC10) == 2)) { + // scales the movie surface to screen width + aviAspect = (float)gWidth / (float)desc.Width; + desc.Width = (int)(desc.Width * aviAspect); + } else { + // scales width proportionally and places the movie surface at the center of the window along the X-axis + aviAspect = (float)desc.Height / (float)gHeight; + desc.Width = (int)(desc.Width / aviAspect); + + offset = (gWidth - desc.Width) / 2; + + ShaderVertices2[0].x += offset; + ShaderVertices2[2].x -= offset; + ShaderVertices2[3].x -= offset; + ShaderVertices2[1].x += offset; + } } byte* VertexPointer; @@ -572,68 +583,6 @@ void Graphics::SetDefaultTechnique() { gpuBltEffect->SetTechnique("T0"); } -class FakePalette2 : IDirectDrawPalette { -private: - ULONG Refs; -public: - FakePalette2() { - Refs = 1; - } - - // IUnknown methods - HRESULT __stdcall QueryInterface(REFIID, LPVOID*) { - return E_NOINTERFACE; - } - - ULONG __stdcall AddRef() { - return ++Refs; - } - - ULONG __stdcall Release() { - if (!--Refs) { - delete this; - return 0; - } else return Refs; - } - - // IDirectDrawPalette methods - HRESULT __stdcall GetCaps(LPDWORD) { UNUSEDFUNCTION; } - HRESULT __stdcall GetEntries(DWORD, DWORD, DWORD, LPPALETTEENTRY) { UNUSEDFUNCTION; } - HRESULT __stdcall Initialize(LPDIRECTDRAW, DWORD, LPPALETTEENTRY) { UNUSEDFUNCTION; } - - /* Called from: - 0x4CB5C7 GNW95_SetPalette_ - 0x4CB36B GNW95_SetPaletteEntries_ - */ - 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; - - CopyMemory(&palette[b], destPal, c * 4); - if (Graphics::GPUBlt) { - if (gpuPalette) { - D3DLOCKED_RECT rect; - if (!FAILED(gpuPalette->LockRect(0, &rect, 0, D3DLOCK_DISCARD))) { - CopyMemory(rect.pBits, palette, 256 * 4); - gpuPalette->UnlockRect(0); - } - } - } else { - // X8B8G8R8 format - for (DWORD i = b; i < b + c; i++) { // swap color B <> R - BYTE clr = *(BYTE*)((DWORD)&palette[i]); // B - *(BYTE*)((DWORD)&palette[i]) = *(BYTE*)((DWORD)&palette[i] + 2); // R - *(BYTE*)((DWORD)&palette[i] + 2) = clr; - } - primaryDDSurface->SetPalette(0); // update - } - if (!Graphics::PlayAviMovie) { - //dlog("\nSetEntries: -> RefreshGraphics", DL_INIT); - RefreshGraphics(); - } - return DD_OK; - } -}; - class FakeSurface2 : IDirectDrawSurface { private: ULONG Refs; @@ -681,10 +630,10 @@ public: movieDesc.lPitch = (a->right - a->left); //xoffset = (ResWidth - movieDesc.lPitch) / 2; - //dlog_f("\nMovieDesc: w:%d, h:%d", DL_INIT, movieDesc.lPitch, movieDesc.dwHeight); + //dlog_f("\nBlt: [MovieDesc: w:%d, h:%d]", DL_INIT, movieDesc.lPitch, movieDesc.dwHeight); IsPlayMovie = true; - if (Graphics::PlayAviMovie) return DD_OK; + //if (Graphics::PlayAviMovie) return DD_OK; BYTE* lockTarget = ((FakeSurface2*)b)->lockTarget; D3DLOCKED_RECT dRect; @@ -745,9 +694,9 @@ public: mainTex->UnlockRect(0); if (!DeviceLost) { + d3d9Device->BeginScene(); d3d9Device->SetStreamSource(0, vBuffer2, 0, sizeof(VertexFormat)); d3d9Device->SetTexture(0, mainTex); - d3d9Device->BeginScene(); if (Graphics::GPUBlt) { UINT unused; gpuBltEffect->Begin(&unused, 0); @@ -839,9 +788,9 @@ public: } HRESULT __stdcall Unlock(LPVOID) { // common game (is primary) - //dlog("\nUnlock()", DL_INIT); + //dlog("\nUnlock", DL_INIT); if (Primary && d3d9Device) { - //dlog(" is primary.", DL_INIT); + //dlog(" - is primary.", DL_INIT); if (DeviceLost) { if (d3d9Device->TestCooperativeLevel() == D3DERR_DEVICENOTRESET) { ResetDevice(false); @@ -942,6 +891,73 @@ start2: bool FakeSurface2::IsPlayMovie; bool FakeSurface2::subTitlesShow; +class FakePalette2 : IDirectDrawPalette { +private: + ULONG Refs; +public: + FakePalette2() { + Refs = 1; + } + + // IUnknown methods + HRESULT __stdcall QueryInterface(REFIID, LPVOID*) { + return E_NOINTERFACE; + } + + ULONG __stdcall AddRef() { + return ++Refs; + } + + ULONG __stdcall Release() { + if (!--Refs) { + delete this; + return 0; + } else return Refs; + } + + // IDirectDrawPalette methods + HRESULT __stdcall GetCaps(LPDWORD) { UNUSEDFUNCTION; } + HRESULT __stdcall GetEntries(DWORD, DWORD, DWORD, LPPALETTEENTRY) { UNUSEDFUNCTION; } + HRESULT __stdcall Initialize(LPDIRECTDRAW, DWORD, LPPALETTEENTRY) { UNUSEDFUNCTION; } + + /* Called from: + 0x4CB5C7 GNW95_SetPalette_ + 0x4CB36B GNW95_SetPaletteEntries_ + */ + 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; + + CopyMemory(&palette[b], destPal, c * 4); + if (Graphics::GPUBlt) { + if (gpuPalette) { + D3DLOCKED_RECT rect; + if (!FAILED(gpuPalette->LockRect(0, &rect, 0, D3DLOCK_DISCARD))) { + CopyMemory(rect.pBits, palette, 256 * 4); + gpuPalette->UnlockRect(0); + } + } + } else { + // X8B8G8R8 format + for (DWORD i = b; i < b + c; i++) { // swap color B <> R + BYTE clr = *(BYTE*)((DWORD)&palette[i]); // B + *(BYTE*)((DWORD)&palette[i]) = *(BYTE*)((DWORD)&palette[i] + 2); // R + *(BYTE*)((DWORD)&palette[i] + 2) = clr; + } + primaryDDSurface->SetPalette(0); // update + if (FakeSurface2::IsPlayMovie) return DD_OK; // prevents flickering at the beginning of playback (w/o HRP & GPUBlt=2) + } + if (!Graphics::PlayAviMovie) { + //dlog("\nSetEntries: -> RefreshGraphics", DL_INIT); + RefreshGraphics(); + } else { + // only for debugging + //dlog("\nSetEntries: -> ShowMovieFrame", DL_INIT); + //Graphics::ShowMovieFrame(); + } + return DD_OK; + } +}; + class FakeDirectDraw2 : IDirectDraw { private: diff --git a/sfall/Modules/Graphics.h b/sfall/Modules/Graphics.h index 5aa2611d..ff657d5c 100644 --- a/sfall/Modules/Graphics.h +++ b/sfall/Modules/Graphics.h @@ -50,6 +50,7 @@ public: static void SetMovieTexture(IDirect3DTexture9* tex); static bool PlayAviMovie; + static bool AviMovieWidthFit; }; extern IDirect3D9* d3d9; diff --git a/sfall/Modules/Movies.cpp b/sfall/Modules/Movies.cpp index 83f39313..2e030bdc 100644 --- a/sfall/Modules/Movies.cpp +++ b/sfall/Modules/Movies.cpp @@ -523,10 +523,14 @@ void Movies::init() { WIP: Task Implement subtitle output from the need to play an mve file in the background. */ - if (Graphics::mode != 0 && GetConfigInt("Graphics", "AllowDShowMovies", 0)) { - MakeJump(0x44E690, gmovie_play_hack); - HookCall(0x44E993, gmovie_play_hook_stop); - /* NOTE: At this address 0x487781, HRP changes the callback procedure to display mve frames. */ + if (Graphics::mode != 0) { + int allowDShowMovies = GetConfigInt("Graphics", "AllowDShowMovies", 0); + if (allowDShowMovies > 0) { + MakeJump(0x44E690, gmovie_play_hack); + HookCall(0x44E993, gmovie_play_hook_stop); + if (allowDShowMovies > 1) Graphics::AviMovieWidthFit = true; + /* NOTE: At this address 0x487781, HRP changes the callback procedure to display mve frames. */ + } } dlogr(" Done", DL_INIT); diff --git a/sfall/main.h b/sfall/main.h index e573372e..738c5359 100644 --- a/sfall/main.h +++ b/sfall/main.h @@ -17,9 +17,10 @@ */ #pragma once -#pragma warning(disable:4996) +#pragma warning(disable: 4996) // function or variable may be unsafe +#pragma warning(disable: 4995) // 'function': name was marked as #pragma deprecated #ifdef NDEBUG -#pragma warning(disable:4414) +#pragma warning(disable: 4414) // 'function': short jump to function converted to near #endif #include