diff --git a/README.md b/README.md index 19cc01b..df70899 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,9 @@ https://github.com/VirtCode/hypr-dynamic-cursors/assets/41426325/9ff64a9b-64e5-4 ### 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. +**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 This plugin is still very early in its development. There are also multiple things which may or may not be implemented in the future: diff --git a/src/cursor.cpp b/src/cursor.cpp index 82d172b..6b6198e 100644 --- a/src/cursor.cpp +++ b/src/cursor.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #define private public #include @@ -22,7 +23,7 @@ #include "cursor.hpp" #include "renderer.hpp" -void renderCursorBox(SP texture, CBox box, CRegion& damage, Vector2D hotspot, float zoom) { +void renderCursorBox(SP 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* POPACITY = (Hyprlang::FLOAT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_OPACITY)->getDataStaticPtr(); @@ -39,7 +40,7 @@ void renderCursorBox(SP texture, CBox box, CRegion& damage, Vector2D h if (!strcmp(*PINVERT_MODE, "invert_hue")) mode = 1; 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 renderCursorTextureInternalWithDamage(texture, &box, &damage, alpha, hotspot, nearest); } @@ -83,7 +84,7 @@ void CDynamicCursors::renderSoftware(CPointerManager* pointers, SP pMo // we rotate the cursor by our calculated amount 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 state, SP texture) { 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; @@ -182,7 +184,19 @@ wlr_buffer* CDynamicCursors::renderHardware(CPointerManager* pointers, SPcurrentCursorImage.size / pointers->currentCursorImage.scale * state->monitor->scale * zoom}.round()}; 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(); glFlush(); @@ -268,16 +282,6 @@ void CDynamicCursors::beforeRender(CPointerManager* pointers) { 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; - } } } @@ -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* 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* PINVERT = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_INVERT)->getDataStaticPtr(); IMode* mode = currentMode(); @@ -304,7 +309,8 @@ void CDynamicCursors::calculate(EModeUpdate type) { if ( 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->angle = angle; diff --git a/src/cursor.hpp b/src/cursor.hpp index f876c1e..f18a2ab 100644 --- a/src/cursor.hpp +++ b/src/cursor.hpp @@ -35,8 +35,6 @@ 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; diff --git a/src/invert/shader.cpp b/src/invert/shader.cpp index 1f79781..3e7a540 100644 --- a/src/invert/shader.cpp +++ b/src/invert/shader.cpp @@ -17,6 +17,7 @@ void CInversionShader::compile(std::string vertex, std::string fragment) { posAttrib = glGetAttribLocation(program, "pos"); proj = glGetUniformLocation(program, "proj"); + screenOffset = glGetUniformLocation(program, "screenOffset"); backgroundTex = glGetUniformLocation(program, "backgroundTex"); cursorTex = glGetUniformLocation(program, "cursorTex"); alpha = glGetUniformLocation(program, "alpha"); diff --git a/src/invert/shader.hpp b/src/invert/shader.hpp index 793491b..01a16df 100644 --- a/src/invert/shader.hpp +++ b/src/invert/shader.hpp @@ -1,7 +1,7 @@ #include #include -// 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 { public: GLuint program = 0; @@ -10,6 +10,7 @@ class CInversionShader { GLint texAttrib = -1; GLint proj = -1; + GLint screenOffset = -1; GLint cursorTex = -1; GLint backgroundTex = -1; GLint alpha = -1; @@ -44,10 +45,12 @@ inline const std::string VERTEX = R"#( varying vec2 v_texcoord; varying vec2 v_screencord; + uniform vec2 screenOffset; + void main() { 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; } )#"; diff --git a/src/renderer.cpp b/src/renderer.cpp index e9e65a1..2d17dde 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -138,7 +138,7 @@ void renderCursorTextureInternalWithDamage(SP tex, CBox* pBox, CRegion glBindTexture(tex->m_iTarget, 0); } -void renderCursorTextureInternalWithDamageInverted(SP tex, CBox* pBox, CRegion* damage, float alpha, Vector2D hotspot, bool nearest, int mode, bool chroma, CColor chromaColor) { +void renderCursorTextureInternalWithDamageInverted(SP tex, CBox* pBox, CRegion* damage, float alpha, Vector2D hotspot, bool nearest, int mode, bool chroma, CColor chromaColor, Vector2D screenOffset) { TRACY_GPU_ZONE("RenderDynamicCursor"); alpha = std::clamp(alpha, 0.f, 1.f); @@ -189,6 +189,8 @@ void renderCursorTextureInternalWithDamageInverted(SP tex, CBox* pBox, wlr_matrix_transpose(glMatrix, glMatrix); glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix); #endif + + glUniform2f(shader->screenOffset, screenOffset.x, screenOffset.y); glUniform1i(shader->backgroundTex, 0); glUniform1i(shader->cursorTex, 1); glUniform1f(shader->alpha, alpha); diff --git a/src/renderer.hpp b/src/renderer.hpp index e512067..da1f87a 100644 --- a/src/renderer.hpp +++ b/src/renderer.hpp @@ -2,5 +2,5 @@ #include void renderCursorTextureInternalWithDamage(SP tex, CBox* pBox, CRegion* damage, float alpha, Vector2D hotspot, bool nearest); -void renderCursorTextureInternalWithDamageInverted(SP tex, CBox* pBox, CRegion* damage, float alpha, Vector2D hotspot, bool nearest, int mode, bool chroma, CColor chromaColor); +void renderCursorTextureInternalWithDamageInverted(SP 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);