capture cursor mask taking monitor rotation into consideration.
This commit is contained in:
Binary file not shown.
@@ -13,9 +13,11 @@ public class Texture : MonoBehaviour
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
monitor_ = value;
|
monitor_ = value;
|
||||||
material = GetComponent<Renderer>().material; // clone
|
if (monitor_ != null) {
|
||||||
material.mainTexture = monitor_.texture;
|
material = GetComponent<Renderer>().material; // clone
|
||||||
material.SetFloat("_Width", transform.localScale.x);
|
material.mainTexture = monitor_.texture;
|
||||||
|
material.SetFloat("_Width", transform.localScale.x);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,31 +87,27 @@ void Cursor::UpdateTexture()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// cursor type
|
// Cursor information
|
||||||
const bool isMono = GetType() == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME;
|
const bool isMono = GetType() == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME;
|
||||||
const bool isColorMask = GetType() == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR;
|
const bool isColorMask = GetType() == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR;
|
||||||
|
const auto cursorImageWidth = GetWidth();
|
||||||
|
const auto cursorImageHeight = GetHeight();
|
||||||
|
const auto cursorImagePitch = GetPitch();
|
||||||
|
|
||||||
// Size
|
// Captured area
|
||||||
const auto w0 = GetWidth();
|
auto capturedImageWidth = cursorImageWidth;
|
||||||
const auto h0 = GetHeight();
|
auto capturedImageHeight = cursorImageHeight;
|
||||||
const auto p = GetPitch();
|
|
||||||
auto w = w0;
|
|
||||||
auto h = h0;
|
|
||||||
|
|
||||||
// Convert the buffer given by API into BGRA32
|
// Convert the buffer given by API into BGRA32
|
||||||
const UINT bgraBufferSize = w0 * h0 * 4;
|
const UINT bgraBufferSize = cursorImageWidth * cursorImageHeight * 4;
|
||||||
if (bgraBufferSize > bgra32BufferSize_)
|
if (bgraBufferSize > bgra32BufferSize_)
|
||||||
{
|
{
|
||||||
bgra32BufferSize_ = bgraBufferSize;
|
bgra32BufferSize_ = bgraBufferSize;
|
||||||
bgra32Buffer_ = std::make_unique<BYTE[]>(bgra32BufferSize_);
|
bgra32Buffer_ = std::make_unique<BYTE[]>(bgra32BufferSize_);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bgra32Buffer_)
|
// Check buffers
|
||||||
{
|
if (!bgra32Buffer_ || !apiBuffer_)
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!apiBuffer_)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -119,41 +115,109 @@ void Cursor::UpdateTexture()
|
|||||||
// If masked, copy the desktop image and merge it with masked image.
|
// If masked, copy the desktop image and merge it with masked image.
|
||||||
if (isMono || isColorMask)
|
if (isMono || isColorMask)
|
||||||
{
|
{
|
||||||
const auto mw = monitor_->GetWidth();
|
const auto monitorWidth = monitor_->GetWidth();
|
||||||
const auto mh = monitor_->GetHeight();
|
const auto monitorHeight = monitor_->GetHeight();
|
||||||
|
const auto monitorRot = static_cast<DXGI_MODE_ROTATION>(monitor_->GetRotation());
|
||||||
|
const auto isVertical =
|
||||||
|
monitorRot == DXGI_MODE_ROTATION_ROTATE90 ||
|
||||||
|
monitorRot == DXGI_MODE_ROTATION_ROTATE270;
|
||||||
|
const auto desktopImageWidth = !isVertical ? monitorWidth : monitorHeight;
|
||||||
|
const auto desktopImageHeight = !isVertical ? monitorHeight : monitorWidth;
|
||||||
|
|
||||||
auto x = x_;
|
auto x = x_;
|
||||||
auto y = y_;
|
auto y = y_;
|
||||||
auto colMin = 0;
|
auto colMin = 0;
|
||||||
auto colMax = w0;
|
auto colMax = cursorImageWidth;
|
||||||
auto rowMin = 0;
|
auto rowMin = 0;
|
||||||
auto rowMax = h0;
|
auto rowMax = cursorImageHeight;
|
||||||
|
|
||||||
if (x < 0)
|
if (x < 0)
|
||||||
{
|
{
|
||||||
x = 0;
|
x = 0;
|
||||||
w = w0 + x_;
|
capturedImageWidth = cursorImageWidth + x_;
|
||||||
colMin = w0 - w;
|
colMin = cursorImageWidth - capturedImageWidth;
|
||||||
}
|
}
|
||||||
if (x + w >= mw)
|
if (x + capturedImageWidth >= monitorWidth)
|
||||||
{
|
{
|
||||||
w = mw - x_;
|
capturedImageWidth = monitorWidth - x_;
|
||||||
colMax = w;
|
colMax = capturedImageWidth;
|
||||||
}
|
}
|
||||||
if (y < 0)
|
if (y < 0)
|
||||||
{
|
{
|
||||||
y = 0;
|
y = 0;
|
||||||
h = h0 + y_;
|
capturedImageHeight = cursorImageHeight + y_;
|
||||||
rowMin = h0 - h;
|
rowMin = cursorImageHeight - capturedImageHeight;
|
||||||
}
|
}
|
||||||
if (y + h >= mh)
|
if (y + capturedImageHeight >= monitorHeight)
|
||||||
{
|
{
|
||||||
h = mh - y_;
|
capturedImageHeight = monitorHeight - y_;
|
||||||
rowMax = h;
|
rowMax = capturedImageHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D11_BOX box;
|
||||||
|
box.front = 0;
|
||||||
|
box.back = 1;
|
||||||
|
|
||||||
|
switch (monitorRot)
|
||||||
|
{
|
||||||
|
case DXGI_MODE_ROTATION_ROTATE90:
|
||||||
|
{
|
||||||
|
box.left = y;
|
||||||
|
box.top = monitorWidth - x - capturedImageWidth;
|
||||||
|
box.right = y + capturedImageWidth;
|
||||||
|
box.bottom = monitorWidth - x;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DXGI_MODE_ROTATION_ROTATE180:
|
||||||
|
{
|
||||||
|
box.left = monitorWidth - x - capturedImageWidth;
|
||||||
|
box.top = monitorHeight - y - capturedImageHeight;
|
||||||
|
box.right = monitorWidth - x;
|
||||||
|
box.bottom = monitorHeight - y;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DXGI_MODE_ROTATION_ROTATE270:
|
||||||
|
{
|
||||||
|
box.left = monitorHeight - y - capturedImageHeight;
|
||||||
|
box.top = x;
|
||||||
|
box.right = monitorHeight - y;
|
||||||
|
box.bottom = x + capturedImageWidth;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DXGI_MODE_ROTATION_IDENTITY:
|
||||||
|
case DXGI_MODE_ROTATION_UNSPECIFIED:
|
||||||
|
{
|
||||||
|
box.left = x;
|
||||||
|
box.top = y;
|
||||||
|
box.right = x + capturedImageWidth;
|
||||||
|
box.bottom = y + capturedImageHeight;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (box.left < 0 ||
|
||||||
|
box.top < 0 ||
|
||||||
|
box.right >= static_cast<UINT>(desktopImageWidth) ||
|
||||||
|
box.bottom >= static_cast<UINT>(desktopImageHeight))
|
||||||
|
{
|
||||||
|
Debug::Error("Cursor::UpdateTexture() => box is out of area.");
|
||||||
|
Debug::Error(
|
||||||
|
" ",
|
||||||
|
"(", box.left, ", ", box.top, ")",
|
||||||
|
" ~ (", box.right, ", ", box.bottom, ") > ",
|
||||||
|
"(", desktopImageWidth, ", ", desktopImageHeight, ")");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (monitor_->GetUnityTexture() == nullptr)
|
||||||
|
{
|
||||||
|
Debug::Error("Cursor::UpdateTexture() => Monitor::GetUnityTexture() is null.");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D11_TEXTURE2D_DESC desc;
|
D3D11_TEXTURE2D_DESC desc;
|
||||||
desc.Width = w;
|
desc.Width = capturedImageWidth;
|
||||||
desc.Height = h;
|
desc.Height = capturedImageHeight;
|
||||||
desc.MipLevels = 1;
|
desc.MipLevels = 1;
|
||||||
desc.ArraySize = 1;
|
desc.ArraySize = 1;
|
||||||
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||||
@@ -171,20 +235,6 @@ void Cursor::UpdateTexture()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D11_BOX box;
|
|
||||||
box.front = 0;
|
|
||||||
box.back = 1;
|
|
||||||
box.left = x;
|
|
||||||
box.top = y;
|
|
||||||
box.right = x + w;
|
|
||||||
box.bottom = y + h;
|
|
||||||
|
|
||||||
if (monitor_->GetUnityTexture() == nullptr)
|
|
||||||
{
|
|
||||||
Debug::Error("Cursor::UpdateTexture() => Monitor::GetUnityTexture() is null.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
ComPtr<ID3D11DeviceContext> context;
|
ComPtr<ID3D11DeviceContext> context;
|
||||||
GetDevice()->GetImmediateContext(&context);
|
GetDevice()->GetImmediateContext(&context);
|
||||||
@@ -209,6 +259,27 @@ void Cursor::UpdateTexture()
|
|||||||
const auto desktop32 = reinterpret_cast<UINT*>(mappedSurface.pBits);
|
const auto desktop32 = reinterpret_cast<UINT*>(mappedSurface.pBits);
|
||||||
const UINT desktopPitch = mappedSurface.Pitch / sizeof(UINT);
|
const UINT desktopPitch = mappedSurface.Pitch / sizeof(UINT);
|
||||||
|
|
||||||
|
// Take the monitor orientation into consideration.
|
||||||
|
const auto getDesktop32 = [&](int col, int row)
|
||||||
|
{
|
||||||
|
switch (monitorRot)
|
||||||
|
{
|
||||||
|
case DXGI_MODE_ROTATION_ROTATE90:
|
||||||
|
return desktop32[(capturedImageWidth - 1 - col) * desktopPitch + row];
|
||||||
|
break;
|
||||||
|
case DXGI_MODE_ROTATION_ROTATE180:
|
||||||
|
return desktop32[(capturedImageHeight - 1 - row) * desktopPitch + (capturedImageWidth - 1 - col)];
|
||||||
|
break;
|
||||||
|
case DXGI_MODE_ROTATION_ROTATE270:
|
||||||
|
return desktop32[col * desktopPitch + (capturedImageHeight - 1 - row)];
|
||||||
|
break;
|
||||||
|
case DXGI_MODE_ROTATION_IDENTITY:
|
||||||
|
case DXGI_MODE_ROTATION_UNSPECIFIED:
|
||||||
|
return desktop32[row * desktopPitch + col];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Access RGBA values at the same time
|
// Access RGBA values at the same time
|
||||||
auto output32 = reinterpret_cast<UINT*>(bgra32Buffer_.get());
|
auto output32 = reinterpret_cast<UINT*>(bgra32Buffer_.get());
|
||||||
|
|
||||||
@@ -219,12 +290,11 @@ void Cursor::UpdateTexture()
|
|||||||
for (int col = colMin, x = 0; col < colMax; ++col, ++x)
|
for (int col = colMin, x = 0; col < colMax; ++col, ++x)
|
||||||
{
|
{
|
||||||
BYTE mask = 0b10000000 >> (col % 8);
|
BYTE mask = 0b10000000 >> (col % 8);
|
||||||
const int i = row * w0 + col;
|
const BYTE andMask = apiBuffer_[col / 8 + row * cursorImagePitch] & mask;
|
||||||
const BYTE andMask = apiBuffer_[col / 8 + row * p] & mask;
|
const BYTE xorMask = apiBuffer_[col / 8 + (row + capturedImageHeight) * cursorImagePitch] & mask;
|
||||||
const BYTE xorMask = apiBuffer_[col / 8 + (row + h) * p] & mask;
|
|
||||||
const UINT andMask32 = andMask ? 0xFFFFFFFF : 0x00000000;
|
const UINT andMask32 = andMask ? 0xFFFFFFFF : 0x00000000;
|
||||||
const UINT xorMask32 = xorMask ? 0xFFFFFFFF : 0x00000000;
|
const UINT xorMask32 = xorMask ? 0xFFFFFFFF : 0x00000000;
|
||||||
output32[i] = (desktop32[y * desktopPitch + x] & andMask32) ^ xorMask32;
|
output32[row * cursorImageWidth + col] = (getDesktop32(x, y) & andMask32) ^ xorMask32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -236,13 +306,13 @@ void Cursor::UpdateTexture()
|
|||||||
{
|
{
|
||||||
for (int col = colMin, x = 0; col < colMax; ++col, ++x)
|
for (int col = colMin, x = 0; col < colMax; ++col, ++x)
|
||||||
{
|
{
|
||||||
const int i = col + row * w0;
|
const int i = col + row * cursorImageWidth;
|
||||||
const int j = col + row * p / sizeof(UINT);
|
const int j = col + row * cursorImagePitch / sizeof(UINT);
|
||||||
|
|
||||||
UINT mask = 0xFF000000 & buffer32[j];
|
UINT mask = 0xFF000000 & buffer32[j];
|
||||||
if (mask)
|
if (mask)
|
||||||
{
|
{
|
||||||
output32[i] = (desktop32[y * desktopPitch + x] ^ buffer32[j]) | 0xFF000000;
|
output32[i] = (getDesktop32(x, y) ^ buffer32[j]) | 0xFF000000;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -261,7 +331,7 @@ void Cursor::UpdateTexture()
|
|||||||
{
|
{
|
||||||
auto output32 = reinterpret_cast<UINT*>(bgra32Buffer_.get());
|
auto output32 = reinterpret_cast<UINT*>(bgra32Buffer_.get());
|
||||||
const auto buffer32 = reinterpret_cast<UINT*>(apiBuffer_.get());
|
const auto buffer32 = reinterpret_cast<UINT*>(apiBuffer_.get());
|
||||||
for (int i = 0; i < w * h; ++i)
|
for (int i = 0; i < cursorImageWidth * cursorImageHeight; ++i)
|
||||||
{
|
{
|
||||||
output32[i] = buffer32[i];
|
output32[i] = buffer32[i];
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user