Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <campbell@blender.org>2022-06-18 08:10:03 +0300
committerCampbell Barton <campbell@blender.org>2022-06-18 10:16:42 +0300
commit498f079d2c3644b47ff5c004bc1cf93a9ba6604b (patch)
tree005d5f0bca3a170a5c0e9aada12ad273a44f1d78
parent881d1c9bc234e203cff033ea02998ce99f3070cd (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.h3
-rw-r--r--intern/ghost/GHOST_IWindow.h2
-rw-r--r--intern/ghost/GHOST_Types.h10
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp8
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.cpp25
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.h2
-rw-r--r--intern/ghost/intern/GHOST_Window.cpp6
-rw-r--r--intern/ghost/intern/GHOST_Window.h2
-rw-r--r--intern/ghost/intern/GHOST_WindowWayland.cpp5
-rw-r--r--intern/ghost/intern/GHOST_WindowWayland.h2
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c132
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);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */