From f98bb033ff14f39188f2bcafe11099c10920cb80 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Mon, 8 Jun 2020 02:53:37 +1000 Subject: [PATCH] HostDisplay: Add an interface for setting software cursor --- src/core/host_display.cpp | 60 +++++++++++++++++++++++++++++++++++++++ src/core/host_display.h | 19 +++++++++++++ 2 files changed, 79 insertions(+) diff --git a/src/core/host_display.cpp b/src/core/host_display.cpp index 67df4e63f..07dd1ce32 100644 --- a/src/core/host_display.cpp +++ b/src/core/host_display.cpp @@ -1,6 +1,7 @@ #include "host_display.h" #include "common/log.h" #include "common/string_util.h" +#include "stb_image.h" #include "stb_image_resize.h" #include "stb_image_write.h" #include @@ -18,6 +19,50 @@ void HostDisplay::WindowResized(s32 new_window_width, s32 new_window_height) m_window_height = new_window_height; } +void HostDisplay::SetSoftwareCursor(std::unique_ptr texture, float scale /*= 1.0f*/) +{ + m_cursor_texture = std::move(texture); + m_cursor_texture_scale = scale; +} + +bool HostDisplay::SetSoftwareCursor(const void* pixels, u32 width, u32 height, u32 stride, float scale /*= 1.0f*/) +{ + std::unique_ptr tex = CreateTexture(width, height, pixels, stride, false); + if (!tex) + return false; + + SetSoftwareCursor(std::move(tex), scale); + return true; +} + +bool HostDisplay::SetSoftwareCursor(const char* path, float scale /*= 1.0f*/) +{ + int width, height, file_channels; + u8* pixel_data = stbi_load(path, &width, &height, &file_channels, 4); + if (!pixel_data) + { + const char* error_reason = stbi_failure_reason(); + Log_ErrorPrintf("Failed to load image from '%s': %s", path, error_reason ? error_reason : "unknown error"); + return false; + } + + std::unique_ptr tex = CreateTexture(static_cast(width), static_cast(height), pixel_data, + sizeof(u32) * static_cast(width), false); + stbi_image_free(pixel_data); + if (!tex) + return false; + + Log_InfoPrintf("Loaded %dx%d image from '%s' for software cursor", width, height, path); + SetSoftwareCursor(std::move(tex), scale); + return true; +} + +void HostDisplay::ClearSoftwareCursor() +{ + m_cursor_texture.reset(); + m_cursor_texture_scale = 1.0f; +} + void HostDisplay::CalculateDrawRect(s32 window_width, s32 window_height, s32* out_left, s32* out_top, s32* out_width, s32* out_height, s32* out_left_padding, s32* out_top_padding, float* out_scale, float* out_y_scale) const @@ -88,6 +133,21 @@ std::tuple HostDisplay::CalculateDrawRect(s32 window_width, return std::make_tuple(left + left_padding, top + top_padding + top_margin, width, height); } +std::tuple HostDisplay::CalculateSoftwareCursorDrawRect() const +{ + const u32 cursor_extents_x = + static_cast(static_cast(m_cursor_texture->GetWidth()) * m_cursor_texture_scale * 0.5f); + const u32 cursor_extents_y = + static_cast(static_cast(m_cursor_texture->GetHeight()) * m_cursor_texture_scale * 0.5f); + + const s32 out_left = m_mouse_position_x - cursor_extents_x; + const s32 out_top = m_mouse_position_y - cursor_extents_y; + const s32 out_width = cursor_extents_x * 2u; + const s32 out_height = cursor_extents_y * 2u; + + return std::tie(out_left, out_top, out_width, out_height); +} + std::tuple HostDisplay::ConvertWindowCoordinatesToDisplayCoordinates(s32 window_x, s32 window_y, s32 window_width, s32 window_height, s32 top_margin) const diff --git a/src/core/host_display.h b/src/core/host_display.h index dee65c20c..687469d01 100644 --- a/src/core/host_display.h +++ b/src/core/host_display.h @@ -106,6 +106,18 @@ public: void SetDisplayTopMargin(s32 height) { m_display_top_margin = height; } void SetDisplayIntegerScaling(bool enabled) { m_display_integer_scaling = enabled; } + /// Sets the software cursor to the specified texture. Ownership of the texture is transferred. + void SetSoftwareCursor(std::unique_ptr texture, float scale = 1.0f); + + /// Sets the software cursor to the specified image. + bool SetSoftwareCursor(const void* pixels, u32 width, u32 height, u32 stride, float scale = 1.0f); + + /// Sets the software cursor to the specified path (png image). + bool SetSoftwareCursor(const char* path, float scale = 1.0f); + + /// Disables the software cursor. + void ClearSoftwareCursor(); + /// Helper function for computing the draw rectangle in a larger window. std::tuple CalculateDrawRect(s32 window_width, s32 window_height, s32 top_margin) const; @@ -125,10 +137,14 @@ public: bool clear_alpha = true); protected: + ALWAYS_INLINE bool HasSoftwareCursor() const { return static_cast(m_cursor_texture); } + void CalculateDrawRect(s32 window_width, s32 window_height, s32* out_left, s32* out_top, s32* out_width, s32* out_height, s32* out_left_padding, s32* out_top_padding, float* out_scale, float* out_y_scale) const; + std::tuple CalculateSoftwareCursorDrawRect() const; + s32 m_window_width = 0; s32 m_window_height = 0; @@ -153,6 +169,9 @@ protected: s32 m_display_top_margin = 0; + std::unique_ptr m_cursor_texture; + float m_cursor_texture_scale = 1.0f; + bool m_display_linear_filtering = false; bool m_display_changed = false; bool m_display_integer_scaling = false;