feat: cursor shake to find

This commit is contained in:
Virt 2024-06-27 17:21:39 +02:00
commit cde5bf84fb
7 changed files with 134 additions and 50 deletions

View file

@ -3,19 +3,26 @@ This plugin makes your cursor more realistic by simulating how it would behave i
Why did I implement this again? Why did I implement this again?
## showcase Inspired by KDE, it also supports shake to find, to enlarge the cursor when it is shaken so it is easier to find it.
## behaviour modes
The plugin supports two different modes, `rotate` and `tilt`. They both are customizable and have a different base behaviour. The plugin supports two different modes, `rotate` and `tilt`. They both are customizable and have a different base behaviour.
#### rotate ### `rotate`
In this mode, the cursor is simulated as a stick which is dragged across the screen on one end. This means it will rotate towards the movement direction, and feels really realistic. In this mode, the cursor is simulated as a stick which is dragged across the screen on one end. This means it will rotate towards the movement direction, and feels really realistic.
https://github.com/VirtCode/hypr-dynamic-cursor/assets/41426325/ccd6d742-8e2b-4073-a35e-318c7e19705c https://github.com/VirtCode/hypr-dynamic-cursor/assets/41426325/ccd6d742-8e2b-4073-a35e-318c7e19705c
#### tilt ### `tilt`
In this mode, the cursor is tilted based on the X direction and speed it is moving at. It was intended to simulate how an object would be affected by air drag, but implemented is only a rough approximation. This mode can also be customized extensively with different activation functions. In this mode, the cursor is tilted based on the X direction and speed it is moving at. It was intended to simulate how an object would be affected by air drag, but implemented is only a rough approximation. This mode can also be customized extensively with different activation functions, and is enabled by default.
https://github.com/VirtCode/hypr-dynamic-cursors/assets/41426325/ae25415c-e77f-4c85-864c-2eedbfe432e3 https://github.com/VirtCode/hypr-dynamic-cursors/assets/41426325/ae25415c-e77f-4c85-864c-2eedbfe432e3
## shake to find
The plugin supports shake to find, akin to how KDE Plasma, MacOS, etc. do it. It is enabled by default.
INSERT VIDEO HERE
## state ## state
This plugin is still very early in its development. **Currently, only the `-git` version of hyprland is supported**. There are also multiple things which may or may not be implemented in the future: This plugin is still very early in its development. **Currently, only the `-git` version of hyprland is supported**. There are also multiple things which may or may not be implemented in the future:
@ -25,10 +32,12 @@ This plugin is still very early in its development. **Currently, only the `-git`
- [X] air drag simulation - [X] air drag simulation
- [ ] pendulum simulation - [ ] pendulum simulation
- [ ] per-shape length and starting angle (if possible) - [ ] per-shape length and starting angle (if possible)
- [X] cursor shake to find
- [ ] overdue refactoring (wait for aquamarine merge)
If anything here sounds interesting to you, don't hesitate to contribute. If anything here sounds interesting to you, don't hesitate to contribute.
Please note that this plugin was created more or less as a joke. I mainly wanted to see how using a rotating or tilted cursor was like. So I will not guarantee any future updates and bugfixes. Please note that this plugin was created more or less as a joke. I mainly wanted to see how using a rotating or tilted cursor was like. So I will not guarantee any future updates and bugfixes. The only useful features, shake to find, was implemented more or less as an afterthought.
## installation ## installation
Installation is supported via `hyprpm`. Supported hyprland versions are `v0.42.0` (yet unreleased) and upwards. The main branch generally tries to target `-git`. Installation is supported via `hyprpm`. Supported hyprland versions are `v0.42.0` (yet unreleased) and upwards. The main branch generally tries to target `-git`.
@ -51,6 +60,7 @@ plugin:dynamic-cursors {
# sets the cursor behaviour, supports these values: # sets the cursor behaviour, supports these values:
# tilt - tilt the cursor based on x-velocity # tilt - tilt the cursor based on x-velocity
# rotate - rotate the cursor based on movement direction # rotate - rotate the cursor based on movement direction
# none - do not change the cursors behaviour
mode = tilt mode = tilt
# minimum angle difference in degrees after which the shape is changed # minimum angle difference in degrees after which the shape is changed
@ -78,6 +88,28 @@ plugin:dynamic-cursors {
# negative_quadratic - negative version of the quadratic one, feels more aggressive # negative_quadratic - negative version of the quadratic one, feels more aggressive
function = negative_quadratic function = negative_quadratic
} }
# enable shake to find
# magnifies the cursor if its is being shaken
shake = true
# for when shake = true
shake {
# controls how soon a shake is detected
# lower values mean sooner
threshold = 4.0
# controls how fast the cursor gets larger
factor = 1.5
# show cursor behaviour `tilt`, `rotate`, etc. while shaking
effects = false
# use nearest-neighbour (pixelated) scaling when shaking
# may look weird when effects are enabled
nearest = true
}
} }
``` ```

View file

@ -4,6 +4,7 @@
#include <cmath> #include <cmath>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <hyprlang.hpp>
#define private public #define private public
#include <hyprland/src/managers/PointerManager.hpp> #include <hyprland/src/managers/PointerManager.hpp>
@ -26,6 +27,7 @@ Reimplements rendering of the software cursor.
Is also largely identical to hyprlands impl, but uses our custom rendering to rotate the 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) { void CDynamicCursors::renderSoftware(CPointerManager* pointers, SP<CMonitor> pMonitor, timespec* now, CRegion& damage, std::optional<Vector2D> overridePos) {
static auto* const* PNEAREST = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_NEAREST)->getDataStaticPtr();
if (!pointers->hasCursor()) if (!pointers->hasCursor())
return; return;
@ -50,12 +52,14 @@ void CDynamicCursors::renderSoftware(CPointerManager* pointers, SP<CMonitor> pMo
return; return;
box.scale(pMonitor->scale); box.scale(pMonitor->scale);
box.w *= zoom;
box.h *= zoom;
// we rotate the cursor by our calculated amount // we rotate the cursor by our calculated amount
box.rot = this->angle; box.rot = this->angle;
// now pass the hotspot to rotate around // now pass the hotspot to rotate around
renderCursorTextureInternalWithDamage(texture, &box, &damage, 1.F, pointers->currentCursorImage.hotspot); renderCursorTextureInternalWithDamage(texture, &box, &damage, 1.F, pointers->currentCursorImage.hotspot * zoom, zoom > 1 && **PNEAREST);
} }
/* /*
@ -65,8 +69,8 @@ It is largely identical to hyprlands implementation, but expands the damage reag
void CDynamicCursors::damageSoftware(CPointerManager* pointers) { void CDynamicCursors::damageSoftware(CPointerManager* pointers) {
// we damage a 3x3 area around the cursor, to accomodate for all possible hotspots and rotations // we damage a 3x3 area around the cursor, to accomodate for all possible hotspots and rotations
Vector2D size = pointers->currentCursorImage.size / pointers->currentCursorImage.scale; Vector2D size = pointers->currentCursorImage.size / pointers->currentCursorImage.scale * zoom;
CBox b = CBox{pointers->pointerPos, size * 3}.translate(-(pointers->currentCursorImage.hotspot + size)); CBox b = CBox{pointers->pointerPos, size * 3}.translate(-(pointers->currentCursorImage.hotspot * zoom + size));
static auto PNOHW = CConfigValue<Hyprlang::INT>("cursor:no_hardware_cursors"); static auto PNOHW = CConfigValue<Hyprlang::INT>("cursor:no_hardware_cursors");
@ -87,10 +91,11 @@ 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* PNEAREST = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_NEAREST)->getDataStaticPtr();
auto output = state->monitor->output; auto output = state->monitor->output;
auto size = pointers->currentCursorImage.size; auto size = pointers->currentCursorImage.size * zoom;
// we try to allocate a buffer that is thrice as big, see software rendering // we try to allocate a buffer that is thrice as big, see software rendering
auto target = size * 3; auto target = size * 3;
@ -151,11 +156,11 @@ wlr_buffer* CDynamicCursors::renderHardware(CPointerManager* pointers, SP<CPoint
g_pHyprOpenGL->clear(CColor{0.F, 0.F, 0.F, 0.F}); g_pHyprOpenGL->clear(CColor{0.F, 0.F, 0.F, 0.F});
// the box should start in the middle portion, rotate by our calculated amount // the box should start in the middle portion, rotate by our calculated amount
CBox xbox = {size, Vector2D{pointers->currentCursorImage.size / pointers->currentCursorImage.scale * state->monitor->scale}.round()}; CBox xbox = {size, Vector2D{pointers->currentCursorImage.size / pointers->currentCursorImage.scale * state->monitor->scale * zoom}.round()};
xbox.rot = this->angle; xbox.rot = this->angle;
// use our custom draw function // use our custom draw function
renderCursorTextureInternalWithDamage(texture, &xbox, &damage, 1.F, pointers->currentCursorImage.hotspot); renderCursorTextureInternalWithDamage(texture, &xbox, &damage, 1.F, pointers->currentCursorImage.hotspot * zoom, zoom > 1 && **PNEAREST);
g_pHyprOpenGL->end(); g_pHyprOpenGL->end();
glFlush(); glFlush();
@ -178,7 +183,7 @@ bool CDynamicCursors::setHardware(CPointerManager* pointers, SP<CPointerManager:
if (!P_MONITOR->output->cursor_swapchain) return false; if (!P_MONITOR->output->cursor_swapchain) return false;
// we need to transform the hotspot manually as we need to indent it by the size // we need to transform the hotspot manually as we need to indent it by the size
const auto HOTSPOT = CBox{(pointers->currentCursorImage.hotspot + pointers->currentCursorImage.size) * P_MONITOR->scale, {0, 0}} const auto HOTSPOT = CBox{(pointers->currentCursorImage.hotspot + pointers->currentCursorImage.size) * P_MONITOR->scale * zoom, {0, 0}}
.transform(wlTransformToHyprutils(wlr_output_transform_invert(P_MONITOR->transform)), P_MONITOR->output->cursor_swapchain->width, P_MONITOR->output->cursor_swapchain->height) .transform(wlTransformToHyprutils(wlr_output_transform_invert(P_MONITOR->transform)), P_MONITOR->output->cursor_swapchain->width, P_MONITOR->output->cursor_swapchain->height)
.pos(); .pos();
@ -226,25 +231,36 @@ Handle cursor tick events.
*/ */
void CDynamicCursors::onTick(CPointerManager* pointers) { void CDynamicCursors::onTick(CPointerManager* pointers) {
static auto const* PMODE = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_MODE)->getDataStaticPtr(); static auto const* PMODE = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_MODE)->getDataStaticPtr();
static auto* const* PSHAKE = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE)->getDataStaticPtr();
if (!strcmp(*PMODE, "tilt")) calculate(); if (!strcmp(*PMODE, "tilt") || **PSHAKE) calculate();
} }
void CDynamicCursors::calculate() { void CDynamicCursors::calculate() {
static auto const* PMODE = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_MODE)->getDataStaticPtr(); static auto const* PMODE = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_MODE)->getDataStaticPtr();
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_EFFECTS = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_EFFECTS)->getDataStaticPtr();
double zoom = 1;
if (**PSHAKE)
zoom = calculateShake();
double angle = 0; double angle = 0;
if (!strcmp(*PMODE, "rotate")) if (!strcmp(*PMODE, "rotate"))
angle = calculateStick(); angle = calculateStick();
else if (!strcmp(*PMODE, "tilt")) else if (!strcmp(*PMODE, "tilt"))
angle = calculateAir(); angle = calculateAir();
else else if (strcmp(*PMODE, "none")) // if not none, print warning
Debug::log(WARN, "[dynamic-cursors] unknown mode specified"); Debug::log(WARN, "[dynamic-cursors] unknown mode specified");
if (zoom > 1 && !**PSHAKE_EFFECTS)
angle = 0;
// we only consider the angle changed if it is larger than 1 degree // we only consider the angle changed if it is larger than 1 degree
if (abs(this->angle - angle) > ((PI / 180) * **PTHRESHOLD)) { if (abs(this->angle - angle) > ((PI / 180) * **PTHRESHOLD) || abs(this->zoom - zoom) > 0.1) {
this->angle = angle; this->angle = angle;
this->zoom = zoom;
// damage software and change hardware cursor shape // damage software and change hardware cursor shape
g_pPointerManager->damageIfSoftware(); g_pPointerManager->damageIfSoftware();
@ -301,32 +317,52 @@ double CDynamicCursors::calculateAir() {
samples_index = (samples_index + 1) % max; // increase for next sample samples_index = (samples_index + 1) % max; // increase for next sample
int first = samples_index; int first = samples_index;
/* turns out this is not relevant on my systems (should've checked before implementing lol):
// motion smooting
// fills samples in between with linear approximations
// accomodates for mice with low polling rates and monitors with high fps
int previous = current == 0 ? max - 1 : current - 1;
if (samples[previous] != samples[current]) {
int steps = std::abs(samples_last_change - previous);
Vector2D amount = (samples[current] - samples[previous]) / steps;
int factor = 1;
for (int i = (samples_last_change + 1) % max; i != current; i = (i + 1) % max) {
samples[i] += amount * factor++;
}
samples_last_change = current;
} else if (samples_last_change == current) {
samples_last_change = first; // next is the last then
}
*/
// calculate speed and tilt // calculate speed and tilt
double speed = (samples[current].x - samples[first].x) / 0.1; double speed = (samples[current].x - samples[first].x) / 0.1;
return airFunction(speed) * (PI / 3); // 120° in both directions return airFunction(speed) * (PI / 3); // 120° in both directions
} }
double CDynamicCursors::calculateShake() {
static auto* const* PTHRESHOLD = (Hyprlang::FLOAT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_THRESHOLD)->getDataStaticPtr();
static auto* const* PFACTOR = (Hyprlang::FLOAT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_FACTOR)->getDataStaticPtr();
int max = g_pHyprRenderer->m_pMostHzMonitor->refreshRate; // 1s worth of history
shake_samples.resize(max);
shake_samples_distance.resize(max);
int previous = shake_samples_index == 0 ? max - 1 : shake_samples_index - 1;
shake_samples[shake_samples_index] = Vector2D{g_pPointerManager->pointerPos};
shake_samples_distance[shake_samples_index] = shake_samples[shake_samples_index].distance(shake_samples[previous]);
shake_samples_index = (shake_samples_index + 1) % max; // increase for next sample
/*
The idea for this algorith was largely inspired by KDE Plasma
https://invent.kde.org/plasma/kwin/-/blob/master/src/plugins/shakecursor/shakedetector.cpp
*/
// calculate total distance travelled
double trail = 0;
for (double distance : shake_samples_distance) trail += distance;
// calculate diagonal of bounding box travelled within
double left = 1e100, right = 0, bottom = 0, top = 1e100;
for (Vector2D position : shake_samples) {
left = std::min(left, position.x);
right = std::max(right, position.x);
top = std::min(top, position.y);
bottom = std::max(bottom, position.y);
}
double diagonal = Vector2D{left, top}.distance(Vector2D(right, bottom));
// discard when the diagonal is small, so we don't have issues with inaccuracies
if (diagonal < 100) return 1.0;
std::cout << trail << " " << diagonal << " " << (trail / diagonal) << "\n";
return std::max(1.0, ((trail / diagonal) - **PTHRESHOLD) * **PFACTOR);
}
double CDynamicCursors::calculateStick() { double CDynamicCursors::calculateStick() {
static auto* const* PLENGTH = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_LENGTH)->getDataStaticPtr(); static auto* const* PLENGTH = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_LENGTH)->getDataStaticPtr();

View file

@ -25,6 +25,8 @@ class CDynamicCursors {
private: private:
// current angle of the cursor in radiants // current angle of the cursor in radiants
double angle; double angle;
// current zoom value of the cursor
double zoom = 1;
// calculates the current angle of the cursor, and changes the cursor shape // calculates the current angle of the cursor, and changes the cursor shape
void calculate(); void calculate();
@ -39,6 +41,11 @@ class CDynamicCursors {
// ring buffer of last position samples // ring buffer of last position samples
std::vector<Vector2D> samples; std::vector<Vector2D> samples;
int samples_index = 0; int samples_index = 0;
double calculateShake();
std::vector<Vector2D> shake_samples;
std::vector<double> shake_samples_distance;
int shake_samples_index = 0;
}; };
inline std::unique_ptr<CDynamicCursors> g_pDynamicCursors; inline std::unique_ptr<CDynamicCursors> g_pDynamicCursors;

View file

@ -4,7 +4,12 @@
#define CONFIG_ENABLED "plugin:dynamic-cursors:enabled" #define CONFIG_ENABLED "plugin:dynamic-cursors:enabled"
#define CONFIG_MODE "plugin:dynamic-cursors:mode" #define CONFIG_MODE "plugin:dynamic-cursors:mode"
#define CONFIG_SHAKE "plugin:dynamic-cursors:shake"
#define CONFIG_THRESHOLD "plugin:dynamic-cursors:threshold" #define CONFIG_THRESHOLD "plugin:dynamic-cursors:threshold"
#define CONFIG_SHAKE_NEAREST "plugin:dynamic-cursors:shake:nearest"
#define CONFIG_SHAKE_THRESHOLD "plugin:dynamic-cursors:shake:threshold"
#define CONFIG_SHAKE_FACTOR "plugin:dynamic-cursors:shake:factor"
#define CONFIG_SHAKE_EFFECTS "plugin:dynamic-cursors:shake:effects"
#define CONFIG_LENGTH "plugin:dynamic-cursors:rotate:length" #define CONFIG_LENGTH "plugin:dynamic-cursors:rotate:length"
#define CONFIG_MASS "plugin:dynamic-cursors:tilt:limit" #define CONFIG_MASS "plugin:dynamic-cursors:tilt:limit"
#define CONFIG_FUNCTION "plugin:dynamic-cursors:tilt:function" #define CONFIG_FUNCTION "plugin:dynamic-cursors:tilt:function"

View file

@ -55,12 +55,10 @@ void hkOnCursorMoved(void* thisptr) {
else return (*(origOnCursorMoved)g_pOnCursorMovedHook->m_pOriginal)(thisptr); else return (*(origOnCursorMoved)g_pOnCursorMovedHook->m_pOriginal)(thisptr);
} }
void onTick() {
g_pDynamicCursors->onTick(g_pPointerManager.get());
}
int onTick(void* data) { int onTick(void* data) {
g_pDynamicCursors->onTick(g_pPointerManager.get()); static auto* const* PENABLED = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_ENABLED)->getDataStaticPtr();
if (**PENABLED) g_pDynamicCursors->onTick(g_pPointerManager.get());
const int TIMEOUT = g_pHyprRenderer->m_pMostHzMonitor ? 1000.0 / g_pHyprRenderer->m_pMostHzMonitor->refreshRate : 16; const int TIMEOUT = g_pHyprRenderer->m_pMostHzMonitor ? 1000.0 / g_pHyprRenderer->m_pMostHzMonitor->refreshRate : 16;
wl_event_source_timer_update(tick, TIMEOUT); wl_event_source_timer_update(tick, TIMEOUT);
@ -111,6 +109,12 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_MODE, Hyprlang::STRING{"tilt"}); HyprlandAPI::addConfigValue(PHANDLE, CONFIG_MODE, Hyprlang::STRING{"tilt"});
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_THRESHOLD, Hyprlang::INT{2}); HyprlandAPI::addConfigValue(PHANDLE, CONFIG_THRESHOLD, Hyprlang::INT{2});
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_SHAKE, Hyprlang::INT{1});
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_SHAKE_NEAREST, Hyprlang::INT{1});
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_SHAKE_EFFECTS, Hyprlang::INT{0});
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_SHAKE_THRESHOLD, Hyprlang::FLOAT{4});
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_SHAKE_FACTOR, Hyprlang::FLOAT{1.5});
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_FUNCTION, Hyprlang::STRING{"negative_quadratic"}); HyprlandAPI::addConfigValue(PHANDLE, CONFIG_FUNCTION, Hyprlang::STRING{"negative_quadratic"});
HyprlandAPI::addConfigValue(PHANDLE, CONFIG_MASS, Hyprlang::INT{5000}); HyprlandAPI::addConfigValue(PHANDLE, CONFIG_MASS, Hyprlang::INT{5000});

View file

@ -44,7 +44,7 @@ void projectCursorBox(float mat[9], CBox& box, eTransform transform, float rotat
/* /*
This renders a texture with damage but rotates the texture around a given hotspot. This renders a texture with damage but rotates the texture around a given hotspot.
*/ */
void renderCursorTextureInternalWithDamage(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, Vector2D hotspot) { void renderCursorTextureInternalWithDamage(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, Vector2D hotspot, bool nearest) {
TRACY_GPU_ZONE("RenderDynamicCursor"); TRACY_GPU_ZONE("RenderDynamicCursor");
alpha = std::clamp(alpha, 0.f, 1.f); alpha = std::clamp(alpha, 0.f, 1.f);
@ -75,7 +75,7 @@ void renderCursorTextureInternalWithDamage(SP<CTexture> tex, CBox* pBox, CRegion
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(tex->m_iTarget, tex->m_iTexID); glBindTexture(tex->m_iTarget, tex->m_iTexID);
if (g_pHyprOpenGL->m_RenderData.useNearestNeighbor) { if (g_pHyprOpenGL->m_RenderData.useNearestNeighbor || nearest) {
glTexParameteri(tex->m_iTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(tex->m_iTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(tex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(tex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
} else { } else {

View file

@ -1,5 +1,5 @@
#include <hyprland/src/render/OpenGL.hpp> #include <hyprland/src/render/OpenGL.hpp>
#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); void renderCursorTextureInternalWithDamage(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, Vector2D hotspot, bool nearest);
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);