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:
parent
71e90210ad
commit
ac305fbbba
216
DDrawCompat/CompatPaletteConverter.cpp
Normal file
216
DDrawCompat/CompatPaletteConverter.cpp
Normal 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);
|
||||
}
|
||||
};
|
17
DDrawCompat/CompatPaletteConverter.h
Normal file
17
DDrawCompat/CompatPaletteConverter.h
Normal 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();
|
||||
}
|
@ -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" />
|
||||
|
@ -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">
|
||||
|
@ -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();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user