From 43cd0d5bb92cf0ef6d5e661da1dc1703f6b0e2cb Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Wed, 5 Feb 2025 17:06:13 +0300 Subject: [PATCH 1/3] Engine: tidy few mouse cursor parameters --- Engine/ac/draw.cpp | 6 +++--- Engine/ac/mouse.cpp | 3 ++- Engine/ac/mouse.h | 2 +- Engine/device/mousew32.cpp | 34 ++++++++++------------------------ Engine/device/mousew32.h | 4 ---- Engine/gui/mylistbox.cpp | 2 -- Engine/main/engine.cpp | 1 - 7 files changed, 16 insertions(+), 36 deletions(-) diff --git a/Engine/ac/draw.cpp b/Engine/ac/draw.cpp index e1e2baec819..07c3c368e9e 100644 --- a/Engine/ac/draw.cpp +++ b/Engine/ac/draw.cpp @@ -80,7 +80,7 @@ extern int displayed_room; extern CharacterInfo*playerchar; extern int eip_guinum; extern int cur_mode,cur_cursor; -extern int hotx,hoty; +extern int mouse_hotx, mouse_hoty; extern int bg_just_changed; @@ -2831,8 +2831,8 @@ void construct_game_screen_overlay(bool draw_mouse) { // Exclusive sub-batch for mouse cursor, to let filter it out (CHECKME later?) gfxDriver->BeginSpriteBatch(Rect(), SpriteTransform(), kFlip_None, nullptr, RENDER_BATCH_MOUSE_CURSOR); - gfxDriver->DrawSprite(mousex - hotx, mousey - hoty, cursor_tx.Ddb); - invalidate_sprite(mousex - hotx, mousey - hoty, cursor_tx.Ddb, false); + gfxDriver->DrawSprite(mousex - mouse_hotx, mousey - mouse_hoty, cursor_tx.Ddb); + invalidate_sprite(mousex - mouse_hotx, mousey - mouse_hoty, cursor_tx.Ddb, false); gfxDriver->EndSpriteBatch(); } } diff --git a/Engine/ac/mouse.cpp b/Engine/ac/mouse.cpp index 5c65411a608..7d6033a4e1b 100644 --- a/Engine/ac/mouse.cpp +++ b/Engine/ac/mouse.cpp @@ -47,6 +47,7 @@ extern IGraphicsDriver *gfxDriver; ScriptMouse scmouse; int cur_mode,cur_cursor; +int mouse_hotx = 0, mouse_hoty = 0; // in game cursor hotspot offset int mouse_frame=0,mouse_delay=0; int lastmx=-1,lastmy=-1; @@ -122,7 +123,7 @@ void SetMouseBounds(int x1, int y1, int x2, int y2) void set_mouse_cursor(int newcurs, bool force_update) { const int hotspotx = game.mcurs[newcurs].hotx, hotspoty = game.mcurs[newcurs].hoty; - Mouse::SetHotspot(hotspotx, hotspoty); + mouse_hotx = hotspotx, mouse_hoty = hotspoty; // if it's same cursor and there's animation in progress, then don't assign a new pic just yet if (!force_update && diff --git a/Engine/ac/mouse.h b/Engine/ac/mouse.h index 84419a216dd..8757e132d90 100644 --- a/Engine/ac/mouse.h +++ b/Engine/ac/mouse.h @@ -95,7 +95,7 @@ extern ScriptMouse scmouse; extern CursorGraphicState cursor_gstate; extern int mousex, mousey; -extern char ignore_bounds; +extern int ignore_bounds; extern int cur_mode; extern int cur_cursor; diff --git a/Engine/device/mousew32.cpp b/Engine/device/mousew32.cpp index 4f1990de8dd..c50e09b23ce 100644 --- a/Engine/device/mousew32.cpp +++ b/Engine/device/mousew32.cpp @@ -33,15 +33,12 @@ using namespace AGS::Common; using namespace AGS::Engine; -char currentcursor = 0; // virtual mouse cursor coordinates -int mousex = 0, mousey = 0, numcurso = -1, hotx = 0, hoty = 0; +int mousex = 0, mousey = 0; // real mouse coordinates and bounds (in window coords) static int real_mouse_x = 0, real_mouse_y = 0; -static int boundx1 = 0, boundx2 = 99999, boundy1 = 0, boundy2 = 99999; -char ignore_bounds = 0; -extern char alpha_blend_cursor; -extern RGB palette[256]; +static Rect mouse_bounds; +int ignore_bounds = 0; // NOTE: this works as a counter for some reason, review later extern volatile bool switched_away; namespace Mouse @@ -71,10 +68,10 @@ Point Mouse::SysToGamePos(int sys_mx, int sys_my) // Clamp to control rect, and optionally script bounds int mx = Math::Clamp(sys_mx, Mouse::ControlRect.Left, Mouse::ControlRect.Right); int my = Math::Clamp(sys_my, Mouse::ControlRect.Top, Mouse::ControlRect.Bottom); - if (!ignore_bounds) + if (ignore_bounds == 0) { - mx = Math::Clamp(mx, boundx1, boundx2); - my = Math::Clamp(my, boundy1, boundy2); + mx = Math::Clamp(mx, mouse_bounds.Left, mouse_bounds.Right); + my = Math::Clamp(my, mouse_bounds.Top, mouse_bounds.Bottom); } // Convert to virtual coordinates Mouse::WindowToGame(mx, my); @@ -98,11 +95,10 @@ void Mouse::Poll() mousex = real_mouse_x; mousey = real_mouse_y; // Optionally apply script bounds - if (!ignore_bounds && - (mousex < boundx1 || mousey < boundy1 || mousex > boundx2 || mousey > boundy2)) + if ((ignore_bounds == 0) && (!mouse_bounds.IsInside(mousex, mousey))) { - mousex = Math::Clamp(mousex, boundx1, boundx2); - mousey = Math::Clamp(mousey, boundy1, boundy2); + mousex = Math::Clamp(mousex, mouse_bounds.Left, mouse_bounds.Right); + mousey = Math::Clamp(mousey, mouse_bounds.Top, mouse_bounds.Bottom); Mouse::SetSysPosition(mousex, mousey); } // Convert to virtual coordinates @@ -118,12 +114,6 @@ void Mouse::SetSysPosition(int x, int y) sys_window_set_mouse(real_mouse_x, real_mouse_y); } -void Mouse::SetHotspot(int x, int y) -{ - hotx = x; - hoty = y; -} - int Mouse::GetButtonCount() { // TODO: can SDL tell number of available/supported buttons at all, or whether mouse is present? @@ -148,11 +138,7 @@ void Mouse::UpdateGraphicArea() void Mouse::SetMoveLimit(const Rect &r) { Rect src_r = OffsetRect(r, play.GetMainViewport().GetLT()); - Rect dst_r = GameScaling.ScaleRange(src_r); - boundx1 = dst_r.Left; - boundy1 = dst_r.Top; - boundx2 = dst_r.Right; - boundy2 = dst_r.Bottom; + mouse_bounds = GameScaling.ScaleRange(src_r); } void Mouse::SetPosition(const Point &p) diff --git a/Engine/device/mousew32.h b/Engine/device/mousew32.h index 8b1aeef4392..27d4b7c6914 100644 --- a/Engine/device/mousew32.h +++ b/Engine/device/mousew32.h @@ -60,11 +60,7 @@ namespace Mouse void Poll(); // Set actual OS cursor position on screen; in native game coordinates void SetPosition(const Point &p); - // Sets the relative position of the cursor's hotspot, in native pixels - void SetHotspot(int x, int y); } extern int mousex, mousey; -extern int hotx, hoty; -extern char currentcursor; diff --git a/Engine/gui/mylistbox.cpp b/Engine/gui/mylistbox.cpp index 35fc5674c9a..2a3674fd91b 100644 --- a/Engine/gui/mylistbox.cpp +++ b/Engine/gui/mylistbox.cpp @@ -23,8 +23,6 @@ using namespace AGS::Common; -extern int numcurso, hotx, hoty; - extern int windowbackgroundcolor; extern int cbuttfont; extern int smcode; diff --git a/Engine/main/engine.cpp b/Engine/main/engine.cpp index 34d1821f4af..6f54d1703b3 100644 --- a/Engine/main/engine.cpp +++ b/Engine/main/engine.cpp @@ -854,7 +854,6 @@ void engine_init_game_settings() update_invorder(); displayed_room = -10; - currentcursor=0; set_our_eip(-4); mousey=100; // stop icon bar popping up From 5feb795698e17435000278b10e656552e7633bff Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Wed, 5 Feb 2025 17:22:33 +0300 Subject: [PATCH 2/3] Engine: when locking mouse, constrain it to the game viewport This requires SDL 2.0.18 or higher to work properly. --- Engine/device/mousew32.cpp | 2 +- Engine/gfx/ali3dsw.cpp | 6 +++--- Engine/platform/base/sys_main.cpp | 19 +++++++++++++++++++ Engine/platform/base/sys_main.h | 1 + 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/Engine/device/mousew32.cpp b/Engine/device/mousew32.cpp index c50e09b23ce..79c5530cb20 100644 --- a/Engine/device/mousew32.cpp +++ b/Engine/device/mousew32.cpp @@ -156,7 +156,7 @@ bool Mouse::IsLockedToWindow() bool Mouse::TryLockToWindow() { if (!LockedToWindow) - LockedToWindow = sys_window_lock_mouse(true); + LockedToWindow = sys_window_lock_mouse(true, Mouse::ControlRect); return LockedToWindow; } diff --git a/Engine/gfx/ali3dsw.cpp b/Engine/gfx/ali3dsw.cpp index 1d48984412a..b1adb0e67d6 100644 --- a/Engine/gfx/ali3dsw.cpp +++ b/Engine/gfx/ali3dsw.cpp @@ -50,7 +50,7 @@ static auto fix_alpha_blender = SDL_ComposeCustomBlendMode( SDL_BLENDFACTOR_ZERO, SDL_BLENDOPERATION_ADD ); -#endif +#endif // SDL_VERSION_ATLEAST(2, 0, 5) SDLRendererGraphicsDriver::SDLRendererGraphicsDriver() { @@ -799,7 +799,7 @@ static uint32_t _trans_alpha_blender32(uint32_t x, uint32_t y, uint32_t n) bool SDLRendererGraphicsDriver::SetVsyncImpl(bool enabled, bool &vsync_res) { - #if SDL_VERSION_ATLEAST(2, 0, 18) +#if SDL_VERSION_ATLEAST(2, 0, 18) if (SDL_RenderSetVSync(_renderer, enabled) == 0) // 0 on success { // gamma might be lost after changing vsync mode at fullscreen @@ -810,7 +810,7 @@ bool SDLRendererGraphicsDriver::SetVsyncImpl(bool enabled, bool &vsync_res) return true; } Debug::Printf(kDbgMsg_Warn, "SDLRenderer: SetVsync (%d) failed: %s", enabled, SDL_GetError()); - #endif +#endif // SDL_VERSION_ATLEAST(2, 0, 18) return false; } diff --git a/Engine/platform/base/sys_main.cpp b/Engine/platform/base/sys_main.cpp index 91169043ad9..20deadb1ecd 100644 --- a/Engine/platform/base/sys_main.cpp +++ b/Engine/platform/base/sys_main.cpp @@ -279,8 +279,27 @@ void sys_window_show_cursor(bool on) { } bool sys_window_lock_mouse(bool on) { + return sys_window_lock_mouse(on, Rect()); +} + +bool sys_window_lock_mouse(bool on, const Rect &bounds) { if (!window) return false; SDL_SetWindowGrab(window, static_cast(on)); +#if SDL_VERSION_ATLEAST(2, 0, 18) + if (on && !bounds.IsEmpty()) + { + SDL_Rect rect; + rect.x = bounds.Left; + rect.y = bounds.Top; + rect.w = bounds.GetWidth(); + rect.h = bounds.GetHeight(); + SDL_SetWindowMouseRect(window, &rect); + } + else + { + SDL_SetWindowMouseRect(window, nullptr); + } +#endif // SDL_VERSION_ATLEAST(2, 0, 18) return on; // TODO: test if successful? } diff --git a/Engine/platform/base/sys_main.h b/Engine/platform/base/sys_main.h index e0360cb6c3a..ad583e9993d 100644 --- a/Engine/platform/base/sys_main.h +++ b/Engine/platform/base/sys_main.h @@ -83,6 +83,7 @@ void sys_window_show_cursor(bool on); // Locks on unlocks mouse inside the window. // Returns new state of the mouse lock. bool sys_window_lock_mouse(bool on); +bool sys_window_lock_mouse(bool on, const Rect &bounds); // Sets mouse position within the game window void sys_window_set_mouse(int x, int y); // Destroy current game window, if one exists. From 5126a5129ca1b5b9154beba7ffdeca8b15aa6f1b Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Wed, 5 Feb 2025 22:52:35 +0300 Subject: [PATCH 3/3] Engine: explicitly do TryLockToWindow in fullscreen, update bounds rect --- Engine/ac/game.cpp | 4 ++-- Engine/ac/mouse.cpp | 1 + Engine/main/engine_setup.cpp | 4 ++-- Engine/main/game_run.cpp | 4 +++- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Engine/ac/game.cpp b/Engine/ac/game.cpp index e5056474f51..9738d2ca2b0 100644 --- a/Engine/ac/game.cpp +++ b/Engine/ac/game.cpp @@ -1520,8 +1520,8 @@ void display_switch_in() { Debug::Printf("Switching back into the game"); ags_clear_input_state(); - // If auto lock option is set, lock mouse to the game window - if (usetup.MouseAutoLock && scsystem.windowed) + // If fullscreen, or auto lock option is set, lock mouse to the game window + if ((scsystem.windowed == 0) || usetup.MouseAutoLock) Mouse::TryLockToWindow(); switched_away = false; } diff --git a/Engine/ac/mouse.cpp b/Engine/ac/mouse.cpp index 7d6033a4e1b..0d1555ef4cb 100644 --- a/Engine/ac/mouse.cpp +++ b/Engine/ac/mouse.cpp @@ -358,6 +358,7 @@ bool Mouse_GetAutoLock() void Mouse_SetAutoLock(bool on) { usetup.MouseAutoLock = on; + // Only update when in windowed mode, as always locked in fullscreen if (scsystem.windowed) { if (usetup.MouseAutoLock) diff --git a/Engine/main/engine_setup.cpp b/Engine/main/engine_setup.cpp index 216bd041241..236b554b7cf 100644 --- a/Engine/main/engine_setup.cpp +++ b/Engine/main/engine_setup.cpp @@ -133,8 +133,8 @@ void engine_post_gfxmode_mouse_setup(const Size &init_desktop) on_coordinates_scaling_changed(); - // If auto lock option is set, lock mouse to the game window - if (usetup.MouseAutoLock && scsystem.windowed != 0) + // If fullscreen, or auto lock option is set, lock mouse to the game window + if ((scsystem.windowed == 0) || usetup.MouseAutoLock) Mouse::TryLockToWindow(); } diff --git a/Engine/main/game_run.cpp b/Engine/main/game_run.cpp index 7c266976a89..a8e97d423de 100644 --- a/Engine/main/game_run.cpp +++ b/Engine/main/game_run.cpp @@ -288,12 +288,14 @@ static bool game_loop_check_ground_level_interactions() static void lock_mouse_on_click() { - if (usetup.MouseAutoLock && scsystem.windowed) + // Only update when in windowed mode, as always locked in fullscreen + if (usetup.MouseAutoLock && scsystem.windowed != 0) Mouse::TryLockToWindow(); } static void toggle_mouse_lock() { + // Only update when in windowed mode, as always locked in fullscreen if (scsystem.windowed) { if (Mouse::IsLockedToWindow())