From ddc45d7f365c98c1481c887078d4df89e7998251 Mon Sep 17 00:00:00 2001 From: narzoul Date: Wed, 26 Jun 2024 00:15:54 +0200 Subject: [PATCH] Fixed clipping issue when moving dialog boxes in Close Combat 4 --- DDrawCompat/DDraw/DirectDrawClipper.cpp | 178 +-------------------- DDrawCompat/DDraw/DirectDrawClipper.h | 4 - DDrawCompat/DDraw/DirectDrawSurface.cpp | 1 - DDrawCompat/DDraw/Surfaces/Surface.cpp | 2 - DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp | 97 +++++++++-- DDrawCompat/DDraw/Surfaces/SurfaceImpl.h | 1 - DDrawCompat/Gdi/Gdi.cpp | 5 - DDrawCompat/Gdi/Gdi.h | 3 - DDrawCompat/Gdi/WinProc.cpp | 11 -- DDrawCompat/Gdi/WinProc.h | 1 - 10 files changed, 85 insertions(+), 218 deletions(-) diff --git a/DDrawCompat/DDraw/DirectDrawClipper.cpp b/DDrawCompat/DDraw/DirectDrawClipper.cpp index 569906c..88a3654 100644 --- a/DDrawCompat/DDraw/DirectDrawClipper.cpp +++ b/DDrawCompat/DDraw/DirectDrawClipper.cpp @@ -1,138 +1,14 @@ -#include #include -#include #include -#include #include #include -#include -#include #include -#include -#include namespace { - struct ClipperData + constexpr void setCompatVtable(IDirectDrawClipperVtbl& /*vtable*/) { - HWND hwnd; - DWORD refCount; - std::vector origClipList; - }; - - std::map g_clipperData; - std::map::iterator> g_surfaceToClipperData; - bool g_isInvalidated = false; - - void updateWindowClipList(CompatRef clipper, ClipperData& data); - - void onWindowPosChange() - { - g_isInvalidated = true; - } - - void restoreOrigClipList(IDirectDrawClipper* clipper, ClipperData& clipperData) - { - getOrigVtable(clipper).SetClipList(clipper, - clipperData.origClipList.empty() ? nullptr : reinterpret_cast(clipperData.origClipList.data()), 0); - clipperData.origClipList.clear(); - } - - void updateWindowClipList(CompatRef clipper, ClipperData& data) - { - HDC dc = GetDCEx(data.hwnd, nullptr, DCX_CACHE | DCX_USESTYLE); - Gdi::Region rgn; - GetRandomRgn(dc, rgn, SYSRGN); - CALL_ORIG_FUNC(ReleaseDC)(data.hwnd, dc); - - auto& mi = DDraw::PrimarySurface::getMonitorInfo(); - if (0 != mi.rcEmulated.left || 0 != mi.rcEmulated.top) - { - rgn.offset(-mi.rcEmulated.left, -mi.rcEmulated.top); - } - - DWORD rgnSize = GetRegionData(rgn, 0, nullptr); - std::vector rgnDataBuf(std::max(rgnSize, sizeof(RGNDATA))); - RGNDATA* rgnData = reinterpret_cast(rgnDataBuf.data()); - GetRegionData(rgn, rgnSize, rgnData); - if (0 == rgnData->rdh.nCount) - { - rgnData->rdh.nCount = 1; - } - - clipper->SetHWnd(&clipper, 0, nullptr); - clipper->SetClipList(&clipper, rgnData, 0); - } - - HRESULT STDMETHODCALLTYPE GetHWnd(IDirectDrawClipper* This, HWND* lphWnd) - { - if (lphWnd) - { - auto it = g_clipperData.find(This); - if (it != g_clipperData.end() && it->second.hwnd) - { - *lphWnd = it->second.hwnd; - return DD_OK; - } - } - return getOrigVtable(This).GetHWnd(This, lphWnd); - } - - HRESULT STDMETHODCALLTYPE SetClipList(IDirectDrawClipper* This, LPRGNDATA lpClipList, DWORD dwFlags) - { - auto it = g_clipperData.find(This); - if (it != g_clipperData.end() && it->second.hwnd) - { - return DDERR_CLIPPERISUSINGHWND; - } - return getOrigVtable(This).SetClipList(This, lpClipList, dwFlags); - } - - HRESULT STDMETHODCALLTYPE SetHWnd(IDirectDrawClipper* This, DWORD dwFlags, HWND hWnd) - { - auto it = g_clipperData.find(This); - if (it == g_clipperData.end()) - { - return getOrigVtable(This).SetHWnd(This, dwFlags, hWnd); - } - - std::vector origClipList; - if (hWnd && !it->second.hwnd) - { - DWORD size = 0; - getOrigVtable(This).GetClipList(This, nullptr, nullptr, &size); - origClipList.resize(size); - getOrigVtable(This).GetClipList(This, nullptr, reinterpret_cast(origClipList.data()), &size); - } - - HRESULT result = getOrigVtable(This).SetHWnd(This, dwFlags, hWnd); - if (SUCCEEDED(result)) - { - if (hWnd) - { - if (!it->second.hwnd) - { - it->second.origClipList = origClipList; - } - it->second.hwnd = hWnd; - updateWindowClipList(*This, it->second); - Gdi::watchWindowPosChanges(&onWindowPosChange); - } - else if (it->second.hwnd) - { - restoreOrigClipList(it->first, it->second); - it->second.hwnd = nullptr; - } - } - return result; - } - - constexpr void setCompatVtable(IDirectDrawClipperVtbl& vtable) - { - vtable.GetHWnd = &GetHWnd; - vtable.SetClipList = &SetClipList; - vtable.SetHWnd = &SetHWnd; } } @@ -150,50 +26,6 @@ namespace DDraw return ExtCreateRegion(nullptr, size, reinterpret_cast(rgnData.data())); } - void setClipper(Surface& surface, IDirectDrawClipper* clipper) - { - auto it = g_surfaceToClipperData.find(&surface); - if (it != g_surfaceToClipperData.end()) - { - auto prevClipper = it->second->first; - auto& prevClipperData = it->second->second; - if (prevClipper == clipper) - { - return; - } - - --prevClipperData.refCount; - if (0 == prevClipperData.refCount) - { - if (prevClipperData.hwnd) - { - restoreOrigClipList(prevClipper, prevClipperData); - getOrigVtable(prevClipper).SetHWnd(prevClipper, 0, prevClipperData.hwnd); - } - g_clipperData.erase(it->second); - } - getOrigVtable(prevClipper).Release(prevClipper); - g_surfaceToClipperData.erase(it); - } - - if (clipper) - { - auto [clipperDataIter, inserted] = g_clipperData.insert({ clipper, ClipperData{} }); - if (inserted) - { - HWND hwnd = nullptr; - getOrigVtable(clipper).GetHWnd(clipper, &hwnd); - if (hwnd) - { - SetHWnd(clipper, 0, hwnd); - } - } - ++clipperDataIter->second.refCount; - g_surfaceToClipperData[&surface] = clipperDataIter; - getOrigVtable(clipper).AddRef(clipper); - } - } - HRESULT setClipRgn(CompatRef clipper, HRGN rgn) { std::vector rgnData; @@ -202,14 +34,6 @@ namespace DDraw return clipper->SetClipList(&clipper, reinterpret_cast(rgnData.data()), 0); } - void update() - { - for (auto& clipperData : g_clipperData) - { - updateWindowClipList(*clipperData.first, clipperData.second); - } - } - void hookVtable(const IDirectDrawClipperVtbl& vtable) { CompatVtable::hookVtable(vtable); diff --git a/DDrawCompat/DDraw/DirectDrawClipper.h b/DDrawCompat/DDraw/DirectDrawClipper.h index ab8477e..68e7365 100644 --- a/DDrawCompat/DDraw/DirectDrawClipper.h +++ b/DDrawCompat/DDraw/DirectDrawClipper.h @@ -6,14 +6,10 @@ namespace DDraw { - class Surface; - namespace DirectDrawClipper { HRGN getClipRgn(CompatRef clipper); - void setClipper(Surface& surface, IDirectDrawClipper* clipper); HRESULT setClipRgn(CompatRef clipper, HRGN rgn); - void update(); void hookVtable(const IDirectDrawClipperVtbl& vtable); } diff --git a/DDrawCompat/DDraw/DirectDrawSurface.cpp b/DDrawCompat/DDraw/DirectDrawSurface.cpp index e332e10..0114217 100644 --- a/DDrawCompat/DDraw/DirectDrawSurface.cpp +++ b/DDrawCompat/DDraw/DirectDrawSurface.cpp @@ -73,7 +73,6 @@ namespace SET_COMPAT_METHOD(QueryInterface); SET_COMPAT_METHOD(ReleaseDC); SET_COMPAT_METHOD(Restore); - SET_COMPAT_METHOD(SetClipper); SET_COMPAT_METHOD(SetPalette); SET_COMPAT_METHOD(Unlock); diff --git a/DDrawCompat/DDraw/Surfaces/Surface.cpp b/DDrawCompat/DDraw/Surfaces/Surface.cpp index 96ed912..ce246fc 100644 --- a/DDrawCompat/DDraw/Surfaces/Surface.cpp +++ b/DDrawCompat/DDraw/Surfaces/Surface.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include #include @@ -60,7 +59,6 @@ namespace DDraw Surface::~Surface() { - DirectDrawClipper::setClipper(*this, nullptr); g_surfaces.erase(this); } diff --git a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp index 55e581a..8034868 100644 --- a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp +++ b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp @@ -7,14 +7,15 @@ #include #include #include -#include #include #include #include +#include #include #include #include #include +#include #include namespace @@ -23,6 +24,87 @@ namespace UINT g_bltSrcSubResourceIndex = 0; RECT g_bltSrcRect = {}; + IDirectDrawClipper* createClipper() + { + IDirectDrawClipper* clipper = nullptr; + CALL_ORIG_PROC(DirectDrawCreateClipper)(0, &clipper, nullptr); + return clipper; + } + + IDirectDrawClipper* getFixedClipper(CompatWeakPtr clipper) + { + HWND hwnd = nullptr; + clipper->GetHWnd(clipper, &hwnd); + if (!hwnd) + { + return nullptr; + } + + static CompatWeakPtr fixedClipper(createClipper()); + if (!fixedClipper) + { + return nullptr; + } + + HDC dc = GetDCEx(hwnd, nullptr, DCX_CACHE | DCX_USESTYLE); + Gdi::Region rgn; + GetRandomRgn(dc, rgn, SYSRGN); + CALL_ORIG_FUNC(ReleaseDC)(hwnd, dc); + + auto& mi = DDraw::PrimarySurface::getMonitorInfo(); + if (0 != mi.rcEmulated.left || 0 != mi.rcEmulated.top) + { + rgn.offset(-mi.rcEmulated.left, -mi.rcEmulated.top); + } + + DWORD rgnSize = GetRegionData(rgn, 0, nullptr); + std::vector rgnDataBuf(std::max(rgnSize, sizeof(RGNDATA) + sizeof(RECT))); + RGNDATA* rgnData = reinterpret_cast(rgnDataBuf.data()); + GetRegionData(rgn, rgnSize, rgnData); + if (0 == rgnData->rdh.nCount) + { + rgnData->rdh.nCount = 1; + } + + fixedClipper->SetClipList(fixedClipper, rgnData, 0); + return fixedClipper; + } + + template + class ClipperFix + { + public: + ClipperFix(TSurface* surface) : m_surface(surface) + { + HRESULT result = getOrigVtable(surface).GetClipper(surface, &m_clipper.getRef()); + if (FAILED(result)) + { + return; + } + + auto fixedClipper = getFixedClipper(m_clipper); + if (!fixedClipper) + { + m_clipper.release(); + return; + } + + getOrigVtable(surface).SetClipper(surface, fixedClipper); + } + + ~ClipperFix() + { + if (m_clipper) + { + getOrigVtable(m_surface).SetClipper(m_surface, m_clipper); + } + } + + private: + TSurface* m_surface; + CompatPtr m_clipper; + }; + template typename DDraw::Types::TDdsCaps getCaps(TSurface* This) { @@ -133,7 +215,7 @@ namespace DDraw { Gdi::WinProc::startFrame(); RealPrimarySurface::waitForFlip(m_data->getDDS()); - DirectDrawClipper::update(); + ClipperFix fix(This); return blt(This, lpDDSrcSurface, lpSrcRect, [=](TSurface* This, TSurface* lpDDSrcSurface, LPRECT lpSrcRect) { return getOrigVtable(This).Blt(This, lpDestRect, lpDDSrcSurface, lpSrcRect, dwFlags, lpDDBltFx); }); } @@ -287,17 +369,6 @@ namespace DDraw return result; } - template - HRESULT SurfaceImpl::SetClipper(TSurface* This, LPDIRECTDRAWCLIPPER lpDDClipper) - { - HRESULT result = getOrigVtable(This).SetClipper(This, lpDDClipper); - if (SUCCEEDED(result)) - { - DDraw::DirectDrawClipper::setClipper(*m_data, lpDDClipper); - } - return result; - } - template HRESULT SurfaceImpl::SetPalette(TSurface* This, LPDIRECTDRAWPALETTE lpDDPalette) { diff --git a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h index 236e755..7686209 100644 --- a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h +++ b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.h @@ -41,7 +41,6 @@ namespace DDraw virtual HRESULT QueryInterface(TSurface* This, REFIID riid, LPVOID* obp); virtual HRESULT ReleaseDC(TSurface* This, HDC hDC); virtual HRESULT Restore(TSurface* This); - virtual HRESULT SetClipper(TSurface* This, LPDIRECTDRAWCLIPPER lpDDClipper); virtual HRESULT SetPalette(TSurface* This, LPDIRECTDRAWPALETTE lpDDPalette); virtual HRESULT SetSurfaceDesc(TSurface* This, TSurfaceDesc* lpddsd, DWORD dwFlags); virtual HRESULT Unlock(TSurface* This, TUnlockParam lpRect); diff --git a/DDrawCompat/Gdi/Gdi.cpp b/DDrawCompat/Gdi/Gdi.cpp index 3f12a13..fe6cc13 100644 --- a/DDrawCompat/Gdi/Gdi.cpp +++ b/DDrawCompat/Gdi/Gdi.cpp @@ -119,9 +119,4 @@ namespace Gdi SetClassLongPtr(hwnd, GCLP_WNDPROC, reinterpret_cast(oldWndProc)); DestroyWindow(hwnd); } - - void watchWindowPosChanges(WindowPosChangeNotifyFunc notifyFunc) - { - WinProc::watchWindowPosChanges(notifyFunc); - } } diff --git a/DDrawCompat/Gdi/Gdi.h b/DDrawCompat/Gdi/Gdi.h index 746d434..5f7f4a4 100644 --- a/DDrawCompat/Gdi/Gdi.h +++ b/DDrawCompat/Gdi/Gdi.h @@ -8,8 +8,6 @@ namespace Gdi { const ATOM MENU_ATOM = 0x8000; - typedef void(*WindowPosChangeNotifyFunc)(); - void checkDesktopComposition(); void dllThreadDetach(); void installHooks(); @@ -17,5 +15,4 @@ namespace Gdi void redraw(HRGN rgn); void redrawWindow(HWND hwnd, HRGN rgn); void unhookWndProc(LPCSTR className, WNDPROC oldWndProc); - void watchWindowPosChanges(WindowPosChangeNotifyFunc notifyFunc); }; diff --git a/DDrawCompat/Gdi/WinProc.cpp b/DDrawCompat/Gdi/WinProc.cpp index 4825260..9a01aed 100644 --- a/DDrawCompat/Gdi/WinProc.cpp +++ b/DDrawCompat/Gdi/WinProc.cpp @@ -55,7 +55,6 @@ namespace decltype(&DwmSetIconicThumbnail) g_dwmSetIconicThumbnail = nullptr; std::map g_menuMaxHeight; - std::set g_windowPosChangeNotifyFuncs; Compat::SrwLock g_windowProcSrwLock; std::map g_windowProc; @@ -580,11 +579,6 @@ namespace void onWindowPosChanged(HWND hwnd, const WINDOWPOS& wp) { - for (auto notifyFunc : g_windowPosChangeNotifyFuncs) - { - notifyFunc(); - } - if (Gdi::Window::isTopLevelWindow(hwnd)) { DDraw::RealPrimarySurface::setPresentationWindowTopmost(); @@ -1069,10 +1063,5 @@ namespace Gdi qpcNow = Time::queryPerformanceCounter(); } } - - void watchWindowPosChanges(WindowPosChangeNotifyFunc notifyFunc) - { - g_windowPosChangeNotifyFuncs.insert(notifyFunc); - } } } diff --git a/DDrawCompat/Gdi/WinProc.h b/DDrawCompat/Gdi/WinProc.h index 935abb7..b827518 100644 --- a/DDrawCompat/Gdi/WinProc.h +++ b/DDrawCompat/Gdi/WinProc.h @@ -12,6 +12,5 @@ namespace Gdi void onCreateWindow(HWND hwnd); void startFrame(); void updatePresentationWindowText(HWND owner); - void watchWindowPosChanges(WindowPosChangeNotifyFunc notifyFunc); } }