mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Support PC_RESERVED palette entry flag for GDI rendering
This commit is contained in:
parent
111719eaf7
commit
d4042f7e95
@ -1,5 +1,4 @@
|
|||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#include "CompatDirectDrawPalette.h"
|
#include "CompatDirectDrawPalette.h"
|
||||||
#include "CompatDirectDrawSurface.h"
|
#include "CompatDirectDrawSurface.h"
|
||||||
@ -25,8 +24,6 @@ namespace
|
|||||||
HANDLE g_ddUnlockEndEvent = nullptr;
|
HANDLE g_ddUnlockEndEvent = nullptr;
|
||||||
bool g_isDelayedUnlockPending = false;
|
bool g_isDelayedUnlockPending = false;
|
||||||
|
|
||||||
PALETTEENTRY g_usedPaletteEntries[256] = {};
|
|
||||||
|
|
||||||
BOOL CALLBACK invalidateWindow(HWND hwnd, LPARAM lParam)
|
BOOL CALLBACK invalidateWindow(HWND hwnd, LPARAM lParam)
|
||||||
{
|
{
|
||||||
if (!IsWindowVisible(hwnd))
|
if (!IsWindowVisible(hwnd))
|
||||||
@ -73,45 +70,6 @@ namespace
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Workaround for correctly drawing icons with a transparent background using BitBlt and a monochrome
|
|
||||||
bitmap mask. Normally black (index 0) and white (index 255) are selected as foreground and background
|
|
||||||
colors on the target DC so that a BitBlt with the SRCAND ROP would preserve the background pixels and
|
|
||||||
set the foreground pixels to 0. (Logical AND with 0xFF preserves all bits.)
|
|
||||||
But if the physical palette contains another, earlier white entry, SRCAND will be performed with the
|
|
||||||
wrong index (less than 0xFF), erasing some of the bits from all background pixels.
|
|
||||||
This workaround replaces all unwanted white entries with a similar color.
|
|
||||||
*/
|
|
||||||
void replaceDuplicateWhitePaletteEntries(DWORD startingEntry, DWORD count)
|
|
||||||
{
|
|
||||||
if (startingEntry + count > 255)
|
|
||||||
{
|
|
||||||
count = 255 - startingEntry;
|
|
||||||
}
|
|
||||||
|
|
||||||
PALETTEENTRY entries[256] = {};
|
|
||||||
std::memcpy(entries, &CompatPrimarySurface::paletteEntries[startingEntry],
|
|
||||||
count * sizeof(PALETTEENTRY));
|
|
||||||
|
|
||||||
bool isReplacementDone = false;
|
|
||||||
for (DWORD i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
if (0xFF == entries[i].peRed && 0xFF == entries[i].peGreen && 0xFF == entries[i].peBlue)
|
|
||||||
{
|
|
||||||
entries[i].peRed = 0xFE;
|
|
||||||
entries[i].peGreen = 0xFE;
|
|
||||||
entries[i].peBlue = 0xFE;
|
|
||||||
isReplacementDone = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isReplacementDone)
|
|
||||||
{
|
|
||||||
CompatDirectDrawPalette::s_origVtable.SetEntries(
|
|
||||||
CompatPrimarySurface::palette, 0, startingEntry, count, entries);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void unlockPrimarySurface()
|
void unlockPrimarySurface()
|
||||||
{
|
{
|
||||||
GdiFlush();
|
GdiFlush();
|
||||||
@ -212,7 +170,6 @@ namespace CompatGdi
|
|||||||
void installHooks()
|
void installHooks()
|
||||||
{
|
{
|
||||||
InitializeCriticalSection(&g_gdiCriticalSection);
|
InitializeCriticalSection(&g_gdiCriticalSection);
|
||||||
CompatPaletteConverter::init();
|
|
||||||
if (CompatGdiDcCache::init())
|
if (CompatGdiDcCache::init())
|
||||||
{
|
{
|
||||||
g_ddUnlockBeginEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
g_ddUnlockBeginEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||||
@ -246,18 +203,9 @@ namespace CompatGdi
|
|||||||
|
|
||||||
void updatePalette(DWORD startingEntry, DWORD count)
|
void updatePalette(DWORD startingEntry, DWORD count)
|
||||||
{
|
{
|
||||||
if (!isEmulationEnabled())
|
if (isEmulationEnabled() && CompatPrimarySurface::palette)
|
||||||
{
|
{
|
||||||
return;
|
CompatGdiDcCache::updatePalette(startingEntry, count);
|
||||||
}
|
|
||||||
|
|
||||||
Compat::ScopedCriticalSection gdiLock(g_gdiCriticalSection);
|
|
||||||
CompatGdiDcCache::clear();
|
|
||||||
|
|
||||||
if (CompatPrimarySurface::palette)
|
|
||||||
{
|
|
||||||
replaceDuplicateWhitePaletteEntries(startingEntry, count);
|
|
||||||
invalidate(nullptr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
#include <cstring>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "CompatDirectDraw.h"
|
#include "CompatDirectDraw.h"
|
||||||
|
#include "CompatDirectDrawPalette.h"
|
||||||
#include "CompatDirectDrawSurface.h"
|
#include "CompatDirectDrawSurface.h"
|
||||||
#include "CompatGdiDcCache.h"
|
#include "CompatGdiDcCache.h"
|
||||||
#include "CompatPrimarySurface.h"
|
#include "CompatPrimarySurface.h"
|
||||||
@ -20,6 +22,8 @@ namespace
|
|||||||
DWORD g_ddLockThreadId = 0;
|
DWORD g_ddLockThreadId = 0;
|
||||||
|
|
||||||
IDirectDraw7* g_directDraw = nullptr;
|
IDirectDraw7* g_directDraw = nullptr;
|
||||||
|
IDirectDrawPalette* g_palette = nullptr;
|
||||||
|
PALETTEENTRY g_paletteEntries[256] = {};
|
||||||
void* g_surfaceMemory = nullptr;
|
void* g_surfaceMemory = nullptr;
|
||||||
LONG g_pitch = 0;
|
LONG g_pitch = 0;
|
||||||
|
|
||||||
@ -74,10 +78,9 @@ namespace
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CompatPrimarySurface::palette)
|
if (CompatPrimarySurface::pixelFormat.dwRGBBitCount <= 8)
|
||||||
{
|
{
|
||||||
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetPalette(
|
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetPalette(surface, g_palette);
|
||||||
surface, CompatPrimarySurface::palette);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return surface;
|
return surface;
|
||||||
@ -168,6 +171,11 @@ namespace CompatGdiDcCache
|
|||||||
bool init()
|
bool init()
|
||||||
{
|
{
|
||||||
g_directDraw = DDrawRepository::getDirectDraw();
|
g_directDraw = DDrawRepository::getDirectDraw();
|
||||||
|
if (g_directDraw)
|
||||||
|
{
|
||||||
|
CompatDirectDraw<IDirectDraw7>::s_origVtable.CreatePalette(
|
||||||
|
g_directDraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256, g_paletteEntries, &g_palette, nullptr);
|
||||||
|
}
|
||||||
return nullptr != g_directDraw;
|
return nullptr != g_directDraw;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,4 +207,31 @@ namespace CompatGdiDcCache
|
|||||||
g_pitch = pitch;
|
g_pitch = pitch;
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updatePalette(DWORD startingEntry, DWORD count)
|
||||||
|
{
|
||||||
|
PALETTEENTRY entries[256] = {};
|
||||||
|
std::memcpy(&entries[startingEntry],
|
||||||
|
&CompatPrimarySurface::paletteEntries[startingEntry],
|
||||||
|
count * sizeof(PALETTEENTRY));
|
||||||
|
|
||||||
|
for (DWORD i = startingEntry; i < startingEntry + count; ++i)
|
||||||
|
{
|
||||||
|
if (entries[i].peFlags & PC_RESERVED)
|
||||||
|
{
|
||||||
|
entries[i] = CompatPrimarySurface::paletteEntries[0];
|
||||||
|
entries[i].peFlags = CompatPrimarySurface::paletteEntries[i].peFlags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != std::memcmp(&g_paletteEntries[startingEntry], &entries[startingEntry],
|
||||||
|
count * sizeof(PALETTEENTRY)))
|
||||||
|
{
|
||||||
|
std::memcpy(&g_paletteEntries[startingEntry], &entries[startingEntry],
|
||||||
|
count * sizeof(PALETTEENTRY));
|
||||||
|
CompatDirectDrawPalette::s_origVtable.SetEntries(
|
||||||
|
g_palette, 0, startingEntry, count, g_paletteEntries);
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,4 +21,5 @@ namespace CompatGdiDcCache
|
|||||||
void releaseDc(const CachedDc& cachedDc);
|
void releaseDc(const CachedDc& cachedDc);
|
||||||
void setDdLockThreadId(DWORD ddLockThreadId);
|
void setDdLockThreadId(DWORD ddLockThreadId);
|
||||||
void setSurfaceMemory(void* surfaceMemory, LONG pitch);
|
void setSurfaceMemory(void* surfaceMemory, LONG pitch);
|
||||||
|
void updatePalette(DWORD startingEntry, DWORD count);
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#include "CompatGdiScrollBar.h"
|
#include "CompatGdiScrollBar.h"
|
||||||
#include "CompatGdiScrollFunctions.h"
|
#include "CompatGdiScrollFunctions.h"
|
||||||
#include "CompatGdiTitleBar.h"
|
#include "CompatGdiTitleBar.h"
|
||||||
#include "CompatPaletteConverter.h"
|
|
||||||
#include "CompatPrimarySurface.h"
|
#include "CompatPrimarySurface.h"
|
||||||
#include "CompatRegistry.h"
|
#include "CompatRegistry.h"
|
||||||
#include "DDrawLog.h"
|
#include "DDrawLog.h"
|
||||||
@ -158,27 +157,8 @@ namespace
|
|||||||
HDC compatDc = CompatGdiDc::getDc(dc, isMenuPaintDc);
|
HDC compatDc = CompatGdiDc::getDc(dc, isMenuPaintDc);
|
||||||
if (compatDc)
|
if (compatDc)
|
||||||
{
|
{
|
||||||
if (CompatPrimarySurface::pixelFormat.dwRGBBitCount <= 8)
|
origWndProc(hwnd, WM_PRINT, reinterpret_cast<WPARAM>(compatDc),
|
||||||
{
|
PRF_NONCLIENT | PRF_ERASEBKGND | PRF_CLIENT);
|
||||||
HDC converterDc = CompatPaletteConverter::lockDc();
|
|
||||||
CompatPaletteConverter::setHalftonePalette();
|
|
||||||
|
|
||||||
origWndProc(hwnd, WM_PRINT, reinterpret_cast<WPARAM>(converterDc),
|
|
||||||
PRF_NONCLIENT | PRF_ERASEBKGND | PRF_CLIENT);
|
|
||||||
|
|
||||||
RECT rect = {};
|
|
||||||
GetWindowRect(hwnd, &rect);
|
|
||||||
CALL_ORIG_FUNC(BitBlt)(compatDc, 0, 0,
|
|
||||||
rect.right - rect.left, rect.bottom - rect.top, converterDc, 0, 0, SRCCOPY);
|
|
||||||
|
|
||||||
CompatPaletteConverter::setPrimaryPalette(0, 256);
|
|
||||||
CompatPaletteConverter::unlockDc();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
origWndProc(hwnd, WM_PRINT, reinterpret_cast<WPARAM>(compatDc),
|
|
||||||
PRF_NONCLIENT | PRF_ERASEBKGND | PRF_CLIENT);
|
|
||||||
}
|
|
||||||
ValidateRect(hwnd, nullptr);
|
ValidateRect(hwnd, nullptr);
|
||||||
CompatGdiDc::releaseDc(dc);
|
CompatGdiDc::releaseDc(dc);
|
||||||
}
|
}
|
||||||
|
@ -14,9 +14,7 @@
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
CRITICAL_SECTION g_criticalSection = {};
|
|
||||||
HDC g_dc = nullptr;
|
HDC g_dc = nullptr;
|
||||||
RGBQUAD g_halftonePalette[256] = {};
|
|
||||||
HGDIOBJ g_oldBitmap = nullptr;
|
HGDIOBJ g_oldBitmap = nullptr;
|
||||||
IDirectDrawSurface7* g_surface = nullptr;
|
IDirectDrawSurface7* g_surface = nullptr;
|
||||||
|
|
||||||
@ -73,18 +71,6 @@ namespace
|
|||||||
CompatDirectDraw<IDirectDraw7>::s_origVtable.CreateSurface(dd, &desc, &surface, nullptr);
|
CompatDirectDraw<IDirectDraw7>::s_origVtable.CreateSurface(dd, &desc, &surface, nullptr);
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initHalftonePalette()
|
|
||||||
{
|
|
||||||
HDC dc = GetDC(nullptr);
|
|
||||||
HPALETTE palette = CreateHalftonePalette(dc);
|
|
||||||
|
|
||||||
GetPaletteEntries(palette, 0, 256, reinterpret_cast<PALETTEENTRY*>(g_halftonePalette));
|
|
||||||
convertPaletteEntriesToRgbQuad(g_halftonePalette, 256);
|
|
||||||
|
|
||||||
DeleteObject(palette);
|
|
||||||
ReleaseDC(nullptr, dc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace CompatPaletteConverter
|
namespace CompatPaletteConverter
|
||||||
@ -122,35 +108,24 @@ namespace CompatPaletteConverter
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Compat::ScopedCriticalSection lock(g_criticalSection);
|
|
||||||
g_oldBitmap = SelectObject(dc, dib);
|
g_oldBitmap = SelectObject(dc, dib);
|
||||||
g_dc = dc;
|
g_dc = dc;
|
||||||
g_surface = surface;
|
g_surface = surface;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void init()
|
HDC getDc()
|
||||||
{
|
{
|
||||||
InitializeCriticalSection(&g_criticalSection);
|
|
||||||
initHalftonePalette();
|
|
||||||
}
|
|
||||||
|
|
||||||
HDC lockDc()
|
|
||||||
{
|
|
||||||
EnterCriticalSection(&g_criticalSection);
|
|
||||||
return g_dc;
|
return g_dc;
|
||||||
}
|
}
|
||||||
|
|
||||||
IDirectDrawSurface7* lockSurface()
|
IDirectDrawSurface7* getSurface()
|
||||||
{
|
{
|
||||||
EnterCriticalSection(&g_criticalSection);
|
|
||||||
return g_surface;
|
return g_surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
void release()
|
void release()
|
||||||
{
|
{
|
||||||
Compat::ScopedCriticalSection lock(g_criticalSection);
|
|
||||||
|
|
||||||
if (!g_surface)
|
if (!g_surface)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -166,7 +141,6 @@ namespace CompatPaletteConverter
|
|||||||
|
|
||||||
void setClipper(IDirectDrawClipper* clipper)
|
void setClipper(IDirectDrawClipper* clipper)
|
||||||
{
|
{
|
||||||
Compat::ScopedCriticalSection lock(g_criticalSection);
|
|
||||||
if (g_surface)
|
if (g_surface)
|
||||||
{
|
{
|
||||||
HRESULT result = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetClipper(
|
HRESULT result = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetClipper(
|
||||||
@ -178,40 +152,15 @@ namespace CompatPaletteConverter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setHalftonePalette()
|
void updatePalette(DWORD startingEntry, DWORD count)
|
||||||
{
|
{
|
||||||
EnterCriticalSection(&g_criticalSection);
|
if (g_dc && CompatPrimarySurface::palette)
|
||||||
SetDIBColorTable(g_dc, 0, 256, g_halftonePalette);
|
|
||||||
LeaveCriticalSection(&g_criticalSection);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setPrimaryPalette(DWORD startingEntry, DWORD count)
|
|
||||||
{
|
|
||||||
Compat::ScopedCriticalSection lock(g_criticalSection);
|
|
||||||
if (g_dc)
|
|
||||||
{
|
{
|
||||||
if (CompatPrimarySurface::palette)
|
RGBQUAD entries[256] = {};
|
||||||
{
|
std::memcpy(entries, &CompatPrimarySurface::paletteEntries[startingEntry],
|
||||||
RGBQUAD entries[256] = {};
|
count * sizeof(PALETTEENTRY));
|
||||||
std::memcpy(entries, &CompatPrimarySurface::paletteEntries[startingEntry],
|
convertPaletteEntriesToRgbQuad(entries, count);
|
||||||
count * sizeof(PALETTEENTRY));
|
SetDIBColorTable(g_dc, startingEntry, count, entries);
|
||||||
convertPaletteEntriesToRgbQuad(entries, count);
|
|
||||||
SetDIBColorTable(g_dc, startingEntry, count, entries);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SetDIBColorTable(g_dc, 0, 256, g_halftonePalette);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void unlockDc()
|
|
||||||
{
|
|
||||||
LeaveCriticalSection(&g_criticalSection);
|
|
||||||
}
|
|
||||||
|
|
||||||
void unlockSurface()
|
|
||||||
{
|
|
||||||
LeaveCriticalSection(&g_criticalSection);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
@ -7,13 +7,9 @@
|
|||||||
namespace CompatPaletteConverter
|
namespace CompatPaletteConverter
|
||||||
{
|
{
|
||||||
bool create();
|
bool create();
|
||||||
void init();
|
HDC getDc();
|
||||||
HDC lockDc();
|
IDirectDrawSurface7* getSurface();
|
||||||
IDirectDrawSurface7* lockSurface();
|
|
||||||
void release();
|
void release();
|
||||||
void setClipper(IDirectDrawClipper* clipper);
|
void setClipper(IDirectDrawClipper* clipper);
|
||||||
void setHalftonePalette();
|
void updatePalette(DWORD startingEntry, DWORD count);
|
||||||
void setPrimaryPalette(DWORD startingEntry, DWORD count);
|
|
||||||
void unlockDc();
|
|
||||||
void unlockSurface();
|
|
||||||
}
|
}
|
||||||
|
@ -53,22 +53,16 @@ namespace
|
|||||||
|
|
||||||
if (CompatPrimarySurface::pixelFormat.dwRGBBitCount <= 8)
|
if (CompatPrimarySurface::pixelFormat.dwRGBBitCount <= 8)
|
||||||
{
|
{
|
||||||
IDirectDrawSurface7* converterSurface = CompatPaletteConverter::lockSurface();
|
origVtable.Blt(CompatPaletteConverter::getSurface(), &g_updateRect,
|
||||||
HDC converterDc = CompatPaletteConverter::lockDc();
|
|
||||||
|
|
||||||
origVtable.Blt(converterSurface, &g_updateRect,
|
|
||||||
CompatPrimarySurface::surface, &g_updateRect, DDBLT_WAIT, nullptr);
|
CompatPrimarySurface::surface, &g_updateRect, DDBLT_WAIT, nullptr);
|
||||||
|
|
||||||
HDC destDc = nullptr;
|
HDC destDc = nullptr;
|
||||||
origVtable.GetDC(dest, &destDc);
|
origVtable.GetDC(dest, &destDc);
|
||||||
result = TRUE == CALL_ORIG_FUNC(BitBlt)(destDc, g_updateRect.left, g_updateRect.top,
|
result = TRUE == CALL_ORIG_FUNC(BitBlt)(destDc, g_updateRect.left, g_updateRect.top,
|
||||||
g_updateRect.right - g_updateRect.left, g_updateRect.bottom - g_updateRect.top,
|
g_updateRect.right - g_updateRect.left, g_updateRect.bottom - g_updateRect.top,
|
||||||
converterDc, g_updateRect.left, g_updateRect.top, SRCCOPY);
|
CompatPaletteConverter::getDc(), g_updateRect.left, g_updateRect.top, SRCCOPY);
|
||||||
origVtable.ReleaseDC(dest, destDc);
|
origVtable.ReleaseDC(dest, destDc);
|
||||||
|
|
||||||
CompatPaletteConverter::unlockDc();
|
|
||||||
CompatPaletteConverter::unlockSurface();
|
|
||||||
|
|
||||||
if (dest == g_frontBuffer)
|
if (dest == g_frontBuffer)
|
||||||
{
|
{
|
||||||
// Force the screen to be updated. It won't refresh from BitBlt alone.
|
// Force the screen to be updated. It won't refresh from BitBlt alone.
|
||||||
@ -374,7 +368,7 @@ void RealPrimarySurface::update()
|
|||||||
|
|
||||||
void RealPrimarySurface::updatePalette(DWORD startingEntry, DWORD count)
|
void RealPrimarySurface::updatePalette(DWORD startingEntry, DWORD count)
|
||||||
{
|
{
|
||||||
CompatPaletteConverter::setPrimaryPalette(startingEntry, count);
|
CompatPaletteConverter::updatePalette(startingEntry, count);
|
||||||
CompatGdi::updatePalette(startingEntry, count);
|
CompatGdi::updatePalette(startingEntry, count);
|
||||||
invalidate(nullptr);
|
invalidate(nullptr);
|
||||||
update();
|
update();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user