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.
This commit is contained in:
parent
881d1c9bc2
commit
498f079d2c
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
|
Loading…
Reference in New Issue