mirror of
https://github.com/virtcode/hypr-dynamic-cursors
synced 2025-09-19 16:13:21 +02:00
feat: inverted hardware cursor support
This commit is contained in:
parent
c6a2b45f97
commit
556a124314
7 changed files with 33 additions and 23 deletions
|
@ -26,9 +26,9 @@ https://github.com/VirtCode/hypr-dynamic-cursors/assets/41426325/9ff64a9b-64e5-4
|
||||||
### inverted cursor (experimental)
|
### inverted cursor (experimental)
|
||||||
You can also finally have an inverted cursor with this plugin. This is similar to the inverted cursor theme found in MS Windows.
|
You can also finally have an inverted cursor with this plugin. This is similar to the inverted cursor theme found in MS Windows.
|
||||||
|
|
||||||
**Note:** Inverted cursors have about the same performance impact as a *basic* screen shader. They are also only supported as software cursors.
|
**Note:** Inverted cursors have about the same performance impact as a *basic* screen shader. They are also currently broken on nvidia.
|
||||||
|
|
||||||
INSERT VIDEO HERE
|
https://github.com/VirtCode/hypr-dynamic-cursors/assets/41426325/b62698d8-d53f-45f2-b36f-2c9752b8f90d
|
||||||
|
|
||||||
## state
|
## state
|
||||||
This plugin is still very early in its development. There are also multiple things which may or may not be implemented in the future:
|
This plugin is still very early in its development. There are also multiple things which may or may not be implemented in the future:
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <hyprlang.hpp>
|
#include <hyprlang.hpp>
|
||||||
|
#include <hyprutils/math/Vector2D.hpp>
|
||||||
|
|
||||||
#define private public
|
#define private public
|
||||||
#include <hyprland/src/managers/PointerManager.hpp>
|
#include <hyprland/src/managers/PointerManager.hpp>
|
||||||
|
@ -22,7 +23,7 @@
|
||||||
#include "cursor.hpp"
|
#include "cursor.hpp"
|
||||||
#include "renderer.hpp"
|
#include "renderer.hpp"
|
||||||
|
|
||||||
void renderCursorBox(SP<CTexture> texture, CBox box, CRegion& damage, Vector2D hotspot, float zoom) {
|
void renderCursorBox(SP<CTexture> texture, CBox box, CRegion& damage, Vector2D hotspot, float zoom, Vector2D offset) {
|
||||||
static auto* const* PNEAREST = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_NEAREST)->getDataStaticPtr();
|
static auto* const* PNEAREST = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_NEAREST)->getDataStaticPtr();
|
||||||
static auto* const* POPACITY = (Hyprlang::FLOAT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_OPACITY)->getDataStaticPtr();
|
static auto* const* POPACITY = (Hyprlang::FLOAT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_OPACITY)->getDataStaticPtr();
|
||||||
|
|
||||||
|
@ -39,7 +40,7 @@ void renderCursorBox(SP<CTexture> texture, CBox box, CRegion& damage, Vector2D h
|
||||||
if (!strcmp(*PINVERT_MODE, "invert_hue")) mode = 1;
|
if (!strcmp(*PINVERT_MODE, "invert_hue")) mode = 1;
|
||||||
else if (!strcmp(*PINVERT_MODE, "hue")) mode = 2;
|
else if (!strcmp(*PINVERT_MODE, "hue")) mode = 2;
|
||||||
|
|
||||||
renderCursorTextureInternalWithDamageInverted(texture, &box, &damage, alpha, hotspot, nearest, mode, **PINVERT_CHROMA, CColor(**PINVERT_CHROMA_COLOR));
|
renderCursorTextureInternalWithDamageInverted(texture, &box, &damage, alpha, hotspot, nearest, mode, **PINVERT_CHROMA, CColor(**PINVERT_CHROMA_COLOR), offset);
|
||||||
} else
|
} else
|
||||||
renderCursorTextureInternalWithDamage(texture, &box, &damage, alpha, hotspot, nearest);
|
renderCursorTextureInternalWithDamage(texture, &box, &damage, alpha, hotspot, nearest);
|
||||||
}
|
}
|
||||||
|
@ -83,7 +84,7 @@ void CDynamicCursors::renderSoftware(CPointerManager* pointers, SP<CMonitor> pMo
|
||||||
// we rotate the cursor by our calculated amount
|
// we rotate the cursor by our calculated amount
|
||||||
box.rot = this->angle;
|
box.rot = this->angle;
|
||||||
|
|
||||||
renderCursorBox(texture, box, damage, pointers->currentCursorImage.hotspot * state->monitor->scale * zoom, zoom);
|
renderCursorBox(texture, box, damage, pointers->currentCursorImage.hotspot * state->monitor->scale * zoom, zoom, Vector2D());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -115,6 +116,7 @@ It is largely copied from hyprland, but adjusted to allow the cursor to be rotat
|
||||||
*/
|
*/
|
||||||
wlr_buffer* CDynamicCursors::renderHardware(CPointerManager* pointers, SP<CPointerManager::SMonitorPointerState> state, SP<CTexture> texture) {
|
wlr_buffer* CDynamicCursors::renderHardware(CPointerManager* pointers, SP<CPointerManager::SMonitorPointerState> state, SP<CTexture> texture) {
|
||||||
static auto* const* PHW_DEBUG= (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_HW_DEBUG)->getDataStaticPtr();
|
static auto* const* PHW_DEBUG= (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_HW_DEBUG)->getDataStaticPtr();
|
||||||
|
static auto* const* PINVERT = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_INVERT)->getDataStaticPtr();
|
||||||
|
|
||||||
auto output = state->monitor->output;
|
auto output = state->monitor->output;
|
||||||
|
|
||||||
|
@ -182,7 +184,19 @@ wlr_buffer* CDynamicCursors::renderHardware(CPointerManager* pointers, SP<CPoint
|
||||||
CBox xbox = {size, Vector2D{pointers->currentCursorImage.size / pointers->currentCursorImage.scale * state->monitor->scale * zoom}.round()};
|
CBox xbox = {size, Vector2D{pointers->currentCursorImage.size / pointers->currentCursorImage.scale * state->monitor->scale * zoom}.round()};
|
||||||
xbox.rot = this->angle;
|
xbox.rot = this->angle;
|
||||||
|
|
||||||
renderCursorBox(texture, xbox, damage, pointers->currentCursorImage.hotspot * state->monitor->scale * zoom, zoom);
|
// calculate correct offset of the offload buffer into the cursor buffer
|
||||||
|
auto offset = Vector2D();
|
||||||
|
if (**PINVERT) {
|
||||||
|
const auto HOTSPOT = CBox{((pointers->currentCursorImage.hotspot * state->monitor->scale) + pointers->currentCursorImage.size) * zoom, {0, 0}}
|
||||||
|
.transform(wlTransformToHyprutils(wlr_output_transform_invert(state->monitor->transform)), state->monitor->output->cursor_swapchain->width, state->monitor->output->cursor_swapchain->height)
|
||||||
|
.pos();
|
||||||
|
|
||||||
|
offset = pointers->getCursorPosForMonitor(state->monitor.lock()) - HOTSPOT;
|
||||||
|
offset.x /= xbox.x;
|
||||||
|
offset.y /= xbox.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderCursorBox(texture, xbox, damage, pointers->currentCursorImage.hotspot * state->monitor->scale * zoom, zoom, offset);
|
||||||
|
|
||||||
g_pHyprOpenGL->end();
|
g_pHyprOpenGL->end();
|
||||||
glFlush();
|
glFlush();
|
||||||
|
@ -268,16 +282,6 @@ void CDynamicCursors::beforeRender(CPointerManager* pointers) {
|
||||||
if (**PINVERT) {
|
if (**PINVERT) {
|
||||||
// we need introspection as we make use of the offloadFB
|
// we need introspection as we make use of the offloadFB
|
||||||
g_pHyprOpenGL->m_RenderData.forceIntrospection = true;
|
g_pHyprOpenGL->m_RenderData.forceIntrospection = true;
|
||||||
|
|
||||||
if (!invertSoftware) {
|
|
||||||
pointers->lockSoftwareAll();
|
|
||||||
invertSoftware = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (invertSoftware) {
|
|
||||||
pointers->unlockSoftwareAll();
|
|
||||||
invertSoftware = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,6 +289,7 @@ void CDynamicCursors::calculate(EModeUpdate type) {
|
||||||
static auto* const* PTHRESHOLD = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_THRESHOLD)->getDataStaticPtr();
|
static auto* const* PTHRESHOLD = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_THRESHOLD)->getDataStaticPtr();
|
||||||
static auto* const* PSHAKE = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE)->getDataStaticPtr();
|
static auto* const* PSHAKE = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE)->getDataStaticPtr();
|
||||||
static auto* const* PSHAKE_EFFECTS = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_EFFECTS)->getDataStaticPtr();
|
static auto* const* PSHAKE_EFFECTS = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_EFFECTS)->getDataStaticPtr();
|
||||||
|
static auto* const* PINVERT = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_INVERT)->getDataStaticPtr();
|
||||||
|
|
||||||
IMode* mode = currentMode();
|
IMode* mode = currentMode();
|
||||||
|
|
||||||
|
@ -304,7 +309,8 @@ void CDynamicCursors::calculate(EModeUpdate type) {
|
||||||
|
|
||||||
if (
|
if (
|
||||||
std::abs(this->angle - angle) > ((PI / 180) * **PTHRESHOLD) ||
|
std::abs(this->angle - angle) > ((PI / 180) * **PTHRESHOLD) ||
|
||||||
this->zoom - zoom != 0 // we don't have a threshold here as this will not happen that often
|
this->zoom - zoom != 0 || // we don't have a threshold here as this will not happen that often
|
||||||
|
(**PINVERT && type == MOVE) // currently we only update inverted cursors on move
|
||||||
) {
|
) {
|
||||||
this->zoom = zoom;
|
this->zoom = zoom;
|
||||||
this->angle = angle;
|
this->angle = angle;
|
||||||
|
|
|
@ -35,8 +35,6 @@ class CDynamicCursors {
|
||||||
|
|
||||||
// whether we have already locked software for cursor zoom
|
// whether we have already locked software for cursor zoom
|
||||||
bool zoomSoftware = false;
|
bool zoomSoftware = false;
|
||||||
// whether we have already locked software for inverted cursors
|
|
||||||
bool invertSoftware = false;
|
|
||||||
|
|
||||||
// modes
|
// modes
|
||||||
CModeRotate rotate;
|
CModeRotate rotate;
|
||||||
|
|
|
@ -17,6 +17,7 @@ void CInversionShader::compile(std::string vertex, std::string fragment) {
|
||||||
posAttrib = glGetAttribLocation(program, "pos");
|
posAttrib = glGetAttribLocation(program, "pos");
|
||||||
|
|
||||||
proj = glGetUniformLocation(program, "proj");
|
proj = glGetUniformLocation(program, "proj");
|
||||||
|
screenOffset = glGetUniformLocation(program, "screenOffset");
|
||||||
backgroundTex = glGetUniformLocation(program, "backgroundTex");
|
backgroundTex = glGetUniformLocation(program, "backgroundTex");
|
||||||
cursorTex = glGetUniformLocation(program, "cursorTex");
|
cursorTex = glGetUniformLocation(program, "cursorTex");
|
||||||
alpha = glGetUniformLocation(program, "alpha");
|
alpha = glGetUniformLocation(program, "alpha");
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <hyprland/src/render/Shader.hpp>
|
#include <hyprland/src/render/Shader.hpp>
|
||||||
|
|
||||||
// we need our own shader class as we have two textures
|
// we need our own shader class as we have two textures, and custom uniforms
|
||||||
class CInversionShader {
|
class CInversionShader {
|
||||||
public:
|
public:
|
||||||
GLuint program = 0;
|
GLuint program = 0;
|
||||||
|
@ -10,6 +10,7 @@ class CInversionShader {
|
||||||
GLint texAttrib = -1;
|
GLint texAttrib = -1;
|
||||||
|
|
||||||
GLint proj = -1;
|
GLint proj = -1;
|
||||||
|
GLint screenOffset = -1;
|
||||||
GLint cursorTex = -1;
|
GLint cursorTex = -1;
|
||||||
GLint backgroundTex = -1;
|
GLint backgroundTex = -1;
|
||||||
GLint alpha = -1;
|
GLint alpha = -1;
|
||||||
|
@ -44,10 +45,12 @@ inline const std::string VERTEX = R"#(
|
||||||
varying vec2 v_texcoord;
|
varying vec2 v_texcoord;
|
||||||
varying vec2 v_screencord;
|
varying vec2 v_screencord;
|
||||||
|
|
||||||
|
uniform vec2 screenOffset;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);
|
gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);
|
||||||
|
|
||||||
v_screencord = gl_Position.xy / 2.0 + vec2(0.5, 0.5); // transform to texture coords
|
v_screencord = (proj * vec3(pos + screenOffset, 1.0)).xy / 2.0 + vec2(0.5, 0.5); // transform to texture coords
|
||||||
v_texcoord = texcoord;
|
v_texcoord = texcoord;
|
||||||
}
|
}
|
||||||
)#";
|
)#";
|
||||||
|
|
|
@ -138,7 +138,7 @@ void renderCursorTextureInternalWithDamage(SP<CTexture> tex, CBox* pBox, CRegion
|
||||||
glBindTexture(tex->m_iTarget, 0);
|
glBindTexture(tex->m_iTarget, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderCursorTextureInternalWithDamageInverted(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, Vector2D hotspot, bool nearest, int mode, bool chroma, CColor chromaColor) {
|
void renderCursorTextureInternalWithDamageInverted(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, Vector2D hotspot, bool nearest, int mode, bool chroma, CColor chromaColor, Vector2D screenOffset) {
|
||||||
TRACY_GPU_ZONE("RenderDynamicCursor");
|
TRACY_GPU_ZONE("RenderDynamicCursor");
|
||||||
|
|
||||||
alpha = std::clamp(alpha, 0.f, 1.f);
|
alpha = std::clamp(alpha, 0.f, 1.f);
|
||||||
|
@ -189,6 +189,8 @@ void renderCursorTextureInternalWithDamageInverted(SP<CTexture> tex, CBox* pBox,
|
||||||
wlr_matrix_transpose(glMatrix, glMatrix);
|
wlr_matrix_transpose(glMatrix, glMatrix);
|
||||||
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix);
|
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
glUniform2f(shader->screenOffset, screenOffset.x, screenOffset.y);
|
||||||
glUniform1i(shader->backgroundTex, 0);
|
glUniform1i(shader->backgroundTex, 0);
|
||||||
glUniform1i(shader->cursorTex, 1);
|
glUniform1i(shader->cursorTex, 1);
|
||||||
glUniform1f(shader->alpha, alpha);
|
glUniform1f(shader->alpha, alpha);
|
||||||
|
|
|
@ -2,5 +2,5 @@
|
||||||
#include <hyprland/src/helpers/math/Math.hpp>
|
#include <hyprland/src/helpers/math/Math.hpp>
|
||||||
|
|
||||||
void renderCursorTextureInternalWithDamage(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, Vector2D hotspot, bool nearest);
|
void renderCursorTextureInternalWithDamage(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, Vector2D hotspot, bool nearest);
|
||||||
void renderCursorTextureInternalWithDamageInverted(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, Vector2D hotspot, bool nearest, int mode, bool chroma, CColor chromaColor);
|
void renderCursorTextureInternalWithDamageInverted(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, Vector2D hotspot, bool nearest, int mode, bool chroma, CColor chromaColor, Vector2D screenOffset);
|
||||||
void projectCursorBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9], Vector2D hotspot);
|
void projectCursorBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9], Vector2D hotspot);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue