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

Fixed incompatibilities with Empire Earth NeoEE mod

See issue #251.
This commit is contained in:
narzoul 2023-11-19 11:13:57 +01:00
parent 329679b4e9
commit 537f79f453
12 changed files with 247 additions and 65 deletions

View File

@ -1317,18 +1317,46 @@ namespace D3dDdi
continue;
}
D3DDDIFORMAT format = D3DDDIFMT_X8R8G8B8;
COLORREF colorKey = 0;
BYTE alpha = 0;
DWORD flags = 0;
if (layeredWindow.dc)
{
colorKey = layeredWindow.colorKey;
alpha = layeredWindow.alpha;
if (CLR_INVALID != colorKey)
{
flags |= ULW_COLORKEY;
}
if (255 != alpha)
{
flags |= ULW_ALPHA;
}
if (layeredWindow.alphaFormat & AC_SRC_ALPHA)
{
format = D3DDDIFMT_A8R8G8B8;
}
}
else
{
GetLayeredWindowAttributes(layeredWindow.hwnd, &colorKey, &alpha, &flags);
}
RECT srcRect = { 0, 0, visibleRect.right - visibleRect.left + 1, visibleRect.bottom - visibleRect.top + 1 };
auto& windowSurface = repo.getTempSysMemSurface(srcRect.right, srcRect.bottom);
auto& texture = repo.getTempTexture(srcRect.right, srcRect.bottom, D3DDDIFMT_A8R8G8B8);
auto& texture = repo.getTempTexture(srcRect.right, srcRect.bottom, format);
if (!windowSurface.resource || !texture.resource)
{
continue;
}
HDC srcDc = GetWindowDC(layeredWindow.hwnd);
HDC srcDc = layeredWindow.dc ? layeredWindow.dc : GetWindowDC(layeredWindow.hwnd);
HDC dstDc = nullptr;
POINT srcOrig = { visibleRect.left - layeredWindow.rect.left, visibleRect.top - layeredWindow.rect.top };
windowSurface.surface->GetDC(windowSurface.surface, &dstDc);
CALL_ORIG_FUNC(BitBlt)(dstDc, 0, 0, srcRect.right - 1, srcRect.bottom - 1,
srcDc, srcOrig.x, srcOrig.y, SRCCOPY);
CALL_ORIG_FUNC(BitBlt)(dstDc, srcRect.right - 1, 0, 1, srcRect.bottom - 1,
@ -1337,16 +1365,16 @@ namespace D3dDdi
srcDc, srcOrig.x, srcOrig.y + srcRect.bottom - 2, SRCCOPY);
CALL_ORIG_FUNC(BitBlt)(dstDc, srcRect.right - 1, srcRect.bottom - 1, 1, 1,
srcDc, srcOrig.x + srcRect.right - 2, srcOrig.y + srcRect.bottom - 2, SRCCOPY);
windowSurface.surface->ReleaseDC(windowSurface.surface, dstDc);
ReleaseDC(layeredWindow.hwnd, srcDc);
if (!layeredWindow.dc)
{
ReleaseDC(layeredWindow.hwnd, srcDc);
}
copySubResourceRegion(*texture.resource, 0, srcRect, *windowSurface.resource, 0, srcRect);
windowSurface.resource->notifyLock(0);
COLORREF colorKey = 0;
BYTE alpha = 0;
DWORD flags = 0;
GetLayeredWindowAttributes(layeredWindow.hwnd, &colorKey, &alpha, &flags);
const ShaderBlitter::ColorKeyInfo ck = { colorKey,
(flags & ULW_COLORKEY) ? D3DDDIFMT_A8R8G8B8 : D3DDDIFMT_UNKNOWN };
@ -1359,9 +1387,17 @@ namespace D3dDdi
srcRect.right--;
srcRect.bottom--;
blitter.textureBlt(dst, dstSubResourceIndex, visibleRect, *texture.resource, 0, srcRect,
D3DTEXF_LINEAR | D3DTEXF_SRGB, ck, (flags & ULW_ALPHA) ? &alpha : nullptr,
layeredWindow.region);
if (layeredWindow.dc)
{
blitter.alphaBlendBlt(dst, dstSubResourceIndex, visibleRect, *texture.resource, 0, srcRect,
ck, (flags & ULW_ALPHA) ? alpha : 255, layeredWindow.region);
}
else
{
blitter.textureBlt(dst, dstSubResourceIndex, visibleRect, *texture.resource, 0, srcRect,
D3DTEXF_LINEAR | D3DTEXF_SRGB, ck, (flags & ULW_ALPHA) ? &alpha : nullptr,
layeredWindow.region);
}
}
}

View File

@ -3,10 +3,12 @@
#include <Config/Settings/DisplayFilter.h>
#include <D3dDdi/Adapter.h>
#include <D3dDdi/Device.h>
#include <D3dDdi/Log/CommonLog.h>
#include <D3dDdi/Resource.h>
#include <D3dDdi/ShaderBlitter.h>
#include <D3dDdi/SurfaceRepository.h>
#include <DDraw/Surfaces/PrimarySurface.h>
#include <Shaders/AlphaBlend.h>
#include <Shaders/Bilinear.h>
#include <Shaders/ColorKey.h>
#include <Shaders/ColorKeyBlend.h>
@ -29,7 +31,8 @@
namespace
{
const UINT BLT_SRCALPHA = 1;
const UINT BLT_COLORKEYTEST = 2;
const UINT BLT_PREMULTIPLIED = 2;
const UINT BLT_COLORKEYTEST = 4;
const UINT CF_HORIZONTAL = 1;
const UINT CF_GAMMARAMP = 2;
@ -41,6 +44,11 @@ namespace
std::array<D3dDdi::DeviceState::ShaderConstF, 2> convertToShaderConst(D3dDdi::ShaderBlitter::ColorKeyInfo colorKeyInfo)
{
if (D3DDDIFMT_UNKNOWN == colorKeyInfo.format)
{
return {};
}
const auto& fi = D3dDdi::getFormatInfo(colorKeyInfo.format);
return { {
{
@ -78,8 +86,16 @@ namespace
namespace D3dDdi
{
std::ostream& operator<<(std::ostream& os, ShaderBlitter::ColorKeyInfo ck)
{
return Compat::LogStruct(os)
<< Compat::hex(ck.colorKey)
<< ck.format;
}
ShaderBlitter::ShaderBlitter(Device& device)
: m_device(device)
, m_psAlphaBlend(createPixelShader(g_psAlphaBlend))
, m_psBilinear(createPixelShader(g_psBilinear))
, m_psColorKey(createPixelShader(g_psColorKey))
, m_psColorKeyBlend(createPixelShader(g_psColorKeyBlend))
@ -106,6 +122,22 @@ namespace D3dDdi
}
}
void ShaderBlitter::alphaBlendBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect,
ColorKeyInfo srcColorKey, BYTE alpha, const Gdi::Region& srcRgn)
{
LOG_FUNC("ShaderBlitter::alphaBlendBlt", static_cast<HANDLE>(dstResource), dstSubResourceIndex, dstRect,
static_cast<HANDLE>(srcResource), srcSubResourceIndex, srcRect,
srcColorKey, static_cast<UINT>(alpha), static_cast<HRGN>(srcRgn));
auto ck = convertToShaderConst(srcColorKey);
ck[0][3] = alpha / 255.0f;
DeviceState::TempPixelShaderConst psConst(m_device.getState(), { 30, 2 }, ck.data());
blt(dstResource, dstSubResourceIndex, dstRect,
srcResource, srcSubResourceIndex, srcRect,
m_psAlphaBlend.get(), D3DTEXF_LINEAR, BLT_SRCALPHA | BLT_PREMULTIPLIED, nullptr, srcRgn);
}
void ShaderBlitter::bicubicBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect, UINT blurPercent)
{
@ -156,7 +188,7 @@ namespace D3dDdi
HANDLE pixelShader, UINT filter, UINT flags, const BYTE* alpha, const Gdi::Region& srcRgn)
{
LOG_FUNC("ShaderBlitter::blt", static_cast<HANDLE>(dstResource), dstSubResourceIndex, dstRect,
static_cast<HANDLE>(srcResource), srcSubResourceIndex, srcRect, pixelShader, filter,
static_cast<HANDLE>(srcResource), srcSubResourceIndex, srcRect, pixelShader, Compat::hex(filter),
Compat::hex(flags), alpha, static_cast<HRGN>(srcRgn));
if (!m_vertexShaderDecl || !pixelShader)
@ -214,9 +246,10 @@ namespace D3dDdi
}
else if (flags & BLT_SRCALPHA)
{
const UINT D3DBLEND_ONE = 2;
const UINT D3DBLEND_SRCALPHA = 5;
const UINT D3DBLEND_INVSRCALPHA = 6;
state.setTempRenderState({ D3DDDIRS_SRCBLEND, D3DBLEND_SRCALPHA });
state.setTempRenderState({ D3DDDIRS_SRCBLEND, (flags & BLT_PREMULTIPLIED) ? D3DBLEND_ONE : D3DBLEND_SRCALPHA });
state.setTempRenderState({ D3DDDIRS_DESTBLEND, D3DBLEND_INVSRCALPHA });
}

View File

@ -31,6 +31,9 @@ namespace D3dDdi
ShaderBlitter& operator=(const ShaderBlitter&) = delete;
ShaderBlitter& operator=(ShaderBlitter&&) = delete;
void alphaBlendBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect,
ColorKeyInfo srcColorKey, BYTE alpha, const Gdi::Region& srcRgn);
void bilinearBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
const Resource& srcResource, UINT srcSubResourceIndex, const RECT& srcRect, UINT blurPercent);
void bicubicBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
@ -117,6 +120,7 @@ namespace D3dDdi
void setTextureCoords(UINT stage, const RECT& rect, UINT width, UINT height);
Device& m_device;
std::unique_ptr<void, ResourceDeleter> m_psAlphaBlend;
std::unique_ptr<void, ResourceDeleter> m_psBilinear;
std::unique_ptr<void, ResourceDeleter> m_psColorKey;
std::unique_ptr<void, ResourceDeleter> m_psColorKeyBlend;
@ -134,4 +138,6 @@ namespace D3dDdi
ConvolutionParams m_convolutionParams;
std::array<Vertex, 4> m_vertices;
};
std::ostream& operator<<(std::ostream& os, ShaderBlitter::ColorKeyInfo ck);
}

View File

@ -478,6 +478,7 @@
<None Include="Shaders\CubicConvolution.hlsli" />
</ItemGroup>
<ItemGroup>
<FxCompile Include="Shaders\AlphaBlend.hlsl" />
<FxCompile Include="Shaders\Bilinear.hlsl" />
<FxCompile Include="Shaders\ColorKey.hlsl" />
<FxCompile Include="Shaders\ColorKeyBlend.hlsl" />

View File

@ -1169,6 +1169,9 @@
<FxCompile Include="Shaders\PointNoFilter.hlsl">
<Filter>Shaders</Filter>
</FxCompile>
<FxCompile Include="Shaders\AlphaBlend.hlsl">
<Filter>Shaders</Filter>
</FxCompile>
</ItemGroup>
<ItemGroup>
<Image Include="arrow.bmp">

View File

@ -40,6 +40,10 @@ namespace Gdi
if (presentationWindow)
{
CALL_ORIG_FUNC(SetLayeredWindowAttributes)(presentationWindow, 0, 255, LWA_ALPHA);
if (owner)
{
AttachThreadInput(GetCurrentThreadId(), GetWindowThreadProcessId(owner, nullptr), FALSE);
}
}
});
return LOG_RESULT(presentationWindow);

View File

@ -755,6 +755,36 @@ namespace
}
}
BOOL WINAPI updateLayeredWindow(HWND hWnd, HDC hdcDst, POINT* pptDst, SIZE* psize,
HDC hdcSrc, POINT* pptSrc, COLORREF crKey, BLENDFUNCTION* pblend, DWORD dwFlags)
{
LOG_FUNC("UpdateLayeredWindow", hWnd, hdcDst, pptDst, psize, hdcSrc, pptSrc, crKey, pblend, dwFlags);
BOOL result = CALL_ORIG_FUNC(UpdateLayeredWindow)(
hWnd, hdcDst, pptDst, psize, hdcSrc, pptSrc, crKey, pblend, dwFlags);
if (result)
{
Gdi::Window::updateLayeredWindowInfo(hWnd, hdcSrc, pptSrc,
(dwFlags & ULW_COLORKEY) ? crKey : CLR_INVALID,
((dwFlags & ULW_ALPHA) && pblend) ? pblend->SourceConstantAlpha : 255,
pblend ? pblend->AlphaFormat : 0);
}
return LOG_RESULT(result);
}
BOOL WINAPI updateLayeredWindowIndirect(HWND hwnd, const UPDATELAYEREDWINDOWINFO* pULWInfo)
{
LOG_FUNC("UpdateLayeredWindowIndirect", hwnd, pULWInfo);
BOOL result = CALL_ORIG_FUNC(UpdateLayeredWindowIndirect)(hwnd, pULWInfo);
if (result && pULWInfo)
{
Gdi::Window::updateLayeredWindowInfo(hwnd, pULWInfo->hdcSrc, pULWInfo->pptSrc,
(pULWInfo->dwFlags & ULW_COLORKEY) ? pULWInfo->crKey : CLR_INVALID,
((pULWInfo->dwFlags & ULW_ALPHA) && pULWInfo->pblend) ? pULWInfo->pblend->SourceConstantAlpha : 255,
pULWInfo->pblend ? pULWInfo->pblend->AlphaFormat : 0);
}
return LOG_RESULT(result);
}
void CALLBACK winEventProc(
HWINEVENTHOOK /*hWinEventHook*/,
DWORD event,
@ -880,6 +910,8 @@ namespace Gdi
HOOK_FUNCTION(user32, SetWindowLongA, setWindowLongA);
HOOK_FUNCTION(user32, SetWindowLongW, setWindowLongW);
HOOK_FUNCTION(user32, SetWindowPos, setWindowPos);
HOOK_FUNCTION(user32, UpdateLayeredWindow, updateLayeredWindow);
HOOK_FUNCTION(user32, UpdateLayeredWindowIndirect, updateLayeredWindowIndirect);
g_dwmSetIconicThumbnail = reinterpret_cast<decltype(&DwmSetIconicThumbnail)>(
GetProcAddress(GetModuleHandle("dwmapi"), "DwmSetIconicThumbnail"));

View File

@ -5,6 +5,7 @@
#include <dwmapi.h>
#include <Common/Log.h>
#include <Common/Rect.h>
#include <D3dDdi/KernelModeThunks.h>
#include <D3dDdi/ScopedCriticalSection.h>
#include <DDraw/RealPrimarySurface.h>
@ -23,6 +24,74 @@
namespace
{
class LayeredWindowContent
{
public:
~LayeredWindowContent()
{
destroy();
}
BYTE getAlpha() const { return m_alpha; }
BYTE getAlphaFormat() const { return m_alphaFormat; }
COLORREF getColorKey() const { return m_colorKey; }
HDC getDc() const { return m_dc; }
void set(HWND hwnd, HDC hdcSrc, const POINT* pptSrc, COLORREF colorKey, BYTE alpha, BYTE alphaFormat)
{
if (hdcSrc)
{
RECT wr = {};
GetWindowRect(hwnd, &wr);
const SIZE size = Rect::getSize(wr);
if (size != m_size)
{
destroy();
m_size = size;
m_dc = CreateCompatibleDC(nullptr);
m_origBmp = SelectObject(m_dc, CALL_ORIG_FUNC(CreateBitmap)(size.cx, size.cy, 1, 32, nullptr));
}
CALL_ORIG_FUNC(BitBlt)(m_dc, 0, 0, size.cx, size.cy,
hdcSrc, pptSrc ? pptSrc->x : 0, pptSrc ? pptSrc->y : 0, SRCCOPY);
if (alphaFormat & AC_SRC_ALPHA)
{
BITMAP bm = {};
GetObject(GetCurrentObject(hdcSrc, OBJ_BITMAP), sizeof(bm), &bm);
if (32 != bm.bmBitsPixel)
{
alphaFormat &= ~AC_SRC_ALPHA;
}
}
}
m_colorKey = colorKey;
m_alpha = alpha;
m_alphaFormat = alphaFormat;
}
private:
void destroy()
{
if (m_dc)
{
DeleteObject(SelectObject(m_dc, m_origBmp));
DeleteDC(m_dc);
m_dc = nullptr;
m_origBmp = nullptr;
}
}
HDC m_dc = nullptr;
HGDIOBJ m_origBmp = nullptr;
SIZE m_size = {};
COLORREF m_colorKey = CLR_INVALID;
BYTE m_alpha = 255;
BYTE m_alphaFormat = 0;
};
struct UpdateWindowContext
{
Gdi::Region obscuredRegion;
@ -39,6 +108,7 @@ namespace
RECT clientRect;
Gdi::Region visibleRegion;
Gdi::Region invalidatedRegion;
LayeredWindowContent layeredWindowContent;
bool isMenu;
bool isLayered;
bool isDpiAware;
@ -90,57 +160,6 @@ namespace
return true;
}
void presentLayeredWindow(CompatWeakPtr<IDirectDrawSurface7> dst,
HWND hwnd, RECT wr, const RECT& monitorRect, HDC& dstDc, Gdi::Region* rgn = nullptr, bool isMenu = false)
{
if (!dst)
{
throw true;
}
if (!dstDc)
{
dst->GetDC(dst, &dstDc);
if (!dstDc)
{
throw false;
}
}
OffsetRect(&wr, -monitorRect.left, -monitorRect.top);
if (rgn)
{
rgn->offset(-monitorRect.left, -monitorRect.top);
}
HDC windowDc = GetWindowDC(hwnd);
if (rgn)
{
SelectClipRgn(dstDc, *rgn);
}
COLORREF colorKey = 0;
BYTE alpha = 255;
DWORD flags = ULW_ALPHA;
if (isMenu || CALL_ORIG_FUNC(GetLayeredWindowAttributes)(hwnd, &colorKey, &alpha, &flags))
{
if (flags & LWA_COLORKEY)
{
CALL_ORIG_FUNC(TransparentBlt)(dstDc, wr.left, wr.top, wr.right - wr.left, wr.bottom - wr.top,
windowDc, 0, 0, wr.right - wr.left, wr.bottom - wr.top, colorKey);
}
else
{
BLENDFUNCTION blend = {};
blend.SourceConstantAlpha = alpha;
CALL_ORIG_FUNC(AlphaBlend)(dstDc, wr.left, wr.top, wr.right - wr.left, wr.bottom - wr.top,
windowDc, 0, 0, wr.right - wr.left, wr.bottom - wr.top, blend);
}
}
CALL_ORIG_FUNC(ReleaseDC)(hwnd, windowDc);
}
void updatePosition(Window& window, const RECT& oldWindowRect, const RECT& oldClientRect,
const Gdi::Region& oldVisibleRegion, Gdi::Region& invalidatedRegion)
{
@ -351,7 +370,14 @@ namespace Gdi
auto& window = **it;
if (window.isLayered && !window.visibleRegion.isEmpty())
{
layeredWindows.push_back({ window.hwnd, window.windowRect, window.visibleRegion });
layeredWindows.push_back({
window.hwnd,
window.windowRect,
window.visibleRegion,
window.layeredWindowContent.getDc(),
window.layeredWindowContent.getColorKey(),
window.layeredWindowContent.getAlpha(),
window.layeredWindowContent.getAlphaFormat() });
}
}
return layeredWindows;
@ -640,6 +666,21 @@ namespace Gdi
}
}
void updateLayeredWindowInfo(HWND hwnd, HDC hdcSrc, const POINT* pptSrc,
COLORREF colorKey, BYTE alpha, BYTE alphaFormat)
{
D3dDdi::ScopedCriticalSection lock;
auto it = g_windows.find(hwnd);
if (it != g_windows.end())
{
it->second.layeredWindowContent.set(hwnd, hdcSrc, pptSrc, colorKey, alpha, alphaFormat);
if (DDraw::RealPrimarySurface::isFullscreen())
{
DDraw::RealPrimarySurface::scheduleOverlayUpdate();
}
}
}
void updatePresentationWindowPos(HWND presentationWindow, HWND owner)
{
if (IsIconic(owner))

View File

@ -15,6 +15,10 @@ namespace Gdi
HWND hwnd;
RECT rect;
Gdi::Region region;
HDC dc;
COLORREF colorKey;
BYTE alpha;
BYTE alphaFormat;
};
HWND getPresentationWindow(HWND hwnd);
@ -31,6 +35,8 @@ namespace Gdi
void present(Gdi::Region excludeRegion);
void setDpiAwareness(HWND hwnd, bool dpiAware);
void updateAll();
void updateLayeredWindowInfo(HWND hwnd, HDC hdcSrc, const POINT* pptSrc,
COLORREF colorKey, BYTE alpha, BYTE alphaFormat);
void updatePresentationWindowPos(HWND presentationWindow, HWND owner);
}
}

View File

@ -0,0 +1,10 @@
sampler2D s_texture : register(s0);
float4 g_colorKey : register(c30);
float4 g_threshold : register(c31);
float4 main(float2 texCoord : TEXCOORD0) : COLOR0
{
float4 color = tex2D(s_texture, texCoord);
const float4 diff = abs(color - g_colorKey);
return all(diff.rgb < g_threshold.rgb) ? 0 : (g_colorKey.a * color);
}

View File

@ -134,6 +134,15 @@ std::ostream& operator<<(std::ostream& os, const BITMAPINFOHEADER& bmih)
<< bmih.biClrImportant;
}
std::ostream& operator<<(std::ostream& os, const BLENDFUNCTION& bf)
{
return Compat::LogStruct(os)
<< static_cast<UINT>(bf.BlendOp)
<< static_cast<UINT>(bf.BlendFlags)
<< static_cast<UINT>(bf.SourceConstantAlpha)
<< static_cast<UINT>(bf.AlphaFormat);
}
std::ostream& operator<<(std::ostream& os, const COMPAREITEMSTRUCT& cis)
{
return Compat::LogStruct(os)

View File

@ -7,6 +7,7 @@
std::ostream& operator<<(std::ostream& os, const BITMAP& bm);
std::ostream& operator<<(std::ostream& os, const BITMAPINFO& bmi);
std::ostream& operator<<(std::ostream& os, const BITMAPINFOHEADER& bmih);
std::ostream& operator<<(std::ostream& os, const BLENDFUNCTION& bf);
std::ostream& operator<<(std::ostream& os, const COMPAREITEMSTRUCT& cis);
std::ostream& operator<<(std::ostream& os, const COPYDATASTRUCT& cds);
std::ostream& operator<<(std::ostream& os, const CREATESTRUCTA& cs);