1
0
mirror of https://github.com/narzoul/DDrawCompat synced 2024-12-30 08:55:36 +01:00

Fixed GDI clipping issues

This commit is contained in:
narzoul 2016-04-03 17:02:00 +02:00
parent c78c7c927f
commit 2d30ff6f94

View File

@ -16,9 +16,7 @@ namespace
CompatDc(const CachedDc& cachedDc = {}) : CachedDc(cachedDc) {} CompatDc(const CachedDc& cachedDc = {}) : CachedDc(cachedDc) {}
DWORD refCount; DWORD refCount;
HDC origDc; HDC origDc;
HGDIOBJ origFont; int savedState;
HGDIOBJ origBrush;
HGDIOBJ origPen;
}; };
typedef std::unordered_map<HDC, CompatDc> CompatDcMap; typedef std::unordered_map<HDC, CompatDc> CompatDcMap;
@ -27,15 +25,14 @@ namespace
struct ExcludeClipRectsData struct ExcludeClipRectsData
{ {
HDC compatDc; HDC compatDc;
POINT origin;
HWND rootWnd; HWND rootWnd;
}; };
void copyDcAttributes(CompatDc& compatDc, HDC origDc, POINT& origin) void copyDcAttributes(CompatDc& compatDc, HDC origDc, POINT& origin)
{ {
compatDc.origFont = SelectObject(compatDc.dc, GetCurrentObject(origDc, OBJ_FONT)); SelectObject(compatDc.dc, GetCurrentObject(origDc, OBJ_FONT));
compatDc.origBrush = SelectObject(compatDc.dc, GetCurrentObject(origDc, OBJ_BRUSH)); SelectObject(compatDc.dc, GetCurrentObject(origDc, OBJ_BRUSH));
compatDc.origPen = SelectObject(compatDc.dc, GetCurrentObject(origDc, OBJ_PEN)); SelectObject(compatDc.dc, GetCurrentObject(origDc, OBJ_PEN));
if (GM_ADVANCED == GetGraphicsMode(origDc)) if (GM_ADVANCED == GetGraphicsMode(origDc))
{ {
@ -44,11 +41,6 @@ namespace
GetWorldTransform(origDc, &transform); GetWorldTransform(origDc, &transform);
SetWorldTransform(compatDc.dc, &transform); SetWorldTransform(compatDc.dc, &transform);
} }
else if (GM_COMPATIBLE != GetGraphicsMode(compatDc.dc))
{
ModifyWorldTransform(compatDc.dc, nullptr, MWT_IDENTITY);
SetGraphicsMode(compatDc.dc, GM_COMPATIBLE);
}
SetMapMode(compatDc.dc, GetMapMode(origDc)); SetMapMode(compatDc.dc, GetMapMode(origDc));
@ -101,17 +93,19 @@ namespace
return TRUE; return TRUE;
} }
RECT rect = {}; RECT windowRect = {};
GetWindowRect(hwnd, &rect); GetWindowRect(hwnd, &windowRect);
OffsetRect(&rect, -excludeClipRectsData->origin.x, -excludeClipRectsData->origin.y);
ExcludeClipRect(excludeClipRectsData->compatDc, rect.left, rect.top, rect.right, rect.bottom); HRGN windowRgn = CreateRectRgnIndirect(&windowRect);
ExtSelectClipRgn(excludeClipRectsData->compatDc, windowRgn, RGN_DIFF);
DeleteObject(windowRgn);
return TRUE; return TRUE;
} }
void excludeClipRectsForOverlappingWindows( void excludeClipRectsForOverlappingWindows(HWND hwnd, bool isMenuWindow, HDC compatDc)
HWND hwnd, bool isMenuWindow, HDC compatDc, const POINT& origin)
{ {
ExcludeClipRectsData excludeClipRectsData = { compatDc, origin, GetAncestor(hwnd, GA_ROOT) }; ExcludeClipRectsData excludeClipRectsData = { compatDc, GetAncestor(hwnd, GA_ROOT) };
if (!isMenuWindow) if (!isMenuWindow)
{ {
EnumWindows(&excludeClipRectForOverlappingWindow, EnumWindows(&excludeClipRectForOverlappingWindow,
@ -129,35 +123,28 @@ namespace
void setClippingRegion(HDC compatDc, HDC origDc, HWND hwnd, bool isMenuWindow, const POINT& origin) void setClippingRegion(HDC compatDc, HDC origDc, HWND hwnd, bool isMenuWindow, const POINT& origin)
{ {
if (isMenuWindow) HRGN clipRgn = CreateRectRgn(0, 0, 0, 0);
if (1 == GetClipRgn(origDc, clipRgn))
{ {
RECT windowRect = {}; OffsetRgn(clipRgn, origin.x, origin.y);
GetWindowRect(hwnd, &windowRect); SelectClipRgn(compatDc, clipRgn);
HRGN windowRgn = CreateRectRgnIndirect(&windowRect);
SelectClipRgn(compatDc, windowRgn);
DeleteObject(windowRgn);
}
else
{
HRGN clipRgn = CreateRectRgn(0, 0, 0, 0);
const bool isEmptyClipRgn = 1 != GetRandomRgn(origDc, clipRgn, SYSRGN);
SelectClipRgn(compatDc, isEmptyClipRgn ? nullptr : clipRgn);
DeleteObject(clipRgn);
HRGN origClipRgn = CreateRectRgn(0, 0, 0, 0);
if (1 == GetClipRgn(origDc, origClipRgn))
{
OffsetRgn(origClipRgn, origin.x, origin.y);
ExtSelectClipRgn(compatDc, origClipRgn, RGN_AND);
}
DeleteObject(origClipRgn);
} }
if (hwnd) if (hwnd)
{ {
excludeClipRectsForOverlappingWindows(hwnd, isMenuWindow, compatDc, origin); if (isMenuWindow || 1 != GetRandomRgn(origDc, clipRgn, SYSRGN))
{
RECT rect = {};
GetWindowRect(hwnd, &rect);
SetRectRgn(clipRgn, rect.left, rect.top, rect.right, rect.bottom);
}
excludeClipRectsForOverlappingWindows(hwnd, isMenuWindow, compatDc);
ExtSelectClipRgn(compatDc, clipRgn, RGN_AND);
} }
DeleteObject(clipRgn);
SetMetaRgn(compatDc);
} }
} }
@ -195,6 +182,7 @@ namespace CompatGdiDc
POINT origin = {}; POINT origin = {};
GetDCOrgEx(origDc, &origin); GetDCOrgEx(origDc, &origin);
compatDc.savedState = SaveDC(compatDc.dc);
copyDcAttributes(compatDc, origDc, origin); copyDcAttributes(compatDc, origDc, origin);
setClippingRegion(compatDc.dc, origDc, hwnd, isMenuWindow, origin); setClippingRegion(compatDc.dc, origDc, hwnd, isMenuWindow, origin);
@ -226,9 +214,7 @@ namespace CompatGdiDc
--compatDc.refCount; --compatDc.refCount;
if (0 == compatDc.refCount) if (0 == compatDc.refCount)
{ {
SelectObject(compatDc.dc, compatDc.origFont); RestoreDC(compatDc.dc, compatDc.savedState);
SelectObject(compatDc.dc, compatDc.origBrush);
SelectObject(compatDc.dc, compatDc.origPen);
CompatGdiDcCache::releaseDc(compatDc); CompatGdiDcCache::releaseDc(compatDc);
g_origDcToCompatDc.erase(origDc); g_origDcToCompatDc.erase(origDc);
} }