mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Emulate hardware cursor in scaled fullscreen mode
This commit is contained in:
parent
647a4bfcff
commit
ccc23c75b9
@ -11,6 +11,12 @@ std::enable_if_t<std::is_class_v<T> && std::is_trivial_v<T>, bool> operator==(co
|
||||
return toTuple(left) == toTuple(right);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_class_v<T>&& std::is_trivial_v<T>, bool> operator!=(const T& left, const T& right)
|
||||
{
|
||||
return toTuple(left) != toTuple(right);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_class_v<T> && std::is_trivial_v<T>, bool> operator<(const T& left, const T& right)
|
||||
{
|
||||
|
@ -82,7 +82,7 @@ namespace D3dDdi
|
||||
Resource* Device::getResource(HANDLE resource)
|
||||
{
|
||||
auto it = m_resources.find(resource);
|
||||
return it != m_resources.end() ? &it->second : nullptr;
|
||||
return it != m_resources.end() ? it->second.get() : nullptr;
|
||||
}
|
||||
|
||||
void Device::prepareForRendering(HANDLE resource, UINT subResourceIndex, bool isReadOnly)
|
||||
@ -90,7 +90,7 @@ namespace D3dDdi
|
||||
auto it = m_resources.find(resource);
|
||||
if (it != m_resources.end())
|
||||
{
|
||||
it->second.prepareForRendering(subResourceIndex, isReadOnly);
|
||||
it->second->prepareForRendering(subResourceIndex, isReadOnly);
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ namespace D3dDdi
|
||||
auto it = m_resources.find(data->hDstResource);
|
||||
if (it != m_resources.end())
|
||||
{
|
||||
return it->second.blt(*data);
|
||||
return it->second->blt(*data);
|
||||
}
|
||||
prepareForRendering(data->hSrcResource, data->SrcSubResourceIndex, true);
|
||||
return m_origVtable.pfnBlt(m_device, data);
|
||||
@ -162,7 +162,7 @@ namespace D3dDdi
|
||||
auto it = m_resources.find(data->hResource);
|
||||
if (it != m_resources.end())
|
||||
{
|
||||
return it->second.colorFill(*data);
|
||||
return it->second->colorFill(*data);
|
||||
}
|
||||
return m_origVtable.pfnColorFill(m_device, data);
|
||||
}
|
||||
@ -180,8 +180,8 @@ namespace D3dDdi
|
||||
{
|
||||
try
|
||||
{
|
||||
Resource resource(*this, *data);
|
||||
m_resources.emplace(resource, std::move(resource));
|
||||
auto resource(std::make_unique<Resource>(*this, *data));
|
||||
m_resources.emplace(*resource, std::move(resource));
|
||||
if (data->Flags.VertexBuffer &&
|
||||
D3DDDIPOOL_SYSTEMMEM == data->Pool &&
|
||||
data->pSurfList[0].pSysMem)
|
||||
@ -283,7 +283,7 @@ namespace D3dDdi
|
||||
auto it = m_resources.find(data->hResource);
|
||||
if (it != m_resources.end())
|
||||
{
|
||||
return it->second.lock(*data);
|
||||
return it->second->lock(*data);
|
||||
}
|
||||
return m_origVtable.pfnLock(m_device, data);
|
||||
}
|
||||
@ -321,7 +321,7 @@ namespace D3dDdi
|
||||
auto it = m_resources.find(data->hResource);
|
||||
if (it != m_resources.end())
|
||||
{
|
||||
return it->second.unlock(*data);
|
||||
return it->second->unlock(*data);
|
||||
}
|
||||
return m_origVtable.pfnUnlock(m_device, data);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
|
||||
#include <d3d.h>
|
||||
#include <d3dnthal.h>
|
||||
@ -71,7 +71,7 @@ namespace D3dDdi
|
||||
D3DDDI_DEVICEFUNCS m_origVtable;
|
||||
Adapter& m_adapter;
|
||||
HANDLE m_device;
|
||||
std::unordered_map<HANDLE, Resource> m_resources;
|
||||
std::map<HANDLE, std::unique_ptr<Resource>> m_resources;
|
||||
Resource* m_renderTarget;
|
||||
UINT m_renderTargetSubResourceIndex;
|
||||
HANDLE m_sharedPrimary;
|
||||
|
@ -19,7 +19,7 @@
|
||||
namespace
|
||||
{
|
||||
D3DDDIFORMAT g_dcFormatOverride = D3DDDIFMT_UNKNOWN;
|
||||
bool g_dcPaletteOverride = false;
|
||||
PALETTEENTRY* g_dcPaletteOverride = nullptr;
|
||||
D3dDdi::KernelModeThunks::AdapterInfo g_gdiAdapterInfo = {};
|
||||
D3dDdi::KernelModeThunks::AdapterInfo g_lastOpenAdapterInfo = {};
|
||||
Compat::SrwLock g_lastOpenAdapterInfoSrwLock;
|
||||
@ -59,8 +59,7 @@ namespace
|
||||
{
|
||||
if (g_dcPaletteOverride)
|
||||
{
|
||||
palette = Gdi::Palette::getHardwarePalette();
|
||||
pData->pColorTable = palette.data();
|
||||
pData->pColorTable = g_dcPaletteOverride;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -313,9 +312,9 @@ namespace D3dDdi
|
||||
g_dcFormatOverride = static_cast<D3DDDIFORMAT>(format);
|
||||
}
|
||||
|
||||
void setDcPaletteOverride(bool enable)
|
||||
void setDcPaletteOverride(PALETTEENTRY* palette)
|
||||
{
|
||||
g_dcPaletteOverride = enable;
|
||||
g_dcPaletteOverride = palette;
|
||||
}
|
||||
|
||||
void waitForVsync()
|
||||
|
@ -22,7 +22,7 @@ namespace D3dDdi
|
||||
UINT getVsyncCounter();
|
||||
void installHooks();
|
||||
void setDcFormatOverride(UINT format);
|
||||
void setDcPaletteOverride(bool enable);
|
||||
void setDcPaletteOverride(PALETTEENTRY* palette);
|
||||
void waitForVsync();
|
||||
bool waitForVsyncCounter(UINT counter);
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <DDraw/Blitter.h>
|
||||
#include <DDraw/RealPrimarySurface.h>
|
||||
#include <DDraw/Surfaces/PrimarySurface.h>
|
||||
#include <Gdi/Cursor.h>
|
||||
#include <Gdi/Palette.h>
|
||||
#include <Gdi/VirtualScreen.h>
|
||||
|
||||
@ -113,6 +114,14 @@ namespace D3dDdi
|
||||
if (m_origData.Flags.Primary)
|
||||
{
|
||||
g_presentationRect = calculatePresentationRect();
|
||||
auto& si = m_origData.pSurfList[0];
|
||||
RECT rect = { 0, 0, static_cast<LONG>(si.Width), static_cast<LONG>(si.Height) };
|
||||
|
||||
Gdi::Cursor::setMonitorClipRect(DDraw::PrimarySurface::getMonitorRect());
|
||||
if (!EqualRect(&g_presentationRect, &rect))
|
||||
{
|
||||
Gdi::Cursor::setEmulated(true);
|
||||
}
|
||||
}
|
||||
|
||||
fixResourceData();
|
||||
@ -141,6 +150,15 @@ namespace D3dDdi
|
||||
data.hResource = m_fixedData.hResource;
|
||||
}
|
||||
|
||||
Resource::~Resource()
|
||||
{
|
||||
if (m_origData.Flags.Primary)
|
||||
{
|
||||
Gdi::Cursor::setEmulated(false);
|
||||
Gdi::Cursor::setMonitorClipRect({});
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT Resource::blt(D3DDDIARG_BLT data)
|
||||
{
|
||||
if (!isValidRect(data.DstSubResourceIndex, data.DstRect))
|
||||
@ -177,7 +195,7 @@ namespace D3dDdi
|
||||
}
|
||||
else if (m_fixedData.Flags.Primary)
|
||||
{
|
||||
return presentationBlt(data, *srcResource);
|
||||
return presentationBlt(data, srcResource);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -511,36 +529,59 @@ namespace D3dDdi
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT Resource::presentationBlt(D3DDDIARG_BLT data, Resource& srcResource)
|
||||
HRESULT Resource::presentationBlt(D3DDDIARG_BLT data, Resource* srcResource)
|
||||
{
|
||||
if (srcResource.m_lockResource &&
|
||||
srcResource.m_lockData[0].isSysMemUpToDate)
|
||||
if (srcResource->m_lockResource &&
|
||||
srcResource->m_lockData[0].isSysMemUpToDate)
|
||||
{
|
||||
srcResource.copyToVidMem(0);
|
||||
srcResource->copyToVidMem(0);
|
||||
}
|
||||
|
||||
if (D3DDDIFMT_P8 == srcResource.m_origData.Format)
|
||||
const auto& si = srcResource->m_fixedData.pSurfList[0];
|
||||
const bool isPalettized = D3DDDIFMT_P8 == srcResource->m_origData.Format;
|
||||
const auto cursorInfo = Gdi::Cursor::getEmulatedCursorInfo();
|
||||
const bool isCursorEmulated = cursorInfo.flags == CURSOR_SHOWING && cursorInfo.hCursor;
|
||||
|
||||
if (isPalettized || isCursorEmulated)
|
||||
{
|
||||
const auto& si = srcResource.m_fixedData.pSurfList[0];
|
||||
auto palettizedBltRenderTarget(SurfaceRepository::get(m_device.getAdapter()).getPaletteBltRenderTarget(
|
||||
si.Width, si.Height));
|
||||
if (!palettizedBltRenderTarget)
|
||||
auto dst(SurfaceRepository::get(m_device.getAdapter()).getRenderTarget(si.Width, si.Height));
|
||||
if (!dst)
|
||||
{
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
auto entries(Gdi::Palette::getHardwarePalette());
|
||||
RGBQUAD pal[256] = {};
|
||||
for (UINT i = 0; i < 256; ++i)
|
||||
if (isPalettized)
|
||||
{
|
||||
pal[i].rgbRed = entries[i].peRed;
|
||||
pal[i].rgbGreen = entries[i].peGreen;
|
||||
pal[i].rgbBlue = entries[i].peBlue;
|
||||
auto entries(Gdi::Palette::getHardwarePalette());
|
||||
RGBQUAD pal[256] = {};
|
||||
for (UINT i = 0; i < 256; ++i)
|
||||
{
|
||||
pal[i].rgbRed = entries[i].peRed;
|
||||
pal[i].rgbGreen = entries[i].peGreen;
|
||||
pal[i].rgbBlue = entries[i].peBlue;
|
||||
}
|
||||
m_device.getShaderBlitter().palettizedBlt(*dst, 0, *srcResource, pal);
|
||||
}
|
||||
else
|
||||
{
|
||||
D3DDDIARG_BLT blt = {};
|
||||
blt.hSrcResource = data.hSrcResource;
|
||||
blt.SrcRect = data.SrcRect;
|
||||
blt.hDstResource = *dst;
|
||||
blt.DstRect = data.SrcRect;
|
||||
blt.Flags.Point = 1;
|
||||
m_device.getOrigVtable().pfnBlt(m_device, &blt);
|
||||
}
|
||||
|
||||
m_device.getShaderBlitter().palettizedBlt(*palettizedBltRenderTarget, 0, srcResource, pal);
|
||||
data.hSrcResource = *palettizedBltRenderTarget;
|
||||
data.SrcSubResourceIndex = 0;
|
||||
srcResource = dst;
|
||||
data.hSrcResource = *dst;
|
||||
}
|
||||
|
||||
if (isCursorEmulated)
|
||||
{
|
||||
RECT monitorRect = DDraw::PrimarySurface::getMonitorRect();
|
||||
POINT pos = { cursorInfo.ptScreenPos.x - monitorRect.left, cursorInfo.ptScreenPos.y - monitorRect.top };
|
||||
m_device.getShaderBlitter().cursorBlt(*srcResource, 0, cursorInfo.hCursor, pos);
|
||||
}
|
||||
|
||||
data.DstRect = g_presentationRect;
|
||||
|
@ -18,10 +18,10 @@ namespace D3dDdi
|
||||
Resource(Device& device, D3DDDIARG_CREATERESOURCE2& data);
|
||||
|
||||
Resource(const Resource&) = delete;
|
||||
Resource(Resource&&) = delete;
|
||||
Resource& operator=(const Resource&) = delete;
|
||||
|
||||
Resource(Resource&&) = default;
|
||||
Resource& operator=(Resource&&) = default;
|
||||
Resource& operator=(Resource&&) = delete;
|
||||
~Resource();
|
||||
|
||||
operator HANDLE() const { return m_handle; }
|
||||
const D3DDDIARG_CREATERESOURCE2& getOrigDesc() const { return m_origData; }
|
||||
@ -43,10 +43,9 @@ namespace D3dDdi
|
||||
Data(const D3DDDIARG_CREATERESOURCE2& data);
|
||||
|
||||
Data(const Data&) = delete;
|
||||
Data(Data&&) = delete;
|
||||
Data& operator=(const Data&) = delete;
|
||||
|
||||
Data(Data&&) = default;
|
||||
Data& operator=(Data&&) = default;
|
||||
Data& operator=(Data&&) = delete;
|
||||
|
||||
std::vector<D3DDDI_SURFACEINFO> surfaceData;
|
||||
};
|
||||
@ -83,7 +82,7 @@ namespace D3dDdi
|
||||
void fixResourceData();
|
||||
bool isOversized() const;
|
||||
bool isValidRect(UINT subResourceIndex, const RECT& rect);
|
||||
HRESULT presentationBlt(D3DDDIARG_BLT data, Resource& srcResource);
|
||||
HRESULT presentationBlt(D3DDDIARG_BLT data, Resource* srcResource);
|
||||
HRESULT splitBlt(D3DDDIARG_BLT& data, UINT& subResourceIndex, RECT& rect, RECT& otherRect);
|
||||
|
||||
template <typename Arg>
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <D3dDdi/Resource.h>
|
||||
#include <D3dDdi/ShaderBlitter.h>
|
||||
#include <D3dDdi/SurfaceRepository.h>
|
||||
#include <Shaders/DrawCursor.h>
|
||||
#include <Shaders/PaletteLookup.h>
|
||||
|
||||
#define CONCAT_(a, b) a##b
|
||||
@ -14,7 +15,8 @@ namespace D3dDdi
|
||||
{
|
||||
ShaderBlitter::ShaderBlitter(Device& device)
|
||||
: m_device(device)
|
||||
, m_psPaletteLookup(createPixelShader(g_psPaletteLookup, sizeof(g_psPaletteLookup)))
|
||||
, m_psDrawCursor(createPixelShader(g_psDrawCursor))
|
||||
, m_psPaletteLookup(createPixelShader(g_psPaletteLookup))
|
||||
, m_vertexShaderDecl(createVertexShaderDecl())
|
||||
{
|
||||
}
|
||||
@ -122,6 +124,46 @@ namespace D3dDdi
|
||||
return data.ShaderHandle;
|
||||
}
|
||||
|
||||
void ShaderBlitter::cursorBlt(const Resource& dstResource, UINT dstSubResourceIndex, HCURSOR cursor, POINT pt)
|
||||
{
|
||||
LOG_FUNC("ShaderBlitter::cursorBlt", static_cast<HANDLE>(dstResource), dstSubResourceIndex, cursor, pt);
|
||||
|
||||
auto& repo = SurfaceRepository::get(m_device.getAdapter());
|
||||
auto cur = repo.getCursor(cursor);
|
||||
auto xorTexture = repo.getLogicalXorTexture();
|
||||
|
||||
pt.x -= cur.hotspot.x;
|
||||
pt.y -= cur.hotspot.y;
|
||||
RECT dstRect = { pt.x, pt.y, pt.x + cur.size.cx, pt.y + cur.size.cy };
|
||||
|
||||
auto& dstDesc = dstResource.getFixedDesc().pSurfList[dstSubResourceIndex];
|
||||
RECT clippedDstRect = {};
|
||||
clippedDstRect.right = dstDesc.Width;
|
||||
clippedDstRect.bottom = dstDesc.Height;
|
||||
IntersectRect(&clippedDstRect, &clippedDstRect, &dstRect);
|
||||
|
||||
if (!cur.maskTexture || !cur.colorTexture || !cur.tempTexture || !xorTexture || IsRectEmpty(&clippedDstRect))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RECT clippedSrcRect = clippedDstRect;
|
||||
OffsetRect(&clippedSrcRect, -dstRect.left, -dstRect.top);
|
||||
|
||||
D3DDDIARG_BLT data = {};
|
||||
data.hSrcResource = dstResource;
|
||||
data.SrcSubResourceIndex = dstSubResourceIndex;
|
||||
data.SrcRect = clippedDstRect;
|
||||
data.hDstResource = *cur.tempTexture;
|
||||
data.DstRect = clippedSrcRect;
|
||||
m_device.getOrigVtable().pfnBlt(m_device, &data);
|
||||
|
||||
SCOPED_STATE(Texture, 1, *cur.maskTexture, D3DTEXF_POINT);
|
||||
SCOPED_STATE(Texture, 2, *cur.colorTexture, D3DTEXF_POINT);
|
||||
SCOPED_STATE(Texture, 3, *xorTexture, D3DTEXF_POINT);
|
||||
blt(dstResource, dstSubResourceIndex, clippedDstRect, *cur.tempTexture, clippedSrcRect, m_psDrawCursor, D3DTEXF_POINT);
|
||||
}
|
||||
|
||||
void ShaderBlitter::palettizedBlt(const Resource& dstResource, UINT dstSubResourceIndex,
|
||||
const Resource& srcResource, RGBQUAD palette[256])
|
||||
{
|
||||
|
@ -16,6 +16,7 @@ namespace D3dDdi
|
||||
ShaderBlitter& operator=(const ShaderBlitter&) = delete;
|
||||
ShaderBlitter& operator=(ShaderBlitter&&) = delete;
|
||||
|
||||
void cursorBlt(const Resource& dstResource, UINT dstSubResourceIndex, HCURSOR cursor, POINT pt);
|
||||
void palettizedBlt(const Resource& dstResource, UINT dstSubResourceIndex,
|
||||
const Resource& srcResource, RGBQUAD palette[256]);
|
||||
|
||||
@ -23,10 +24,17 @@ namespace D3dDdi
|
||||
void blt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
|
||||
const Resource& srcResource, const RECT& srcRect, HANDLE pixelShader, UINT filter);
|
||||
|
||||
template <int N>
|
||||
HANDLE createPixelShader(const BYTE(&code)[N])
|
||||
{
|
||||
return createPixelShader(code, N);
|
||||
}
|
||||
|
||||
HANDLE createPixelShader(const BYTE* code, UINT size);
|
||||
HANDLE createVertexShaderDecl();
|
||||
|
||||
Device& m_device;
|
||||
HANDLE m_psDrawCursor;
|
||||
HANDLE m_psPaletteLookup;
|
||||
HANDLE m_vertexShaderDecl;
|
||||
};
|
||||
|
@ -1,8 +1,15 @@
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <Windows.h>
|
||||
#include <d3dkmthk.h>
|
||||
|
||||
#include <Common/Comparison.h>
|
||||
#include <D3dDdi/Adapter.h>
|
||||
#include <D3dDdi/Device.h>
|
||||
#include <D3dDdi/KernelModeThunks.h>
|
||||
#include <D3dDdi/Resource.h>
|
||||
#include <D3dDdi/SurfaceRepository.h>
|
||||
#include <DDraw/DirectDrawSurface.h>
|
||||
|
||||
@ -15,6 +22,9 @@ namespace D3dDdi
|
||||
{
|
||||
SurfaceRepository::SurfaceRepository(const Adapter& adapter)
|
||||
: m_adapter(adapter)
|
||||
, m_cursor(nullptr)
|
||||
, m_cursorSize{}
|
||||
, m_cursorHotspot{}
|
||||
{
|
||||
}
|
||||
|
||||
@ -57,10 +67,136 @@ namespace D3dDdi
|
||||
return g_repositories.emplace(adapter.getLuid(), SurfaceRepository(adapter)).first->second;
|
||||
}
|
||||
|
||||
Resource* SurfaceRepository::getPaletteBltRenderTarget(DWORD width, DWORD height)
|
||||
Resource* SurfaceRepository::getBitmapResource(
|
||||
Surface& surface, HBITMAP bitmap, const RECT& rect, const DDPIXELFORMAT& pf, DWORD caps)
|
||||
{
|
||||
return getResource(m_paletteBltRenderTarget, width, height, DDraw::DirectDraw::getRgbPixelFormat(32),
|
||||
DDSCAPS_3DDEVICE | DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY);
|
||||
DWORD width = rect.right - rect.left;
|
||||
DWORD height = rect.bottom - rect.top;
|
||||
auto resource = getResource(surface, width, height, pf, caps);
|
||||
if (!resource)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HDC srcDc = CreateCompatibleDC(nullptr);
|
||||
HGDIOBJ prevBitmap = SelectObject(srcDc, bitmap);
|
||||
HDC dstDc = nullptr;
|
||||
PALETTEENTRY palette[256] = {};
|
||||
palette[255] = { 0xFF, 0xFF, 0xFF };
|
||||
KernelModeThunks::setDcPaletteOverride(palette);
|
||||
surface.surface->GetDC(surface.surface, &dstDc);
|
||||
KernelModeThunks::setDcPaletteOverride(nullptr);
|
||||
|
||||
CALL_ORIG_FUNC(BitBlt)(dstDc, 0, 0, width, height, srcDc, rect.left, rect.top, SRCCOPY);
|
||||
|
||||
surface.surface->ReleaseDC(surface.surface, dstDc);
|
||||
SelectObject(srcDc, prevBitmap);
|
||||
DeleteDC(srcDc);
|
||||
return resource;
|
||||
}
|
||||
|
||||
SurfaceRepository::Cursor SurfaceRepository::getCursor(HCURSOR cursor)
|
||||
{
|
||||
if (isLost(m_cursorMaskTexture) || isLost(m_cursorColorTexture))
|
||||
{
|
||||
m_cursor = nullptr;
|
||||
release(m_cursorMaskTexture);
|
||||
release(m_cursorColorTexture);
|
||||
}
|
||||
|
||||
if (cursor != m_cursor)
|
||||
{
|
||||
m_cursor = cursor;
|
||||
ICONINFO iconInfo = {};
|
||||
if (!GetIconInfo(cursor, &iconInfo))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
BITMAP bm = {};
|
||||
GetObject(iconInfo.hbmMask, sizeof(bm), &bm);
|
||||
|
||||
RECT rect = {};
|
||||
SetRect(&rect, 0, 0, bm.bmWidth, bm.bmHeight);
|
||||
if (!iconInfo.hbmColor)
|
||||
{
|
||||
rect.bottom /= 2;
|
||||
}
|
||||
|
||||
getBitmapResource(m_cursorMaskTexture, iconInfo.hbmMask, rect,
|
||||
DDraw::DirectDraw::getRgbPixelFormat(8), DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY);
|
||||
|
||||
if (iconInfo.hbmColor)
|
||||
{
|
||||
getBitmapResource(m_cursorColorTexture, iconInfo.hbmColor, rect,
|
||||
DDraw::DirectDraw::getRgbPixelFormat(32), DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY);
|
||||
DeleteObject(iconInfo.hbmColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
OffsetRect(&rect, 0, rect.bottom);
|
||||
getBitmapResource(m_cursorColorTexture, iconInfo.hbmMask, rect,
|
||||
DDraw::DirectDraw::getRgbPixelFormat(8), DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY);
|
||||
}
|
||||
DeleteObject(iconInfo.hbmMask);
|
||||
|
||||
m_cursorMaskTexture.resource->prepareForRendering(0, true);
|
||||
m_cursorColorTexture.resource->prepareForRendering(0, true);
|
||||
|
||||
m_cursorSize.cx = rect.right - rect.left;
|
||||
m_cursorSize.cy = rect.bottom - rect.top;
|
||||
m_cursorHotspot.x = iconInfo.xHotspot;
|
||||
m_cursorHotspot.y = iconInfo.yHotspot;
|
||||
}
|
||||
|
||||
Cursor result = {};
|
||||
result.cursor = m_cursor;
|
||||
result.size = m_cursorSize;
|
||||
result.hotspot = m_cursorHotspot;
|
||||
result.maskTexture = m_cursorMaskTexture.resource;
|
||||
result.colorTexture = m_cursorColorTexture.resource;
|
||||
result.tempTexture = getResource(m_cursorTempTexture, m_cursorSize.cx, m_cursorSize.cy,
|
||||
DDraw::DirectDraw::getRgbPixelFormat(32), DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY);
|
||||
return result;
|
||||
}
|
||||
|
||||
Resource* SurfaceRepository::getLogicalXorTexture()
|
||||
{
|
||||
return getInitializedResource(m_logicalXorTexture, 256, 256, DDraw::DirectDraw::getRgbPixelFormat(8),
|
||||
DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY,
|
||||
[](const DDSURFACEDESC2& desc) {
|
||||
BYTE* p = static_cast<BYTE*>(desc.lpSurface);
|
||||
for (UINT y = 0; y < 256; ++y)
|
||||
{
|
||||
for (UINT x = 0; x < 256; ++x)
|
||||
{
|
||||
p[x] = static_cast<BYTE>(x ^ y);
|
||||
}
|
||||
p += desc.lPitch;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Resource* SurfaceRepository::getInitializedResource(Surface& surface, DWORD width, DWORD height,
|
||||
const DDPIXELFORMAT& pf, DWORD caps, std::function<void(const DDSURFACEDESC2&)> initFunc)
|
||||
{
|
||||
if (!isLost(surface) || !getResource(surface, width, height, pf, caps))
|
||||
{
|
||||
return surface.resource;
|
||||
}
|
||||
|
||||
DDSURFACEDESC2 desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
surface.surface->Lock(surface.surface, nullptr, &desc, DDLOCK_DISCARDCONTENTS | DDLOCK_WAIT, nullptr);
|
||||
if (!desc.lpSurface)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
initFunc(desc);
|
||||
surface.surface->Unlock(surface.surface, nullptr);
|
||||
surface.resource->prepareForRendering(0, true);
|
||||
return surface.resource;
|
||||
}
|
||||
|
||||
Resource* SurfaceRepository::getPaletteTexture()
|
||||
@ -69,18 +205,18 @@ namespace D3dDdi
|
||||
DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY);
|
||||
}
|
||||
|
||||
Resource* SurfaceRepository::getRenderTarget(DWORD width, DWORD height)
|
||||
{
|
||||
return getResource(m_renderTarget, width, height, DDraw::DirectDraw::getRgbPixelFormat(32),
|
||||
DDSCAPS_3DDEVICE | DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY);
|
||||
}
|
||||
|
||||
Resource* SurfaceRepository::getResource(Surface& surface, DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps)
|
||||
{
|
||||
if (surface.surface)
|
||||
if (surface.surface && (surface.width != width || surface.height != height ||
|
||||
0 != memcmp(&surface.pixelFormat, &pf, sizeof(pf)) || isLost(surface)))
|
||||
{
|
||||
DDSURFACEDESC2 desc = {};
|
||||
desc.dwSize = sizeof(desc);
|
||||
surface.surface->GetSurfaceDesc(surface.surface, &desc);
|
||||
if (desc.dwWidth != width || desc.dwHeight != height || FAILED(surface.surface->IsLost(surface.surface)))
|
||||
{
|
||||
surface.surface->Release(surface.surface);
|
||||
surface = {};
|
||||
}
|
||||
release(surface);
|
||||
}
|
||||
|
||||
if (!surface.surface)
|
||||
@ -90,9 +226,26 @@ namespace D3dDdi
|
||||
{
|
||||
surface.resource = D3dDdi::Device::findResource(
|
||||
DDraw::DirectDrawSurface::getDriverResourceHandle(*surface.surface));
|
||||
surface.width = width;
|
||||
surface.height = height;
|
||||
surface.pixelFormat = pf;
|
||||
}
|
||||
}
|
||||
|
||||
return surface.resource;
|
||||
}
|
||||
|
||||
bool SurfaceRepository::isLost(Surface& surface)
|
||||
{
|
||||
return !surface.surface || FAILED(surface.surface->IsLost(surface.surface));
|
||||
}
|
||||
|
||||
void SurfaceRepository::release(Surface& surface)
|
||||
{
|
||||
if (surface.surface)
|
||||
{
|
||||
surface.surface->Release(surface.surface);
|
||||
surface = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <ddraw.h>
|
||||
|
||||
#include <Common/CompatWeakPtr.h>
|
||||
@ -12,8 +14,20 @@ namespace D3dDdi
|
||||
class SurfaceRepository
|
||||
{
|
||||
public:
|
||||
Resource* getPaletteBltRenderTarget(DWORD width, DWORD height);
|
||||
struct Cursor
|
||||
{
|
||||
HCURSOR cursor;
|
||||
SIZE size;
|
||||
POINT hotspot;
|
||||
Resource* maskTexture;
|
||||
Resource* colorTexture;
|
||||
Resource* tempTexture;
|
||||
};
|
||||
|
||||
Cursor getCursor(HCURSOR cursor);
|
||||
Resource* getLogicalXorTexture();
|
||||
Resource* getPaletteTexture();
|
||||
Resource* getRenderTarget(DWORD width, DWORD height);
|
||||
|
||||
static SurfaceRepository& get(const Adapter& adapter);
|
||||
|
||||
@ -22,15 +36,30 @@ namespace D3dDdi
|
||||
{
|
||||
CompatWeakPtr<IDirectDrawSurface7> surface;
|
||||
Resource* resource;
|
||||
DWORD width;
|
||||
DWORD height;
|
||||
DDPIXELFORMAT pixelFormat;
|
||||
};
|
||||
|
||||
SurfaceRepository(const Adapter& adapter);
|
||||
|
||||
CompatWeakPtr<IDirectDrawSurface7> createSurface(DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps);
|
||||
Resource* getBitmapResource(Surface& surface, HBITMAP bitmap, const RECT& rect, const DDPIXELFORMAT& pf, DWORD caps);
|
||||
Resource* getInitializedResource(Surface& surface, DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps,
|
||||
std::function<void(const DDSURFACEDESC2&)> initFunc);
|
||||
Resource* getResource(Surface& surface, DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps);
|
||||
bool isLost(Surface& surface);
|
||||
void release(Surface& surface);
|
||||
|
||||
const Adapter& m_adapter;
|
||||
Surface m_paletteBltRenderTarget;
|
||||
HCURSOR m_cursor;
|
||||
SIZE m_cursorSize;
|
||||
POINT m_cursorHotspot;
|
||||
Surface m_cursorMaskTexture;
|
||||
Surface m_cursorColorTexture;
|
||||
Surface m_cursorTempTexture;
|
||||
Surface m_logicalXorTexture;
|
||||
Surface m_paletteTexture;
|
||||
Surface m_renderTarget;
|
||||
};
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <Common/Comparison.h>
|
||||
#include <Common/CompatPtr.h>
|
||||
#include <Common/Hook.h>
|
||||
#include <Common/Time.h>
|
||||
@ -16,7 +17,9 @@
|
||||
#include <DDraw/Surfaces/PrimarySurface.h>
|
||||
#include <DDraw/Types.h>
|
||||
#include <Gdi/Caret.h>
|
||||
#include <Gdi/Cursor.h>
|
||||
#include <Gdi/Gdi.h>
|
||||
#include <Gdi/Palette.h>
|
||||
#include <Gdi/VirtualScreen.h>
|
||||
#include <Gdi/Window.h>
|
||||
#include <Win32/DisplayMode.h>
|
||||
@ -142,7 +145,7 @@ namespace
|
||||
|
||||
g_surfaceDesc = desc;
|
||||
g_isFullScreen = isFlippable;
|
||||
g_isUpdatePending = false;
|
||||
g_isUpdatePending = true;
|
||||
g_qpcLastUpdate = Time::queryPerformanceCounter() - Time::msToQpc(Config::delayedFlipModeTimeout);
|
||||
|
||||
if (isFlippable)
|
||||
@ -169,9 +172,10 @@ namespace
|
||||
Gdi::Region excludeRegion(DDraw::PrimarySurface::getMonitorRect());
|
||||
Gdi::Window::present(excludeRegion);
|
||||
|
||||
D3dDdi::KernelModeThunks::setDcPaletteOverride(true);
|
||||
auto palette(Gdi::Palette::getHardwarePalette());
|
||||
D3dDdi::KernelModeThunks::setDcPaletteOverride(palette.data());
|
||||
bltToPrimaryChain(*src);
|
||||
D3dDdi::KernelModeThunks::setDcPaletteOverride(false);
|
||||
D3dDdi::KernelModeThunks::setDcPaletteOverride(nullptr);
|
||||
|
||||
if (g_isFullScreen && src == DDraw::PrimarySurface::getGdiSurface())
|
||||
{
|
||||
@ -222,10 +226,15 @@ namespace
|
||||
D3dDdi::KernelModeThunks::waitForVsync();
|
||||
}
|
||||
skipWaitForVsync = false;
|
||||
Gdi::Caret::blink();
|
||||
Sleep(1);
|
||||
|
||||
DDraw::ScopedThreadLock lock;
|
||||
Gdi::Caret::blink();
|
||||
if (Gdi::Cursor::update())
|
||||
{
|
||||
g_isUpdatePending = true;
|
||||
}
|
||||
|
||||
if (g_isUpdatePending && !isPresentPending())
|
||||
{
|
||||
auto qpcNow = Time::queryPerformanceCounter();
|
||||
|
@ -282,6 +282,7 @@
|
||||
<ClInclude Include="Direct3d\Visitors\Direct3dVtblVisitor.h" />
|
||||
<ClInclude Include="Dll\Dll.h" />
|
||||
<ClInclude Include="Gdi\CompatDc.h" />
|
||||
<ClInclude Include="Gdi\Cursor.h" />
|
||||
<ClInclude Include="Gdi\Font.h" />
|
||||
<ClInclude Include="Gdi\Gdi.h" />
|
||||
<ClInclude Include="Gdi\Caret.h" />
|
||||
@ -366,6 +367,7 @@
|
||||
<ClCompile Include="Dll\DllMain.cpp" />
|
||||
<ClCompile Include="Dll\Dll.cpp" />
|
||||
<ClCompile Include="Gdi\CompatDc.cpp" />
|
||||
<ClCompile Include="Gdi\Cursor.cpp" />
|
||||
<ClCompile Include="Gdi\Font.cpp" />
|
||||
<ClCompile Include="Gdi\Gdi.cpp" />
|
||||
<ClCompile Include="Gdi\Caret.cpp" />
|
||||
@ -397,6 +399,7 @@
|
||||
<None Include="genversion.ps1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<FxCompile Include="Shaders\DrawCursor.hlsl" />
|
||||
<FxCompile Include="Shaders\PaletteLookup.hlsl" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
@ -435,6 +435,9 @@
|
||||
<ClInclude Include="D3dDdi\SurfaceRepository.h">
|
||||
<Filter>Header Files\D3dDdi</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Gdi\Cursor.h">
|
||||
<Filter>Header Files\Gdi</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Gdi\Gdi.cpp">
|
||||
@ -683,6 +686,9 @@
|
||||
<ClCompile Include="D3dDdi\SurfaceRepository.cpp">
|
||||
<Filter>Source Files\D3dDdi</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Gdi\Cursor.cpp">
|
||||
<Filter>Source Files\Gdi</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="DDrawCompat.rc">
|
||||
@ -698,5 +704,8 @@
|
||||
<FxCompile Include="Shaders\PaletteLookup.hlsl">
|
||||
<Filter>Shaders</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="Shaders\DrawCursor.hlsl">
|
||||
<Filter>Shaders</Filter>
|
||||
</FxCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
248
DDrawCompat/Gdi/Cursor.cpp
Normal file
248
DDrawCompat/Gdi/Cursor.cpp
Normal file
@ -0,0 +1,248 @@
|
||||
#include <Common/ScopedCriticalSection.h>
|
||||
|
||||
#include <Common/Hook.h>
|
||||
#include <Common/Log.h>
|
||||
#include <DDraw/Surfaces/PrimarySurface.h>
|
||||
#include <Gdi/Cursor.h>
|
||||
#include <Win32/DisplayMode.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
RECT g_clipRect = {};
|
||||
HCURSOR g_cursor = nullptr;
|
||||
bool g_isEmulated = false;
|
||||
RECT g_monitorClipRect = {};
|
||||
HCURSOR g_nullCursor = nullptr;
|
||||
CURSORINFO g_prevCursorInfo = {};
|
||||
Compat::CriticalSection g_cs;
|
||||
|
||||
RECT intersectRect(RECT rect1, RECT rect2);
|
||||
void normalizeRect(RECT& rect);
|
||||
|
||||
BOOL WINAPI clipCursor(const RECT* lpRect)
|
||||
{
|
||||
LOG_FUNC("ClipCursor", lpRect);
|
||||
Compat::ScopedCriticalSection lock(g_cs);
|
||||
BOOL result = CALL_ORIG_FUNC(ClipCursor)(lpRect);
|
||||
if (!result || IsRectEmpty(&g_monitorClipRect))
|
||||
{
|
||||
return LOG_RESULT(result);
|
||||
}
|
||||
|
||||
CALL_ORIG_FUNC(GetClipCursor)(&g_clipRect);
|
||||
RECT rect = intersectRect(g_clipRect, g_monitorClipRect);
|
||||
CALL_ORIG_FUNC(ClipCursor)(&rect);
|
||||
return LOG_RESULT(result);
|
||||
}
|
||||
|
||||
BOOL WINAPI getClipCursor(LPRECT lpRect)
|
||||
{
|
||||
LOG_FUNC("GetClipCursor", lpRect);
|
||||
Compat::ScopedCriticalSection lock(g_cs);
|
||||
BOOL result = CALL_ORIG_FUNC(GetClipCursor)(lpRect);
|
||||
if (result && !IsRectEmpty(&g_monitorClipRect))
|
||||
{
|
||||
*lpRect = g_clipRect;
|
||||
}
|
||||
return LOG_RESULT(result);
|
||||
}
|
||||
|
||||
HCURSOR WINAPI getCursor()
|
||||
{
|
||||
LOG_FUNC("GetCursor");
|
||||
Compat::ScopedCriticalSection lock(g_cs);
|
||||
return LOG_RESULT(g_isEmulated ? g_cursor : CALL_ORIG_FUNC(GetCursor)());
|
||||
}
|
||||
|
||||
BOOL WINAPI getCursorInfo(PCURSORINFO pci)
|
||||
{
|
||||
LOG_FUNC("GetCursorInfo", pci);
|
||||
Compat::ScopedCriticalSection lock(g_cs);
|
||||
BOOL result = CALL_ORIG_FUNC(GetCursorInfo)(pci);
|
||||
if (result && pci->hCursor == g_nullCursor)
|
||||
{
|
||||
pci->hCursor = g_cursor;
|
||||
}
|
||||
return LOG_RESULT(result);
|
||||
}
|
||||
|
||||
RECT intersectRect(RECT rect1, RECT rect2)
|
||||
{
|
||||
normalizeRect(rect1);
|
||||
normalizeRect(rect2);
|
||||
IntersectRect(&rect1, &rect1, &rect2);
|
||||
return rect1;
|
||||
}
|
||||
|
||||
void normalizeRect(RECT& rect)
|
||||
{
|
||||
if (rect.left == rect.right && rect.top == rect.bottom)
|
||||
{
|
||||
rect.right++;
|
||||
rect.bottom++;
|
||||
}
|
||||
}
|
||||
|
||||
HCURSOR WINAPI setCursor(HCURSOR hCursor)
|
||||
{
|
||||
LOG_FUNC("SetCursor", hCursor);
|
||||
return LOG_RESULT(Gdi::Cursor::setCursor(hCursor));
|
||||
}
|
||||
|
||||
void updateClipRect()
|
||||
{
|
||||
auto hwnd = GetForegroundWindow();
|
||||
if (!hwnd)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DWORD pid = 0;
|
||||
GetWindowThreadProcessId(hwnd, &pid);
|
||||
if (pid != GetCurrentProcessId())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RECT realClipRect = {};
|
||||
CALL_ORIG_FUNC(GetClipCursor)(&realClipRect);
|
||||
|
||||
RECT clipRect = intersectRect(g_clipRect, g_monitorClipRect);
|
||||
if (!EqualRect(&clipRect, &realClipRect))
|
||||
{
|
||||
CALL_ORIG_FUNC(ClipCursor)(&clipRect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Gdi
|
||||
{
|
||||
namespace Cursor
|
||||
{
|
||||
CURSORINFO getEmulatedCursorInfo()
|
||||
{
|
||||
CURSORINFO ci = {};
|
||||
ci.cbSize = sizeof(ci);
|
||||
|
||||
Compat::ScopedCriticalSection lock(g_cs);
|
||||
if (g_isEmulated)
|
||||
{
|
||||
CALL_ORIG_FUNC(GetCursorInfo)(&ci);
|
||||
if (ci.hCursor == g_nullCursor)
|
||||
{
|
||||
ci.hCursor = g_cursor;
|
||||
}
|
||||
else
|
||||
{
|
||||
ci.hCursor = nullptr;
|
||||
ci.flags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ci;
|
||||
}
|
||||
|
||||
void installHooks()
|
||||
{
|
||||
BYTE andPlane = 0xFF;
|
||||
BYTE xorPlane = 0;
|
||||
g_nullCursor = CreateCursor(nullptr, 0, 0, 1, 1, &andPlane, &xorPlane);
|
||||
|
||||
HOOK_FUNCTION(user32, ClipCursor, clipCursor);
|
||||
HOOK_FUNCTION(user32, GetCursor, getCursor);
|
||||
HOOK_FUNCTION(user32, GetCursorInfo, getCursorInfo);
|
||||
HOOK_FUNCTION(user32, GetClipCursor, getClipCursor);
|
||||
HOOK_FUNCTION(user32, SetCursor, ::setCursor);
|
||||
}
|
||||
|
||||
bool isEmulated()
|
||||
{
|
||||
return g_isEmulated;
|
||||
}
|
||||
|
||||
HCURSOR setCursor(HCURSOR cursor)
|
||||
{
|
||||
Compat::ScopedCriticalSection lock(g_cs);
|
||||
if (!g_isEmulated)
|
||||
{
|
||||
return CALL_ORIG_FUNC(SetCursor)(cursor);
|
||||
}
|
||||
|
||||
HCURSOR prevCursor = g_cursor;
|
||||
if (cursor != g_nullCursor)
|
||||
{
|
||||
g_cursor = cursor;
|
||||
CALL_ORIG_FUNC(SetCursor)(cursor ? g_nullCursor : nullptr);
|
||||
}
|
||||
return prevCursor;
|
||||
}
|
||||
|
||||
void setEmulated(bool isEmulated)
|
||||
{
|
||||
Compat::ScopedCriticalSection lock(g_cs);
|
||||
if (isEmulated == g_isEmulated)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g_isEmulated = isEmulated;
|
||||
g_prevCursorInfo = {};
|
||||
|
||||
if (isEmulated)
|
||||
{
|
||||
setCursor(CALL_ORIG_FUNC(GetCursor)());
|
||||
}
|
||||
else
|
||||
{
|
||||
CALL_ORIG_FUNC(SetCursor)(g_cursor);
|
||||
g_cursor = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void setMonitorClipRect(const RECT& rect)
|
||||
{
|
||||
Compat::ScopedCriticalSection lock(g_cs);
|
||||
if (IsRectEmpty(&rect))
|
||||
{
|
||||
if (!IsRectEmpty(&g_monitorClipRect))
|
||||
{
|
||||
CALL_ORIG_FUNC(ClipCursor)(&g_clipRect);
|
||||
g_clipRect = {};
|
||||
g_monitorClipRect = {};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsRectEmpty(&g_monitorClipRect))
|
||||
{
|
||||
CALL_ORIG_FUNC(GetClipCursor)(&g_clipRect);
|
||||
}
|
||||
g_monitorClipRect = rect;
|
||||
updateClipRect();
|
||||
}
|
||||
}
|
||||
|
||||
bool update()
|
||||
{
|
||||
Compat::ScopedCriticalSection lock(g_cs);
|
||||
if (!IsRectEmpty(&g_monitorClipRect))
|
||||
{
|
||||
updateClipRect();
|
||||
}
|
||||
|
||||
if (g_isEmulated)
|
||||
{
|
||||
CURSORINFO cursorInfo = getEmulatedCursorInfo();
|
||||
if ((CURSOR_SHOWING == cursorInfo.flags) != (CURSOR_SHOWING == g_prevCursorInfo.flags) ||
|
||||
CURSOR_SHOWING == cursorInfo.flags &&
|
||||
(cursorInfo.hCursor != g_prevCursorInfo.hCursor || cursorInfo.ptScreenPos != g_prevCursorInfo.ptScreenPos))
|
||||
{
|
||||
g_prevCursorInfo = cursorInfo;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
17
DDrawCompat/Gdi/Cursor.h
Normal file
17
DDrawCompat/Gdi/Cursor.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
namespace Gdi
|
||||
{
|
||||
namespace Cursor
|
||||
{
|
||||
CURSORINFO getEmulatedCursorInfo();
|
||||
void installHooks();
|
||||
bool isEmulated();
|
||||
HCURSOR setCursor(HCURSOR cursor);
|
||||
void setMonitorClipRect(const RECT& rect);
|
||||
void setEmulated(bool isEmulated);
|
||||
bool update();
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
#include <DDraw/Surfaces/PrimarySurface.h>
|
||||
#include <Gdi/Caret.h>
|
||||
#include <Gdi/Cursor.h>
|
||||
#include <Gdi/Dc.h>
|
||||
#include <Gdi/DcFunctions.h>
|
||||
#include <Gdi/Font.h>
|
||||
@ -46,6 +47,7 @@ namespace Gdi
|
||||
ScrollFunctions::installHooks();
|
||||
User32WndProcs::installHooks();
|
||||
Caret::installHooks();
|
||||
Cursor::installHooks();
|
||||
Font::installHooks();
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include <D3dDdi/ScopedCriticalSection.h>
|
||||
#include <DDraw/RealPrimarySurface.h>
|
||||
#include <Gdi/CompatDc.h>
|
||||
#include <Gdi/Cursor.h>
|
||||
#include <Gdi/ScrollBar.h>
|
||||
#include <Gdi/ScrollFunctions.h>
|
||||
#include <Gdi/TitleBar.h>
|
||||
@ -194,6 +196,57 @@ namespace
|
||||
}
|
||||
return origDefWindowProc(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
case WM_SETCURSOR:
|
||||
{
|
||||
if (!Gdi::Cursor::isEmulated())
|
||||
{
|
||||
return origDefWindowProc(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
switch (LOWORD(lParam))
|
||||
{
|
||||
case HTLEFT:
|
||||
case HTRIGHT:
|
||||
Gdi::Cursor::setCursor(LoadCursor(nullptr, IDC_SIZEWE));
|
||||
return TRUE;
|
||||
|
||||
case HTTOP:
|
||||
case HTBOTTOM:
|
||||
Gdi::Cursor::setCursor(LoadCursor(nullptr, IDC_SIZENS));
|
||||
return TRUE;
|
||||
|
||||
case HTTOPLEFT:
|
||||
case HTBOTTOMRIGHT:
|
||||
Gdi::Cursor::setCursor(LoadCursor(nullptr, IDC_SIZENWSE));
|
||||
return TRUE;
|
||||
|
||||
case HTBOTTOMLEFT:
|
||||
case HTTOPRIGHT:
|
||||
Gdi::Cursor::setCursor(LoadCursor(nullptr, IDC_SIZENESW));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
HWND parent = GetAncestor(hwnd, GA_PARENT);
|
||||
if (parent && SendMessage(parent, msg, wParam, lParam))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (HTCLIENT == LOWORD(lParam))
|
||||
{
|
||||
auto cursor = GetClassLong(hwnd, GCL_HCURSOR);
|
||||
if (cursor)
|
||||
{
|
||||
Gdi::Cursor::setCursor(reinterpret_cast<HCURSOR>(cursor));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Gdi::Cursor::setCursor(LoadCursor(nullptr, IDC_ARROW));
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return defPaintProc(hwnd, msg, wParam, lParam, origDefWindowProc);
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <Common/ScopedSrwLock.h>
|
||||
#include <Dll/Dll.h>
|
||||
#include <Gdi/CompatDc.h>
|
||||
#include <Gdi/Cursor.h>
|
||||
#include <Gdi/Dc.h>
|
||||
#include <Gdi/PresentationWindow.h>
|
||||
#include <Gdi/ScrollBar.h>
|
||||
@ -172,65 +173,6 @@ namespace
|
||||
IsWindowUnicode(hwnd) ? it->second.wndProcW : it->second.wndProcA);
|
||||
}
|
||||
|
||||
void CALLBACK objectCreateEvent(
|
||||
HWINEVENTHOOK /*hWinEventHook*/,
|
||||
DWORD /*event*/,
|
||||
HWND hwnd,
|
||||
LONG idObject,
|
||||
LONG /*idChild*/,
|
||||
DWORD /*dwEventThread*/,
|
||||
DWORD /*dwmsEventTime*/)
|
||||
{
|
||||
if (OBJID_WINDOW == idObject && !Gdi::PresentationWindow::isPresentationWindow(hwnd))
|
||||
{
|
||||
onCreateWindow(hwnd);
|
||||
}
|
||||
}
|
||||
|
||||
void CALLBACK objectStateChangeEvent(
|
||||
HWINEVENTHOOK /*hWinEventHook*/,
|
||||
DWORD /*event*/,
|
||||
HWND hwnd,
|
||||
LONG idObject,
|
||||
LONG /*idChild*/,
|
||||
DWORD /*dwEventThread*/,
|
||||
DWORD /*dwmsEventTime*/)
|
||||
{
|
||||
switch (idObject)
|
||||
{
|
||||
case OBJID_TITLEBAR:
|
||||
{
|
||||
HDC dc = GetWindowDC(hwnd);
|
||||
Gdi::TitleBar(hwnd).drawButtons(dc);
|
||||
ReleaseDC(hwnd, dc);
|
||||
break;
|
||||
}
|
||||
|
||||
case OBJID_CLIENT:
|
||||
if (!isUser32ScrollBar(hwnd))
|
||||
{
|
||||
break;
|
||||
}
|
||||
case OBJID_HSCROLL:
|
||||
case OBJID_VSCROLL:
|
||||
{
|
||||
HDC dc = GetWindowDC(hwnd);
|
||||
if (OBJID_CLIENT == idObject)
|
||||
{
|
||||
SendMessage(GetParent(hwnd), WM_CTLCOLORSCROLLBAR,
|
||||
reinterpret_cast<WPARAM>(dc), reinterpret_cast<LPARAM>(hwnd));
|
||||
}
|
||||
else
|
||||
{
|
||||
DefWindowProc(hwnd, WM_CTLCOLORSCROLLBAR,
|
||||
reinterpret_cast<WPARAM>(dc), reinterpret_cast<LPARAM>(hwnd));
|
||||
}
|
||||
ReleaseDC(hwnd, dc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onCreateWindow(HWND hwnd)
|
||||
{
|
||||
LOG_FUNC("onCreateWindow", hwnd);
|
||||
@ -425,6 +367,72 @@ namespace
|
||||
}
|
||||
return LOG_RESULT(result);
|
||||
}
|
||||
|
||||
void CALLBACK winEventProc(
|
||||
HWINEVENTHOOK /*hWinEventHook*/,
|
||||
DWORD event,
|
||||
HWND hwnd,
|
||||
LONG idObject,
|
||||
LONG /*idChild*/,
|
||||
DWORD /*dwEventThread*/,
|
||||
DWORD /*dwmsEventTime*/)
|
||||
{
|
||||
LOG_FUNC("winEventProc", Compat::hex(event), hwnd, idObject);
|
||||
|
||||
switch (event)
|
||||
{
|
||||
case EVENT_OBJECT_CREATE:
|
||||
if (OBJID_WINDOW == idObject && !Gdi::PresentationWindow::isPresentationWindow(hwnd))
|
||||
{
|
||||
onCreateWindow(hwnd);
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_OBJECT_NAMECHANGE:
|
||||
case EVENT_OBJECT_SHOW:
|
||||
case EVENT_OBJECT_HIDE:
|
||||
if (OBJID_CURSOR == idObject && Gdi::Cursor::isEmulated())
|
||||
{
|
||||
Gdi::Cursor::setCursor(GetCursor());
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_OBJECT_STATECHANGE:
|
||||
switch (idObject)
|
||||
{
|
||||
case OBJID_TITLEBAR:
|
||||
{
|
||||
HDC dc = GetWindowDC(hwnd);
|
||||
Gdi::TitleBar(hwnd).drawButtons(dc);
|
||||
ReleaseDC(hwnd, dc);
|
||||
break;
|
||||
}
|
||||
|
||||
case OBJID_CLIENT:
|
||||
if (!isUser32ScrollBar(hwnd))
|
||||
{
|
||||
break;
|
||||
}
|
||||
case OBJID_HSCROLL:
|
||||
case OBJID_VSCROLL:
|
||||
{
|
||||
HDC dc = GetWindowDC(hwnd);
|
||||
if (OBJID_CLIENT == idObject)
|
||||
{
|
||||
SendMessage(GetParent(hwnd), WM_CTLCOLORSCROLLBAR,
|
||||
reinterpret_cast<WPARAM>(dc), reinterpret_cast<LPARAM>(hwnd));
|
||||
}
|
||||
else
|
||||
{
|
||||
DefWindowProc(hwnd, WM_CTLCOLORSCROLLBAR,
|
||||
reinterpret_cast<WPARAM>(dc), reinterpret_cast<LPARAM>(hwnd));
|
||||
}
|
||||
ReleaseDC(hwnd, dc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Gdi
|
||||
@ -461,9 +469,13 @@ namespace Gdi
|
||||
HOOK_FUNCTION(user32, UpdateLayeredWindowIndirect, updateLayeredWindowIndirect);
|
||||
|
||||
SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_CREATE,
|
||||
Dll::g_currentModule, &objectCreateEvent, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
|
||||
Dll::g_currentModule, &winEventProc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
|
||||
SetWinEventHook(EVENT_OBJECT_NAMECHANGE, EVENT_OBJECT_NAMECHANGE,
|
||||
Dll::g_currentModule, &winEventProc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
|
||||
SetWinEventHook(EVENT_OBJECT_SHOW, EVENT_OBJECT_HIDE,
|
||||
Dll::g_currentModule, &winEventProc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
|
||||
SetWinEventHook(EVENT_OBJECT_STATECHANGE, EVENT_OBJECT_STATECHANGE,
|
||||
Dll::g_currentModule, &objectStateChangeEvent, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
|
||||
Dll::g_currentModule, &winEventProc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
|
||||
}
|
||||
|
||||
void onCreateWindow(HWND hwnd)
|
||||
|
19
DDrawCompat/Shaders/DrawCursor.hlsl
Normal file
19
DDrawCompat/Shaders/DrawCursor.hlsl
Normal file
@ -0,0 +1,19 @@
|
||||
sampler2D s_dstTexture : register(s0);
|
||||
sampler2D s_maskTexture : register(s1);
|
||||
sampler2D s_colorTexture : register(s2);
|
||||
sampler2D s_xorTexture : register(s3);
|
||||
|
||||
float4 main(float2 texCoord : TEXCOORD0) : COLOR0
|
||||
{
|
||||
float4 dst = tex2D(s_dstTexture, texCoord);
|
||||
float4 mask = tex2D(s_maskTexture, texCoord);
|
||||
float4 color = tex2D(s_colorTexture, texCoord);
|
||||
|
||||
float4 maskedDst = dst * mask;
|
||||
|
||||
return float4(
|
||||
tex2D(s_xorTexture, float2(maskedDst.r, color.r)).r,
|
||||
tex2D(s_xorTexture, float2(maskedDst.g, color.g)).r,
|
||||
tex2D(s_xorTexture, float2(maskedDst.b, color.b)).r,
|
||||
1);
|
||||
}
|
@ -46,7 +46,6 @@ namespace
|
||||
};
|
||||
|
||||
DWORD g_desktopBpp = 0;
|
||||
RECT g_cursorRect = {};
|
||||
ULONG g_displaySettingsUniquenessBias = 0;
|
||||
EmulatedDisplayMode g_emulatedDisplayMode = {};
|
||||
Compat::SrwLock g_srwLock;
|
||||
@ -148,12 +147,9 @@ namespace
|
||||
return result;
|
||||
}
|
||||
|
||||
RECT clipRect = {};
|
||||
|
||||
{
|
||||
Compat::ScopedSrwLockExclusive srwLock(g_srwLock);
|
||||
++g_displaySettingsUniquenessBias;
|
||||
clipRect = g_cursorRect;
|
||||
if (lpDevMode)
|
||||
{
|
||||
g_emulatedDisplayMode.width = lpDevMode->dmPelsWidth;
|
||||
@ -167,8 +163,6 @@ namespace
|
||||
g_emulatedDisplayMode.rect.bottom = g_emulatedDisplayMode.rect.top + lpDevMode->dmPelsHeight;
|
||||
g_emulatedDisplayMode.diff.cx = lpDevMode->dmPelsWidth - currDevMode.dmPelsWidth;
|
||||
g_emulatedDisplayMode.diff.cy = lpDevMode->dmPelsHeight - currDevMode.dmPelsHeight;
|
||||
|
||||
IntersectRect(&clipRect, &clipRect, &g_emulatedDisplayMode.rect);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -177,8 +171,6 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
CALL_ORIG_FUNC(ClipCursor)(&clipRect);
|
||||
|
||||
auto& dm = lpDevMode ? *lpDevMode : currDevMode;
|
||||
LPARAM resolution = (dm.dmPelsHeight << 16) | dm.dmPelsWidth;
|
||||
EnumWindows(sendDisplayChange, resolution);
|
||||
@ -209,31 +201,6 @@ namespace
|
||||
lpszDeviceName, lpDevMode, hwnd, dwflags, lParam));
|
||||
}
|
||||
|
||||
BOOL WINAPI clipCursor(const RECT* lpRect)
|
||||
{
|
||||
LOG_FUNC("ClipCursor", lpRect);
|
||||
BOOL result = CALL_ORIG_FUNC(ClipCursor)(lpRect);
|
||||
if (!result)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
RECT rect = {};
|
||||
CALL_ORIG_FUNC(GetClipCursor)(&rect);
|
||||
|
||||
{
|
||||
Compat::ScopedSrwLockExclusive srwLock(g_srwLock);
|
||||
g_cursorRect = rect;
|
||||
if (!g_emulatedDisplayMode.deviceName.empty())
|
||||
{
|
||||
IntersectRect(&rect, &rect, &g_emulatedDisplayMode.rect);
|
||||
CALL_ORIG_FUNC(ClipCursor)(&rect);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void disableDwm8And16BitMitigation()
|
||||
{
|
||||
auto user32 = GetModuleHandle("user32");
|
||||
@ -342,17 +309,6 @@ namespace
|
||||
return CALL_ORIG_FUNC(GdiEntry13)() + g_displaySettingsUniquenessBias;
|
||||
}
|
||||
|
||||
BOOL WINAPI getClipCursor(LPRECT lpRect)
|
||||
{
|
||||
LOG_FUNC("GetClipCursor", lpRect);
|
||||
BOOL result = CALL_ORIG_FUNC(GetClipCursor)(lpRect);
|
||||
if (result)
|
||||
{
|
||||
*lpRect = g_cursorRect;
|
||||
}
|
||||
return LOG_RESULT(result);
|
||||
}
|
||||
|
||||
template <typename DevMode, typename EnumDisplaySettingsExFunc, typename Char>
|
||||
SIZE getConfiguredResolution(EnumDisplaySettingsExFunc origEnumDisplaySettingsEx, const Char* deviceName)
|
||||
{
|
||||
@ -671,16 +627,13 @@ namespace Win32
|
||||
g_desktopBpp = dm.dmBitsPerPel;
|
||||
g_emulatedDisplayMode.bpp = dm.dmBitsPerPel;
|
||||
|
||||
GetClipCursor(&g_cursorRect);
|
||||
EnumDisplayMonitors(nullptr, nullptr, &initMonitor, 0);
|
||||
|
||||
HOOK_FUNCTION(user32, ChangeDisplaySettingsExA, changeDisplaySettingsExA);
|
||||
HOOK_FUNCTION(user32, ChangeDisplaySettingsExW, changeDisplaySettingsExW);
|
||||
HOOK_FUNCTION(user32, ClipCursor, clipCursor);
|
||||
HOOK_FUNCTION(user32, EnumDisplaySettingsExA, enumDisplaySettingsExA);
|
||||
HOOK_FUNCTION(user32, EnumDisplaySettingsExW, enumDisplaySettingsExW);
|
||||
HOOK_FUNCTION(gdi32, GdiEntry13, gdiEntry13);
|
||||
HOOK_FUNCTION(user32, GetClipCursor, getClipCursor);
|
||||
HOOK_FUNCTION(gdi32, GetDeviceCaps, getDeviceCaps);
|
||||
HOOK_FUNCTION(user32, GetMonitorInfoA, getMonitorInfoA);
|
||||
HOOK_FUNCTION(user32, GetMonitorInfoW, getMonitorInfoW);
|
||||
|
Loading…
x
Reference in New Issue
Block a user