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

DIB based palette converter

This commit is contained in:
narzoul 2016-03-28 23:32:54 +02:00
parent 71e90210ad
commit ac305fbbba
5 changed files with 261 additions and 68 deletions

View File

@ -0,0 +1,216 @@
#include <algorithm>
#include "CompatDirectDraw.h"
#include "CompatDirectDrawPalette.h"
#include "CompatDirectDrawSurface.h"
#include "CompatPaletteConverter.h"
#include "CompatPrimarySurface.h"
#include "DDrawRepository.h"
#include "DDrawTypes.h"
#include "Hook.h"
#include "RealPrimarySurface.h"
namespace
{
CRITICAL_SECTION g_criticalSection = {};
HDC g_dc = nullptr;
RGBQUAD g_halftonePalette[256] = {};
HGDIOBJ g_oldBitmap = nullptr;
IDirectDrawSurface7* g_surface = nullptr;
void convertPaletteEntriesToRgbQuad(RGBQUAD (&entries)[256])
{
for (int i = 0; i < 256; ++i)
{
entries[i].rgbReserved = 0;
std::swap(entries[i].rgbRed, entries[i].rgbBlue);
}
}
HBITMAP createDibSection(void*& bits)
{
struct PalettizedBitmapInfo
{
BITMAPINFOHEADER header;
PALETTEENTRY colors[256];
};
PalettizedBitmapInfo bmi = {};
bmi.header.biSize = sizeof(bmi.header);
bmi.header.biWidth = RealPrimarySurface::s_surfaceDesc.dwWidth;
bmi.header.biHeight = -static_cast<LONG>(RealPrimarySurface::s_surfaceDesc.dwHeight);
bmi.header.biPlanes = 1;
bmi.header.biBitCount = 8;
bmi.header.biCompression = BI_RGB;
bmi.header.biClrUsed = 256;
return CreateDIBSection(nullptr, reinterpret_cast<BITMAPINFO*>(&bmi),
DIB_RGB_COLORS, &bits, nullptr, 0);
}
IDirectDrawSurface7* createSurface(void* bits)
{
IDirectDraw7* dd = DDrawRepository::getDirectDraw();
if (!dd)
{
return nullptr;
}
DDSURFACEDESC2 desc = {};
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS |
DDSD_PITCH | DDSD_LPSURFACE;
desc.dwWidth = RealPrimarySurface::s_surfaceDesc.dwWidth;
desc.dwHeight = RealPrimarySurface::s_surfaceDesc.dwHeight;
desc.ddpfPixelFormat = CompatPrimarySurface::displayMode.pixelFormat;
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
desc.lPitch = (RealPrimarySurface::s_surfaceDesc.dwWidth + 3) & ~3;
desc.lpSurface = bits;
IDirectDrawSurface7* surface = nullptr;
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);
DeleteObject(palette);
ReleaseDC(nullptr, dc);
}
}
namespace CompatPaletteConverter
{
bool init()
{
if (CompatPrimarySurface::displayMode.pixelFormat.dwRGBBitCount > 8 &&
RealPrimarySurface::s_surfaceDesc.ddpfPixelFormat.dwRGBBitCount > 8)
{
return true;
}
static bool isFirstInit = true;
if (isFirstInit)
{
InitializeCriticalSection(&g_criticalSection);
initHalftonePalette();
isFirstInit = false;
}
void* bits = nullptr;
HBITMAP dib = createDibSection(bits);
if (!dib)
{
Compat::Log() << "Failed to create the palette converter DIB section";
return false;
}
IDirectDrawSurface7* surface = createSurface(bits);
if (!surface)
{
Compat::Log() << "Failed to create the palette converter surface";
DeleteObject(dib);
return false;
}
HDC dc = CALL_ORIG_FUNC(CreateCompatibleDC)(nullptr);
if (!dc)
{
Compat::Log() << "Failed to create the palette converter DC";
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Release(surface);
DeleteObject(dib);
return false;
}
EnterCriticalSection(&g_criticalSection);
g_oldBitmap = SelectObject(dc, dib);
g_dc = dc;
g_surface = surface;
LeaveCriticalSection(&g_criticalSection);
return true;
}
HDC lockDc()
{
EnterCriticalSection(&g_criticalSection);
return g_dc;
}
IDirectDrawSurface7* lockSurface()
{
EnterCriticalSection(&g_criticalSection);
return g_surface;
}
void release()
{
EnterCriticalSection(&g_criticalSection);
if (!g_surface)
{
LeaveCriticalSection(&g_criticalSection);
return;
}
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.Release(g_surface);
g_surface = nullptr;
DeleteObject(SelectObject(g_dc, g_oldBitmap));
DeleteDC(g_dc);
g_dc = nullptr;
LeaveCriticalSection(&g_criticalSection);
}
void setClipper(IDirectDrawClipper* clipper)
{
EnterCriticalSection(&g_criticalSection);
if (g_surface)
{
HRESULT result = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetClipper(
g_surface, clipper);
if (FAILED(result))
{
LOG_ONCE("Failed to set a clipper on the palette converter surface: " << result);
}
}
LeaveCriticalSection(&g_criticalSection);
}
void setPalette(IDirectDrawPalette* palette)
{
EnterCriticalSection(&g_criticalSection);
if (g_dc)
{
if (palette)
{
RGBQUAD entries[256] = {};
CompatDirectDrawPalette::s_origVtable.GetEntries(
palette, 0, 0, 256, reinterpret_cast<PALETTEENTRY*>(entries));
convertPaletteEntriesToRgbQuad(entries);
SetDIBColorTable(g_dc, 0, 256, entries);
}
else
{
SetDIBColorTable(g_dc, 0, 256, g_halftonePalette);
}
}
LeaveCriticalSection(&g_criticalSection);
}
void unlockDc()
{
LeaveCriticalSection(&g_criticalSection);
}
void unlockSurface()
{
LeaveCriticalSection(&g_criticalSection);
}
};

View File

@ -0,0 +1,17 @@
#pragma once
#define CINTERFACE
#include <ddraw.h>
namespace CompatPaletteConverter
{
bool init();
HDC lockDc();
IDirectDrawSurface7* lockSurface();
void release();
void setClipper(IDirectDrawClipper* clipper);
void setPalette(IDirectDrawPalette* palette);
void unlockDc();
void unlockSurface();
}

View File

@ -155,6 +155,7 @@
<ClInclude Include="CompatGdiScrollFunctions.h" />
<ClInclude Include="CompatGdiTitleBar.h" />
<ClInclude Include="CompatGdiWinProc.h" />
<ClInclude Include="CompatPaletteConverter.h" />
<ClInclude Include="CompatRegistry.h" />
<ClInclude Include="Config.h" />
<ClInclude Include="DDrawProcs.h" />
@ -187,6 +188,7 @@
<ClCompile Include="CompatGdiScrollFunctions.cpp" />
<ClCompile Include="CompatGdiTitleBar.cpp" />
<ClCompile Include="CompatGdiWinProc.cpp" />
<ClCompile Include="CompatPaletteConverter.cpp" />
<ClCompile Include="CompatRegistry.cpp" />
<ClCompile Include="CompatVtable.cpp" />
<ClCompile Include="DDrawLog.cpp" />

View File

@ -102,6 +102,9 @@
<ClInclude Include="DDrawRepository.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CompatPaletteConverter.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="DllMain.cpp">
@ -176,6 +179,9 @@
<ClCompile Include="DDrawRepository.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CompatPaletteConverter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="DDrawCompat.def">

View File

@ -3,6 +3,7 @@
#include "CompatDirectDraw.h"
#include "CompatDirectDrawSurface.h"
#include "CompatGdi.h"
#include "CompatPaletteConverter.h"
#include "CompatPrimarySurface.h"
#include "Config.h"
#include "DDrawProcs.h"
@ -18,7 +19,6 @@ namespace
IDirectDrawSurface7* g_frontBuffer = nullptr;
IDirectDrawSurface7* g_backBuffer = nullptr;
IDirectDrawSurface7* g_paletteConverterSurface = nullptr;
IReleaseNotifier g_releaseNotifier(onRelease);
HANDLE g_updateThread = nullptr;
@ -46,22 +46,23 @@ namespace
clipper->lpVtbl->Release(clipper);
}
if (g_paletteConverterSurface)
if (CompatPrimarySurface::pixelFormat.dwRGBBitCount <= 8)
{
origVtable.Blt(g_paletteConverterSurface, nullptr, CompatPrimarySurface::surface, nullptr,
IDirectDrawSurface7* converterSurface = CompatPaletteConverter::lockSurface();
HDC converterDc = CompatPaletteConverter::lockDc();
origVtable.Blt(converterSurface, nullptr, CompatPrimarySurface::surface, nullptr,
DDBLT_WAIT, nullptr);
HDC destDc = nullptr;
origVtable.GetDC(dest, &destDc);
HDC converterDc = nullptr;
origVtable.GetDC(g_paletteConverterSurface, &converterDc);
result = TRUE == CALL_ORIG_FUNC(BitBlt)(destDc, 0, 0,
RealPrimarySurface::s_surfaceDesc.dwWidth, RealPrimarySurface::s_surfaceDesc.dwHeight,
converterDc, 0, 0, SRCCOPY);
origVtable.ReleaseDC(g_paletteConverterSurface, converterDc);
origVtable.ReleaseDC(dest, destDc);
CompatPaletteConverter::unlockDc();
CompatPaletteConverter::unlockSurface();
}
else
{
@ -73,36 +74,6 @@ namespace
return result;
}
template <typename DirectDraw>
HRESULT createPaletteConverterSurface(DirectDraw& dd)
{
if (CompatPrimarySurface::displayMode.pixelFormat.dwRGBBitCount > 8 &&
RealPrimarySurface::s_surfaceDesc.ddpfPixelFormat.dwRGBBitCount > 8)
{
return DD_OK;
}
typename Types<DirectDraw>::TSurfaceDesc desc = {};
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS;
desc.dwWidth = RealPrimarySurface::s_surfaceDesc.dwWidth;
desc.dwHeight = RealPrimarySurface::s_surfaceDesc.dwHeight;
desc.ddpfPixelFormat = CompatPrimarySurface::displayMode.pixelFormat;
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
typedef typename Types<DirectDraw>::TCreatedSurface TCreatedSurface;
TCreatedSurface* surface = nullptr;
HRESULT result = CompatDirectDraw<DirectDraw>::s_origVtable.CreateSurface(&dd, &desc, &surface, nullptr);
if (SUCCEEDED(result))
{
CompatDirectDrawSurface<TCreatedSurface>::s_origVtable.QueryInterface(
surface, IID_IDirectDrawSurface7, reinterpret_cast<LPVOID*>(&g_paletteConverterSurface));
CompatDirectDrawSurface<TCreatedSurface>::s_origVtable.Release(surface);
}
return result;
}
DWORD getTimeElapsedInMs(const LARGE_INTEGER& time)
{
LARGE_INTEGER currentTime = {};
@ -117,11 +88,7 @@ namespace
g_frontBuffer = nullptr;
g_backBuffer = nullptr;
g_isFullScreen = false;
if (g_paletteConverterSurface)
{
g_paletteConverterSurface->lpVtbl->Release(g_paletteConverterSurface);
g_paletteConverterSurface = nullptr;
}
CompatPaletteConverter::release();
ZeroMemory(&RealPrimarySurface::s_surfaceDesc, sizeof(RealPrimarySurface::s_surfaceDesc));
@ -220,13 +187,11 @@ HRESULT RealPrimarySurface::create(DirectDraw& dd)
s_surfaceDesc.dwSize = sizeof(s_surfaceDesc);
g_frontBuffer->lpVtbl->GetSurfaceDesc(g_frontBuffer, &s_surfaceDesc);
result = createPaletteConverterSurface(dd);
if (FAILED(result))
if (!CompatPaletteConverter::init())
{
Compat::Log() << "Failed to create palette converter surface";
g_frontBuffer->lpVtbl->Release(g_frontBuffer);
g_frontBuffer = nullptr;
return result;
return DDERR_GENERIC;
}
if (isFlippable)
@ -322,15 +287,7 @@ HRESULT RealPrimarySurface::restore()
void RealPrimarySurface::setClipper(LPDIRECTDRAWCLIPPER clipper)
{
if (g_paletteConverterSurface)
{
HRESULT result = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetClipper(
g_paletteConverterSurface, clipper);
if (FAILED(result))
{
LOG_ONCE("Failed to set the clipper on the converter surface: " << result);
}
}
CompatPaletteConverter::setClipper(clipper);
HRESULT result = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetClipper(
g_frontBuffer, clipper);
@ -342,20 +299,10 @@ void RealPrimarySurface::setClipper(LPDIRECTDRAWCLIPPER clipper)
void RealPrimarySurface::setPalette(LPDIRECTDRAWPALETTE palette)
{
auto& origVtable = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable;
if (g_paletteConverterSurface && CompatPrimarySurface::pixelFormat.dwRGBBitCount <= 8)
{
HRESULT result = origVtable.SetPalette(g_paletteConverterSurface, palette);
if (FAILED(result))
{
LOG_ONCE("Failed to set the palette on the converter surface: " << result);
}
}
if (s_surfaceDesc.ddpfPixelFormat.dwRGBBitCount <= 8)
{
HRESULT result = origVtable.SetPalette(g_frontBuffer, palette);
HRESULT result = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetPalette(
g_frontBuffer, palette);
if (FAILED(result) && DDERR_NOPALETTEATTACHED != result)
{
LOG_ONCE("Failed to set the palette on the real primary surface: " << result);
@ -373,6 +320,11 @@ void RealPrimarySurface::update()
void RealPrimarySurface::updatePalette()
{
if (CompatPrimarySurface::pixelFormat.dwRGBBitCount <= 8)
{
CompatPaletteConverter::setPalette(CompatPrimarySurface::palette);
}
CompatGdi::updatePalette();
updateNow();
}