diff --git a/sfall/FalloutEngine.cpp b/sfall/FalloutEngine.cpp index bad851af..16dd6a79 100644 --- a/sfall/FalloutEngine.cpp +++ b/sfall/FalloutEngine.cpp @@ -399,6 +399,7 @@ const DWORD gsnd_build_weapon_sfx_name_ = 0x451760; const DWORD gsound_background_pause_ = 0x450B50; const DWORD gsound_background_stop_ = 0x450AB4; const DWORD gsound_background_unpause_ = 0x450B64; +const DWORD gsound_background_volume_get_set_ = 0x450620; const DWORD gsound_play_sfx_file_ = 0x4519A8; const DWORD gsound_red_butt_press_ = 0x451970; const DWORD gsound_red_butt_release_ = 0x451978; @@ -518,6 +519,7 @@ const DWORD mouse_hide_ = 0x4CA534; const DWORD mouse_in_ = 0x4CA8C8; const DWORD mouse_show_ = 0x4CA34C; const DWORD move_inventory_ = 0x474708; +const DWORD movieUpdate_ = 0x487BEC; const DWORD new_obj_id_ = 0x4A386C; const DWORD NixHotLines_ = 0x4999C0; const DWORD nrealloc_ = 0x4F1669; @@ -1137,6 +1139,10 @@ long __fastcall WordWrap(const char* text, int maxWidth, DWORD* buf, BYTE* count WRAP_WATCOM_FCALL4(_word_wrap_, text, maxWidth, buf, count) } +long __stdcall GSoundBackgroundVolumeGetSet(long setVolume) { + WRAP_WATCOM_CALL1(gsound_background_volume_get_set_, setVolume) +} + WINinfo* __stdcall GNWFind(long winRef) { WRAP_WATCOM_CALL1(GNW_find_, winRef) } diff --git a/sfall/FalloutEngine.h b/sfall/FalloutEngine.h index 34599310..43a329f4 100644 --- a/sfall/FalloutEngine.h +++ b/sfall/FalloutEngine.h @@ -228,6 +228,7 @@ #define _stack_offset 0x59E844 #define _stat_data 0x51D53C #define _stat_flag 0x66452A +#define _subtitles 0x663974 #define _sWindows 0x6727B0 #define _Tag_ 0x5708B0 #define _tag_skill 0x668070 @@ -638,6 +639,7 @@ extern const DWORD gsnd_build_weapon_sfx_name_; extern const DWORD gsound_background_pause_; extern const DWORD gsound_background_stop_; extern const DWORD gsound_background_unpause_; +extern const DWORD gsound_background_volume_get_set_; extern const DWORD gsound_play_sfx_file_; extern const DWORD gsound_red_butt_press_; extern const DWORD gsound_red_butt_release_; @@ -763,6 +765,7 @@ extern const DWORD mouse_hide_; extern const DWORD mouse_in_; extern const DWORD mouse_show_; extern const DWORD move_inventory_; +extern const DWORD movieUpdate_; extern const DWORD new_obj_id_; extern const DWORD NixHotLines_; extern const DWORD nrealloc_; @@ -1160,6 +1163,8 @@ long __fastcall GetGameConfigString(const char* outValue, const char* section, c long __fastcall WordWrap(const char* text, int maxWidth, DWORD* buf, BYTE* count); +long __stdcall GSoundBackgroundVolumeGetSet(long setVolume); + WINinfo* __stdcall GNWFind(long winRef); DWORD __stdcall WinAdd(long x, long y, long width, long height, long bgColorIndex, long flags); diff --git a/sfall/Graphics.cpp b/sfall/Graphics.cpp index 9dc55080..3904b692 100644 --- a/sfall/Graphics.cpp +++ b/sfall/Graphics.cpp @@ -21,15 +21,12 @@ #define DEBUGMESS(a, b) OutputDebugStringA(a b) #else #ifndef NDEBUG -#define DEBUGMESS(a, b) DebugPrintf(a, b) +#define DEBUGMESS(a, b) MessageBoxA(0, "Unused function called.", b, MB_TASKMODAL) //DebugPrintf(a, b) #else #define DEBUGMESS(a, b) #endif #endif -#include -#include -#include #include "main.h" @@ -51,13 +48,15 @@ static DWORD ResHeight; DWORD GPUBlt; DWORD GraphicsMode; +bool PlayAviMovie = false; + static BYTE* titlesBuffer = nullptr; -static DWORD movieHeight = 0; -//static DWORD movieWidth = 0; -static DWORD yoffset; -//static DWORD xoffset; + +static DWORD yoffset, movieHeight = 0; +//static DWORD xoffset, movieWidth = 0; static bool DeviceLost = false; + static DDSURFACEDESC surfaceDesc; static DDSURFACEDESC movieDesc; @@ -68,29 +67,34 @@ static DWORD gWidth; static DWORD gHeight; static int ScrollWindowKey; + static bool windowInit = false; static DWORD windowLeft = 0; static DWORD windowTop = 0; +static HWND window; static DWORD ShaderVersion; -static HWND window; IDirect3D9* d3d9 = 0; IDirect3DDevice9* d3d9Device = 0; + static IDirect3DTexture9* Tex = 0; static IDirect3DTexture9* sTex1 = 0; static IDirect3DTexture9* sTex2 = 0; + static IDirect3DSurface9* sSurf1 = 0; static IDirect3DSurface9* sSurf2 = 0; static IDirect3DSurface9* backbuffer = 0; + static IDirect3DVertexBuffer9* vBuffer; static IDirect3DVertexBuffer9* vBuffer2; static IDirect3DVertexBuffer9* movieBuffer; + static IDirect3DTexture9* gpuPalette; static IDirect3DTexture9* movieTex = 0; static ID3DXEffect* gpuBltEffect; -static const char* gpuEffect= +static const char* gpuEffect = "texture image;" "texture palette;" "texture head;" @@ -154,22 +158,28 @@ struct sShader { static std::vector shaders; static std::vector shaderTextures; -#define MYVERTEXFORMAT D3DFVF_XYZRHW|D3DFVF_TEX1 -struct MyVertex { - float x,y,z,w,u,v; +#define _VERTEXFORMAT D3DFVF_XYZRHW|D3DFVF_TEX1 + +struct VertexFormat { + float x, y, z, w, u, v; }; -static MyVertex ShaderVertices[] = { +static VertexFormat ShaderVertices[] = { + // x y z rhw u v {-0.5, -0.5, 0, 1, 0, 0}, {-0.5, 479.5, 0, 1, 0, 1}, {639.5, -0.5, 0, 1, 1, 0}, {639.5, 479.5, 0, 1, 1, 1} }; -void GetFalloutWindowInfo(DWORD* width, DWORD* height, HWND* wnd) { - *width = gWidth; - *height = gHeight; - *wnd = window; +HWND GetFalloutWindowInfo(RECT* rect) { + if (rect) { + rect->left = windowLeft; + rect->top = windowTop; + rect->right = gWidth; + rect->bottom = gHeight; + } + return window; } long Gfx_GetGameWidthRes() { @@ -297,35 +307,45 @@ static void WindowInit() { LoadGlobalShader(); } -static void ResetDevice(bool CreateNew) { +static void GetDisplayMode(D3DDISPLAYMODE &ddm) { + ZeroMemory(&ddm, sizeof(ddm)); + d3d9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &ddm); + dlog_f("Display mode format id: %d\n", DL_INIT, ddm.Format); +} + +static void ResetDevice(bool createNew) { D3DPRESENT_PARAMETERS params; ZeroMemory(¶ms, sizeof(params)); + + D3DDISPLAYMODE dispMode; + GetDisplayMode(dispMode); + params.BackBufferCount = 1; - params.BackBufferFormat = (GraphicsMode == 5) ? D3DFMT_UNKNOWN : D3DFMT_X8R8G8B8; + params.BackBufferFormat = dispMode.Format; // (GraphicsMode == 5) ? D3DFMT_UNKNOWN : D3DFMT_X8R8G8B8; params.BackBufferWidth = gWidth; params.BackBufferHeight = gHeight; params.EnableAutoDepthStencil = false; - params.MultiSampleQuality = 0; - params.MultiSampleType = D3DMULTISAMPLE_NONE; + //params.MultiSampleQuality = 0; + //params.MultiSampleType = D3DMULTISAMPLE_NONE; params.Windowed = (GraphicsMode == 5); params.SwapEffect = D3DSWAPEFFECT_DISCARD; params.hDeviceWindow = window; params.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + if (!params.Windowed) params.FullScreen_RefreshRateInHz = dispMode.RefreshRate; bool software = false; - if (CreateNew) { + if (createNew) { dlog("Creating D3D9 Device...", DL_MAIN); - if (FAILED(d3d9->CreateDevice(0, D3DDEVTYPE_HAL, window, D3DCREATE_PUREDEVICE | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE, ¶ms, &d3d9Device))) { + if (FAILED(d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window, D3DCREATE_PUREDEVICE | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE, ¶ms, &d3d9Device))) { + dlog(" Failed to create D3D9 Device. Use software vertex processing.", DL_MAIN); software = true; - d3d9->CreateDevice(0, D3DDEVTYPE_HAL, window, D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE, ¶ms, &d3d9Device); + d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window, D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE, ¶ms, &d3d9Device); } D3DCAPS9 caps; d3d9Device->GetDeviceCaps(&caps); - ShaderVersion = ((caps.PixelShaderVersion & 0x0000ff00) >> 8) * 10 + (caps.PixelShaderVersion & 0xff); + ShaderVersion = ((caps.PixelShaderVersion & 0x0000FF00) >> 8) * 10 + (caps.PixelShaderVersion & 0xFF); - if (GPUBlt == 2) { - if (ShaderVersion < 20) GPUBlt = 0; - } + if (GPUBlt == 2 && ShaderVersion < 20) GPUBlt = 0; if (GPUBlt) { D3DXCreateEffect(d3d9Device, gpuEffect, strlen(gpuEffect), 0, 0, 0, 0, &gpuBltEffect, 0); @@ -367,15 +387,15 @@ static void ResetDevice(bool CreateNew) { sTex2->GetSurfaceLevel(0, &sSurf2); d3d9Device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer); - d3d9Device->CreateVertexBuffer(4 * sizeof(MyVertex), D3DUSAGE_WRITEONLY | (software ? D3DUSAGE_SOFTWAREPROCESSING : 0), MYVERTEXFORMAT, D3DPOOL_DEFAULT, &vBuffer, 0); + d3d9Device->CreateVertexBuffer(4 * sizeof(VertexFormat), D3DUSAGE_WRITEONLY | (software ? D3DUSAGE_SOFTWAREPROCESSING : 0), _VERTEXFORMAT, D3DPOOL_DEFAULT, &vBuffer, 0); byte* VertexPointer; vBuffer->Lock(0, 0, (void**)&VertexPointer, 0); CopyMemory(VertexPointer, ShaderVertices, sizeof(ShaderVertices)); vBuffer->Unlock(); - d3d9Device->CreateVertexBuffer(4 * sizeof(MyVertex), D3DUSAGE_WRITEONLY | (software ? D3DUSAGE_SOFTWAREPROCESSING : 0), MYVERTEXFORMAT, D3DPOOL_DEFAULT, &movieBuffer, 0); + d3d9Device->CreateVertexBuffer(4 * sizeof(VertexFormat), D3DUSAGE_WRITEONLY | (software ? D3DUSAGE_SOFTWAREPROCESSING : 0), _VERTEXFORMAT, D3DPOOL_DEFAULT, &movieBuffer, 0); - MyVertex ShaderVertices2[4] = { + VertexFormat ShaderVertices2[4] = { ShaderVertices[0], ShaderVertices[1], ShaderVertices[2], @@ -387,40 +407,42 @@ static void ResetDevice(bool CreateNew) { ShaderVertices2[3].y = (float)gHeight - 0.5f; ShaderVertices2[3].x = (float)gWidth - 0.5f; - d3d9Device->CreateVertexBuffer(4 * sizeof(MyVertex), D3DUSAGE_WRITEONLY | (software ? D3DUSAGE_SOFTWAREPROCESSING : 0), MYVERTEXFORMAT, D3DPOOL_DEFAULT, &vBuffer2, 0); + d3d9Device->CreateVertexBuffer(4 * sizeof(VertexFormat), D3DUSAGE_WRITEONLY | (software ? D3DUSAGE_SOFTWAREPROCESSING : 0), _VERTEXFORMAT, D3DPOOL_DEFAULT, &vBuffer2, 0); vBuffer2->Lock(0, 0, (void**)&VertexPointer, 0); CopyMemory(VertexPointer, ShaderVertices2, sizeof(ShaderVertices2)); vBuffer2->Unlock(); - d3d9Device->SetFVF(MYVERTEXFORMAT); + d3d9Device->SetFVF(_VERTEXFORMAT); d3d9Device->SetTexture(0, Tex); - d3d9Device->SetStreamSource(0, vBuffer, 0, sizeof(MyVertex)); + d3d9Device->SetStreamSource(0, vBuffer, 0, sizeof(VertexFormat)); - d3d9Device->SetRenderState(D3DRS_ALPHABLENDENABLE, false); // default false - d3d9Device->SetRenderState(D3DRS_ALPHATESTENABLE, false); // default false + //d3d9Device->SetRenderState(D3DRS_ALPHABLENDENABLE, false); // default false + //d3d9Device->SetRenderState(D3DRS_ALPHATESTENABLE, false); // default false d3d9Device->SetRenderState(D3DRS_ZENABLE, false); d3d9Device->SetRenderState(D3DRS_CULLMODE, 2); //d3d9Device->SetRenderState(D3DRS_TEXTUREFACTOR, 0); - if (CreateNew) dlogr(" Done.", DL_MAIN); + if (createNew) dlogr(" Done", DL_MAIN); } static void Present() { if (ScrollWindowKey != 0 && ((ScrollWindowKey > 0 && KeyDown((BYTE)ScrollWindowKey)) || (ScrollWindowKey == -1 && (KeyDown(DIK_LCONTROL) || KeyDown(DIK_RCONTROL))) - || (ScrollWindowKey == -2 && (KeyDown(DIK_LMENU) || KeyDown(DIK_RMENU))) - || (ScrollWindowKey == -3 && (KeyDown(DIK_LSHIFT) || KeyDown(DIK_RSHIFT))))) + || (ScrollWindowKey == -2 && (KeyDown(DIK_LMENU) || KeyDown(DIK_RMENU))) + || (ScrollWindowKey == -3 && (KeyDown(DIK_LSHIFT) || KeyDown(DIK_RSHIFT))))) { int winx, winy; GetMouse(&winx, &winy); windowLeft += winx; windowTop += winy; + RECT r, r2; r.left = windowLeft; r.right = windowLeft + gWidth; r.top = windowTop; r.bottom = windowTop + gHeight; AdjustWindowRect(&r, WS_OVERLAPPED | WS_CAPTION | WS_BORDER, false); + r.right -= (r.left - windowLeft); r.left = windowLeft; r.bottom -= (r.top - windowTop); @@ -455,6 +477,9 @@ static void Present() { } if (d3d9Device->Present(0, 0, 0, 0) == D3DERR_DEVICELOST) { + #ifndef NDEBUG + dlogr("Present: DEVICELOST", DL_MAIN); + #endif d3d9Device->SetTexture(0, 0); SAFERELEASE(Tex) SAFERELEASE(backbuffer); @@ -476,10 +501,9 @@ static void Present() { void RefreshGraphics() { if (DeviceLost) return; - //Tex->UnlockRect(0); + d3d9Device->BeginScene(); - //d3d9Device->SetFVF(D3DFVF_XYZRHW|D3DFVF_TEX1); - d3d9Device->SetStreamSource(0, vBuffer, 0, sizeof(MyVertex)); + d3d9Device->SetStreamSource(0, vBuffer, 0, sizeof(VertexFormat)); d3d9Device->SetRenderTarget(0, sSurf1); if (GPUBlt && shadersSize) { @@ -513,7 +537,7 @@ void RefreshGraphics() { d3d9Device->SetTexture(0, sTex2); } - d3d9Device->SetStreamSource(0, vBuffer2, 0, sizeof(MyVertex)); + d3d9Device->SetStreamSource(0, vBuffer2, 0, sizeof(VertexFormat)); d3d9Device->SetRenderTarget(0, backbuffer); if (GPUBlt && !shadersSize) { UINT unused; @@ -525,20 +549,26 @@ void RefreshGraphics() { gpuBltEffect->EndPass(); gpuBltEffect->End(); } + d3d9Device->EndScene(); Present(); } -void SetMovieTexture(void* tex) { - movieTex = (IDirect3DTexture9*)tex; +void Gfx_SetMovieTexture(IDirect3DTexture9* tex) { + dlog("\nSet movie texture.", DL_INIT); + movieTex = tex; + if (!tex) { + PlayAviMovie = false; + return; + } + D3DSURFACE_DESC desc; movieTex->GetLevelDesc(0, &desc); + float aspect = (float)desc.Width / (float)desc.Height; float winaspect = (float)gWidth / (float)gHeight; - byte* VertexPointer; - movieBuffer->Lock(0, 0, (void**)&VertexPointer, 0); - MyVertex ShaderVertices2[4] = { + VertexFormat ShaderVertices2[4] = { ShaderVertices[0], ShaderVertices[1], ShaderVertices[2], @@ -564,20 +594,49 @@ void SetMovieTexture(void* tex) { aspect = (float)desc.Height / (float)gHeight; desc.Width = (int)(desc.Width / aspect); gap = (gWidth - desc.Width) / 2; + ShaderVertices2[0].x += gap; ShaderVertices2[2].x -= gap; ShaderVertices2[3].x -= gap; ShaderVertices2[1].x += gap; } + + byte* VertexPointer; + movieBuffer->Lock(0, 0, (void**)&VertexPointer, 0); CopyMemory(VertexPointer, ShaderVertices2, sizeof(ShaderVertices2)); movieBuffer->Unlock(); + + PlayAviMovie = true; } -void _stdcall PlayMovieFrame() { - d3d9Device->SetTexture(0, movieTex); - d3d9Device->SetStreamSource(0, movieBuffer, 0, sizeof(MyVertex)); +void Gfx_ShowMovieFrame() { + //d3d9Device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255, 0, 255), 1.0f, 0); // for debbuging d3d9Device->BeginScene(); + + if (GPUBlt && shadersSize) { + d3d9Device->SetTexture(0, sTex2); + } else { + d3d9Device->SetTexture(0, Tex); + } + d3d9Device->SetStreamSource(0, vBuffer2, 0, sizeof(VertexFormat)); + d3d9Device->SetRenderTarget(0, backbuffer); + + if (GPUBlt /*&& !shadersSize*/) { + UINT unused; + gpuBltEffect->Begin(&unused, 0); + gpuBltEffect->BeginPass(0); + } d3d9Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + if (GPUBlt /*&& !shadersSize*/) { + gpuBltEffect->EndPass(); + gpuBltEffect->End(); + } + + // for movie + d3d9Device->SetTexture(0, movieTex); + d3d9Device->SetStreamSource(0, movieBuffer, 0, sizeof(VertexFormat)); + d3d9Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + d3d9Device->EndScene(); Present(); } @@ -646,7 +705,11 @@ public: HRESULT _stdcall GetEntries(DWORD, DWORD, DWORD, LPPALETTEENTRY) { UNUSEDFUNCTION; } HRESULT _stdcall Initialize(LPDIRECTDRAW, DWORD, LPPALETTEENTRY) { UNUSEDFUNCTION; } - HRESULT _stdcall SetEntries(DWORD, DWORD b, DWORD c, LPPALETTEENTRY destPal) { + /* Called from: + 0x4CB5C7 GNW95_SetPalette_ + 0x4CB36B GNW95_SetPaletteEntries_ + */ + HRESULT _stdcall SetEntries(DWORD, 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); @@ -666,7 +729,11 @@ public: *(BYTE*)((DWORD)&palette[i] + 2) = clr; } } - RefreshGraphics(); + if (!PlayAviMovie) { + RefreshGraphics(); + } else { + Gfx_ShowMovieFrame(); + } return DD_OK; } }; @@ -676,14 +743,16 @@ private: ULONG Refs; bool Primary; BYTE* lockTarget; + +public: static bool IsPlayMovie; static bool subTitlesShow; -public: FakeSurface2(bool primary) { Refs = 1; Primary = primary; lockTarget = new BYTE[ResWidth * ResHeight]; + if (!windowInit) std::memset(lockTarget, 0, ResWidth * ResHeight); } // IUnknown methods @@ -707,10 +776,12 @@ public: HRESULT _stdcall AddAttachedSurface(LPDIRECTDRAWSURFACE) { UNUSEDFUNCTION; } HRESULT _stdcall AddOverlayDirtyRect(LPRECT) { UNUSEDFUNCTION; } - HRESULT _stdcall Blt(LPRECT a, LPDIRECTDRAWSURFACE b, LPRECT c, DWORD d, LPDDBLTFX e) { // for game movies (is not primary) - //if (((FakeSurface2*)b)->Primary) return DD_OK; // for testing + HRESULT _stdcall Blt(LPRECT a, LPDIRECTDRAWSURFACE b, LPRECT c, DWORD d, LPDDBLTFX e) { // used for game movies (is not primary) + //dlog("\nBlt()", DL_INIT); IsPlayMovie = true; + if (PlayAviMovie) return DD_OK; + movieHeight = (a->bottom - a->top); yoffset = (ResHeight - movieHeight) / 2; //movieWidth = (a->right - a->left); @@ -773,7 +844,7 @@ public: Tex->UnlockRect(0); if (!DeviceLost) { - d3d9Device->SetStreamSource(0, vBuffer2, 0, sizeof(MyVertex)); + d3d9Device->SetStreamSource(0, vBuffer2, 0, sizeof(VertexFormat)); d3d9Device->SetTexture(0, Tex); d3d9Device->BeginScene(); if (GPUBlt) { @@ -812,8 +883,18 @@ public: HRESULT _stdcall Initialize(LPDIRECTDRAW, LPDDSURFACEDESC) { UNUSEDFUNCTION; } HRESULT _stdcall IsLost() { UNUSEDFUNCTION; } + /* Called from: + 0x4CB887 GNW95_ShowRect_ (c=1) + 0x48699D movieShowFrame_ (c=0) + 0x4CBBFA GNW95_zero_vid_mem_ (c=1) + */ HRESULT _stdcall Lock(LPRECT a, LPDDSURFACEDESC b, DWORD c, HANDLE d) { *b = (Primary) ? surfaceDesc : movieDesc; + /*if (Primary) { + dlog("\nLock() uses surfaceDesc.", DL_INIT); + } else { + dlog("\nLock() uses movieDesc.", DL_INIT); + }*/ b->lpSurface = lockTarget; return DD_OK; } @@ -833,7 +914,9 @@ public: } HRESULT _stdcall Unlock(LPVOID) { // common game (is primary) + //dlog("\nUnlock()", DL_INIT); if (Primary && d3d9Device) { + //dlog(" is primary.", DL_INIT); if (DeviceLost) { if (d3d9Device->TestCooperativeLevel() == D3DERR_DEVICENOTRESET) { ResetDevice(false); @@ -915,7 +998,7 @@ start2: } } Tex->UnlockRect(0); - if (!IsPlayMovie) { + if (!IsPlayMovie && !PlayAviMovie) { subTitlesShow = false; RefreshGraphics(); }; @@ -944,9 +1027,10 @@ public: // IUnknown methods HRESULT _stdcall QueryInterface(REFIID, LPVOID*) { return E_NOINTERFACE; } + ULONG _stdcall AddRef() { return ++Refs; } - ULONG _stdcall Release() { + ULONG _stdcall Release() { // called from game on exit if (!--Refs) { globalShaderActive = false; GraphicsResetOnGameLoad(); @@ -965,7 +1049,6 @@ public: SAFERELEASE(gpuPalette); SAFERELEASE(gpuBltEffect); SAFERELEASE(movieBuffer); - SAFERELEASE(movieTex); delete this; return 0; } else return Refs; @@ -981,9 +1064,11 @@ public: } HRESULT _stdcall CreateSurface(LPDDSURFACEDESC a, LPDIRECTDRAWSURFACE* b, IUnknown* c) { - if (a->dwFlags == 1 && a->ddsCaps.dwCaps == DDSCAPS_PRIMARYSURFACE) + //dlog("\nCreateSurface", DL_INIT); + if (a->dwFlags == 1 && a->ddsCaps.dwCaps == DDSCAPS_PRIMARYSURFACE) { + //dlog(" primary.", DL_INIT); *b = (IDirectDrawSurface*)new FakeSurface2(true); - else + } else *b = (IDirectDrawSurface*)new FakeSurface2(false); return DD_OK; @@ -1007,13 +1092,13 @@ public: window = a; if (!d3d9Device) { - ResetDevice(true); CoInitialize(0); + ResetDevice(true); // create } dlog("Creating D3D9 Device window...", DL_MAIN); if (GraphicsMode == 5) { - SetWindowLong(a, GWL_STYLE, WS_OVERLAPPED | WS_CAPTION | WS_BORDER); + SetWindowLong(a, GWL_STYLE, WS_OVERLAPPED | WS_CAPTION | WS_BORDER | WS_MINIMIZEBOX); RECT r; r.left = 0; r.right = gWidth; @@ -1024,10 +1109,10 @@ public: r.left = 0; r.bottom -= r.top; r.top = 0; - SetWindowPos(a, HWND_NOTOPMOST, 0, 0, r.right, r.bottom, SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_SHOWWINDOW); + SetWindowPos(a, HWND_NOTOPMOST, r.left, r.top, r.right, r.bottom, SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_SHOWWINDOW); } - dlogr(" Done.", DL_MAIN); + dlogr(" Done", DL_MAIN); return DD_OK; } @@ -1046,18 +1131,21 @@ HRESULT _stdcall FakeDirectDrawCreate2(void*, IDirectDraw** b, void*) { } ZeroMemory(&surfaceDesc, sizeof(DDSURFACEDESC)); + surfaceDesc.dwSize = sizeof(DDSURFACEDESC); surfaceDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_PITCH; surfaceDesc.dwWidth = ResWidth; surfaceDesc.dwHeight = ResHeight; surfaceDesc.ddpfPixelFormat.dwRGBBitCount = 16; surfaceDesc.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); - surfaceDesc.ddpfPixelFormat.dwRBitMask = 0xf800; - surfaceDesc.ddpfPixelFormat.dwGBitMask = 0x7e0; - surfaceDesc.ddpfPixelFormat.dwBBitMask = 0x1f; + surfaceDesc.ddpfPixelFormat.dwRBitMask = 0xF800; // 1111100000000000 + surfaceDesc.ddpfPixelFormat.dwGBitMask = 0x7E0; // 0000011111100000 + surfaceDesc.ddpfPixelFormat.dwBBitMask = 0x1F; // 0000000000011111 surfaceDesc.ddpfPixelFormat.dwFlags = DDPF_RGB; surfaceDesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE; surfaceDesc.lPitch = ResWidth; + + // set params for .mve surface movieDesc = surfaceDesc; movieDesc.lPitch = 640; movieDesc.dwHeight = 480; @@ -1070,8 +1158,9 @@ HRESULT _stdcall FakeDirectDrawCreate2(void*, IDirectDraw** b, void*) { gHeight = ResHeight; } GPUBlt = GetConfigInt("Graphics", "GPUBlt", 0); - if (!GPUBlt || GPUBlt > 2) GPUBlt = 2; // Swap them around to keep compatibility with old ddraw.ini's - else if (GPUBlt == 2) GPUBlt = 0; // Use CPU + if (!GPUBlt || GPUBlt > 2) + GPUBlt = 2; // Swap them around to keep compatibility with old ddraw.ini + else if (GPUBlt == 2) GPUBlt = 0; // Use CPU if (GraphicsMode == 5) { ScrollWindowKey = GetConfigInt("Input", "WindowScrollKey", 0); @@ -1082,7 +1171,7 @@ HRESULT _stdcall FakeDirectDrawCreate2(void*, IDirectDraw** b, void*) { *b = (IDirectDraw*)new FakeDirectDraw2(); - dlogr(" Done.", DL_MAIN); + dlogr(" Done", DL_MAIN); return DD_OK; } diff --git a/sfall/Graphics.h b/sfall/Graphics.h index 3d08d250..3e647436 100644 --- a/sfall/Graphics.h +++ b/sfall/Graphics.h @@ -27,6 +27,8 @@ extern DWORD GraphicsMode; extern DWORD GPUBlt; +extern bool PlayAviMovie; + extern IDirect3D9* d3d9; extern IDirect3DDevice9* d3d9Device; @@ -55,7 +57,7 @@ int _stdcall GetShaderTexture(DWORD d, DWORD id); void _stdcall SetShaderTexture(DWORD d, const char* param, DWORD value); void RefreshGraphics(); -void GetFalloutWindowInfo(DWORD* width, DWORD* height, HWND* window); +HWND GetFalloutWindowInfo(RECT* rect); -void SetMovieTexture(void* tex); -void _stdcall PlayMovieFrame(); +void Gfx_SetMovieTexture(IDirect3DTexture9* tex); +void Gfx_ShowMovieFrame(); diff --git a/sfall/Movies.cpp b/sfall/Movies.cpp index c1d8baf4..074d0e3a 100644 --- a/sfall/Movies.cpp +++ b/sfall/Movies.cpp @@ -16,8 +16,6 @@ * along with this program. If not, see . */ -//#include // should be above DX SDK includes to avoid warning 4995 - #include #include #include @@ -32,42 +30,33 @@ static DWORD MoviePtrs[MaxMovies]; char MoviePaths[MaxMovies * 65]; +static bool aviIsReadyToPlay = false; + class CAllocator : public IVMRSurfaceAllocator9, IVMRImagePresenter9 { private: - IDirect3DSurface9* surface; - IVMRSurfaceAllocatorNotify9 *pAllocNotify; ULONG RefCount; - IDirect3DTexture9* ptex; + IVMRSurfaceAllocatorNotify9 *pAllocNotify; -public: - IDirect3DTexture9* tex; + std::vector surfaces; + IDirect3DTexture9* pTex; + IDirect3DTexture9* mTex; - CAllocator() { - RefCount = 1; - surface = nullptr; - pAllocNotify = nullptr; - tex = nullptr; - ptex = nullptr; - } + HRESULT __stdcall TerminateDevice(DWORD_PTR dwID) { + dlog_f("\nTerminate Device id: %d\n", DL_INIT, dwID); - ULONG _stdcall AddRef() { - return ++RefCount; - } + SAFERELEASE(pTex); + SAFERELEASE(mTex); - ULONG _stdcall Release() { - if (--RefCount == 0) { - TerminateDevice(0); - if (pAllocNotify) { - pAllocNotify->Release(); - pAllocNotify = nullptr; - } + for (std::vector::iterator it = surfaces.begin(); it != surfaces.end(); ++it) { + SAFERELEASE((*it)); } - return RefCount; + surfaces.clear(); + + return S_OK; } - HRESULT _stdcall QueryInterface(const IID &riid, void** ppvObject) { + HRESULT __stdcall QueryInterface(const IID &riid, void** ppvObject) { HRESULT hr = E_NOINTERFACE; - if (ppvObject == nullptr) { hr = E_POINTER; } else if (riid == IID_IVMRSurfaceAllocator9) { @@ -83,84 +72,123 @@ public: AddRef(); hr = S_OK; } + return hr; + } + + HRESULT __stdcall InitializeDevice(DWORD_PTR dwUserID, VMR9AllocationInfo *lpAllocInfo, DWORD *lpNumBuffers) { + dlog("\nInitialize Device:", DL_INIT); + + lpAllocInfo->dwFlags |= VMR9AllocFlag_TextureSurface; + lpAllocInfo->Pool = D3DPOOL_SYSTEMMEM; + + // Ask the VMR-9 to allocate the surfaces for us. + for (std::vector::iterator it = surfaces.begin(); it != surfaces.end(); ++it) { + SAFERELEASE((*it)); + } + surfaces.resize(*lpNumBuffers); + + HRESULT hr = pAllocNotify->AllocateSurfaceHelper(lpAllocInfo, lpNumBuffers, &surfaces[0]); + if (FAILED(hr)) return hr; + + dlog_f(" Height: %d,", DL_INIT, lpAllocInfo->dwHeight); + dlog_f(" Width: %d,", DL_INIT, lpAllocInfo->dwWidth); + dlog_f(" Format: %d", DL_INIT, lpAllocInfo->Format); + + hr = surfaces[0]->GetContainer(IID_IDirect3DTexture9, (void**)&pTex); + if (FAILED(hr)) { + TerminateDevice(-1); + return hr; + } + + if (d3d9Device->CreateTexture(lpAllocInfo->dwWidth, lpAllocInfo->dwHeight, 1, 0, lpAllocInfo->Format, D3DPOOL_DEFAULT, &mTex, nullptr) != D3D_OK) { + dlog(" Failed to create movie texture!", DL_INIT); + } + return S_OK; + } + + HRESULT __stdcall GetSurface(DWORD_PTR dwUserID, DWORD surfaceIndex, DWORD surfaceFlags, IDirect3DSurface9 **lplpSurface) { + dlog_f("\nGet Surface index: %d", DL_INIT, surfaceIndex); + if (surfaceIndex >= surfaces.size()) return E_FAIL; + + *lplpSurface = surfaces[surfaceIndex]; + (*lplpSurface)->AddRef(); + + dlog(" OK.", DL_INIT); + return S_OK; + } + + HRESULT __stdcall StartPresenting(DWORD_PTR dwUserID) { + dlog("\nStart Presenting.", DL_INIT); + Gfx_SetMovieTexture(mTex); + return S_OK; + } + + HRESULT __stdcall StopPresenting(DWORD_PTR dwUserID) { + dlog("\nStop Presenting.", DL_INIT); + return S_OK; + } + + HRESULT __stdcall PresentImage(DWORD_PTR dwUserID, VMR9PresentationInfo *lpPresInfo) { + #ifndef NDEBUG + dlog("\nPresent Image.", DL_INIT); + #endif + d3d9Device->UpdateTexture(pTex, mTex); + return S_OK; + } + +public: + CAllocator() { + RefCount = 1; + pAllocNotify = nullptr; + mTex = nullptr; + pTex = nullptr; + } + + ULONG __stdcall AddRef() { + return ++RefCount; + } + + ULONG _stdcall Release() { + if (--RefCount == 0) { + TerminateDevice(-2); + if (pAllocNotify) { + pAllocNotify->Release(); + pAllocNotify = nullptr; + } + } + return RefCount; + } + + HRESULT __stdcall AdviseNotify(IVMRSurfaceAllocatorNotify9 *lpIVMRSurfAllocNotify) { + if (!lpIVMRSurfAllocNotify) return E_FAIL; + + pAllocNotify = lpIVMRSurfAllocNotify; + pAllocNotify->AddRef(); + + // Set the device + HMONITOR hMonitor = d3d9->GetAdapterMonitor(D3DADAPTER_DEFAULT); + HRESULT hr = pAllocNotify->SetD3DDevice(d3d9Device, hMonitor); return hr; } - HRESULT _stdcall InitializeDevice(DWORD_PTR dwUserID, VMR9AllocationInfo *lpAllocInfo, DWORD *lpNumBuffers) { - HRESULT hr; - //Set the device - hr = pAllocNotify->SetD3DDevice(d3d9Device, d3d9->GetAdapterMonitor(0)); - //if (hr != S_OK) return hr; - - lpAllocInfo->dwFlags |= VMR9AllocFlag_TextureSurface; - lpAllocInfo->Pool = D3DPOOL_SYSTEMMEM; - // Ask the VMR-9 to allocate the surfaces for us. - hr = pAllocNotify->AllocateSurfaceHelper(lpAllocInfo, lpNumBuffers, &surface); - if (FAILED(hr)) return hr; - - hr = surface->GetContainer(IID_IDirect3DTexture9, (void**)&ptex); - if (FAILED(hr)) { - TerminateDevice(0); - return hr; - } - - d3d9Device->CreateTexture(lpAllocInfo->dwWidth, lpAllocInfo->dwHeight, 1, 0, lpAllocInfo->Format, D3DPOOL_DEFAULT, &tex, nullptr); - - return S_OK; - } - - HRESULT _stdcall TerminateDevice(DWORD_PTR dwID) { - SAFERELEASE(ptex); - SAFERELEASE(surface); - SAFERELEASE(tex); - return S_OK; - } - - HRESULT _stdcall GetSurface(DWORD_PTR dwUserID, DWORD SurfaceIndex, DWORD SurfaceFlags, IDirect3DSurface9 **lplpSurface) { - if (SurfaceIndex != 0) return E_FAIL; - *lplpSurface = surface; - surface->AddRef(); - return S_OK; - } - - HRESULT _stdcall AdviseNotify(IVMRSurfaceAllocatorNotify9 *lpIVMRSurfAllocNotify) { - if (lpIVMRSurfAllocNotify) { - pAllocNotify = lpIVMRSurfAllocNotify; - pAllocNotify->AddRef(); - return S_OK; - } else { - return E_FAIL; - } - } - - HRESULT _stdcall StartPresenting(DWORD_PTR dwUserID) { - return S_OK; - } - HRESULT _stdcall StopPresenting(DWORD_PTR dwUserID) { - return S_OK; - } - HRESULT _stdcall PresentImage(DWORD_PTR dwUserID, VMR9PresentationInfo *lpPresInfo) { - d3d9Device->UpdateTexture(ptex, tex); - return S_OK; + IDirect3DTexture9* GetMovieTexture() { + return mTex; } }; struct sDSTexture { + CAllocator *pMyAlloc; IGraphBuilder *pGraph; - ICaptureGraphBuilder2 *pBuild; + //ICaptureGraphBuilder2 *pBuild; IBaseFilter *pVmr; IVMRFilterConfig9 *pConfig; IVMRSurfaceAllocatorNotify9 *pAlloc; IMediaControl *pControl; - CAllocator *pMyAlloc; IMediaSeeking *pSeek; -}; +} movieInterface; -static IDirect3DTexture9* tex; -static sDSTexture info; - -void ResumeMovie(sDSTexture* movie) { +void PlayMovie(sDSTexture* movie) { movie->pControl->Run(); } @@ -171,7 +199,7 @@ void PauseMovie(sDSTexture* movie) { void StopMovie(sDSTexture* movie) { movie->pControl->Stop(); } - +/* void RewindMovie(sDSTexture* movie) { LONGLONG time = 0; movie->pSeek->SetPositions(&time, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); @@ -181,92 +209,135 @@ void SeekMovie(sDSTexture* movie, DWORD shortTime) { LONGLONG time = shortTime * 10000; movie->pSeek->SetPositions(&time, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); } - -DWORD FreeMovie(sDSTexture* info) { - if (info->pControl) info->pControl->Release(); - if (info->pSeek) info->pSeek->Release(); - if (info->pAlloc) info->pAlloc->Release(); - if (info->pMyAlloc) info->pMyAlloc->Release(); - if (info->pConfig) info->pConfig->Release(); - if (info->pVmr) info->pVmr->Release(); - if (info->pGraph) info->pGraph->Release(); - if (info->pBuild) info->pBuild->Release(); +*/ +DWORD FreeMovie(sDSTexture* movie) { + #ifndef NDEBUG + dlog("\nRelease movie interfaces.", DL_INIT); + #endif + if (movie->pControl) movie->pControl->Release(); + if (movie->pSeek) movie->pSeek->Release(); + if (movie->pAlloc) movie->pAlloc->Release(); + if (movie->pMyAlloc) movie->pMyAlloc->Release(); + if (movie->pConfig) movie->pConfig->Release(); + if (movie->pVmr) movie->pVmr->Release(); + if (movie->pGraph) movie->pGraph->Release(); + //if (movie->pBuild) movie->pBuild->Release(); return 0; } -DWORD CreateDSGraph(wchar_t* path, IDirect3DTexture9** tex, sDSTexture* result) { - memset(result, 0, sizeof(sDSTexture)); +DWORD CreateDSGraph(wchar_t* path, sDSTexture* movie) { + dlog("\nCreating DirectShow graph...", DL_INIT); + + ZeroMemory(movie, sizeof(sDSTexture)); // Create the Capture Graph Builder. - HRESULT hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, 0, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void**)&result->pBuild); - if (hr != S_OK) return FreeMovie(result); + //HRESULT hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, 0, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void**)&movie->pBuild); + //if (hr != S_OK) return FreeMovie(movie); // Create the Filter Graph Manager. - hr = CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&result->pGraph); - if (hr != S_OK) return FreeMovie(result); + HRESULT hr = CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&movie->pGraph); + if (hr != S_OK) return FreeMovie(movie); // Initialize the Capture Graph Builder. - hr = result->pBuild->SetFiltergraph(result->pGraph); - if (hr != S_OK) return FreeMovie(result); + //hr = movie->pBuild->SetFiltergraph(movie->pGraph); + //if (hr != S_OK) return FreeMovie(movie); - hr = CoCreateInstance(CLSID_VideoMixingRenderer9, 0, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&result->pVmr); - if (hr != S_OK) return FreeMovie(result); + hr = CoCreateInstance(CLSID_VideoMixingRenderer9, 0, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&movie->pVmr); + if (hr != S_OK) return FreeMovie(movie); - hr = result->pGraph->AddFilter(result->pVmr, L"VMR9"); - if (hr != S_OK) return FreeMovie(result); + hr = movie->pGraph->QueryInterface(IID_IMediaControl, (void**)&movie->pControl); + hr |= movie->pGraph->QueryInterface(IID_IMediaSeeking, (void**)&movie->pSeek); + if (hr != S_OK) return FreeMovie(movie); - result->pVmr->QueryInterface(IID_IVMRFilterConfig9, (void**)&result->pConfig); - result->pConfig->SetRenderingMode(VMR9Mode_Renderless); - result->pVmr->QueryInterface(IID_IVMRSurfaceAllocatorNotify9, (void**)&result->pAlloc); + hr = movie->pVmr->QueryInterface(IID_IVMRFilterConfig9, (void**)&movie->pConfig); + if (hr != S_OK) return FreeMovie(movie); - result->pMyAlloc = new CAllocator(); + hr = movie->pConfig->SetRenderingMode(VMR9Mode_Renderless); + if (hr != S_OK) return FreeMovie(movie); - result->pMyAlloc->AdviseNotify(result->pAlloc); - result->pAlloc->AdviseSurfaceAllocator(0, (IVMRSurfaceAllocator9*)result->pMyAlloc); + /* + Custom Allocator-Presenter for VMR-9: + https://docs.microsoft.com/en-us/windows/win32/directshow/supplying-a-custom-allocator-presenter-for-vmr-9 + */ + movie->pMyAlloc = new CAllocator(); - hr = result->pGraph->QueryInterface(IID_IMediaControl, (void**)&result->pControl); - hr |= result->pGraph->QueryInterface(IID_IMediaSeeking, (void**)&result->pSeek); - if (hr != S_OK) return FreeMovie(result); + hr = movie->pVmr->QueryInterface(IID_IVMRSurfaceAllocatorNotify9, (void**)&movie->pAlloc); + if (hr != S_OK) return FreeMovie(movie); - result->pGraph->RenderFile(path, nullptr); - result->pControl->Run(); + hr = movie->pAlloc->AdviseSurfaceAllocator(0, (IVMRSurfaceAllocator9*)movie->pMyAlloc); + if (hr != S_OK) return FreeMovie(movie); - *tex = result->pMyAlloc->tex; - return 1; + hr = movie->pMyAlloc->AdviseNotify(movie->pAlloc); + if (hr != S_OK) return FreeMovie(movie); + /****************************************************/ + + hr = movie->pGraph->AddFilter(movie->pVmr, L"VMR9"); + if (hr != S_OK) return FreeMovie(movie); + + dlog_f("\nStart rendering file.", DL_INIT); + hr = movie->pGraph->RenderFile(path, nullptr); + if (hr != S_OK) dlog_f(" ERROR: %d", DL_INIT, hr); + + #ifndef NDEBUG + if (movie->pMyAlloc->GetMovieTexture()) dlog_f("\nMovieTex: %d", DL_INIT, *(DWORD*)movie->pMyAlloc->GetMovieTexture()); + #endif + return (movie->pMyAlloc->GetMovieTexture()) ? 1 : 0; } -static DWORD PlayFrameHook3() { - PlayMovieFrame(); - if (GetAsyncKeyState(VK_ESCAPE)) return 0; +// Movie play looping +static DWORD PlayMovieLoop() { + Gfx_ShowMovieFrame(); + + if (GetAsyncKeyState(VK_ESCAPE)) { + StopMovie(&movieInterface); + return 0; // break play + } _int64 pos, end; - info.pSeek->GetCurrentPosition(&pos); - info.pSeek->GetStopPosition(&end); + movieInterface.pSeek->GetCurrentPosition(&pos); + movieInterface.pSeek->GetStopPosition(&end); - return (end == pos) ? 0 : 1; + bool isPlayEnd = (end == pos); + if (isPlayEnd) StopMovie(&movieInterface); + + return !isPlayEnd; // 0 - for breaking play } -static void __declspec(naked) PlayFrameHook1() { +static void __declspec(naked) gmovie_play_hook() { __asm { push ecx; xor eax, eax; - call GNW95_process_message_; //windows message pump - call PlayFrameHook3; + call GNW95_process_message_; // windows message pump + call PlayMovieLoop; pop ecx; retn; } } -static void __declspec(naked) PlayFrameHook2() { +static void __declspec(naked) gmovie_play_hook_wsub() { __asm { - xor eax,eax; - dec eax; + push ecx; + xor eax, eax; + call GNW95_process_message_; // windows message pump + call movieUpdate_; // for playing mve + call PlayMovieLoop; + pop ecx; retn; } } -static DWORD __cdecl PreparePlayMovie(const DWORD id) { - //Get file path in unicode +static void __declspec(naked) gmovie_play_hook_input() { + __asm { + xor eax,eax; + dec eax; + retn; // return -1 + } +} + +static DWORD backgroundVolume = 0; + +static DWORD __fastcall PreparePlayMovie(const DWORD id) { + // Get file path in unicode wchar_t path[MAX_PATH]; char* master_patches = *ptr_patches; DWORD len = 0; @@ -282,26 +353,57 @@ static DWORD __cdecl PreparePlayMovie(const DWORD id) { } wcscpy_s(&path[len - 3], 5, L"avi"); - //Check for existance of file - HANDLE h = CreateFileW(path, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); - if (h == INVALID_HANDLE_VALUE) return 0; - CloseHandle(h); + // Check for existance of file + if (GetFileAttributesW(path) & FILE_ATTRIBUTE_DIRECTORY) return 0; // also file not found - //Create texture and dshow info - if (!CreateDSGraph(path, &tex, &info)) return 0; + // Create texture and graph filter + if (!CreateDSGraph(path, &movieInterface)) return FreeMovie(&movieInterface); - GetAsyncKeyState(VK_ESCAPE); - SetMovieTexture(tex); - HookCall(0x44E937, PlayFrameHook1); - HookCall(0x44E949, PlayFrameHook2); + HookCall(0x44E949,gmovie_play_hook_input); // block get_input_ (if subtitles are disabled then mve videos will not be played) + // patching gmovie_play_ for disabled game subtitles + if (*(DWORD*)_subtitles == 0) { + HookCall(0x44E937, gmovie_play_hook); // looping call moviePlaying_ + SafeWrite8(0x4CB850, 0xC3); // GNW95_ShowRect_ blocking image rendering from the 'descSurface' surface when subtitles are disabled (optional) + } else { + HookCall(0x44E937, gmovie_play_hook_wsub); // looping call moviePlaying_ + //SafeWrite8(0x486654, 0xC3); // blocking movie_MVE_ShowFrame_ + //SafeWrite8(0x486900, 0xC3); // blocking movieShowFrame_ + SafeWrite8(0x4F5F40, 0xC3); // blocking sfShowFrame_ for disabling the display of mve video frames - return 1; + #ifdef NDEBUG // mute sound because mve file is still being played to get subtitles + backgroundVolume = GSoundBackgroundVolumeGetSet(0); + #endif + } + + //WIP + //SafeWrite32(0x4C73B2, 0x2E); + //BlockCall(0x48827E); + //BlockCall(0x44E92B); + //aviIsReadyToPlay = true; + + PlayMovie(&movieInterface); + + return 1; // play AVI } static void _stdcall PlayMovieRestore() { - SafeWrite32(0x44E938, 0x3934C); - SafeWrite32(0x44E94A, 0x7A22A); - FreeMovie(&info); + #ifndef NDEBUG + dlog("\nPlay Movie Restore.", DL_INIT); + #endif + + SafeWrite32(0x44E938, 0x3934C); // call moviePlaying_ + SafeWrite32(0x44E94A, 0x7A22A); // call get_input_ + + if (*(DWORD*)_subtitles == 0) { + SafeWrite8(0x4CB850, 0x53); // GNW95_ShowRect_ + } else { + SafeWrite8(0x4F5F40, 0x53); // push ebx + if (backgroundVolume) backgroundVolume = GSoundBackgroundVolumeGetSet(backgroundVolume); // restore volume + } + + Gfx_SetMovieTexture(0); + FreeMovie(&movieInterface); + //aviIsReadyToPlay = false; } static const DWORD gmovie_play_addr = 0x44E695; @@ -312,6 +414,7 @@ static void __declspec(naked) gmovie_play_hack() { push ecx; push edx; push eax; + mov ecx, eax; call PreparePlayMovie; test eax,eax; pop eax; @@ -334,7 +437,8 @@ return: retn; } } -///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// struct sDSSound { DWORD id; @@ -357,11 +461,11 @@ static void* musicLoopPtr = nullptr; static void FreeSound(sDSSound* sound) { sound->pEvent->SetNotifyWindow(0, WM_APP, 0); + SAFERELEASE(sound->pAudio); SAFERELEASE(sound->pEvent); SAFERELEASE(sound->pSeek); SAFERELEASE(sound->pControl); SAFERELEASE(sound->pGraph); - SAFERELEASE(sound->pAudio); delete sound; } @@ -419,7 +523,7 @@ LRESULT CALLBACK SoundWndProc(HWND wnd, UINT msg, WPARAM w, LPARAM l) { } static void CreateSndWnd() { - dlog("Creating sfall sound windows.", DL_INIT); + dlog("Creating sfall sound callback windows.", DL_INIT); if (GraphicsMode == 0) CoInitialize(0); WNDCLASSEX wcx; @@ -427,10 +531,10 @@ static void CreateSndWnd() { wcx.cbSize = sizeof(wcx); wcx.lpfnWndProc = SoundWndProc; wcx.hInstance = GetModuleHandleA(0); - wcx.lpszClassName = "SfallSndWnd"; + wcx.lpszClassName = "sfallSndWnd"; RegisterClassEx(&wcx); - soundwindow = CreateWindow("SfallSndWnd", "SndWnd", 0, 0, 0, 0, 0, HWND_MESSAGE, 0, GetModuleHandleA(0), 0); + soundwindow = CreateWindow("sfallSndWnd", "SndWnd", 0, 0, 0, 0, 0, HWND_MESSAGE, 0, GetModuleHandleA(0), 0); dlogr(" Done", DL_INIT); } @@ -519,6 +623,7 @@ static sDSSound* PlayingSound(wchar_t* path, bool loop) { result->pGraph->QueryInterface(IID_IMediaEventEx, (void**)&result->pEvent); result->pEvent->SetNotifyWindow((OAHWND)soundwindow, WM_APP, id); + result->pGraph->QueryInterface(IID_IBasicAudio, (void**)&result->pAudio); result->pControl->RenderFile(path); @@ -540,16 +645,13 @@ static bool __cdecl SoundFileLoad(DWORD called, const char* path) { wchar_t buf[256]; mbstowcs_s(0, buf, path, 256); - bool found = false; + bool isExist = false; int len = wcslen(buf) - 3; for (int i = 0; i < 3; i++) { buf[len] = 0; wcscat_s(buf, SoundExtensions[i]); - - HANDLE h = CreateFileW(buf, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); - if (h == INVALID_HANDLE_VALUE) continue; - CloseHandle(h); - found = true; + if (GetFileAttributesW(buf) & FILE_ATTRIBUTE_DIRECTORY) continue; // also file not found + isExist = true; break; } @@ -559,7 +661,7 @@ static bool __cdecl SoundFileLoad(DWORD called, const char* path) { StopSfallSound(musicLoopPtr); musicLoopPtr = nullptr; } - if (!found) return false; + if (!isExist) return false; if (music) { //strcpy_s(playingMusicFile, path); @@ -753,7 +855,7 @@ void MoviesInit() { dlog("Applying movie patch.", DL_INIT); if (*((DWORD*)0x00518DA0) != 0x00503300) { - dlog("Error: The value at address 0x00518DA0 is not equal to 0x00503300.", DL_INIT); + dlog("Error: The value at address 0x001073A0 is not equal to 0x00503300.", DL_INIT); } for (int i = 0; i < MaxMovies; i++) { MoviePtrs[i] = (DWORD)&MoviePaths[65 * i]; @@ -773,8 +875,16 @@ void MoviesInit() { SafeWrite32(0x44E75E, (DWORD)MoviePtrs); SafeWrite32(0x44E78A, (DWORD)MoviePtrs); dlog(".", DL_INIT); - if (GraphicsMode != 0 && GetConfigInt("Graphics", "AllowDShowMovies", 0)) { // TODO: implementation not working + /* + WIP: Task + Necessary to implement setting the volume according to the volume control in Fallout settings. + Add fade effects and brightness adjustment for videos. + Implement subtitle output from the need to play an mve file in the background. + Fix minor bugs. + */ + if (GraphicsMode != 0 && GetConfigInt("Graphics", "AllowDShowMovies", 0)) { MakeJump(0x44E690, gmovie_play_hack); + /* NOTE: At this address 0x487781, HRP changes the callback procedure to display mve frames. */ } dlogr(" Done", DL_INIT); diff --git a/sfall/ddraw.cpp b/sfall/ddraw.cpp index c559a2be..20a4c196 100644 --- a/sfall/ddraw.cpp +++ b/sfall/ddraw.cpp @@ -84,13 +84,13 @@ __declspec(naked) void FakeDirectDrawEnumerateW() { _asm jmp [ddraw.DirectDrawEnumerateW]; } -//__declspec(naked) void FakeDllCanUnloadNow() { -// _asm jmp [ddraw.DllCanUnloadNow]; -//} +__declspec(naked) void FakeDllCanUnloadNow() { + _asm jmp [ddraw.DllCanUnloadNow]; +} -//__declspec(naked) void FakeDllGetClassObject() { -// _asm jmp [ddraw.DllGetClassObject]; -//} +__declspec(naked) void FakeDllGetClassObject() { + _asm jmp [ddraw.DllGetClassObject]; +} __declspec(naked) void FakeGetDDSurfaceLocal() { _asm jmp [ddraw.GetDDSurfaceLocal]; @@ -111,3 +111,7 @@ __declspec(naked) void FakeRegisterSpecialCase() { __declspec(naked) void FakeReleaseDDThreadLock() { _asm jmp [ddraw.ReleaseDDThreadLock]; } + +__declspec(naked) void FakeSetAppCompatData() { + _asm jmp [ddraw.SetAppCompatData]; +} diff --git a/sfall/exports.def b/sfall/exports.def index 29acfccc..329541ee 100644 --- a/sfall/exports.def +++ b/sfall/exports.def @@ -16,13 +16,15 @@ DirectDrawEnumerateA = FakeDirectDrawEnumerateA @12 DirectDrawEnumerateExA = FakeDirectDrawEnumerateExA @13 DirectDrawEnumerateExW = FakeDirectDrawEnumerateExW @14 DirectDrawEnumerateW = FakeDirectDrawEnumerateW @15 -;DllCanUnloadNow = FakeDllCanUnloadNow @16 -;DllGetClassObject = FakeDllGetClassObject @17 +DllCanUnloadNow = FakeDllCanUnloadNow PRIVATE +DllGetClassObject = FakeDllGetClassObject PRIVATE GetDDSurfaceLocal = FakeGetDDSurfaceLocal @18 GetOLEThunkData = FakeGetOLEThunkData @19 GetSurfaceFromDC = FakeGetSurfaceFromDC @20 RegisterSpecialCase = FakeRegisterSpecialCase @21 ReleaseDDThreadLock = FakeReleaseDDThreadLock @22 +SetAppCompatData = FakeSetAppCompatData @23 -DirectDrawCreat2 = FakeDirectDrawCreate2 -DirectInputCreateA = FakeDirectInputCreate +; sfall override +DirectDrawCreat2 = FakeDirectDrawCreate2 @24 +DirectInputCreateA = FakeDirectInputCreate @25 diff --git a/sfall/main.cpp b/sfall/main.cpp index 15ff36c5..0aa3bea8 100644 --- a/sfall/main.cpp +++ b/sfall/main.cpp @@ -825,13 +825,14 @@ static bool LoadOriginalDll(DWORD dwReason) { ddraw.DirectDrawEnumerateExA = GetProcAddress(ddraw.dll, "DirectDrawEnumerateExA"); ddraw.DirectDrawEnumerateExW = GetProcAddress(ddraw.dll, "DirectDrawEnumerateExW"); ddraw.DirectDrawEnumerateW = GetProcAddress(ddraw.dll, "DirectDrawEnumerateW"); - //ddraw.DllCanUnloadNow = GetProcAddress(ddraw.dll, "DllCanUnloadNow"); - //ddraw.DllGetClassObject = GetProcAddress(ddraw.dll, "DllGetClassObject"); + ddraw.DllCanUnloadNow = GetProcAddress(ddraw.dll, "DllCanUnloadNow"); + ddraw.DllGetClassObject = GetProcAddress(ddraw.dll, "DllGetClassObject"); ddraw.GetDDSurfaceLocal = GetProcAddress(ddraw.dll, "GetDDSurfaceLocal"); ddraw.GetOLEThunkData = GetProcAddress(ddraw.dll, "GetOLEThunkData"); ddraw.GetSurfaceFromDC = GetProcAddress(ddraw.dll, "GetSurfaceFromDC"); ddraw.RegisterSpecialCase = GetProcAddress(ddraw.dll, "RegisterSpecialCase"); ddraw.ReleaseDDThreadLock = GetProcAddress(ddraw.dll, "ReleaseDDThreadLock"); + ddraw.SetAppCompatData = GetProcAddress(ddraw.dll, "SetAppCompatData"); } return true; case DLL_PROCESS_DETACH: diff --git a/sfall/main.h b/sfall/main.h index af6ecc28..90b7d0b9 100644 --- a/sfall/main.h +++ b/sfall/main.h @@ -51,12 +51,13 @@ struct ddrawDll { FARPROC DirectDrawEnumerateA; FARPROC DirectDrawEnumerateExW; FARPROC DirectDrawEnumerateW; - //FARPROC DllCanUnloadNow; - //FARPROC DllGetClassObject; + FARPROC DllCanUnloadNow; + FARPROC DllGetClassObject; FARPROC GetDDSurfaceLocal; FARPROC GetOLEThunkData; FARPROC GetSurfaceFromDC; FARPROC RegisterSpecialCase; + FARPROC SetAppCompatData; }; // global flag, indicating that debugging features of Sfall are enabled