render: Scale relative mouse motion better for logical sizing

From hmk:

"When scaling is enabled (e.g. via SDL_RenderSetLogicalSize, size not equal
to window size), mouse motion events are also scaled.  Small motions are
rounded up (SDL_max() when the value after scaling is less than 1), while
larger motions are truncated by the floating point -> integer conversion.

https://hg.libsdl.org/SDL/file/b18197f9bf9d/src/render/SDL_render.c#l658

The end result feels something like mouse reverse mouse acceleration + angle
snapping at low speeds, but less consistent (amount of truncation & rounding
depends on how fast the mouse is moved) and potentially much worse if the
scaling factor is large.  This pretty much makes it useless for anything
where you need precise mouse aiming (think of games).  I suspect this is why
aiming gets so terrible in some games that let you use scaling to reduce the
render resolution (e.g. Ion Fury).

With 4x4 scaling, I can reproduce a situation where it takes three fast flicks
of the mouse across the pad to undo one slow sweep across the pad.  In other
words, extreme reverse acceleration.  This does not happen when scaling is
disabled.

Furthermore, any game that uses relative mouse motion events for 3D camera
rotation probably wants the raw mouse deltas and not a value that depends on
scaling and resolution and rounding and truncation.  Ideal camera rotation
just takes mouse input, multiplies it by sensitivity, and adds it to the
angle-in-radians or whatever measure is used for yaw & pitch.  Pixels and
screen resolution or window dimensions should not be a part of the equation
at all, even if it could be implemented without rounding errors.

[...]

This [patch] completely eliminates angle snapping for me, and makes
sensitivity consistent.  In other words, it's completely usable for, say,
aiming in a first person shooter."

Partially fixes Bugzilla #4811.
This commit is contained in:
hmk 2020-04-10 12:23:08 -04:00
parent d292f6bd4f
commit aa188048f1
2 changed files with 14 additions and 8 deletions

View file

@ -660,15 +660,17 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event)
event->motion.y -= (int)(viewport.y * renderer->dpi_scale.y); event->motion.y -= (int)(viewport.y * renderer->dpi_scale.y);
event->motion.x = (int)(event->motion.x / (scale.x * renderer->dpi_scale.x)); event->motion.x = (int)(event->motion.x / (scale.x * renderer->dpi_scale.x));
event->motion.y = (int)(event->motion.y / (scale.y * renderer->dpi_scale.y)); event->motion.y = (int)(event->motion.y / (scale.y * renderer->dpi_scale.y));
if (event->motion.xrel > 0) { if (event->motion.xrel != 0) {
event->motion.xrel = SDL_max(1, (int)(event->motion.xrel / (scale.x * renderer->dpi_scale.x))); float rel = renderer->xrel + event->motion.xrel / (scale.x * renderer->dpi_scale.x);
} else if (event->motion.xrel < 0) { float trunc = SDL_truncf(rel);
event->motion.xrel = SDL_min(-1, (int)(event->motion.xrel / (scale.x * renderer->dpi_scale.x))); renderer->xrel = rel - trunc;
event->motion.xrel = trunc;
} }
if (event->motion.yrel > 0) { if (event->motion.yrel != 0) {
event->motion.yrel = SDL_max(1, (int)(event->motion.yrel / (scale.y * renderer->dpi_scale.y))); float rel = renderer->yrel + event->motion.yrel / (scale.y * renderer->dpi_scale.y);
} else if (event->motion.yrel < 0) { float trunc = SDL_truncf(rel);
event->motion.yrel = SDL_min(-1, (int)(event->motion.yrel / (scale.y * renderer->dpi_scale.y))); renderer->yrel = rel - trunc;
event->motion.yrel = trunc;
} }
} }
} }

View file

@ -189,6 +189,10 @@ struct SDL_Renderer
/* The pixel to point coordinate scale */ /* The pixel to point coordinate scale */
SDL_FPoint dpi_scale; SDL_FPoint dpi_scale;
/* Remainder from scaled relative motion */
float xrel;
float yrel;
/* The list of textures */ /* The list of textures */
SDL_Texture *textures; SDL_Texture *textures;
SDL_Texture *target; SDL_Texture *target;