display cursor on Windows
This commit is contained in:
parent
ba69d4a6f0
commit
e4135a8302
2 changed files with 106 additions and 24 deletions
|
|
@ -5,13 +5,14 @@ project(Sunshine)
|
|||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
add_subdirectory(Simple-Web-Server)
|
||||
add_subdirectory(moonlight-common-c/enet)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
find_package(FFmpeg REQUIRED)
|
||||
find_package(Boost COMPONENTS filesystem log REQUIRED)
|
||||
find_package(Boost COMPONENTS log filesystem REQUIRED)
|
||||
|
||||
add_subdirectory(Simple-Web-Server)
|
||||
add_subdirectory(moonlight-common-c/enet)
|
||||
|
||||
if(WIN32)
|
||||
set(PLATFORM_TARGET_FILES
|
||||
|
|
|
|||
|
|
@ -119,15 +119,98 @@ struct img_t : public ::platf::img_t {
|
|||
};
|
||||
|
||||
struct cursor_t {
|
||||
int x, y;
|
||||
int width, height;
|
||||
int pitch;
|
||||
|
||||
std::vector<std::uint8_t> img_data;
|
||||
bool visible;
|
||||
|
||||
DXGI_OUTDUPL_POINTER_SHAPE_INFO shape_info;
|
||||
int x, y;
|
||||
bool visible;
|
||||
};
|
||||
|
||||
void blend_cursor_monochrome(const cursor_t &cursor, img_t &img) {
|
||||
int height = cursor.shape_info.Height / 2;
|
||||
int width = cursor.shape_info.Width;
|
||||
int pitch = cursor.shape_info.Pitch;
|
||||
|
||||
int delta_height = std::min(height, std::max(0, img.height - cursor.y));
|
||||
int delta_width = std::min(width, std::max(0, img.width - cursor.x));
|
||||
|
||||
auto pixels_per_byte = width / pitch;
|
||||
auto bytes_per_row = delta_width / pixels_per_byte;
|
||||
|
||||
auto img_data = (int*)img.data;
|
||||
for(int i = 0; i < delta_height; ++i) {
|
||||
auto and_mask = &cursor.img_data[i * pitch];
|
||||
auto xor_mask = &cursor.img_data[(i + height) * pitch];
|
||||
|
||||
auto img_pixel_p = &img_data[(i + cursor.y) * img.width + cursor.x];
|
||||
|
||||
for(int x = 0; x < bytes_per_row; ++x) {
|
||||
for(auto bit = 0u; bit < 8; ++bit) {
|
||||
int and_ = *and_mask & (1 << (7 - bit)) ? -1 : 0;
|
||||
int xor_ = *xor_mask & (1 << (7 - bit)) ? -1 : 0;
|
||||
|
||||
*img_pixel_p &= and_;
|
||||
*img_pixel_p ^= xor_;
|
||||
|
||||
++img_pixel_p;
|
||||
}
|
||||
|
||||
++and_mask;
|
||||
++xor_mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void blend_cursor_color(const cursor_t &cursor, img_t &img) {
|
||||
int height = cursor.shape_info.Height;
|
||||
int width = cursor.shape_info.Width;
|
||||
int pitch = cursor.shape_info.Pitch;
|
||||
|
||||
int delta_height = std::min(height, std::max(0, img.height - cursor.y));
|
||||
int delta_width = std::min(width, std::max(0, img.width - cursor.x));
|
||||
|
||||
auto img_data = (int*)img.data;
|
||||
auto size_of_pixel = pitch / width;
|
||||
BOOST_LOG(info) << "size_of_pixel ["sv << size_of_pixel << ']';
|
||||
for(int i = 0; i < delta_height; ++i) {
|
||||
auto cursor_begin = &cursor.img_data[i * pitch];
|
||||
auto cursor_end = cursor_begin + delta_width * size_of_pixel;
|
||||
|
||||
auto img_pixel_p = &img_data[(i + cursor.y) * img.width + cursor.x];
|
||||
for(auto cursor_p = cursor_begin; cursor_p != cursor_end; cursor_p += size_of_pixel) {
|
||||
auto colors_in = (uint8_t*)img_pixel_p;
|
||||
|
||||
//TODO: When use of IDXGIOutput5 is implemented, support different color formats
|
||||
auto alpha = cursor_p[0];
|
||||
if(alpha == 255) {
|
||||
colors_in[0] = cursor_p[3];
|
||||
colors_in[1] = cursor_p[2];
|
||||
colors_in[2] = cursor_p[1];
|
||||
}
|
||||
else {
|
||||
colors_in[0] = cursor_p[3] + (colors_in[0] * (255 - alpha) + 255/2) / 255;
|
||||
colors_in[1] = cursor_p[2] + (colors_in[1] * (255 - alpha) + 255/2) / 255;
|
||||
colors_in[2] = cursor_p[1] + (colors_in[2] * (255 - alpha) + 255/2) / 255;
|
||||
}
|
||||
++img_pixel_p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void blend_cursor(const cursor_t &cursor, img_t &img) {
|
||||
switch(cursor.shape_info.Type) {
|
||||
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR:
|
||||
blend_cursor_color(cursor, img);
|
||||
break;
|
||||
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME:
|
||||
blend_cursor_monochrome(cursor, img);
|
||||
break;
|
||||
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR:
|
||||
default:
|
||||
BOOST_LOG(warning) << "Unsupported cursor format ["sv << cursor.shape_info.Type << ']';
|
||||
}
|
||||
}
|
||||
|
||||
class display_t : public ::platf::display_t, public std::enable_shared_from_this<display_t> {
|
||||
public:
|
||||
capture_e snapshot(std::unique_ptr<::platf::img_t> &img_base, bool cursor_visible) override {
|
||||
|
|
@ -145,28 +228,26 @@ public:
|
|||
}
|
||||
|
||||
if (frame_info.PointerShapeBufferSize > 0) {
|
||||
cursor.img_data.resize(frame_info.PointerShapeBufferSize);
|
||||
DXGI_OUTDUPL_POINTER_SHAPE_INFO shape_info;
|
||||
|
||||
auto &img_data = cursor.img_data;
|
||||
|
||||
img_data.resize(frame_info.PointerShapeBufferSize);
|
||||
|
||||
UINT dummy;
|
||||
status = dup.dup->GetFramePointerShape(img_data.size(), img_data.data(), &dummy, &shape_info);
|
||||
status = dup.dup->GetFramePointerShape(img_data.size(), img_data.data(), &dummy, &cursor.shape_info);
|
||||
if (FAILED(status)) {
|
||||
BOOST_LOG(error) << "Failed to get new pointer shape [0x"sv << util::hex(status).to_string_view() << ']';
|
||||
|
||||
return capture_e::error;
|
||||
}
|
||||
|
||||
if (shape_info.Type != DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR) {
|
||||
BOOST_LOG(warning) << "Unsupported cursor format ["sv << shape_info.Type << ']';
|
||||
}
|
||||
|
||||
cursor.width = shape_info.Width;
|
||||
cursor.height = shape_info.Height;
|
||||
cursor.pitch = shape_info.Pitch;
|
||||
}
|
||||
|
||||
if(frame_info.LastMouseUpdateTime.QuadPart) {
|
||||
cursor.x = frame_info.PointerPosition.Position.x;
|
||||
cursor.y = frame_info.PointerPosition.Position.y;
|
||||
cursor.visible = frame_info.PointerPosition.Visible;
|
||||
}
|
||||
|
||||
// If frame has not been updated, skip
|
||||
if (frame_info.LastPresentTime.QuadPart == 0) {
|
||||
return capture_e::timeout;
|
||||
}
|
||||
|
|
@ -185,10 +266,6 @@ public:
|
|||
device_ctx->CopyResource((ID3D11Resource *) img->texture.get(), (ID3D11Resource *) src.get());
|
||||
}
|
||||
|
||||
cursor.x = frame_info.PointerPosition.Position.x;
|
||||
cursor.y = frame_info.PointerPosition.Position.y;
|
||||
cursor.visible = frame_info.PointerPosition.Visible;
|
||||
|
||||
status = device_ctx->Map((ID3D11Resource *) img->texture.get(), 0, D3D11_MAP_READ, 0, &img->map);
|
||||
if (FAILED(status)) {
|
||||
if (status == DXGI_ERROR_WAS_STILL_DRAWING) {
|
||||
|
|
@ -204,6 +281,10 @@ public:
|
|||
img->width = width;
|
||||
img->height = height;
|
||||
|
||||
if(cursor_visible && cursor.visible) {
|
||||
blend_cursor(cursor, *img);
|
||||
}
|
||||
|
||||
return capture_e::ok;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue