diff options
author | Campbell Barton <campbell@blender.org> | 2022-06-18 08:10:03 +0300 |
---|---|---|
committer | Campbell Barton <campbell@blender.org> | 2022-06-18 10:16:42 +0300 |
commit | 498f079d2c3644b47ff5c004bc1cf93a9ba6604b (patch) | |
tree | 005d5f0bca3a170a5c0e9aada12ad273a44f1d78 | |
parent | 881d1c9bc234e203cff033ea02998ce99f3070cd (diff) |
GHOST/Wayland: support displaying custom software cursors
Add a method to access the custom cursor from GHOST which is used
for drawing a software cursor. This means the knife tools cursor now
work as expected.
Although non-custom cursors are still not supported.
-rw-r--r-- | intern/ghost/GHOST_C-api.h | 3 | ||||
-rw-r--r-- | intern/ghost/GHOST_IWindow.h | 2 | ||||
-rw-r--r-- | intern/ghost/GHOST_Types.h | 10 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_C-api.cpp | 8 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_SystemWayland.cpp | 25 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_SystemWayland.h | 2 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_Window.cpp | 6 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_Window.h | 2 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_WindowWayland.cpp | 5 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_WindowWayland.h | 2 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_draw.c | 132 |
11 files changed, 175 insertions, 22 deletions
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index 08ca9603985..5ace0fcc9d2 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -364,6 +364,9 @@ extern GHOST_TSuccess GHOST_SetCustomCursorShape(GHOST_WindowHandle windowhandle int hotY, bool canInvertColor); +extern GHOST_TSuccess GHOST_GetCursorBitmap(GHOST_WindowHandle windowhandle, + GHOST_CursorBitmapRef *bitmap); + /** * Returns the visibility state of the cursor. * \param windowhandle: The handle to the window. diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h index f9552246e89..f712d9bd9f0 100644 --- a/intern/ghost/GHOST_IWindow.h +++ b/intern/ghost/GHOST_IWindow.h @@ -285,6 +285,8 @@ class GHOST_IWindow { int hotY, bool canInvertColor) = 0; + virtual GHOST_TSuccess getCursorBitmap(GHOST_CursorBitmapRef *bitmap) = 0; + /** * Returns the visibility state of the cursor. * \return The visibility state of the cursor. diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index 78f2b24ea78..35bde3d4413 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -44,6 +44,16 @@ GHOST_DECLARE_HANDLE(GHOST_XrContextHandle); typedef void (*GHOST_TBacktraceFn)(void *file_handle); +/** + * A reference to cursor bitmap data. + */ +typedef struct { + /** `RGBA` bytes. */ + const uint8_t *data; + int data_size[2]; + int hot_spot[2]; +} GHOST_CursorBitmapRef; + typedef struct { int flags; } GHOST_GLSettings; diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index 032ecd6aab5..2b5414cd47b 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -326,6 +326,14 @@ GHOST_TSuccess GHOST_SetCustomCursorShape(GHOST_WindowHandle windowhandle, return window->setCustomCursorShape(bitmap, mask, sizex, sizey, hotX, hotY, canInvertColor); } +GHOST_TSuccess GHOST_GetCursorBitmap(GHOST_WindowHandle windowhandle, + GHOST_CursorBitmapRef *bitmap) +{ + GHOST_IWindow *window = (GHOST_IWindow *)windowhandle; + + return window->getCursorBitmap(bitmap); +} + bool GHOST_GetCursorVisibility(GHOST_WindowHandle windowhandle) { GHOST_IWindow *window = (GHOST_IWindow *)windowhandle; diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp index bff96b3c0a4..aebee003145 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.cpp +++ b/intern/ghost/intern/GHOST_SystemWayland.cpp @@ -96,6 +96,7 @@ struct buffer_t { struct cursor_t { bool visible = false; + bool is_custom = false; struct wl_surface *wl_surface = nullptr; struct wl_buffer *wl_buffer = nullptr; struct wl_cursor_image wl_image = {0}; @@ -2587,6 +2588,7 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorShape(GHOST_TStandardCursor shape) return GHOST_kFailure; } + c->is_custom = false; c->wl_buffer = buffer; c->wl_image = *image; @@ -2650,6 +2652,7 @@ GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(uint8_t *bitmap, nullptr, cursor->file_buffer->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (cursor->file_buffer->data == MAP_FAILED) { + cursor->file_buffer->data = nullptr; close(fd); return GHOST_kFailure; } @@ -2694,6 +2697,7 @@ GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(uint8_t *bitmap, } } + cursor->is_custom = true; cursor->wl_buffer = buffer; cursor->wl_image.width = uint32_t(sizex); cursor->wl_image.height = uint32_t(sizey); @@ -2705,6 +2709,27 @@ GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(uint8_t *bitmap, return GHOST_kSuccess; } +GHOST_TSuccess GHOST_SystemWayland::getCursorBitmap(GHOST_CursorBitmapRef *bitmap) +{ + cursor_t *cursor = &d->inputs[0]->cursor; + if (cursor->file_buffer->data == nullptr) { + return GHOST_kFailure; + } + if (!cursor->is_custom) { + return GHOST_kFailure; + } + + bitmap->data_size[0] = cursor->wl_image.width; + bitmap->data_size[1] = cursor->wl_image.height; + + bitmap->hot_spot[0] = cursor->wl_image.hotspot_x; + bitmap->hot_spot[1] = cursor->wl_image.hotspot_y; + + bitmap->data = (uint8_t *)static_cast<void *>(cursor->file_buffer->data); + + return GHOST_kSuccess; +} + GHOST_TSuccess GHOST_SystemWayland::setCursorVisibility(bool visible) { if (d->inputs.empty()) { diff --git a/intern/ghost/intern/GHOST_SystemWayland.h b/intern/ghost/intern/GHOST_SystemWayland.h index 6faff8d57c1..04aa4063947 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.h +++ b/intern/ghost/intern/GHOST_SystemWayland.h @@ -122,6 +122,8 @@ class GHOST_SystemWayland : public GHOST_System { int hotY, bool canInvertColor); + GHOST_TSuccess getCursorBitmap(GHOST_CursorBitmapRef *bitmap); + GHOST_TSuccess setCursorVisibility(bool visible); bool supportsCursorWarp(); diff --git a/intern/ghost/intern/GHOST_Window.cpp b/intern/ghost/intern/GHOST_Window.cpp index d6dcb269c8f..3f093840d0c 100644 --- a/intern/ghost/intern/GHOST_Window.cpp +++ b/intern/ghost/intern/GHOST_Window.cpp @@ -208,6 +208,12 @@ GHOST_TSuccess GHOST_Window::setCustomCursorShape( return GHOST_kFailure; } +GHOST_TSuccess GHOST_Window::getCursorBitmap(GHOST_CursorBitmapRef * /*bitmap*/) +{ + /* Sub-classes may override. */ + return GHOST_kFailure; +} + void GHOST_Window::setAcceptDragOperation(bool canAccept) { m_canAcceptDragOperation = canAccept; diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h index 6ca2651fad0..5ff91c05b16 100644 --- a/intern/ghost/intern/GHOST_Window.h +++ b/intern/ghost/intern/GHOST_Window.h @@ -117,6 +117,8 @@ class GHOST_Window : public GHOST_IWindow { int hotY, bool canInvertColor); + GHOST_TSuccess getCursorBitmap(GHOST_CursorBitmapRef *bitmap); + /** * Returns the visibility state of the cursor. * \return The visibility state of the cursor. diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp index 8c7183971ab..941e08ff035 100644 --- a/intern/ghost/intern/GHOST_WindowWayland.cpp +++ b/intern/ghost/intern/GHOST_WindowWayland.cpp @@ -503,6 +503,11 @@ GHOST_TSuccess GHOST_WindowWayland::setWindowCustomCursorShape( return m_system->setCustomCursorShape(bitmap, mask, sizex, sizey, hotX, hotY, canInvertColor); } +GHOST_TSuccess GHOST_WindowWayland::getCursorBitmap(GHOST_CursorBitmapRef *bitmap) +{ + return m_system->getCursorBitmap(bitmap); +} + void GHOST_WindowWayland::setTitle(const char *title) { xdg_toplevel_set_title(w->xdg_toplevel, title); diff --git a/intern/ghost/intern/GHOST_WindowWayland.h b/intern/ghost/intern/GHOST_WindowWayland.h index f9effc636a1..d1eadd8fcd4 100644 --- a/intern/ghost/intern/GHOST_WindowWayland.h +++ b/intern/ghost/intern/GHOST_WindowWayland.h @@ -54,6 +54,8 @@ class GHOST_WindowWayland : public GHOST_Window { bool canInvertColor) override; bool getCursorGrabUseSoftwareDisplay() override; + GHOST_TSuccess getCursorBitmap(GHOST_CursorBitmapRef *bitmap) override; + void setTitle(const char *title) override; std::string getTitle() const override; diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index abf7aa65da7..aaa28b1fd85 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -41,6 +41,7 @@ #include "GPU_debug.h" #include "GPU_framebuffer.h" #include "GPU_immediate.h" +#include "GPU_matrix.h" #include "GPU_state.h" #include "GPU_texture.h" #include "GPU_viewport.h" @@ -193,27 +194,69 @@ static void wm_software_cursor_motion_clear(void) g_software_cursor.xy[1] = -1; } -static void wm_software_cursor_draw(wmWindow *win, const struct GrabState *grab_state) +static void wm_software_cursor_draw_bitmap(const int event_xy[2], + const GHOST_CursorBitmapRef *bitmap) { - int x = win->eventstate->xy[0]; - int y = win->eventstate->xy[1]; + GPU_blend(GPU_BLEND_ALPHA); - if (grab_state->wrap_axis & GHOST_kAxisX) { - const int min = grab_state->bounds[0]; - const int max = grab_state->bounds[2]; - if (min != max) { - x = mod_i(x - min, max - min) + min; - } - } - if (grab_state->wrap_axis & GHOST_kGrabAxisY) { - const int height = WM_window_pixels_y(win); - const int min = height - grab_state->bounds[1]; - const int max = height - grab_state->bounds[3]; - if (min != max) { - y = mod_i(y - max, min - max) + max; - } - } + float gl_matrix[4][4]; + GPUTexture *texture = GPU_texture_create_2d( + "softeare_cursor", bitmap->data_size[0], bitmap->data_size[1], 1, GPU_RGBA8, NULL); + GPU_texture_update(texture, GPU_DATA_UBYTE, bitmap->data); + GPU_texture_filter_mode(texture, false); + + GPU_matrix_push(); + + const int scale = (int)U.pixelsize; + + unit_m4(gl_matrix); + + gl_matrix[3][0] = event_xy[0] - (bitmap->hot_spot[0] * scale); + gl_matrix[3][1] = event_xy[1] - ((bitmap->data_size[1] - bitmap->hot_spot[1]) * scale); + + gl_matrix[0][0] = bitmap->data_size[0] * scale; + gl_matrix[1][1] = bitmap->data_size[1] * scale; + + GPU_matrix_mul(gl_matrix); + + GPUVertFormat *imm_format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(imm_format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + uint texCoord = GPU_vertformat_attr_add( + imm_format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + + /* Use 3D image for correct display of planar tracked images. */ + immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_MODULATE_ALPHA); + + immBindTexture("image", texture); + immUniform1f("alpha", 1.0f); + + immBegin(GPU_PRIM_TRI_FAN, 4); + + immAttr2f(texCoord, 0.0f, 1.0f); + immVertex3f(pos, 0.0f, 0.0f, 0.0f); + + immAttr2f(texCoord, 1.0f, 1.0f); + immVertex3f(pos, 1.0f, 0.0f, 0.0f); + + immAttr2f(texCoord, 1.0f, 0.0f); + immVertex3f(pos, 1.0f, 1.0f, 0.0f); + + immAttr2f(texCoord, 0.0f, 0.0f); + immVertex3f(pos, 0.0f, 1.0f, 0.0f); + + immEnd(); + immUnbindProgram(); + + GPU_matrix_pop(); + GPU_texture_unbind(texture); + GPU_texture_free(texture); + + GPU_blend(GPU_BLEND_NONE); +} + +static void wm_software_cursor_draw_crosshair(const int event_xy[2]) +{ /* Draw a primitive cross-hair cursor. * NOTE: the `win->cursor` could be used for drawing although it's complicated as some cursors * are set by the operating-system, where the pixel information isn't easily available. */ @@ -226,19 +269,64 @@ static void wm_software_cursor_draw(wmWindow *win, const struct GrabState *grab_ { const int ofs_line = (8 * unit); const int ofs_size = (2 * unit); - immRecti(pos, x - ofs_line, y - ofs_size, x + ofs_line, y + ofs_size); - immRecti(pos, x - ofs_size, y - ofs_line, x + ofs_size, y + ofs_line); + immRecti(pos, + event_xy[0] - ofs_line, + event_xy[1] - ofs_size, + event_xy[0] + ofs_line, + event_xy[1] + ofs_size); + immRecti(pos, + event_xy[0] - ofs_size, + event_xy[1] - ofs_line, + event_xy[0] + ofs_size, + event_xy[1] + ofs_line); } immUniformColor4f(0, 0, 0, 1); { const int ofs_line = (7 * unit); const int ofs_size = (1 * unit); - immRecti(pos, x - ofs_line, y - ofs_size, x + ofs_line, y + ofs_size); - immRecti(pos, x - ofs_size, y - ofs_line, x + ofs_size, y + ofs_line); + immRecti(pos, + event_xy[0] - ofs_line, + event_xy[1] - ofs_size, + event_xy[0] + ofs_line, + event_xy[1] + ofs_size); + immRecti(pos, + event_xy[0] - ofs_size, + event_xy[1] - ofs_line, + event_xy[0] + ofs_size, + event_xy[1] + ofs_line); } immUnbindProgram(); } +static void wm_software_cursor_draw(wmWindow *win, const struct GrabState *grab_state) +{ + int event_xy[2] = {UNPACK2(win->eventstate->xy)}; + + if (grab_state->wrap_axis & GHOST_kAxisX) { + const int min = grab_state->bounds[0]; + const int max = grab_state->bounds[2]; + if (min != max) { + event_xy[0] = mod_i(event_xy[0] - min, max - min) + min; + } + } + if (grab_state->wrap_axis & GHOST_kGrabAxisY) { + const int height = WM_window_pixels_y(win); + const int min = height - grab_state->bounds[1]; + const int max = height - grab_state->bounds[3]; + if (min != max) { + event_xy[1] = mod_i(event_xy[1] - max, min - max) + max; + } + } + + GHOST_CursorBitmapRef bitmap = {0}; + if (GHOST_GetCursorBitmap(win->ghostwin, &bitmap) == GHOST_kSuccess) { + wm_software_cursor_draw_bitmap(event_xy, &bitmap); + } + else { + wm_software_cursor_draw_crosshair(event_xy); + } +} + /** \} */ /* -------------------------------------------------------------------- */ |