mirror of
https://github.com/virtcode/hypr-dynamic-cursors
synced 2025-09-19 08:03:21 +02:00
feat: inverted config, setup and docs
This commit is contained in:
parent
69e2583e57
commit
ec4db58ade
5 changed files with 108 additions and 55 deletions
32
README.md
32
README.md
|
@ -28,6 +28,13 @@ The plugin supports shake to find, akin to how KDE Plasma, MacOS, etc. do it. It
|
|||
|
||||
https://github.com/VirtCode/hypr-dynamic-cursors/assets/41426325/9ff64a9b-64e5-4595-b721-dcb4d62bee18
|
||||
|
||||
### 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.
|
||||
|
||||
**Note:** Inverted cursors have about the same performance impact as a *basic* screen shader. They are also only supported as software cursors.
|
||||
|
||||
INSERT VIDEO HERE
|
||||
|
||||
## 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:
|
||||
|
||||
|
@ -39,7 +46,7 @@ This plugin is still very early in its development. There are also multiple thin
|
|||
- [X] per-shape length and starting angle (if possible)
|
||||
- [X] cursor shake to find
|
||||
- [X] overdue refactoring (wait for aquamarine merge)
|
||||
- [ ] ~~inverted cursor?~~ (i think out of scope here, but see the [inverted branch](https://github.com/VirtCode/hypr-dynamic-cursors/tree/inverted))
|
||||
- [X] inverted cursor!
|
||||
- [ ] hyprcursor magified shape
|
||||
|
||||
If anything here sounds interesting to you, don't hesitate to contribute.
|
||||
|
@ -183,6 +190,29 @@ plugin:dynamic-cursors {
|
|||
# see #3
|
||||
ipc = false
|
||||
}
|
||||
|
||||
# enables inverted cursor
|
||||
# this replaces your cursor shape with the inverted colors of the background
|
||||
# by default, this replaces the non transparent parts of your cursor
|
||||
# WARNING: inverted cursors are experimental and have a high performance impact
|
||||
invert = true
|
||||
|
||||
# for when invert = true
|
||||
invert {
|
||||
|
||||
# shader function that is used on the background color, supports:
|
||||
# invert - take the negative of the color
|
||||
# invert_hue - take the negative of the color and shift hue by 180°
|
||||
# hue - only shift hue by 180°
|
||||
shader = invert
|
||||
|
||||
# apply a chroma key algorithm to the cursor
|
||||
# this allows for only replacing certain parts of the cursor texture
|
||||
chroma = false
|
||||
|
||||
# color to replace when chroma = true
|
||||
chroma:color = rgba(000000ff)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -49,17 +49,33 @@ CDynamicCursors::~CDynamicCursors() {
|
|||
}
|
||||
}
|
||||
|
||||
void renderCursorBox(SP<CTexture> texture, CBox box, CRegion& damage, Vector2D hotspot, float zoom) {
|
||||
static auto* const* PNEAREST = (Hyprlang::INT* const*) getConfig(CONFIG_SHAKE_NEAREST);
|
||||
|
||||
static auto* const* PINVERT = (Hyprlang::INT* const*) getConfig(CONFIG_INVERT);
|
||||
static auto const* PINVERT_MODE = (Hyprlang::INT* const*) getConfig(CONFIG_INVERT_SHADER);
|
||||
static auto* const* PINVERT_CHROMA = (Hyprlang::STRING const*) getConfig(CONFIG_INVERT_CHROMA);
|
||||
static auto* const* PINVERT_CHROMA_COLOR = (Hyprlang::INT* const*) getConfig(CONFIG_INVERT_CHROMA_COLOR);
|
||||
|
||||
bool nearest = zoom > 1 && **PNEAREST;
|
||||
|
||||
if (**PINVERT) {
|
||||
int mode = 0;
|
||||
if (!strcmp(*PINVERT_MODE, "invert_hue")) mode = 1;
|
||||
else if (!strcmp(*PINVERT_MODE, "hue")) mode = 2;
|
||||
|
||||
renderCursorTextureInternalWithDamageInverted(texture, &box, &damage, 1.f, hotspot, nearest, mode, **PINVERT_CHROMA, CColor(**PINVERT_CHROMA_COLOR));
|
||||
} else
|
||||
renderCursorTextureInternalWithDamage(texture, &box, &damage, 1.f, hotspot, nearest);
|
||||
}
|
||||
|
||||
/*
|
||||
Reimplements rendering of the software cursor.
|
||||
Is also largely identical to hyprlands impl, but uses our custom rendering to rotate the cursor.
|
||||
*/
|
||||
void CDynamicCursors::renderSoftware(CPointerManager* pointers, SP<CMonitor> pMonitor, timespec* now, CRegion& damage, std::optional<Vector2D> overridePos) {
|
||||
<<<<<<< HEAD
|
||||
static auto* const* PNEAREST = (Hyprlang::INT* const*) getConfig(CONFIG_SHAKE_NEAREST);
|
||||
=======
|
||||
static auto* const* PNEAREST = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_NEAREST)->getDataStaticPtr();
|
||||
static auto* const* PINVERT = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_INVERT)->getDataStaticPtr();
|
||||
>>>>>>> c8ae8fe (feat: basic inverted rendering)
|
||||
static auto* const* PINVERT = (Hyprlang::INT* const*) getConfig(CONFIG_INVERT);
|
||||
|
||||
if (!pointers->hasCursor())
|
||||
return;
|
||||
|
@ -99,17 +115,10 @@ void CDynamicCursors::renderSoftware(CPointerManager* pointers, SP<CMonitor> pMo
|
|||
box.rot = resultShown.rotation;
|
||||
|
||||
// now pass the hotspot to rotate around
|
||||
<<<<<<< HEAD
|
||||
renderCursorTextureInternalWithDamage(texture, &box, &damage, 1.F, nullptr, 0, pointers->currentCursorImage.hotspot * state->monitor->scale * zoom, zoom > 1 && **PNEAREST, resultShown.stretch.angle, resultShown.stretch.magnitude);
|
||||
renderCursorBox(texture, box, damage, pointers->currentCursorImage.hotspot * state->monitor->scale * zoom, zoom);
|
||||
|
||||
if (pointers->currentCursorImage.surface)
|
||||
pointers->currentCursorImage.surface->resource()->frame(now);
|
||||
=======
|
||||
if (**PINVERT)
|
||||
renderCursorTextureInternalWithDamageInverted(texture, &box, &damage, 1.F, pointers->currentCursorImage.hotspot * state->monitor->scale * zoom, zoom > 1 && **PNEAREST);
|
||||
else
|
||||
renderCursorTextureInternalWithDamage(texture, &box, &damage, 1.F, pointers->currentCursorImage.hotspot * state->monitor->scale * zoom, zoom > 1 && **PNEAREST);
|
||||
>>>>>>> c8ae8fe (feat: basic inverted rendering)
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -143,16 +152,9 @@ void CDynamicCursors::damageSoftware(CPointerManager* pointers) {
|
|||
This function reimplements the hardware cursor buffer drawing.
|
||||
It is largely copied from hyprland, but adjusted to allow the cursor to be rotated.
|
||||
*/
|
||||
<<<<<<< HEAD
|
||||
SP<Aquamarine::IBuffer> CDynamicCursors::renderHardware(CPointerManager* pointers, SP<CPointerManager::SMonitorPointerState> state, SP<CTexture> texture) {
|
||||
static auto* const* PHW_DEBUG = (Hyprlang::INT* const*) getConfig(CONFIG_HW_DEBUG);
|
||||
static auto* const* PNEAREST = (Hyprlang::INT* const*) getConfig(CONFIG_SHAKE_NEAREST);
|
||||
=======
|
||||
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* PNEAREST = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_NEAREST)->getDataStaticPtr();
|
||||
static auto* const* PINVERT = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_INVERT)->getDataStaticPtr();
|
||||
>>>>>>> c8ae8fe (feat: basic inverted rendering)
|
||||
|
||||
auto output = state->monitor->output;
|
||||
|
||||
|
@ -262,14 +264,7 @@ wlr_buffer* CDynamicCursors::renderHardware(CPointerManager* pointers, SP<CPoint
|
|||
xbox.rot = resultShown.rotation;
|
||||
|
||||
// use our custom draw function
|
||||
<<<<<<< HEAD
|
||||
renderCursorTextureInternalWithDamage(texture, &xbox, &damage, 1.F, pointers->currentCursorImage.waitTimeline, pointers->currentCursorImage.waitPoint, pointers->currentCursorImage.hotspot * state->monitor->scale * zoom, zoom > 1 && **PNEAREST, resultShown.stretch.angle, resultShown.stretch.magnitude);
|
||||
=======
|
||||
if (**PINVERT)
|
||||
renderCursorTextureInternalWithDamageInverted(texture, &xbox, &damage, 1.F, pointers->currentCursorImage.hotspot * state->monitor->scale * zoom, zoom > 1 && **PNEAREST);
|
||||
else
|
||||
renderCursorTextureInternalWithDamage(texture, &xbox, &damage, 1.F, pointers->currentCursorImage.hotspot * state->monitor->scale * zoom, zoom > 1 && **PNEAREST);
|
||||
>>>>>>> c8ae8fe (feat: basic inverted rendering)
|
||||
renderCursorBox(texture, xbox, damage, pointers->currentCursorImage.hotspot * state->monitor->scale * zoom, zoom);
|
||||
|
||||
g_pHyprOpenGL->end();
|
||||
glFlush();
|
||||
|
@ -359,6 +354,25 @@ IMode* CDynamicCursors::currentMode() {
|
|||
else return nullptr;
|
||||
}
|
||||
|
||||
void CDynamicCursors::beforeRender(CPointerManager* pointers) {
|
||||
static auto* const* PINVERT = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_INVERT)->getDataStaticPtr();
|
||||
|
||||
if (**PINVERT) {
|
||||
// we need introspection as we make use of the offloadFB
|
||||
g_pHyprOpenGL->m_RenderData.forceIntrospection = true;
|
||||
|
||||
if (!invertSoftware) {
|
||||
pointers->lockSoftwareAll();
|
||||
invertSoftware = true;
|
||||
}
|
||||
} else {
|
||||
if (invertSoftware) {
|
||||
pointers->unlockSoftwareAll();
|
||||
invertSoftware = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CDynamicCursors::calculate(EModeUpdate type) {
|
||||
static auto* const* PTHRESHOLD = (Hyprlang::INT* const*) getConfig(CONFIG_THRESHOLD);
|
||||
static auto* const* PSHAKE = (Hyprlang::INT* const*) getConfig(CONFIG_SHAKE);
|
||||
|
|
|
@ -20,6 +20,8 @@ class CDynamicCursors {
|
|||
void onCursorMoved(CPointerManager* pointers);
|
||||
/* called on tick */
|
||||
void onTick(CPointerManager* pointers);
|
||||
/* called before render */
|
||||
void beforeRender(CPointerManager* pointers);
|
||||
|
||||
/* hook on renderSoftwareCursorsFor */
|
||||
void renderSoftware(CPointerManager* pointers, SP<CMonitor> pMonitor, timespec* now, CRegion& damage, std::optional<Vector2D> overridePos);
|
||||
|
@ -46,6 +48,8 @@ class CDynamicCursors {
|
|||
|
||||
// whether we have already locked software for cursor zoom
|
||||
bool zoomSoftware = false;
|
||||
// whether we have already locked software for inverted cursors
|
||||
bool invertSoftware = false;
|
||||
|
||||
// modes
|
||||
CModeRotate rotate;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "src/debug/Log.hpp"
|
||||
#include "src/render/Renderer.hpp"
|
||||
|
||||
#define private public
|
||||
#include <hyprland/src/render/OpenGL.hpp>
|
||||
|
@ -20,6 +21,10 @@ void CInversionShader::compile(std::string vertex, std::string fragment) {
|
|||
backgroundTex = glGetUniformLocation(program, "backgroundTex");
|
||||
cursorTex = glGetUniformLocation(program, "cursorTex");
|
||||
alpha = glGetUniformLocation(program, "alpha");
|
||||
chroma = glGetUniformLocation(program, "chroma");
|
||||
chromaColor = glGetUniformLocation(program, "chromaColor");
|
||||
mode = glGetUniformLocation(program, "mode");
|
||||
|
||||
applyTint = glGetUniformLocation(program, "applyTint");
|
||||
tint = glGetUniformLocation(program, "tint");
|
||||
}
|
||||
|
@ -30,13 +35,11 @@ CInversionShader::~CInversionShader() {
|
|||
}
|
||||
|
||||
CShaders::CShaders() {
|
||||
RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL)),
|
||||
"Couldn't set current EGL!");
|
||||
g_pHyprRenderer->makeEGLCurrent();
|
||||
|
||||
rgba.compile(VERTEX, RGBA);
|
||||
ext.compile(VERTEX, EXT);
|
||||
rgbx.compile(VERTEX, RGBX);
|
||||
|
||||
RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL)),
|
||||
"Couldn't set current EGL!");
|
||||
g_pHyprRenderer->unsetEGL();
|
||||
}
|
||||
|
|
|
@ -5,18 +5,17 @@
|
|||
class CInversionShader {
|
||||
public:
|
||||
GLuint program = 0;
|
||||
|
||||
GLint posAttrib = -1;
|
||||
GLint texAttrib = -1;
|
||||
|
||||
GLint proj = -1;
|
||||
GLint color = -1;
|
||||
GLint alphaMatte = -1;
|
||||
GLint cursorTex = -1;
|
||||
GLint backgroundTex = -1;
|
||||
GLint alpha = -1;
|
||||
GLint posAttrib = -1;
|
||||
GLint texAttrib = -1;
|
||||
GLint matteTexAttrib = -1;
|
||||
GLint discardOpaque = -1;
|
||||
GLint discardAlpha = -1;
|
||||
GLfloat discardAlphaValue = -1;
|
||||
GLint mode = -1;
|
||||
GLint chroma = -1;
|
||||
GLint chromaColor = -1;
|
||||
|
||||
GLint applyTint = -1;
|
||||
GLint tint = -1;
|
||||
|
@ -66,25 +65,28 @@ inline const std::string RGBA = R"#(
|
|||
uniform int applyTint;
|
||||
uniform vec3 tint;
|
||||
|
||||
uniform int mode;
|
||||
uniform int chroma;
|
||||
uniform vec4 chromaColor;
|
||||
|
||||
void main() {
|
||||
|
||||
vec4 cursor = texture2D(cursorTex, v_texcoord);
|
||||
|
||||
// load and invert background
|
||||
vec4 background = texture2D(backgroundTex, v_screencord);
|
||||
background.rgb = vec3(1.0, 1.0, 1.0) - background.rgb;
|
||||
|
||||
// invert based on mode
|
||||
if (mode == 0 || mode == 1) // invert
|
||||
background.rgb = vec3(1.0, 1.0, 1.0) - background.rgb;
|
||||
if (mode == 1 || mode == 2) // hueshift
|
||||
background.rgb = -background.rgb + dot(vec3(0.26312, 0.5283, 0.10488), background.rgb) * 2.0;
|
||||
|
||||
background *= cursor[3]; // premultiplied alpha
|
||||
vec4 pixColor = background;
|
||||
|
||||
// invert hue
|
||||
//background.rgb = -background.rgb + dot(vec3(0.26312, 0.5283, 0.10488), background.rgb) * 2.0;
|
||||
|
||||
vec4 pixColor = cursor;
|
||||
//if (cursor[3] != 1.0) pixColor = cursor;
|
||||
//pixColor = vec4(v_screencord + vec2(1.0, 1.0) / 2.0, 0.0, 1.0);
|
||||
|
||||
vec4 chroma = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
float diff = (abs(chroma.x - cursor.x) + abs(chroma.y - cursor.y) + abs(chroma.z - cursor.z) + abs(chroma.w - cursor.w)) / 4.0;
|
||||
pixColor = background * (1.0 - diff) + cursor * diff;
|
||||
// this is a very crude "chroma algorithm", feel free to contribute a better one
|
||||
if (chroma == 1) {
|
||||
float diff = (abs(chromaColor.x - cursor.x) + abs(chromaColor.y - cursor.y) + abs(chromaColor.z - cursor.z) + abs(chromaColor.w - cursor.w)) / 4.0;
|
||||
pixColor = background * (1.0 - diff) + cursor * diff;
|
||||
}
|
||||
|
||||
if (applyTint == 1) {
|
||||
pixColor[0] = pixColor[0] * tint[0];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue