From 95f809939291b19b52617fb19c4e8ce7a52853ca Mon Sep 17 00:00:00 2001 From: hecomi Date: Thu, 17 Nov 2016 23:19:46 +0900 Subject: [PATCH] capture cursor mask taking monitor rotation into consideration. --- .../Plugins/x86_64/uDesktopDuplication.dll | Bin 69632 -> 71680 bytes Assets/uDesktopDuplication/Scripts/Texture.cs | 8 +- .../uDesktopDuplication/Cursor.cpp | 174 ++++++++++++------ 3 files changed, 127 insertions(+), 55 deletions(-) diff --git a/Assets/uDesktopDuplication/Plugins/x86_64/uDesktopDuplication.dll b/Assets/uDesktopDuplication/Plugins/x86_64/uDesktopDuplication.dll index dd3384612350eb18e017354724a75d470c69f358..00cb45171826ebc9f63c7d4c09f9f3768d9ad908 100644 GIT binary patch delta 30972 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 delta 28652 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.material; // clone - material.mainTexture = monitor_.texture; - material.SetFloat("_Width", transform.localScale.x); + if (monitor_ != null) { + material = GetComponent().material; // clone + material.mainTexture = monitor_.texture; + material.SetFloat("_Width", transform.localScale.x); + } } } diff --git a/Plugins/uDesktopDuplication/uDesktopDuplication/Cursor.cpp b/Plugins/uDesktopDuplication/uDesktopDuplication/Cursor.cpp index 1249fcb..9788b38 100644 --- a/Plugins/uDesktopDuplication/uDesktopDuplication/Cursor.cpp +++ b/Plugins/uDesktopDuplication/uDesktopDuplication/Cursor.cpp @@ -87,31 +87,27 @@ void Cursor::UpdateTexture() return; } - // cursor type + // Cursor information const bool isMono = GetType() == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME; const bool isColorMask = GetType() == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR; + const auto cursorImageWidth = GetWidth(); + const auto cursorImageHeight = GetHeight(); + const auto cursorImagePitch = GetPitch(); - // Size - const auto w0 = GetWidth(); - const auto h0 = GetHeight(); - const auto p = GetPitch(); - auto w = w0; - auto h = h0; + // Captured area + auto capturedImageWidth = cursorImageWidth; + auto capturedImageHeight = cursorImageHeight; // Convert the buffer given by API into BGRA32 - const UINT bgraBufferSize = w0 * h0 * 4; + const UINT bgraBufferSize = cursorImageWidth * cursorImageHeight * 4; if (bgraBufferSize > bgra32BufferSize_) { bgra32BufferSize_ = bgraBufferSize; bgra32Buffer_ = std::make_unique(bgra32BufferSize_); } - if (!bgra32Buffer_) - { - return; - } - - if (!apiBuffer_) + // Check buffers + if (!bgra32Buffer_ || !apiBuffer_) { return; } @@ -119,41 +115,109 @@ void Cursor::UpdateTexture() // If masked, copy the desktop image and merge it with masked image. if (isMono || isColorMask) { - const auto mw = monitor_->GetWidth(); - const auto mh = monitor_->GetHeight(); + const auto monitorWidth = monitor_->GetWidth(); + const auto monitorHeight = monitor_->GetHeight(); + const auto monitorRot = static_cast(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 y = y_; auto colMin = 0; - auto colMax = w0; + auto colMax = cursorImageWidth; auto rowMin = 0; - auto rowMax = h0; + auto rowMax = cursorImageHeight; if (x < 0) { x = 0; - w = w0 + x_; - colMin = w0 - w; + capturedImageWidth = cursorImageWidth + x_; + colMin = cursorImageWidth - capturedImageWidth; } - if (x + w >= mw) + if (x + capturedImageWidth >= monitorWidth) { - w = mw - x_; - colMax = w; + capturedImageWidth = monitorWidth - x_; + colMax = capturedImageWidth; } if (y < 0) { y = 0; - h = h0 + y_; - rowMin = h0 - h; + capturedImageHeight = cursorImageHeight + y_; + rowMin = cursorImageHeight - capturedImageHeight; } - if (y + h >= mh) + if (y + capturedImageHeight >= monitorHeight) { - h = mh - y_; - rowMax = h; + capturedImageHeight = monitorHeight - y_; + 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(desktopImageWidth) || + box.bottom >= static_cast(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; - desc.Width = w; - desc.Height = h; + desc.Width = capturedImageWidth; + desc.Height = capturedImageHeight; desc.MipLevels = 1; desc.ArraySize = 1; desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; @@ -171,20 +235,6 @@ void Cursor::UpdateTexture() 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 context; GetDevice()->GetImmediateContext(&context); @@ -209,6 +259,27 @@ void Cursor::UpdateTexture() const auto desktop32 = reinterpret_cast(mappedSurface.pBits); 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 auto output32 = reinterpret_cast(bgra32Buffer_.get()); @@ -219,12 +290,11 @@ void Cursor::UpdateTexture() for (int col = colMin, x = 0; col < colMax; ++col, ++x) { BYTE mask = 0b10000000 >> (col % 8); - const int i = row * w0 + col; - const BYTE andMask = apiBuffer_[col / 8 + row * p] & mask; - const BYTE xorMask = apiBuffer_[col / 8 + (row + h) * p] & mask; + const BYTE andMask = apiBuffer_[col / 8 + row * cursorImagePitch] & mask; + const BYTE xorMask = apiBuffer_[col / 8 + (row + capturedImageHeight) * cursorImagePitch] & mask; const UINT andMask32 = andMask ? 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) { - const int i = col + row * w0; - const int j = col + row * p / sizeof(UINT); + const int i = col + row * cursorImageWidth; + const int j = col + row * cursorImagePitch / sizeof(UINT); UINT mask = 0xFF000000 & buffer32[j]; if (mask) { - output32[i] = (desktop32[y * desktopPitch + x] ^ buffer32[j]) | 0xFF000000; + output32[i] = (getDesktop32(x, y) ^ buffer32[j]) | 0xFF000000; } else { @@ -261,7 +331,7 @@ void Cursor::UpdateTexture() { auto output32 = reinterpret_cast(bgra32Buffer_.get()); const auto buffer32 = reinterpret_cast(apiBuffer_.get()); - for (int i = 0; i < w * h; ++i) + for (int i = 0; i < cursorImageWidth * cursorImageHeight; ++i) { output32[i] = buffer32[i]; }