capture cursor mask taking monitor rotation into consideration.

This commit is contained in:
hecomi
2016-11-17 23:19:46 +09:00
parent 9c62157c0c
commit 95f8099392
3 changed files with 127 additions and 55 deletions
@@ -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];
} }