mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Fixed clipping issue when moving dialog boxes in Close Combat 4
This commit is contained in:
parent
767c8d28ee
commit
ddc45d7f36
@ -1,138 +1,14 @@
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <Common/CompatRef.h>
|
||||
#include <Common/CompatVtable.h>
|
||||
#include <D3dDdi/KernelModeThunks.h>
|
||||
#include <DDraw/DirectDrawClipper.h>
|
||||
#include <DDraw/ScopedThreadLock.h>
|
||||
#include <DDraw/Surfaces/PrimarySurface.h>
|
||||
#include <DDraw/Surfaces/Surface.h>
|
||||
#include <DDraw/Visitors/DirectDrawClipperVtblVisitor.h>
|
||||
#include <Gdi/Gdi.h>
|
||||
#include <Gdi/Region.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
struct ClipperData
|
||||
constexpr void setCompatVtable(IDirectDrawClipperVtbl& /*vtable*/)
|
||||
{
|
||||
HWND hwnd;
|
||||
DWORD refCount;
|
||||
std::vector<unsigned char> origClipList;
|
||||
};
|
||||
|
||||
std::map<IDirectDrawClipper*, ClipperData> g_clipperData;
|
||||
std::map<DDraw::Surface*, std::map<IDirectDrawClipper*, ClipperData>::iterator> g_surfaceToClipperData;
|
||||
bool g_isInvalidated = false;
|
||||
|
||||
void updateWindowClipList(CompatRef<IDirectDrawClipper> clipper, ClipperData& data);
|
||||
|
||||
void onWindowPosChange()
|
||||
{
|
||||
g_isInvalidated = true;
|
||||
}
|
||||
|
||||
void restoreOrigClipList(IDirectDrawClipper* clipper, ClipperData& clipperData)
|
||||
{
|
||||
getOrigVtable(clipper).SetClipList(clipper,
|
||||
clipperData.origClipList.empty() ? nullptr : reinterpret_cast<RGNDATA*>(clipperData.origClipList.data()), 0);
|
||||
clipperData.origClipList.clear();
|
||||
}
|
||||
|
||||
void updateWindowClipList(CompatRef<IDirectDrawClipper> 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<unsigned char> rgnDataBuf(std::max<DWORD>(rgnSize, sizeof(RGNDATA)));
|
||||
RGNDATA* rgnData = reinterpret_cast<RGNDATA*>(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<unsigned char> 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<RGNDATA*>(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*>(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<IDirectDrawClipper> clipper, HRGN rgn)
|
||||
{
|
||||
std::vector<unsigned char> rgnData;
|
||||
@ -202,14 +34,6 @@ namespace DDraw
|
||||
return clipper->SetClipList(&clipper, reinterpret_cast<RGNDATA*>(rgnData.data()), 0);
|
||||
}
|
||||
|
||||
void update()
|
||||
{
|
||||
for (auto& clipperData : g_clipperData)
|
||||
{
|
||||
updateWindowClipList(*clipperData.first, clipperData.second);
|
||||
}
|
||||
}
|
||||
|
||||
void hookVtable(const IDirectDrawClipperVtbl& vtable)
|
||||
{
|
||||
CompatVtable<IDirectDrawClipperVtbl>::hookVtable<ScopedThreadLock>(vtable);
|
||||
|
@ -6,14 +6,10 @@
|
||||
|
||||
namespace DDraw
|
||||
{
|
||||
class Surface;
|
||||
|
||||
namespace DirectDrawClipper
|
||||
{
|
||||
HRGN getClipRgn(CompatRef<IDirectDrawClipper> clipper);
|
||||
void setClipper(Surface& surface, IDirectDrawClipper* clipper);
|
||||
HRESULT setClipRgn(CompatRef<IDirectDrawClipper> clipper, HRGN rgn);
|
||||
void update();
|
||||
|
||||
void hookVtable(const IDirectDrawClipperVtbl& vtable);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
#include <Common/CompatPtr.h>
|
||||
#include <Config/Settings/AlignSysMemSurfaces.h>
|
||||
#include <DDraw/DirectDrawClipper.h>
|
||||
#include <DDraw/DirectDrawSurface.h>
|
||||
#include <DDraw/Surfaces/Surface.h>
|
||||
#include <DDraw/Surfaces/SurfaceImpl.h>
|
||||
@ -60,7 +59,6 @@ namespace DDraw
|
||||
|
||||
Surface::~Surface()
|
||||
{
|
||||
DirectDrawClipper::setClipper(*this, nullptr);
|
||||
g_surfaces.erase(this);
|
||||
}
|
||||
|
||||
|
@ -7,14 +7,15 @@
|
||||
#include <Common/CompatPtr.h>
|
||||
#include <D3dDdi/Device.h>
|
||||
#include <D3dDdi/Resource.h>
|
||||
#include <DDraw/DirectDrawClipper.h>
|
||||
#include <DDraw/DirectDrawSurface.h>
|
||||
#include <DDraw/LogUsedResourceFormat.h>
|
||||
#include <DDraw/RealPrimarySurface.h>
|
||||
#include <DDraw/Surfaces/PrimarySurface.h>
|
||||
#include <DDraw/Surfaces/Surface.h>
|
||||
#include <DDraw/Surfaces/SurfaceImpl.h>
|
||||
#include <Direct3d/Direct3d.h>
|
||||
#include <Dll/Dll.h>
|
||||
#include <Gdi/Region.h>
|
||||
#include <Gdi/WinProc.h>
|
||||
|
||||
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<IDirectDrawClipper> clipper)
|
||||
{
|
||||
HWND hwnd = nullptr;
|
||||
clipper->GetHWnd(clipper, &hwnd);
|
||||
if (!hwnd)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static CompatWeakPtr<IDirectDrawClipper> 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<unsigned char> rgnDataBuf(std::max<DWORD>(rgnSize, sizeof(RGNDATA) + sizeof(RECT)));
|
||||
RGNDATA* rgnData = reinterpret_cast<RGNDATA*>(rgnDataBuf.data());
|
||||
GetRegionData(rgn, rgnSize, rgnData);
|
||||
if (0 == rgnData->rdh.nCount)
|
||||
{
|
||||
rgnData->rdh.nCount = 1;
|
||||
}
|
||||
|
||||
fixedClipper->SetClipList(fixedClipper, rgnData, 0);
|
||||
return fixedClipper;
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
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<IDirectDrawClipper> m_clipper;
|
||||
};
|
||||
|
||||
template <typename TSurface>
|
||||
typename DDraw::Types<TSurface>::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 <typename TSurface>
|
||||
HRESULT SurfaceImpl<TSurface>::SetClipper(TSurface* This, LPDIRECTDRAWCLIPPER lpDDClipper)
|
||||
{
|
||||
HRESULT result = getOrigVtable(This).SetClipper(This, lpDDClipper);
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
DDraw::DirectDrawClipper::setClipper(*m_data, lpDDClipper);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename TSurface>
|
||||
HRESULT SurfaceImpl<TSurface>::SetPalette(TSurface* This, LPDIRECTDRAWPALETTE lpDDPalette)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -119,9 +119,4 @@ namespace Gdi
|
||||
SetClassLongPtr(hwnd, GCLP_WNDPROC, reinterpret_cast<LONG>(oldWndProc));
|
||||
DestroyWindow(hwnd);
|
||||
}
|
||||
|
||||
void watchWindowPosChanges(WindowPosChangeNotifyFunc notifyFunc)
|
||||
{
|
||||
WinProc::watchWindowPosChanges(notifyFunc);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -55,7 +55,6 @@ namespace
|
||||
decltype(&DwmSetIconicThumbnail) g_dwmSetIconicThumbnail = nullptr;
|
||||
|
||||
std::map<HMENU, UINT> g_menuMaxHeight;
|
||||
std::set<Gdi::WindowPosChangeNotifyFunc> g_windowPosChangeNotifyFuncs;
|
||||
|
||||
Compat::SrwLock g_windowProcSrwLock;
|
||||
std::map<HWND, WindowProc> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,5 @@ namespace Gdi
|
||||
void onCreateWindow(HWND hwnd);
|
||||
void startFrame();
|
||||
void updatePresentationWindowText(HWND owner);
|
||||
void watchWindowPosChanges(WindowPosChangeNotifyFunc notifyFunc);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user