From 03b31040e5eb1ec11a72ecd1bff450b02946f066 Mon Sep 17 00:00:00 2001 From: "N.E.C" Date: Fri, 30 Dec 2022 15:16:14 -0800 Subject: [PATCH 01/13] Run menu in absolute cursor mode to match OS --- TheForceEngine/TFE_DarkForces/GameUI/menu.cpp | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp b/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp index 4f9ad4833..829a03450 100644 --- a/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp +++ b/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp @@ -37,6 +37,7 @@ namespace TFE_DarkForces /////////////////////////////////////////// void menu_init() { + TFE_Input::enableRelativeMode(false); } void menu_destroy() @@ -48,6 +49,38 @@ namespace TFE_DarkForces { delt_resetState(); } + + // Get bounds of menu in display coordinates + static LRect menu_getDisplayRect() + { + DisplayInfo displayInfo; + TFE_RenderBackend::getDisplayInfo(&displayInfo); + + LRect bounds; + lcanvas_getBounds(&bounds); + s32 canvasWidth = bounds.right - bounds.left; + s32 canvasHeight = bounds.bottom - bounds.top; + + ScreenRect* uiRect = vfb_getScreenRect(VFB_RECT_UI); + fixed16_16 xScale = vfb_getXScale(); + fixed16_16 yScale = vfb_getYScale(); + + s32 virtualWidth = floor16(mul16(intToFixed16(320), xScale)); + s32 offset = max(0, ((uiRect->right - uiRect->left + 1) - virtualWidth) / 2); + + s32 right = offset + virtualWidth * displayInfo.width / canvasWidth; + s32 bot = displayInfo.height; + + LRect result; + lrect_set(&result, offset, 0, right, bot); + return result; + } + + // Smoothly interpolate a value in range x0..x1 to a new value in range y0..y1. + static s32 interpolate(s32 value, s32 x0, s32 x1, s32 y0, s32 y1) + { + return y0 + (value - x0) * (y1 - y0) / (x1 - x0); + } void menu_handleMousePosition() { @@ -59,8 +92,14 @@ namespace TFE_DarkForces s32 width = bounds.right - bounds.left; s32 height = bounds.bottom - bounds.top; + LRect displayRect = menu_getDisplayRect(); + s32 mx, my; TFE_Input::getMousePos(&mx, &my); + TFE_System::logWrite(LOG_MSG, "Menu", "Native mouse pos %d, %d", mx, my); + TFE_System::logWrite(LOG_MSG, "Menu", "canvas bounds %d, %d, %d, %d", bounds.left, bounds.top, bounds.right, bounds.bottom); + TFE_System::logWrite(LOG_MSG, "Menu", "Menu display rect %d, %d, %d, %d", displayRect.left, displayRect.top, displayRect.right, displayRect.bottom); +#if 0 s_cursorPosAccum = { 12*mx/10, my }; // Account for 320x200 in 4:3 scaling. if (displayInfo.width >= displayInfo.height) @@ -73,6 +112,13 @@ namespace TFE_DarkForces s_cursorPos.x = clamp(s_cursorPosAccum.x * (s32)width / (s32)displayInfo.width, 0, (s32)width - 3); s_cursorPos.z = clamp(s_cursorPosAccum.z * (s32)width / (s32)displayInfo.width, 0, (s32)height - 3); } +#else + s_cursorPosAccum = { + interpolate(mx, displayRect.left, displayRect.right, bounds.left, bounds.right), + interpolate(my, displayRect.top, displayRect.bottom, bounds.top, bounds.bottom), + }; + s_cursorPos = s_cursorPosAccum; +#endif } void menu_resetCursor() From b9bb3793ff4c28bc59a97f90f3fc45f920bae7ae Mon Sep 17 00:00:00 2001 From: "N.E.C" Date: Fri, 30 Dec 2022 20:47:05 -0800 Subject: [PATCH 02/13] Switch away from relative mode in escape menu and PDA --- .../TFE_DarkForces/GameUI/escapeMenu.cpp | 12 ++++++----- TheForceEngine/TFE_DarkForces/GameUI/menu.cpp | 20 ++----------------- TheForceEngine/TFE_DarkForces/GameUI/pda.cpp | 6 ++++++ .../TFE_DarkForces/darkForcesMain.cpp | 3 +++ TheForceEngine/TFE_Input/input.cpp | 11 ++++++++++ TheForceEngine/TFE_Input/input.h | 2 ++ TheForceEngine/main.cpp | 12 +++++++++++ 7 files changed, 43 insertions(+), 23 deletions(-) diff --git a/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.cpp b/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.cpp index ce254065f..6de8f203f 100644 --- a/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.cpp +++ b/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.cpp @@ -223,6 +223,9 @@ namespace TFE_DarkForces void escapeMenu_open(u8* framebuffer, u8* palette) { + TFE_Input::enableRelativeMode(false); + TFE_Input::enableOSCursor(false); // Cursor will be drawn by us + // TFE reticle_enable(false); @@ -249,6 +252,9 @@ namespace TFE_DarkForces // TFE reticle_enable(true); + + TFE_Input::enableRelativeMode(true); + TFE_Input::enableOSCursor(false); } JBool escapeMenu_isOpen() @@ -508,11 +514,7 @@ namespace TFE_DarkForces EscapeMenuAction action = escapeMenu_updateUI(); if (action != ESC_CONTINUE) { - s_emState.escMenuOpen = JFALSE; - resumeLevelSound(); - - // TFE - reticle_enable(true); + escapeMenu_close(); } escapeMenu_draw(JTRUE, JTRUE); diff --git a/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp b/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp index 829a03450..154115097 100644 --- a/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp +++ b/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp @@ -37,7 +37,6 @@ namespace TFE_DarkForces /////////////////////////////////////////// void menu_init() { - TFE_Input::enableRelativeMode(false); } void menu_destroy() @@ -96,29 +95,12 @@ namespace TFE_DarkForces s32 mx, my; TFE_Input::getMousePos(&mx, &my); - TFE_System::logWrite(LOG_MSG, "Menu", "Native mouse pos %d, %d", mx, my); - TFE_System::logWrite(LOG_MSG, "Menu", "canvas bounds %d, %d, %d, %d", bounds.left, bounds.top, bounds.right, bounds.bottom); - TFE_System::logWrite(LOG_MSG, "Menu", "Menu display rect %d, %d, %d, %d", displayRect.left, displayRect.top, displayRect.right, displayRect.bottom); -#if 0 - s_cursorPosAccum = { 12*mx/10, my }; // Account for 320x200 in 4:3 scaling. - if (displayInfo.width >= displayInfo.height) - { - s_cursorPos.x = clamp(s_cursorPosAccum.x * (s32)height / (s32)displayInfo.height, 0, (s32)width - 3); - s_cursorPos.z = clamp(s_cursorPosAccum.z * (s32)height / (s32)displayInfo.height, 0, (s32)height - 3); - } - else - { - s_cursorPos.x = clamp(s_cursorPosAccum.x * (s32)width / (s32)displayInfo.width, 0, (s32)width - 3); - s_cursorPos.z = clamp(s_cursorPosAccum.z * (s32)width / (s32)displayInfo.width, 0, (s32)height - 3); - } -#else s_cursorPosAccum = { interpolate(mx, displayRect.left, displayRect.right, bounds.left, bounds.right), interpolate(my, displayRect.top, displayRect.bottom, bounds.top, bounds.bottom), }; s_cursorPos = s_cursorPosAccum; -#endif } void menu_resetCursor() @@ -137,6 +119,8 @@ namespace TFE_DarkForces u8* menu_startupDisplay() { + TFE_Input::enableRelativeMode(false); + TFE_Input::enableOSCursor(false); // Cursor will be drawn by us vfb_setResolution(320, 200); return vfb_getCpuBuffer(); } diff --git a/TheForceEngine/TFE_DarkForces/GameUI/pda.cpp b/TheForceEngine/TFE_DarkForces/GameUI/pda.cpp index a92b78df9..f30e26a7f 100644 --- a/TheForceEngine/TFE_DarkForces/GameUI/pda.cpp +++ b/TheForceEngine/TFE_DarkForces/GameUI/pda.cpp @@ -117,6 +117,9 @@ namespace TFE_DarkForces /////////////////////////////////////////// void pda_start(const char* levelName) { + TFE_Input::enableRelativeMode(false); + TFE_Input::enableOSCursor(false); // Cursor will be drawn by us + // TFE reticle_enable(false); s_mouseAccum = { 0 }; @@ -240,6 +243,9 @@ namespace TFE_DarkForces TFE_Jedi::renderer_setType(RendererType(graphics->rendererIndex)); TFE_Jedi::renderer_setLimits(); } + + TFE_Input::enableRelativeMode(true); + TFE_Input::enableOSCursor(false); } void pda_update() diff --git a/TheForceEngine/TFE_DarkForces/darkForcesMain.cpp b/TheForceEngine/TFE_DarkForces/darkForcesMain.cpp index 9284f91d4..b6e3e9392 100644 --- a/TheForceEngine/TFE_DarkForces/darkForcesMain.cpp +++ b/TheForceEngine/TFE_DarkForces/darkForcesMain.cpp @@ -735,6 +735,9 @@ namespace TFE_DarkForces } break; case GMODE_MISSION: { + TFE_Input::enableRelativeMode(true); + TFE_Input::enableOSCursor(false); + sound_levelStart(); bitmap_setAllocator(s_levelRegion); diff --git a/TheForceEngine/TFE_Input/input.cpp b/TheForceEngine/TFE_Input/input.cpp index 14008cb9c..97e1144bc 100644 --- a/TheForceEngine/TFE_Input/input.cpp +++ b/TheForceEngine/TFE_Input/input.cpp @@ -32,6 +32,7 @@ namespace TFE_Input s32 s_mousePos[2] = { 0 }; bool s_relativeMode = false; + bool s_osCursorEnabled = true; static const char* const* s_controllerAxisNames; static const char* const* s_controllerButtonNames; @@ -140,6 +141,11 @@ namespace TFE_Input { s_relativeMode = enable; } + + void enableOSCursor(bool enable) + { + s_osCursorEnabled = enable; + } // Buffered Input void setBufferedInput(const char* text) @@ -330,6 +336,11 @@ namespace TFE_Input return s_relativeMode; } + bool osCursorEnabled() + { + return s_osCursorEnabled; + } + // Buffered Input const char* getBufferedText() { diff --git a/TheForceEngine/TFE_Input/input.h b/TheForceEngine/TFE_Input/input.h index b2315f5ea..cdd24a89e 100644 --- a/TheForceEngine/TFE_Input/input.h +++ b/TheForceEngine/TFE_Input/input.h @@ -36,6 +36,7 @@ namespace TFE_Input void setMousePos(s32 x, s32 y); void enableRelativeMode(bool enable); + void enableOSCursor(bool enable); // Buffered Input void setBufferedInput(const char* text); @@ -55,6 +56,7 @@ namespace TFE_Input bool mouseDown(MouseButton button); bool mousePressed(MouseButton button); bool relativeModeEnabled(); + bool osCursorEnabled(); void clearKeyPressed(KeyboardCode key); void clearAccumulatedMouseMove(); // Buffered Input diff --git a/TheForceEngine/main.cpp b/TheForceEngine/main.cpp index dce628e4e..fc3b99de5 100644 --- a/TheForceEngine/main.cpp +++ b/TheForceEngine/main.cpp @@ -654,6 +654,7 @@ int main(int argc, char* argv[]) u32 frame = 0u; bool showPerf = false; bool relativeMode = false; + bool osCursorVisible = true; TFE_System::logWrite(LOG_MSG, "Progam Flow", "The Force Engine Game Loop Started"); while (s_loop && !TFE_System::quitMessagePosted()) { @@ -664,6 +665,17 @@ int main(int argc, char* argv[]) { relativeMode = enableRelative; SDL_SetRelativeMouseMode(relativeMode ? SDL_TRUE : SDL_FALSE); + + // XXX: When relative mode is disabled, SDL will show the OS cursor. + // This line causes the OS cursor to be hidden again if it should be invisible. + osCursorVisible = true; + } + + bool enableOSCursor = TFE_Input::osCursorEnabled(); + if (osCursorVisible != enableOSCursor) + { + osCursorVisible = enableOSCursor; + SDL_ShowCursor(osCursorVisible ? 1 : 0); } // System events From 04c124d4f5fc60550a8edd5067c79c743dbaba8a Mon Sep 17 00:00:00 2001 From: "N.E.C" Date: Sat, 31 Dec 2022 11:54:56 -0800 Subject: [PATCH 03/13] Add new TFE_Input::setMouseCursorMode function --- .../TFE_DarkForces/GameUI/escapeMenu.cpp | 6 ++-- TheForceEngine/TFE_DarkForces/GameUI/menu.cpp | 3 +- TheForceEngine/TFE_DarkForces/GameUI/pda.cpp | 6 ++-- .../TFE_DarkForces/darkForcesMain.cpp | 3 +- TheForceEngine/TFE_DarkForces/mission.cpp | 2 +- TheForceEngine/TFE_FrontEndUI/frontEndUi.cpp | 15 ++++----- TheForceEngine/TFE_Input/input.cpp | 21 +++--------- TheForceEngine/TFE_Input/input.h | 6 ++-- TheForceEngine/TFE_Input/inputEnum.h | 8 +++++ TheForceEngine/main.cpp | 32 +++++++------------ 10 files changed, 40 insertions(+), 62 deletions(-) diff --git a/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.cpp b/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.cpp index 6de8f203f..f786ec248 100644 --- a/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.cpp +++ b/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.cpp @@ -223,8 +223,7 @@ namespace TFE_DarkForces void escapeMenu_open(u8* framebuffer, u8* palette) { - TFE_Input::enableRelativeMode(false); - TFE_Input::enableOSCursor(false); // Cursor will be drawn by us + TFE_Input::setMouseCursorMode(MCURSORMODE_ABSOLUTE); // TFE reticle_enable(false); @@ -253,8 +252,7 @@ namespace TFE_DarkForces // TFE reticle_enable(true); - TFE_Input::enableRelativeMode(true); - TFE_Input::enableOSCursor(false); + TFE_Input::setMouseCursorMode(MCURSORMODE_RELATIVE); } JBool escapeMenu_isOpen() diff --git a/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp b/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp index 154115097..48c309f4a 100644 --- a/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp +++ b/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp @@ -119,8 +119,7 @@ namespace TFE_DarkForces u8* menu_startupDisplay() { - TFE_Input::enableRelativeMode(false); - TFE_Input::enableOSCursor(false); // Cursor will be drawn by us + TFE_Input::setMouseCursorMode(MCURSORMODE_ABSOLUTE); vfb_setResolution(320, 200); return vfb_getCpuBuffer(); } diff --git a/TheForceEngine/TFE_DarkForces/GameUI/pda.cpp b/TheForceEngine/TFE_DarkForces/GameUI/pda.cpp index f30e26a7f..cb7559198 100644 --- a/TheForceEngine/TFE_DarkForces/GameUI/pda.cpp +++ b/TheForceEngine/TFE_DarkForces/GameUI/pda.cpp @@ -117,8 +117,7 @@ namespace TFE_DarkForces /////////////////////////////////////////// void pda_start(const char* levelName) { - TFE_Input::enableRelativeMode(false); - TFE_Input::enableOSCursor(false); // Cursor will be drawn by us + TFE_Input::setMouseCursorMode(MCURSORMODE_RELATIVE); // TFE reticle_enable(false); @@ -244,8 +243,7 @@ namespace TFE_DarkForces TFE_Jedi::renderer_setLimits(); } - TFE_Input::enableRelativeMode(true); - TFE_Input::enableOSCursor(false); + TFE_Input::setMouseCursorMode(MCURSORMODE_RELATIVE); } void pda_update() diff --git a/TheForceEngine/TFE_DarkForces/darkForcesMain.cpp b/TheForceEngine/TFE_DarkForces/darkForcesMain.cpp index b6e3e9392..5064d1776 100644 --- a/TheForceEngine/TFE_DarkForces/darkForcesMain.cpp +++ b/TheForceEngine/TFE_DarkForces/darkForcesMain.cpp @@ -735,8 +735,7 @@ namespace TFE_DarkForces } break; case GMODE_MISSION: { - TFE_Input::enableRelativeMode(true); - TFE_Input::enableOSCursor(false); + TFE_Input::setMouseCursorMode(MCURSORMODE_RELATIVE); sound_levelStart(); diff --git a/TheForceEngine/TFE_DarkForces/mission.cpp b/TheForceEngine/TFE_DarkForces/mission.cpp index 1aa3fe7ed..13987fad1 100644 --- a/TheForceEngine/TFE_DarkForces/mission.cpp +++ b/TheForceEngine/TFE_DarkForces/mission.cpp @@ -143,7 +143,7 @@ namespace TFE_DarkForces // Close the console so the cheat can be executed. TFE_FrontEndUI::toggleConsole(); mission_pause(JFALSE); - TFE_Input::enableRelativeMode(true); + TFE_Input::setMouseCursorMode(MCURSORMODE_RELATIVE); } void console_spawnEnemy(const ConsoleArgList& args) diff --git a/TheForceEngine/TFE_FrontEndUI/frontEndUi.cpp b/TheForceEngine/TFE_FrontEndUI/frontEndUi.cpp index 0c98647f4..2d36024ee 100644 --- a/TheForceEngine/TFE_FrontEndUI/frontEndUi.cpp +++ b/TheForceEngine/TFE_FrontEndUI/frontEndUi.cpp @@ -158,7 +158,7 @@ namespace TFE_FrontEndUI static bool s_bindingPopupOpen = false; static bool s_consoleActive = false; - static bool s_relativeMode; + static MouseCursorMode s_oldMouseCursorMode = MCURSORMODE_OS; static bool s_canSave = false; static bool s_drawNoGameDataMsg = false; @@ -245,7 +245,7 @@ namespace TFE_FrontEndUI s_appState = APP_STATE_MENU; s_menuRetState = APP_STATE_MENU; s_subUI = FEUI_NONE; - s_relativeMode = false; + s_oldMouseCursorMode = MCURSORMODE_OS; s_drawNoGameDataMsg = false; s_uiScale = (f32)TFE_Ui::getUiScale() * 0.01f; @@ -327,8 +327,8 @@ namespace TFE_FrontEndUI { s_appState = APP_STATE_MENU; s_subUI = FEUI_CONFIG; - s_relativeMode = TFE_Input::relativeModeEnabled(); - TFE_Input::enableRelativeMode(false); + s_oldMouseCursorMode = TFE_Input::getMouseCursorMode(); + TFE_Input::setMouseCursorMode(MCURSORMODE_OS); pickCurrentResolution(); } @@ -348,7 +348,7 @@ namespace TFE_FrontEndUI s_drawNoGameDataMsg = false; s_appState = s_menuRetState; TFE_Settings::writeToDisk(); - TFE_Input::enableRelativeMode(s_relativeMode); + TFE_Input::setMouseCursorMode(s_oldMouseCursorMode); inputMapping_serialize(); return s_appState; @@ -458,7 +458,6 @@ namespace TFE_FrontEndUI if (s_subUI == FEUI_NONE) { s_menuRetState = APP_STATE_MENU; - s_relativeMode = false; const f32 windowPadding = 16.0f; // required padding so that a window completely holds a control without clipping. @@ -743,7 +742,7 @@ namespace TFE_FrontEndUI s_drawNoGameDataMsg = false; s_appState = s_menuRetState; TFE_Settings::writeToDisk(); - TFE_Input::enableRelativeMode(s_relativeMode); + TFE_Input::setMouseCursorMode(s_oldMouseCursorMode); inputMapping_serialize(); } if (s_menuRetState != APP_STATE_MENU && ImGui::Button("Exit to Menu", sideBarButtonSize)) @@ -1120,7 +1119,7 @@ namespace TFE_FrontEndUI s_subUI = FEUI_NONE; s_appState = s_menuRetState; s_drawNoGameDataMsg = false; - TFE_Input::enableRelativeMode(s_relativeMode); + TFE_Input::setMouseCursorMode(s_oldMouseCursorMode); } void configSaveLoadBegin(bool save) diff --git a/TheForceEngine/TFE_Input/input.cpp b/TheForceEngine/TFE_Input/input.cpp index 97e1144bc..45079bcef 100644 --- a/TheForceEngine/TFE_Input/input.cpp +++ b/TheForceEngine/TFE_Input/input.cpp @@ -31,8 +31,7 @@ namespace TFE_Input s32 s_mouseMoveAccum[2] = { 0 }; s32 s_mousePos[2] = { 0 }; - bool s_relativeMode = false; - bool s_osCursorEnabled = true; + MouseCursorMode s_mouseCursorMode = MCURSORMODE_OS; static const char* const* s_controllerAxisNames; static const char* const* s_controllerButtonNames; @@ -137,14 +136,9 @@ namespace TFE_Input s_mousePos[1] = y; } - void enableRelativeMode(bool enable) + void setMouseCursorMode(MouseCursorMode mode) { - s_relativeMode = enable; - } - - void enableOSCursor(bool enable) - { - s_osCursorEnabled = enable; + s_mouseCursorMode = mode; } // Buffered Input @@ -331,14 +325,9 @@ namespace TFE_Input return s_mousePressed[button] != 0; } - bool relativeModeEnabled() - { - return s_relativeMode; - } - - bool osCursorEnabled() + MouseCursorMode getMouseCursorMode() { - return s_osCursorEnabled; + return s_mouseCursorMode; } // Buffered Input diff --git a/TheForceEngine/TFE_Input/input.h b/TheForceEngine/TFE_Input/input.h index cdd24a89e..770685642 100644 --- a/TheForceEngine/TFE_Input/input.h +++ b/TheForceEngine/TFE_Input/input.h @@ -35,8 +35,7 @@ namespace TFE_Input void setRelativeMousePos(s32 x, s32 y); void setMousePos(s32 x, s32 y); - void enableRelativeMode(bool enable); - void enableOSCursor(bool enable); + void setMouseCursorMode(MouseCursorMode mode); // Buffered Input void setBufferedInput(const char* text); @@ -55,8 +54,7 @@ namespace TFE_Input bool keyModDown(KeyModifier keyMod); bool mouseDown(MouseButton button); bool mousePressed(MouseButton button); - bool relativeModeEnabled(); - bool osCursorEnabled(); + MouseCursorMode getMouseCursorMode(); void clearKeyPressed(KeyboardCode key); void clearAccumulatedMouseMove(); // Buffered Input diff --git a/TheForceEngine/TFE_Input/inputEnum.h b/TheForceEngine/TFE_Input/inputEnum.h index 00f3edcbf..43ef6cda2 100644 --- a/TheForceEngine/TFE_Input/inputEnum.h +++ b/TheForceEngine/TFE_Input/inputEnum.h @@ -63,6 +63,14 @@ enum MouseButton MBUTTON_UNKNOWN = MBUTTON_COUNT }; +enum MouseCursorMode +{ + MCURSORMODE_OS = 0, + MCURSORMODE_ABSOLUTE, + MCURSORMODE_RELATIVE, + MCURSORMODE_COUNT +}; + // Matches SDL2 Keycodes but provided seperately for possible future changes and to avoid having to include SDL2 where it doesn't make sense. enum KeyboardCode { diff --git a/TheForceEngine/main.cpp b/TheForceEngine/main.cpp index fc3b99de5..b76d5138d 100644 --- a/TheForceEngine/main.cpp +++ b/TheForceEngine/main.cpp @@ -352,7 +352,7 @@ void setAppState(AppState newState, int argc, char* argv[]) } else { - TFE_Input::enableRelativeMode(true); + TFE_Input::setMouseCursorMode(MCURSORMODE_RELATIVE); } } else @@ -389,7 +389,7 @@ void setAppState(AppState newState, int argc, char* argv[]) } else { - TFE_Input::enableRelativeMode(true); + TFE_Input::setMouseCursorMode(MCURSORMODE_RELATIVE); } } } @@ -653,29 +653,19 @@ int main(int argc, char* argv[]) // Game loop u32 frame = 0u; bool showPerf = false; - bool relativeMode = false; - bool osCursorVisible = true; + MouseCursorMode mouseCursorMode = MCURSORMODE_OS; TFE_System::logWrite(LOG_MSG, "Progam Flow", "The Force Engine Game Loop Started"); while (s_loop && !TFE_System::quitMessagePosted()) { TFE_FRAME_BEGIN(); - - bool enableRelative = TFE_Input::relativeModeEnabled(); - if (enableRelative != relativeMode) - { - relativeMode = enableRelative; - SDL_SetRelativeMouseMode(relativeMode ? SDL_TRUE : SDL_FALSE); - - // XXX: When relative mode is disabled, SDL will show the OS cursor. - // This line causes the OS cursor to be hidden again if it should be invisible. - osCursorVisible = true; - } - bool enableOSCursor = TFE_Input::osCursorEnabled(); - if (osCursorVisible != enableOSCursor) + MouseCursorMode newMouseCursorMode = TFE_Input::getMouseCursorMode(); + if (newMouseCursorMode != mouseCursorMode) { - osCursorVisible = enableOSCursor; - SDL_ShowCursor(osCursorVisible ? 1 : 0); + mouseCursorMode = newMouseCursorMode; + SDL_SetRelativeMouseMode(mouseCursorMode == MCURSORMODE_RELATIVE ? SDL_TRUE : SDL_FALSE); + // FIXME: This doesn't work; the OS cursor is visible in absolute mode for some reason. + SDL_ShowCursor(mouseCursorMode == MCURSORMODE_OS ? 1 : 0); } // System events @@ -751,7 +741,7 @@ int main(int argc, char* argv[]) if (s_curGame) { s_curGame->pauseGame(false); - TFE_Input::enableRelativeMode(true); + TFE_Input::setMouseCursorMode(MCURSORMODE_RELATIVE); } } else if (inputMapping_getActionState(IAS_CONSOLE) == STATE_PRESSED) @@ -760,7 +750,7 @@ int main(int argc, char* argv[]) if (s_curGame) { s_curGame->pauseGame(isOpening); - TFE_Input::enableRelativeMode(!isOpening); + TFE_Input::setMouseCursorMode(!isOpening ? MCURSORMODE_RELATIVE : MCURSORMODE_OS); } } else if (TFE_Input::keyPressed(KEY_F9) && TFE_Input::keyDown(KEY_LALT)) From e4669864711d9c952a4c36518f07c364247a956c Mon Sep 17 00:00:00 2001 From: "N.E.C" Date: Sun, 1 Jan 2023 17:01:32 -0800 Subject: [PATCH 04/13] Correctly position cursor in Agent and mission menu --- TheForceEngine/TFE_DarkForces/GameUI/menu.cpp | 39 +++++++++++-------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp b/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp index 48c309f4a..9c59d4c8b 100644 --- a/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp +++ b/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp @@ -55,23 +55,23 @@ namespace TFE_DarkForces DisplayInfo displayInfo; TFE_RenderBackend::getDisplayInfo(&displayInfo); - LRect bounds; - lcanvas_getBounds(&bounds); - s32 canvasWidth = bounds.right - bounds.left; - s32 canvasHeight = bounds.bottom - bounds.top; - - ScreenRect* uiRect = vfb_getScreenRect(VFB_RECT_UI); - fixed16_16 xScale = vfb_getXScale(); - fixed16_16 yScale = vfb_getYScale(); - - s32 virtualWidth = floor16(mul16(intToFixed16(320), xScale)); - s32 offset = max(0, ((uiRect->right - uiRect->left + 1) - virtualWidth) / 2); - - s32 right = offset + virtualWidth * displayInfo.width / canvasWidth; - s32 bot = displayInfo.height; - + // Assume the display rect is a 4:3 rectangle centered in the display frame. + // FIXME: This assumption might not be reliable in all scenarios. LRect result; - lrect_set(&result, offset, 0, right, bot); + if (displayInfo.height * 4 < displayInfo.width * 3) + { + // Display is wider than 4:3; Use pillarboxing + s32 displayedWidth = displayInfo.height * 4 / 3; + s32 left = (displayInfo.width - displayedWidth) / 2; + lrect_set(&result, left, 0, left + displayedWidth, displayInfo.height); + } + else + { + // Display is taller than 4:3; Use letterboxing + s32 displayedHeight = displayInfo.width * 3 / 4; + s32 top = (displayInfo.height - displayedHeight) / 2; + lrect_set(&result, 0, top, displayInfo.width, top + displayedHeight); + } return result; } @@ -126,6 +126,13 @@ namespace TFE_DarkForces void menu_blitCursor(s32 x, s32 y, u8* framebuffer) { + LRect bounds; + lcanvas_getBounds(&bounds); + if (x < bounds.left || x > bounds.right || y < bounds.top || y > bounds.bottom) + { + return; + } + blitDeltaFrame(&s_cursor, x, y, framebuffer); } From 641d3c19ebe4d22f999922580a6e33712319c4ef Mon Sep 17 00:00:00 2001 From: "N.E.C" Date: Sun, 1 Jan 2023 21:39:02 -0800 Subject: [PATCH 05/13] Fix OS cursor being shown when it shouldn't be visible --- TheForceEngine/main.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/TheForceEngine/main.cpp b/TheForceEngine/main.cpp index 7419a8861..fb074178f 100644 --- a/TheForceEngine/main.cpp +++ b/TheForceEngine/main.cpp @@ -36,6 +36,8 @@ // Replace with music system #include +#include "TFE_Ui/imGUI/imgui.h" + #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN 1 #include @@ -669,10 +671,12 @@ int main(int argc, char* argv[]) { mouseCursorMode = newMouseCursorMode; SDL_SetRelativeMouseMode(mouseCursorMode == MCURSORMODE_RELATIVE ? SDL_TRUE : SDL_FALSE); - // FIXME: This doesn't work; the OS cursor is visible in absolute mode for some reason. - SDL_ShowCursor(mouseCursorMode == MCURSORMODE_OS ? 1 : 0); + SDL_ShowCursor(mouseCursorMode == MCURSORMODE_OS ? SDL_ENABLE : SDL_DISABLE); } + // ImGui requires the cursor state to be set every frame, or else it will show the cursor by default. + ImGui::SetMouseCursor(mouseCursorMode == MCURSORMODE_OS ? ImGuiMouseCursor_Arrow : ImGuiMouseCursor_None); + // System events SDL_Event event; while (SDL_PollEvent(&event)) { handleEvent(event); } From acb372bb4170b6aea2f47e2f40a0438e386b256d Mon Sep 17 00:00:00 2001 From: "N.E.C" Date: Sun, 1 Jan 2023 21:44:41 -0800 Subject: [PATCH 06/13] Fix cursor not being set to absolute mode in PDA --- TheForceEngine/TFE_DarkForces/GameUI/pda.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TheForceEngine/TFE_DarkForces/GameUI/pda.cpp b/TheForceEngine/TFE_DarkForces/GameUI/pda.cpp index cb7559198..5b6fc4687 100644 --- a/TheForceEngine/TFE_DarkForces/GameUI/pda.cpp +++ b/TheForceEngine/TFE_DarkForces/GameUI/pda.cpp @@ -117,7 +117,7 @@ namespace TFE_DarkForces /////////////////////////////////////////// void pda_start(const char* levelName) { - TFE_Input::setMouseCursorMode(MCURSORMODE_RELATIVE); + TFE_Input::setMouseCursorMode(MCURSORMODE_ABSOLUTE); // TFE reticle_enable(false); From 80f763d39fc543dbce425b3859334d4f1bf7a3c1 Mon Sep 17 00:00:00 2001 From: "N.E.C" Date: Mon, 2 Jan 2023 20:09:29 -0800 Subject: [PATCH 07/13] Attempt to warp cursor to center when opening menu (this doesn't work); Better cursor positioning in escape menu (not perfect) --- .../TFE_DarkForces/GameUI/escapeMenu.cpp | 28 +++++++++++-------- TheForceEngine/TFE_DarkForces/GameUI/menu.cpp | 13 ++++++++- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.cpp b/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.cpp index f786ec248..cc0f745f5 100644 --- a/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.cpp +++ b/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.cpp @@ -1,5 +1,7 @@ #include +#include + #include "escapeMenu.h" #include "delt.h" #include "uiDraw.h" @@ -718,9 +720,18 @@ namespace TFE_DarkForces DisplayInfo displayInfo; TFE_RenderBackend::getDisplayInfo(&displayInfo); - s_emState.cursorPosAccum = { (s32)displayInfo.width >> 1, (s32)displayInfo.height >> 1 }; + s_emState.cursorPosAccum = { (s32)displayInfo.width / 2, (s32)displayInfo.height / 2 }; s_emState.cursorPos.x = clamp(s_emState.cursorPosAccum.x * (s32)height / (s32)displayInfo.height, 0, (s32)width - 3); s_emState.cursorPos.z = clamp(s_emState.cursorPosAccum.z * (s32)height / (s32)displayInfo.height, 0, (s32)height - 3); + + // FIXME: this doesn't center the cursor correctly + SDL_WarpMouseInWindow(NULL, s_emState.cursorPos.x, s_emState.cursorPos.z); + } + + // Smoothly interpolate a value in range x0..x1 to a new value in range y0..y1. + static s32 interpolate(s32 value, s32 x0, s32 x1, s32 y0, s32 y1) + { + return y0 + (value - x0) * (y1 - y0) / (x1 - x0); } void escMenu_handleMousePosition() @@ -740,16 +751,9 @@ namespace TFE_DarkForces s32 mx, my; TFE_Input::getMousePos(&mx, &my); s_emState.cursorPosAccum = { mx, my }; - - if (displayInfo.width >= displayInfo.height) - { - s_emState.cursorPos.x = clamp(s_emState.cursorPosAccum.x * (s32)height / (s32)displayInfo.height, 0, (s32)width - 3); - s_emState.cursorPos.z = clamp(s_emState.cursorPosAccum.z * (s32)height / (s32)displayInfo.height, 0, (s32)height - 3); - } - else - { - s_emState.cursorPos.x = clamp(s_emState.cursorPosAccum.x * (s32)width / (s32)displayInfo.width, 0, (s32)width - 3); - s_emState.cursorPos.z = clamp(s_emState.cursorPosAccum.z * (s32)width / (s32)displayInfo.width, 0, (s32)height - 3); - } + s_emState.cursorPos = { + interpolate(mx, 0, displayInfo.width, 0, width), + interpolate(my, 0, displayInfo.height, 0, height), + }; } } \ No newline at end of file diff --git a/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp b/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp index 9c59d4c8b..7e775fbc8 100644 --- a/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp +++ b/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp @@ -1,5 +1,7 @@ #include +#include + #include "menu.h" #include "delt.h" #include "uiDraw.h" @@ -112,9 +114,18 @@ namespace TFE_DarkForces DisplayInfo displayInfo; TFE_RenderBackend::getDisplayInfo(&displayInfo); - s_cursorPosAccum = { (s32)displayInfo.width >> 1, (s32)displayInfo.height >> 1 }; + s_cursorPosAccum = { (s32)displayInfo.width / 2, (s32)displayInfo.height / 2 }; s_cursorPos.x = clamp(s_cursorPosAccum.x * (s32)height / (s32)displayInfo.height, 0, (s32)width - 3); s_cursorPos.z = clamp(s_cursorPosAccum.z * (s32)height / (s32)displayInfo.height, 0, (s32)height - 3); + + LRect bounds; + lcanvas_getBounds(&bounds); + + LRect displayRect = menu_getDisplayRect(); + SDL_WarpMouseInWindow(NULL, + interpolate(s_cursorPos.x, bounds.left, bounds.right, displayRect.left, displayRect.right), + interpolate(s_cursorPos.z, bounds.top, bounds.bottom, displayRect.top, displayRect.bottom) + ); } u8* menu_startupDisplay() From 7b6b876ed7c25f47c1ee600a83dfec00a7e5e005 Mon Sep 17 00:00:00 2001 From: "N.E.C" Date: Tue, 3 Jan 2023 17:54:51 -0800 Subject: [PATCH 08/13] Fix cursor positioning in escape menu (probably breaks in widescreen mode) --- .../TFE_DarkForces/GameUI/escapeMenu.cpp | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.cpp b/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.cpp index cc0f745f5..d1eba0b23 100644 --- a/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.cpp +++ b/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -728,6 +729,33 @@ namespace TFE_DarkForces SDL_WarpMouseInWindow(NULL, s_emState.cursorPos.x, s_emState.cursorPos.z); } + // Get bounds of menu in display coordinates + static LRect escMenu_getDisplayRect() + { + DisplayInfo displayInfo; + TFE_RenderBackend::getDisplayInfo(&displayInfo); + + // Assume the display rect is a 4:3 rectangle centered in the display frame. + // FIXME: This assumption might not be reliable in all scenarios. + // This will probably break in widescreen mode. Where is the function to get the actual display rect?? + LRect result; + if (displayInfo.height * 4 < displayInfo.width * 3) + { + // Display is wider than 4:3; Use pillarboxing + s32 displayedWidth = displayInfo.height * 4 / 3; + s32 left = (displayInfo.width - displayedWidth) / 2; + lrect_set(&result, left, 0, left + displayedWidth, displayInfo.height); + } + else + { + // Display is taller than 4:3; Use letterboxing + s32 displayedHeight = displayInfo.width * 3 / 4; + s32 top = (displayInfo.height - displayedHeight) / 2; + lrect_set(&result, 0, top, displayInfo.width, top + displayedHeight); + } + return result; + } + // Smoothly interpolate a value in range x0..x1 to a new value in range y0..y1. static s32 interpolate(s32 value, s32 x0, s32 x1, s32 y0, s32 y1) { @@ -748,12 +776,14 @@ namespace TFE_DarkForces MonitorInfo monitorInfo; TFE_RenderBackend::getCurrentMonitorInfo(&monitorInfo); + LRect displayRect = escMenu_getDisplayRect(); + s32 mx, my; TFE_Input::getMousePos(&mx, &my); s_emState.cursorPosAccum = { mx, my }; s_emState.cursorPos = { - interpolate(mx, 0, displayInfo.width, 0, width), - interpolate(my, 0, displayInfo.height, 0, height), + interpolate(mx, displayRect.left, displayRect.right, 0, width), + interpolate(my, displayRect.top, displayRect.bottom, 0, height), }; } } \ No newline at end of file From 4f545da9d41233bda179d8cadbf41b9b4c1cf3c0 Mon Sep 17 00:00:00 2001 From: "N.E.C" Date: Tue, 3 Jan 2023 18:15:37 -0800 Subject: [PATCH 09/13] Don't draw cursor when mouse leaves window --- TheForceEngine/TFE_DarkForces/GameUI/agentMenu.cpp | 5 ++++- TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.cpp | 11 +++++++---- .../TFE_DarkForces/GameUI/missionBriefing.cpp | 5 ++++- TheForceEngine/TFE_DarkForces/GameUI/pda.cpp | 5 ++++- TheForceEngine/TFE_Input/input.cpp | 11 +++++++++++ TheForceEngine/TFE_Input/input.h | 2 ++ TheForceEngine/TFE_Ui/ui.cpp | 5 +++++ TheForceEngine/TFE_Ui/ui.h | 3 +++ TheForceEngine/main.cpp | 1 + 9 files changed, 41 insertions(+), 7 deletions(-) diff --git a/TheForceEngine/TFE_DarkForces/GameUI/agentMenu.cpp b/TheForceEngine/TFE_DarkForces/GameUI/agentMenu.cpp index 27bb793a4..878642530 100644 --- a/TheForceEngine/TFE_DarkForces/GameUI/agentMenu.cpp +++ b/TheForceEngine/TFE_DarkForces/GameUI/agentMenu.cpp @@ -486,7 +486,10 @@ namespace TFE_DarkForces void agentMenu_blit() { setPalette(); - menu_blitCursor(s_cursorPos.x, s_cursorPos.z, s_framebuffer); + if (TFE_Input::isMouseInWindow()) + { + menu_blitCursor(s_cursorPos.x, s_cursorPos.z, s_framebuffer); + } menu_blitToScreen(s_framebuffer); } diff --git a/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.cpp b/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.cpp index d1eba0b23..21bc4d35f 100644 --- a/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.cpp +++ b/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.cpp @@ -368,7 +368,7 @@ namespace TFE_DarkForces } // Draw the mouse. - if (drawMouse) + if (drawMouse && TFE_Input::isMouseInWindow()) { screenGPU_blitTextureScaled(&s_cursor.texture, nullptr, intToFixed16(s_emState.cursorPos.x), intToFixed16(s_emState.cursorPos.z), xScale, yScale, 31); } @@ -438,8 +438,11 @@ namespace TFE_DarkForces blitDeltaFrame(&s_emState.confirmMenuFrames[s_emState.buttonPressed == CONFIRM_NO ? CONFIRM_QUIT_NOBTN_DOWN : CONFIRM_QUIT_NOBTN_UP], 0, 0, s_emState.framebuffer); } - // Draw the mouse. - blitDeltaFrame(&s_cursor, s_emState.cursorPos.x, s_emState.cursorPos.z, s_emState.framebuffer); + if (drawMouse && TFE_Input::isMouseInWindow()) + { + // Draw the mouse. + blitDeltaFrame(&s_cursor, s_emState.cursorPos.x, s_emState.cursorPos.z, s_emState.framebuffer); + } } else { @@ -503,7 +506,7 @@ namespace TFE_DarkForces } // Draw the mouse. - if (drawMouse) + if (drawMouse && TFE_Input::isMouseInWindow()) { blitDeltaFrameScaled(&s_cursor, s_emState.cursorPos.x, s_emState.cursorPos.z, xScale, yScale, s_emState.framebuffer); } diff --git a/TheForceEngine/TFE_DarkForces/GameUI/missionBriefing.cpp b/TheForceEngine/TFE_DarkForces/GameUI/missionBriefing.cpp index 9dfd8c2da..68055106b 100644 --- a/TheForceEngine/TFE_DarkForces/GameUI/missionBriefing.cpp +++ b/TheForceEngine/TFE_DarkForces/GameUI/missionBriefing.cpp @@ -420,7 +420,10 @@ namespace TFE_DarkForces lactorDelt_draw(s_briefActor, &rect, &s_missionTextRect, x, y, JTRUE); lcanvas_clearClipRect(); - menu_blitCursor(s_cursorPos.x, s_cursorPos.z, s_framebuffer); + if (TFE_Input::isMouseInWindow()) + { + menu_blitCursor(s_cursorPos.x, s_cursorPos.z, s_framebuffer); + } menu_blitToScreen(); return JTRUE; } diff --git a/TheForceEngine/TFE_DarkForces/GameUI/pda.cpp b/TheForceEngine/TFE_DarkForces/GameUI/pda.cpp index 5b6fc4687..73703173e 100644 --- a/TheForceEngine/TFE_DarkForces/GameUI/pda.cpp +++ b/TheForceEngine/TFE_DarkForces/GameUI/pda.cpp @@ -316,7 +316,10 @@ namespace TFE_DarkForces // Doing that we need to restore the transparent color before blitting the mouse cursor, otherwise its black edges will // show up incorrectly. screenDraw_setTransColor(0); - menu_blitCursorScaled(s_cursorPos.x, s_cursorPos.z, vfb_getCpuBuffer()); + if (TFE_Input::isMouseInWindow()) + { + menu_blitCursorScaled(s_cursorPos.x, s_cursorPos.z, vfb_getCpuBuffer()); + } vfb_swap(); } diff --git a/TheForceEngine/TFE_Input/input.cpp b/TheForceEngine/TFE_Input/input.cpp index 45079bcef..c3d70cf0e 100644 --- a/TheForceEngine/TFE_Input/input.cpp +++ b/TheForceEngine/TFE_Input/input.cpp @@ -26,6 +26,7 @@ namespace TFE_Input u8 s_mouseDown[MBUTTON_COUNT] = { 0 }; u8 s_mousePressed[MBUTTON_COUNT] = { 0 }; + bool s_mouseInWindow = true; s32 s_mouseWheel[2] = { 0 }; s32 s_mouseMove[2] = { 0 }; s32 s_mouseMoveAccum[2] = { 0 }; @@ -122,6 +123,11 @@ namespace TFE_Input s_mouseWheel[1] = dy; } + void setMouseInWindow(bool mouseInWindow) + { + s_mouseInWindow = mouseInWindow; + } + void setRelativeMousePos(s32 x, s32 y) { s_mouseMove[0] = x; @@ -191,6 +197,11 @@ namespace TFE_Input s_mouseMoveAccum[1] = 0; } + bool isMouseInWindow() + { + return s_mouseInWindow; + } + void getMousePos(s32* x, s32* y) { assert(x && y); diff --git a/TheForceEngine/TFE_Input/input.h b/TheForceEngine/TFE_Input/input.h index 770685642..e8193305a 100644 --- a/TheForceEngine/TFE_Input/input.h +++ b/TheForceEngine/TFE_Input/input.h @@ -32,6 +32,7 @@ namespace TFE_Input void setMouseButtonUp(MouseButton button); void setMouseWheel(s32 dx, s32 dy); + void setMouseInWindow(bool mouseInWindow); void setRelativeMousePos(s32 x, s32 y); void setMousePos(s32 x, s32 y); @@ -45,6 +46,7 @@ namespace TFE_Input f32 getAxis(Axis axis); void getMouseMove(s32* x, s32* y); void getAccumulatedMouseMove(s32* x, s32* y); + bool isMouseInWindow(); void getMousePos(s32* x, s32* y); void getMouseWheel(s32* dx, s32* dy); bool buttonDown(Button button); diff --git a/TheForceEngine/TFE_Ui/ui.cpp b/TheForceEngine/TFE_Ui/ui.cpp index 0ca5c8eb2..54f57377d 100644 --- a/TheForceEngine/TFE_Ui/ui.cpp +++ b/TheForceEngine/TFE_Ui/ui.cpp @@ -67,6 +67,11 @@ void shutdown() ImGui::DestroyContext(); } +SDL_Window* getSDLWindow() +{ + return s_window; +} + void setUiScale(s32 scale) { s_uiScale = scale; diff --git a/TheForceEngine/TFE_Ui/ui.h b/TheForceEngine/TFE_Ui/ui.h index 2a1029e6a..efac6cb7f 100644 --- a/TheForceEngine/TFE_Ui/ui.h +++ b/TheForceEngine/TFE_Ui/ui.h @@ -18,6 +18,8 @@ typedef std::vector FileResult; +struct SDL_Window; + namespace TFE_Ui { bool init(void* window, void* context, s32 uiScale = 100); @@ -27,6 +29,7 @@ namespace TFE_Ui void begin(); void render(); + SDL_Window* getSDLWindow(); void setUiScale(s32 scale); s32 getUiScale(); diff --git a/TheForceEngine/main.cpp b/TheForceEngine/main.cpp index fb074178f..b9da4a8f1 100644 --- a/TheForceEngine/main.cpp +++ b/TheForceEngine/main.cpp @@ -682,6 +682,7 @@ int main(int argc, char* argv[]) while (SDL_PollEvent(&event)) { handleEvent(event); } // Handle mouse state. + TFE_Input::setMouseInWindow(SDL_GetMouseFocus() == TFE_Ui::getSDLWindow()); s32 mouseX, mouseY; s32 mouseAbsX, mouseAbsY; u32 state = SDL_GetRelativeMouseState(&mouseX, &mouseY); From 8d6eed57d2bf7fb2eb08900f0165d6ce7507ab0c Mon Sep 17 00:00:00 2001 From: "N.E.C" Date: Tue, 3 Jan 2023 18:42:12 -0800 Subject: [PATCH 10/13] Use absolute mouse mode by default; Cursor can now leave window during cutscenes --- TheForceEngine/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TheForceEngine/main.cpp b/TheForceEngine/main.cpp index b9da4a8f1..baaef3613 100644 --- a/TheForceEngine/main.cpp +++ b/TheForceEngine/main.cpp @@ -355,7 +355,7 @@ void setAppState(AppState newState, int argc, char* argv[]) } else { - TFE_Input::setMouseCursorMode(MCURSORMODE_RELATIVE); + TFE_Input::setMouseCursorMode(MCURSORMODE_ABSOLUTE); } } else @@ -392,7 +392,7 @@ void setAppState(AppState newState, int argc, char* argv[]) } else { - TFE_Input::setMouseCursorMode(MCURSORMODE_RELATIVE); + TFE_Input::setMouseCursorMode(MCURSORMODE_ABSOLUTE); } } } From a9afca70f1cce133f054dc58c951a520e5a8a0af Mon Sep 17 00:00:00 2001 From: "N.E.C" Date: Wed, 4 Jan 2023 15:38:10 -0800 Subject: [PATCH 11/13] Factor out display rect calculation to new function in render backend --- .../TFE_DarkForces/GameUI/escapeMenu.cpp | 38 ++---------------- TheForceEngine/TFE_DarkForces/GameUI/menu.cpp | 39 ++----------------- TheForceEngine/TFE_DarkForces/Landru/lrect.h | 1 + TheForceEngine/TFE_Jedi/Math/core_math.h | 6 +++ .../Win32OpenGL/renderBackend.cpp | 20 ++++++++-- .../TFE_RenderBackend/renderBackend.h | 4 ++ 6 files changed, 35 insertions(+), 73 deletions(-) diff --git a/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.cpp b/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.cpp index 21bc4d35f..ab36c12f1 100644 --- a/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.cpp +++ b/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.cpp @@ -21,6 +21,7 @@ #include #include #include +#include using namespace TFE_Jedi; using namespace TFE_Input; @@ -729,40 +730,7 @@ namespace TFE_DarkForces s_emState.cursorPos.z = clamp(s_emState.cursorPosAccum.z * (s32)height / (s32)displayInfo.height, 0, (s32)height - 3); // FIXME: this doesn't center the cursor correctly - SDL_WarpMouseInWindow(NULL, s_emState.cursorPos.x, s_emState.cursorPos.z); - } - - // Get bounds of menu in display coordinates - static LRect escMenu_getDisplayRect() - { - DisplayInfo displayInfo; - TFE_RenderBackend::getDisplayInfo(&displayInfo); - - // Assume the display rect is a 4:3 rectangle centered in the display frame. - // FIXME: This assumption might not be reliable in all scenarios. - // This will probably break in widescreen mode. Where is the function to get the actual display rect?? - LRect result; - if (displayInfo.height * 4 < displayInfo.width * 3) - { - // Display is wider than 4:3; Use pillarboxing - s32 displayedWidth = displayInfo.height * 4 / 3; - s32 left = (displayInfo.width - displayedWidth) / 2; - lrect_set(&result, left, 0, left + displayedWidth, displayInfo.height); - } - else - { - // Display is taller than 4:3; Use letterboxing - s32 displayedHeight = displayInfo.width * 3 / 4; - s32 top = (displayInfo.height - displayedHeight) / 2; - lrect_set(&result, 0, top, displayInfo.width, top + displayedHeight); - } - return result; - } - - // Smoothly interpolate a value in range x0..x1 to a new value in range y0..y1. - static s32 interpolate(s32 value, s32 x0, s32 x1, s32 y0, s32 y1) - { - return y0 + (value - x0) * (y1 - y0) / (x1 - x0); + SDL_WarpMouseInWindow(TFE_Ui::getSDLWindow(), s_emState.cursorPos.x, s_emState.cursorPos.z); } void escMenu_handleMousePosition() @@ -779,7 +747,7 @@ namespace TFE_DarkForces MonitorInfo monitorInfo; TFE_RenderBackend::getCurrentMonitorInfo(&monitorInfo); - LRect displayRect = escMenu_getDisplayRect(); + LRect displayRect = TFE_RenderBackend::calcDisplayRect(); s32 mx, my; TFE_Input::getMousePos(&mx, &my); diff --git a/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp b/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp index 7e775fbc8..54403cc6c 100644 --- a/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp +++ b/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp @@ -19,6 +19,7 @@ #include #include #include +#include using namespace TFE_Jedi; @@ -50,38 +51,6 @@ namespace TFE_DarkForces { delt_resetState(); } - - // Get bounds of menu in display coordinates - static LRect menu_getDisplayRect() - { - DisplayInfo displayInfo; - TFE_RenderBackend::getDisplayInfo(&displayInfo); - - // Assume the display rect is a 4:3 rectangle centered in the display frame. - // FIXME: This assumption might not be reliable in all scenarios. - LRect result; - if (displayInfo.height * 4 < displayInfo.width * 3) - { - // Display is wider than 4:3; Use pillarboxing - s32 displayedWidth = displayInfo.height * 4 / 3; - s32 left = (displayInfo.width - displayedWidth) / 2; - lrect_set(&result, left, 0, left + displayedWidth, displayInfo.height); - } - else - { - // Display is taller than 4:3; Use letterboxing - s32 displayedHeight = displayInfo.width * 3 / 4; - s32 top = (displayInfo.height - displayedHeight) / 2; - lrect_set(&result, 0, top, displayInfo.width, top + displayedHeight); - } - return result; - } - - // Smoothly interpolate a value in range x0..x1 to a new value in range y0..y1. - static s32 interpolate(s32 value, s32 x0, s32 x1, s32 y0, s32 y1) - { - return y0 + (value - x0) * (y1 - y0) / (x1 - x0); - } void menu_handleMousePosition() { @@ -93,7 +62,7 @@ namespace TFE_DarkForces s32 width = bounds.right - bounds.left; s32 height = bounds.bottom - bounds.top; - LRect displayRect = menu_getDisplayRect(); + LRect displayRect = TFE_RenderBackend::calcDisplayRect(); s32 mx, my; TFE_Input::getMousePos(&mx, &my); @@ -121,8 +90,8 @@ namespace TFE_DarkForces LRect bounds; lcanvas_getBounds(&bounds); - LRect displayRect = menu_getDisplayRect(); - SDL_WarpMouseInWindow(NULL, + LRect displayRect = TFE_RenderBackend::calcDisplayRect(); + SDL_WarpMouseInWindow(TFE_Ui::getSDLWindow(), interpolate(s_cursorPos.x, bounds.left, bounds.right, displayRect.left, displayRect.right), interpolate(s_cursorPos.z, bounds.top, bounds.bottom, displayRect.top, displayRect.bottom) ); diff --git a/TheForceEngine/TFE_DarkForces/Landru/lrect.h b/TheForceEngine/TFE_DarkForces/Landru/lrect.h index b557065d2..28852a273 100644 --- a/TheForceEngine/TFE_DarkForces/Landru/lrect.h +++ b/TheForceEngine/TFE_DarkForces/Landru/lrect.h @@ -16,6 +16,7 @@ namespace TFE_DarkForces LEXTENT }; + // A rectangle. The top left is inclusive and the bottom right is exclusive. struct LRect { s16 top; diff --git a/TheForceEngine/TFE_Jedi/Math/core_math.h b/TheForceEngine/TFE_Jedi/Math/core_math.h index eda4aa074..7635faed7 100644 --- a/TheForceEngine/TFE_Jedi/Math/core_math.h +++ b/TheForceEngine/TFE_Jedi/Math/core_math.h @@ -57,6 +57,12 @@ namespace TFE_Jedi b = tmp; } + // Smoothly interpolate a value in range x0..x1 to a new value in range y0..y1. + inline s32 interpolate(s32 value, s32 x0, s32 x1, s32 y0, s32 y1) + { + return y0 + (value - x0) * (y1 - y0) / (x1 - x0); + } + inline s32 sign(s32 x) { return x < 0 ? -1 : 1; diff --git a/TheForceEngine/TFE_RenderBackend/Win32OpenGL/renderBackend.cpp b/TheForceEngine/TFE_RenderBackend/Win32OpenGL/renderBackend.cpp index 5d2c28614..5e1405f38 100644 --- a/TheForceEngine/TFE_RenderBackend/Win32OpenGL/renderBackend.cpp +++ b/TheForceEngine/TFE_RenderBackend/Win32OpenGL/renderBackend.cpp @@ -722,9 +722,7 @@ namespace TFE_RenderBackend glDrawArrays(GL_LINES, 0, lineCount * 2); } - // Setup the Post effect chain based on current settings. - // TODO: Move out of render backend since this should be independent of the backend. - void setupPostEffectChain(bool useDynamicTexture) + TFE_DarkForces::LRect calcDisplayRect() { s32 x = 0, y = 0; s32 w = m_windowState.width; @@ -753,6 +751,22 @@ namespace TFE_RenderBackend // letterbox y = std::max(0, ((s32)m_windowState.height - h) / 2); } + + TFE_DarkForces::LRect result; + TFE_DarkForces::lrect_set(&result, x, y, x + w, y + h); + return result; + } + + // Setup the Post effect chain based on current settings. + // TODO: Move out of render backend since this should be independent of the backend. + void setupPostEffectChain(bool useDynamicTexture) + { + TFE_DarkForces::LRect displayRect = calcDisplayRect(); + s32 x = displayRect.left; + s32 y = displayRect.top; + s32 w = displayRect.right - displayRect.left; + s32 h = displayRect.bottom - displayRect.top; + TFE_PostProcess::clearEffectStack(); if (useDynamicTexture) diff --git a/TheForceEngine/TFE_RenderBackend/renderBackend.h b/TheForceEngine/TFE_RenderBackend/renderBackend.h index 97dc57b80..78c03d4fd 100644 --- a/TheForceEngine/TFE_RenderBackend/renderBackend.h +++ b/TheForceEngine/TFE_RenderBackend/renderBackend.h @@ -13,6 +13,7 @@ #include #include #include +#include enum WindowFlags { @@ -163,4 +164,7 @@ namespace TFE_RenderBackend // Generic line draw. void drawLines(u32 lineCount); + + // Get rectangle of displayed image relative to window. + TFE_DarkForces::LRect calcDisplayRect(); }; From f295abce410c1776631d99ff46f5ed91760fdddb Mon Sep 17 00:00:00 2001 From: "N.E.C" Date: Mon, 16 Jan 2023 23:00:11 -0800 Subject: [PATCH 12/13] Fix compile error --- TheForceEngine/TFE_FrontEndUI/frontEndUi.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/TheForceEngine/TFE_FrontEndUI/frontEndUi.cpp b/TheForceEngine/TFE_FrontEndUI/frontEndUi.cpp index 488328669..09e636223 100644 --- a/TheForceEngine/TFE_FrontEndUI/frontEndUi.cpp +++ b/TheForceEngine/TFE_FrontEndUI/frontEndUi.cpp @@ -442,8 +442,7 @@ namespace TFE_FrontEndUI s_drawNoGameDataMsg = false; s_appState = APP_STATE_EXIT_TO_MENU; s_selectedModCmd[0] = 0; - s_relativeMode = false; - TFE_Input::enableRelativeMode(s_relativeMode); + TFE_Input::setMouseCursorMode(MCURSORMODE_OS); if (TFE_Settings::getSystemSettings()->returnToModLoader && s_modLoaded) { From 9dc3ec78e7db8a0112d372eba01ad3027a48a080 Mon Sep 17 00:00:00 2001 From: "N.E.C" Date: Sun, 29 Jan 2023 21:14:33 -0800 Subject: [PATCH 13/13] Fix compiler errors after merge --- TheForceEngine/TFE_DarkForces/mission.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TheForceEngine/TFE_DarkForces/mission.cpp b/TheForceEngine/TFE_DarkForces/mission.cpp index 9352bef32..cb3c5eb09 100644 --- a/TheForceEngine/TFE_DarkForces/mission.cpp +++ b/TheForceEngine/TFE_DarkForces/mission.cpp @@ -152,7 +152,7 @@ namespace TFE_DarkForces s_queuedCheatID = CHEAT_##c ; \ TFE_FrontEndUI::toggleConsole(); \ mission_pause(JFALSE); \ - TFE_Input::enableRelativeMode(true); \ + TFE_Input:setMouseCursorMode(MCURSORMODE_RELATIVE); \ } CHEAT_CMD(LACDS); CHEAT_CMD(LANTFH);