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 <cstring>
|
||||
|
||||
#include "CompatDirectDrawPalette.h"
|
||||
#include "CompatDirectDrawSurface.h"
|
||||
@ -25,8 +24,6 @@ namespace
|
||||
HANDLE g_ddUnlockEndEvent = nullptr;
|
||||
bool g_isDelayedUnlockPending = false;
|
||||
|
||||
PALETTEENTRY g_usedPaletteEntries[256] = {};
|
||||
|
||||
BOOL CALLBACK invalidateWindow(HWND hwnd, LPARAM lParam)
|
||||
{
|
||||
if (!IsWindowVisible(hwnd))
|
||||
@ -73,45 +70,6 @@ namespace
|
||||
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()
|
||||
{
|
||||
GdiFlush();
|
||||
@ -212,7 +170,6 @@ namespace CompatGdi
|
||||
void installHooks()
|
||||
{
|
||||
InitializeCriticalSection(&g_gdiCriticalSection);
|
||||
CompatPaletteConverter::init();
|
||||
if (CompatGdiDcCache::init())
|
||||
{
|
||||
g_ddUnlockBeginEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
@ -246,18 +203,9 @@ namespace CompatGdi
|
||||
|
||||
void updatePalette(DWORD startingEntry, DWORD count)
|
||||
{
|
||||
if (!isEmulationEnabled())
|
||||
if (isEmulationEnabled() && CompatPrimarySurface::palette)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Compat::ScopedCriticalSection gdiLock(g_gdiCriticalSection);
|
||||
CompatGdiDcCache::clear();
|
||||
|
||||
if (CompatPrimarySurface::palette)
|
||||
{
|
||||
replaceDuplicateWhitePaletteEntries(startingEntry, count);
|
||||
invalidate(nullptr);
|
||||
CompatGdiDcCache::updatePalette(startingEntry, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#include "CompatDirectDraw.h"
|
||||
#include "CompatDirectDrawPalette.h"
|
||||
#include "CompatDirectDrawSurface.h"
|
||||
#include "CompatGdiDcCache.h"
|
||||
#include "CompatPrimarySurface.h"
|
||||
@ -20,6 +22,8 @@ namespace
|
||||
DWORD g_ddLockThreadId = 0;
|
||||
|
||||
IDirectDraw7* g_directDraw = nullptr;
|
||||
IDirectDrawPalette* g_palette = nullptr;
|
||||
PALETTEENTRY g_paletteEntries[256] = {};
|
||||
void* g_surfaceMemory = nullptr;
|
||||
LONG g_pitch = 0;
|
||||
|
||||
@ -74,10 +78,9 @@ namespace
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (CompatPrimarySurface::palette)
|
||||
if (CompatPrimarySurface::pixelFormat.dwRGBBitCount <= 8)
|
||||
{
|
||||
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetPalette(
|
||||
surface, CompatPrimarySurface::palette);
|
||||
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetPalette(surface, g_palette);
|
||||
}
|
||||
|
||||
return surface;
|
||||
@ -168,6 +171,11 @@ namespace CompatGdiDcCache
|
||||
bool init()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@ -199,4 +207,31 @@ namespace CompatGdiDcCache
|
||||
g_pitch = pitch;
|
||||
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 setDdLockThreadId(DWORD ddLockThreadId);
|
||||
void setSurfaceMemory(void* surfaceMemory, LONG pitch);
|
||||
void updatePalette(DWORD startingEntry, DWORD count);
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
#include "CompatGdiScrollBar.h"
|
||||
#include "CompatGdiScrollFunctions.h"
|
||||
#include "CompatGdiTitleBar.h"
|
||||
#include "CompatPaletteConverter.h"
|
||||
#include "CompatPrimarySurface.h"
|
||||
#include "CompatRegistry.h"
|
||||
#include "DDrawLog.h"
|
||||
@ -158,27 +157,8 @@ namespace
|
||||
HDC compatDc = CompatGdiDc::getDc(dc, isMenuPaintDc);
|
||||
if (compatDc)
|
||||
{
|
||||
if (CompatPrimarySurface::pixelFormat.dwRGBBitCount <= 8)
|
||||
{
|
||||
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);
|
||||
}
|
||||
origWndProc(hwnd, WM_PRINT, reinterpret_cast<WPARAM>(compatDc),
|
||||
PRF_NONCLIENT | PRF_ERASEBKGND | PRF_CLIENT);
|
||||
ValidateRect(hwnd, nullptr);
|
||||
CompatGdiDc::releaseDc(dc);
|
||||
}
|
||||
|
@ -14,9 +14,7 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
CRITICAL_SECTION g_criticalSection = {};
|
||||
HDC g_dc = nullptr;
|
||||
RGBQUAD g_halftonePalette[256] = {};
|
||||
HGDIOBJ g_oldBitmap = nullptr;
|
||||
IDirectDrawSurface7* g_surface = nullptr;
|
||||
|
||||
@ -73,18 +71,6 @@ namespace
|
||||
CompatDirectDraw<IDirectDraw7>::s_origVtable.CreateSurface(dd, &desc, &surface, nullptr);
|
||||
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
|
||||
@ -122,35 +108,24 @@ namespace CompatPaletteConverter
|
||||
return false;
|
||||
}
|
||||
|
||||
Compat::ScopedCriticalSection lock(g_criticalSection);
|
||||
g_oldBitmap = SelectObject(dc, dib);
|
||||
g_dc = dc;
|
||||
g_surface = surface;
|
||||
return true;
|
||||
}
|
||||
|
||||
void init()
|
||||
HDC getDc()
|
||||
{
|
||||
InitializeCriticalSection(&g_criticalSection);
|
||||
initHalftonePalette();
|
||||
}
|
||||
|
||||
HDC lockDc()
|
||||
{
|
||||
EnterCriticalSection(&g_criticalSection);
|
||||
return g_dc;
|
||||
}
|
||||
|
||||
IDirectDrawSurface7* lockSurface()
|
||||
IDirectDrawSurface7* getSurface()
|
||||
{
|
||||
EnterCriticalSection(&g_criticalSection);
|
||||
return g_surface;
|
||||
}
|
||||
|
||||
void release()
|
||||
{
|
||||
Compat::ScopedCriticalSection lock(g_criticalSection);
|
||||
|
||||
if (!g_surface)
|
||||
{
|
||||
return;
|
||||
@ -166,7 +141,6 @@ namespace CompatPaletteConverter
|
||||
|
||||
void setClipper(IDirectDrawClipper* clipper)
|
||||
{
|
||||
Compat::ScopedCriticalSection lock(g_criticalSection);
|
||||
if (g_surface)
|
||||
{
|
||||
HRESULT result = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetClipper(
|
||||
@ -178,40 +152,15 @@ namespace CompatPaletteConverter
|
||||
}
|
||||
}
|
||||
|
||||
void setHalftonePalette()
|
||||
void updatePalette(DWORD startingEntry, DWORD count)
|
||||
{
|
||||
EnterCriticalSection(&g_criticalSection);
|
||||
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 (g_dc && CompatPrimarySurface::palette)
|
||||
{
|
||||
if (CompatPrimarySurface::palette)
|
||||
{
|
||||
RGBQUAD entries[256] = {};
|
||||
std::memcpy(entries, &CompatPrimarySurface::paletteEntries[startingEntry],
|
||||
count * sizeof(PALETTEENTRY));
|
||||
convertPaletteEntriesToRgbQuad(entries, count);
|
||||
SetDIBColorTable(g_dc, startingEntry, count, entries);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetDIBColorTable(g_dc, 0, 256, g_halftonePalette);
|
||||
}
|
||||
RGBQUAD entries[256] = {};
|
||||
std::memcpy(entries, &CompatPrimarySurface::paletteEntries[startingEntry],
|
||||
count * sizeof(PALETTEENTRY));
|
||||
convertPaletteEntriesToRgbQuad(entries, count);
|
||||
SetDIBColorTable(g_dc, startingEntry, count, entries);
|
||||
}
|
||||
}
|
||||
|
||||
void unlockDc()
|
||||
{
|
||||
LeaveCriticalSection(&g_criticalSection);
|
||||
}
|
||||
|
||||
void unlockSurface()
|
||||
{
|
||||
LeaveCriticalSection(&g_criticalSection);
|
||||
}
|
||||
};
|
||||
|
@ -7,13 +7,9 @@
|
||||
namespace CompatPaletteConverter
|
||||
{
|
||||
bool create();
|
||||
void init();
|
||||
HDC lockDc();
|
||||
IDirectDrawSurface7* lockSurface();
|
||||
HDC getDc();
|
||||
IDirectDrawSurface7* getSurface();
|
||||
void release();
|
||||
void setClipper(IDirectDrawClipper* clipper);
|
||||
void setHalftonePalette();
|
||||
void setPrimaryPalette(DWORD startingEntry, DWORD count);
|
||||
void unlockDc();
|
||||
void unlockSurface();
|
||||
void updatePalette(DWORD startingEntry, DWORD count);
|
||||
}
|
||||
|
@ -53,22 +53,16 @@ namespace
|
||||
|
||||
if (CompatPrimarySurface::pixelFormat.dwRGBBitCount <= 8)
|
||||
{
|
||||
IDirectDrawSurface7* converterSurface = CompatPaletteConverter::lockSurface();
|
||||
HDC converterDc = CompatPaletteConverter::lockDc();
|
||||
|
||||
origVtable.Blt(converterSurface, &g_updateRect,
|
||||
origVtable.Blt(CompatPaletteConverter::getSurface(), &g_updateRect,
|
||||
CompatPrimarySurface::surface, &g_updateRect, DDBLT_WAIT, nullptr);
|
||||
|
||||
HDC destDc = nullptr;
|
||||
origVtable.GetDC(dest, &destDc);
|
||||
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,
|
||||
converterDc, g_updateRect.left, g_updateRect.top, SRCCOPY);
|
||||
CompatPaletteConverter::getDc(), g_updateRect.left, g_updateRect.top, SRCCOPY);
|
||||
origVtable.ReleaseDC(dest, destDc);
|
||||
|
||||
CompatPaletteConverter::unlockDc();
|
||||
CompatPaletteConverter::unlockSurface();
|
||||
|
||||
if (dest == g_frontBuffer)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
CompatPaletteConverter::setPrimaryPalette(startingEntry, count);
|
||||
CompatPaletteConverter::updatePalette(startingEntry, count);
|
||||
CompatGdi::updatePalette(startingEntry, count);
|
||||
invalidate(nullptr);
|
||||
update();
|
||||
|
Loading…
x
Reference in New Issue
Block a user