Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alpha Centauri - Mouse jumps during movement instructions #318

Closed
vv221 opened this issue Sep 5, 2023 · 3 comments
Closed

Alpha Centauri - Mouse jumps during movement instructions #318

vv221 opened this issue Sep 5, 2023 · 3 comments

Comments

@vv221
Copy link

vv221 commented Sep 5, 2023

In Alpha Centauri, one way to give a movement instruction to a unit is to press the left mouse button, move the mouse while keeping the button pressed, and releasing it when the cursor is over the destination tile.

With a real libSDL-1.2.so.0 library, this works as expected.

When libSDL-1.2.so.0 is provided by sdl12-compat, an unexpected behaviour happens: when the mouse button is pressed, the cursor jumps to another part of the screen, leading to unexpected movement instructions if the mouse button is released to early. You need to first move the cursor back to where you want the unit to go before releasing it.

The mouse cursor does another jump when the mouse button is released, but this has no big impact on gameplay because it seems to happen after the movement instruction is given to the unit.

System details

I got the same behaviour on two distinct systems:

  • Debian Bookworm
  • sdl12-compat 1.2.60
  • SDL 2.26.5
  • Debian Trixie/Sid
  • sdl12-compat 1.2.64
  • SDL 2.28.3

Apha Centauri setup

The build I tested has a slight difference with the out-of-the-box Loki version: to avoid the requirement on old compatibility libraries, a small shim is preloaded that allows it to run on top of current libraries.

The game is run from the dynamic binaries (smac.dynamic), not the static ones.

Here is a copy of the shim:

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>

void *__builtin_new(size_t size)
{
    return malloc(size);
}

void __builtin_delete(void *ptr)
{
    free(ptr);
}

void *__builtin_vec_new(size_t size)
{
    return malloc(size);
}

void __builtin_vec_delete(void *ptr)
{
    free(ptr);
}

And its source: https://github.com/ZeroPointEnergy/smacshim

@sulix
Copy link
Contributor

sulix commented Sep 6, 2023

I can reproduce this here. It seems to only occur when running fullscreen — the game's fine windowed. This is partly because the game normally uses a hardware cursor, but switches to a software one (and relative mode?) when moving a unit this way. Since the game is pillarboxed in fullscreen, this makes me suspect the mouse scaling. SDL_MOUSE_RELATIVE_SCALING has no obvious effect, so it might be something subtler.

Indeed, removing the extra code to reset the position in UpdateRelativeMouseMode seems to fix this, so maybe there's something funny going on in SDL2's logical scaling with SDL_GetMouseState(). Apparently that was added to handle Wolf4SDL, and I know there are a few other games which try to synchronise the position of a hardware / software cursor, so this merits further testing.

@vv221
Copy link
Author

vv221 commented Sep 6, 2023

It seems to only occur when running fullscreen — the game's fine windowed.

Thanks for the tip, it works fine here. I will use that combined with tweaking the desktop resolution to approximate a fullscreen mode until a more durable fix can be found.

sulix added a commit to sulix/sdl12-compat that referenced this issue Sep 13, 2023
sdl12-compat tracks the mouse position in the MousePosition variable,
even when we're not in relative mouse mode. We therefore don't need to
call SDL20_GetMouseState() to update it before entering relative mouse
mode: we already have it from the last SDL_MOUSEMOTION event, and have
already applied any scaling we need.

This is important, because SDL_GetMouseState() returns the _raw_ mouse
coordinates, not the ones scaled by SDL_RenderSetLogicalSize(). So we
end up with a mismatch. This results in a mouse offset on non-OpenGL,
scaled games, like Alpha Centauri in fullscreen (see libsdl-org#318).

We could fix this by calling SDL_RenderWindowToLogical() instead, but
that complicates the codepath as we don't always have an SDL_Renderer
(we might be using OpenGL), so this seems cleaner.

I've tested this with SMAC (where it fixes the bug) and Wolf4SDL (which
was cited in the commit which introduced this check). Both work fine.
sulix added a commit to sulix/sdl12-compat that referenced this issue Sep 13, 2023
sdl12-compat tracks the mouse position in the MousePosition variable,
even when we're not in relative mouse mode. We therefore don't need to
call SDL20_GetMouseState() to update it before entering relative mouse
mode: we already have it from the last SDL_MOUSEMOTION event, and have
already applied any scaling we need.

This is important, because SDL_GetMouseState() returns the _raw_ mouse
coordinates, not the ones scaled by SDL_RenderSetLogicalSize(). So we
end up with a mismatch. This results in a mouse offset on non-OpenGL,
scaled games, like Alpha Centauri in fullscreen (see libsdl-org#318).

We could fix this by calling SDL_RenderWindowToLogical() instead, but
that complicates the codepath as we don't always have an SDL_Renderer
(we might be using OpenGL), so this seems cleaner.

I've tested this with SMAC (where it fixes the bug) and Wolf4SDL (which
was cited in the commit which introduced this check). Both work fine.
@sulix
Copy link
Contributor

sulix commented Sep 13, 2023

So this appears to be caused by our using SDL_GetMouseState() when entering relative mode, despite SDL_GetMouseState() returning raw coordinates (without SDL_Renderer's logical scaling applied). All the other coordinates we get from the message queue, which is scaled by a filter, and then track ourselves anyway.

PR #320 fixes this for me. We could call SDL_RenderWindowToLogical() instead, but personally I think relying on the message queue for everything is cleaner. Happy to change it if you prefer, though.

slouken pushed a commit that referenced this issue Sep 13, 2023
sdl12-compat tracks the mouse position in the MousePosition variable,
even when we're not in relative mouse mode. We therefore don't need to
call SDL20_GetMouseState() to update it before entering relative mouse
mode: we already have it from the last SDL_MOUSEMOTION event, and have
already applied any scaling we need.

This is important, because SDL_GetMouseState() returns the _raw_ mouse
coordinates, not the ones scaled by SDL_RenderSetLogicalSize(). So we
end up with a mismatch. This results in a mouse offset on non-OpenGL,
scaled games, like Alpha Centauri in fullscreen (see #318).

We could fix this by calling SDL_RenderWindowToLogical() instead, but
that complicates the codepath as we don't always have an SDL_Renderer
(we might be using OpenGL), so this seems cleaner.

I've tested this with SMAC (where it fixes the bug) and Wolf4SDL (which
was cited in the commit which introduced this check). Both work fine.
@icculus icculus closed this as completed Sep 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants