diff --git a/TheForceEngine/TFE_DarkForces/GameUI/agentMenu.cpp b/TheForceEngine/TFE_DarkForces/GameUI/agentMenu.cpp index 82808c720..6c2e7e71d 100644 --- a/TheForceEngine/TFE_DarkForces/GameUI/agentMenu.cpp +++ b/TheForceEngine/TFE_DarkForces/GameUI/agentMenu.cpp @@ -497,7 +497,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 2e6dea7a7..c63850738 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" @@ -7,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -18,6 +21,7 @@ #include #include #include +#include using namespace TFE_Jedi; using namespace TFE_Input; @@ -237,6 +241,8 @@ namespace TFE_DarkForces void escapeMenu_open(u8* framebuffer, u8* palette) { + TFE_Input::setMouseCursorMode(MCURSORMODE_ABSOLUTE); + // TFE reticle_enable(false); @@ -256,13 +262,20 @@ namespace TFE_DarkForces s_emState.escMenuOpen = JFALSE; } - void escapeMenu_close() + void escapeMenu_close(EscapeMenuAction action) { s_emState.escMenuOpen = JFALSE; + // Avoid sound pops due to buffered sound when returning to the Agent or Main menu. + if (!s_levelComplete || action != ESC_ABORT_OR_NEXT) + { + clearBufferedSound(); + } resumeLevelSound(); // TFE reticle_enable(true); + + TFE_Input::setMouseCursorMode(MCURSORMODE_RELATIVE); } JBool escapeMenu_isOpen() @@ -375,7 +388,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); } @@ -445,8 +458,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 { @@ -510,7 +526,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); } @@ -524,16 +540,7 @@ namespace TFE_DarkForces EscapeMenuAction action = escapeMenu_updateUI(); if (action != ESC_CONTINUE) { - s_emState.escMenuOpen = JFALSE; - // Avoid sound pops due to buffered sound when returning to the Agent or Main menu. - if (!s_levelComplete || action != ESC_ABORT_OR_NEXT) - { - clearBufferedSound(); - } - resumeLevelSound(); - - // TFE - reticle_enable(true); + escapeMenu_close(action); } escapeMenu_draw(JTRUE, JTRUE); @@ -739,9 +746,12 @@ 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(TFE_Ui::getSDLWindow(), s_emState.cursorPos.x, s_emState.cursorPos.z); } void escMenu_handleMousePosition() @@ -758,19 +768,14 @@ namespace TFE_DarkForces MonitorInfo monitorInfo; TFE_RenderBackend::getCurrentMonitorInfo(&monitorInfo); + LRect displayRect = TFE_RenderBackend::calcDisplayRect(); + 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, displayRect.left, displayRect.right, 0, width), + interpolate(my, displayRect.top, displayRect.bottom, 0, height), + }; } } \ No newline at end of file diff --git a/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.h b/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.h index c004d0be9..19890371c 100644 --- a/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.h +++ b/TheForceEngine/TFE_DarkForces/GameUI/escapeMenu.h @@ -24,7 +24,7 @@ namespace TFE_DarkForces // Opens the escape menu, which sets up the background. void escapeMenu_open(u8* framebuffer, u8* palette); - void escapeMenu_close(); + void escapeMenu_close(EscapeMenuAction action); void escapeMenu_resetLevel(); // Returns JTRUE if the escape menu is open. diff --git a/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp b/TheForceEngine/TFE_DarkForces/GameUI/menu.cpp index 4f9ad4833..54403cc6c 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" @@ -17,6 +19,7 @@ #include #include #include +#include using namespace TFE_Jedi; @@ -59,20 +62,16 @@ namespace TFE_DarkForces s32 width = bounds.right - bounds.left; s32 height = bounds.bottom - bounds.top; + LRect displayRect = TFE_RenderBackend::calcDisplayRect(); + s32 mx, my; TFE_Input::getMousePos(&mx, &my); - 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); - } + 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; } void menu_resetCursor() @@ -84,19 +83,36 @@ 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 = 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) + ); } u8* menu_startupDisplay() { + TFE_Input::setMouseCursorMode(MCURSORMODE_ABSOLUTE); vfb_setResolution(320, 200); return vfb_getCpuBuffer(); } 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); } diff --git a/TheForceEngine/TFE_DarkForces/GameUI/missionBriefing.cpp b/TheForceEngine/TFE_DarkForces/GameUI/missionBriefing.cpp index 82ecdb8c2..31dd60f7e 100644 --- a/TheForceEngine/TFE_DarkForces/GameUI/missionBriefing.cpp +++ b/TheForceEngine/TFE_DarkForces/GameUI/missionBriefing.cpp @@ -427,7 +427,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 5fe716a64..98d3ef2f3 100644 --- a/TheForceEngine/TFE_DarkForces/GameUI/pda.cpp +++ b/TheForceEngine/TFE_DarkForces/GameUI/pda.cpp @@ -120,6 +120,8 @@ namespace TFE_DarkForces /////////////////////////////////////////// void pda_start(const char* levelName) { + TFE_Input::setMouseCursorMode(MCURSORMODE_ABSOLUTE); + // TFE reticle_enable(false); s_mouseAccum = { 0 }; @@ -243,6 +245,8 @@ namespace TFE_DarkForces TFE_Jedi::renderer_setType(RendererType(graphics->rendererIndex)); TFE_Jedi::renderer_setLimits(); } + + TFE_Input::setMouseCursorMode(MCURSORMODE_RELATIVE); } void pda_update() @@ -316,7 +320,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_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_DarkForces/darkForcesMain.cpp b/TheForceEngine/TFE_DarkForces/darkForcesMain.cpp index 959ee125b..9353311a7 100644 --- a/TheForceEngine/TFE_DarkForces/darkForcesMain.cpp +++ b/TheForceEngine/TFE_DarkForces/darkForcesMain.cpp @@ -753,6 +753,8 @@ namespace TFE_DarkForces } break; case GMODE_MISSION: { + TFE_Input::setMouseCursorMode(MCURSORMODE_RELATIVE); + sound_levelStart(); bitmap_setAllocator(s_levelRegion); diff --git a/TheForceEngine/TFE_DarkForces/mission.cpp b/TheForceEngine/TFE_DarkForces/mission.cpp index f52793561..c175e6bae 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); } #define CHEAT_CMD(c) \ @@ -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); diff --git a/TheForceEngine/TFE_FrontEndUI/frontEndUi.cpp b/TheForceEngine/TFE_FrontEndUI/frontEndUi.cpp index da42a76e1..0b3fa9120 100644 --- a/TheForceEngine/TFE_FrontEndUI/frontEndUi.cpp +++ b/TheForceEngine/TFE_FrontEndUI/frontEndUi.cpp @@ -176,7 +176,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; @@ -272,7 +272,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; char fontpath[TFE_MAX_PATH]; @@ -361,8 +361,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(); } @@ -382,7 +382,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; @@ -460,8 +460,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) { @@ -550,7 +549,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. @@ -848,7 +846,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)) @@ -1228,7 +1226,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 15554d8d8..5cf071ff9 100644 --- a/TheForceEngine/TFE_Input/input.cpp +++ b/TheForceEngine/TFE_Input/input.cpp @@ -26,12 +26,13 @@ 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 }; s32 s_mousePos[2] = { 0 }; - bool s_relativeMode = false; + MouseCursorMode s_mouseCursorMode = MCURSORMODE_OS; static const char* const* s_controllerAxisNames; static const char* const* s_controllerButtonNames; @@ -116,6 +117,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; @@ -130,9 +136,9 @@ namespace TFE_Input s_mousePos[1] = y; } - void enableRelativeMode(bool enable) + void setMouseCursorMode(MouseCursorMode mode) { - s_relativeMode = enable; + s_mouseCursorMode = mode; } // Buffered Input @@ -185,6 +191,11 @@ namespace TFE_Input s_mouseMoveAccum[1] = 0; } + bool isMouseInWindow() + { + return s_mouseInWindow; + } + void getMousePos(s32* x, s32* y) { assert(x && y); @@ -319,9 +330,9 @@ namespace TFE_Input return s_mousePressed[button] != 0; } - bool relativeModeEnabled() + MouseCursorMode getMouseCursorMode() { - return s_relativeMode; + return s_mouseCursorMode; } // Buffered Input diff --git a/TheForceEngine/TFE_Input/input.h b/TheForceEngine/TFE_Input/input.h index 64326c16d..74c0a579a 100644 --- a/TheForceEngine/TFE_Input/input.h +++ b/TheForceEngine/TFE_Input/input.h @@ -32,10 +32,11 @@ 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); - void enableRelativeMode(bool enable); + void setMouseCursorMode(MouseCursorMode mode); // Buffered Input void setBufferedInput(const char* text); @@ -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); @@ -54,7 +56,7 @@ namespace TFE_Input bool keyModDown(KeyModifier keyMod, bool allowAltOnNone = false); bool mouseDown(MouseButton button); bool mousePressed(MouseButton button); - bool relativeModeEnabled(); + 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/TFE_Jedi/Math/core_math.h b/TheForceEngine/TFE_Jedi/Math/core_math.h index 31c67c88d..af2d316a5 100644 --- a/TheForceEngine/TFE_Jedi/Math/core_math.h +++ b/TheForceEngine/TFE_Jedi/Math/core_math.h @@ -67,6 +67,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 af06fd434..966e70679 100644 --- a/TheForceEngine/TFE_RenderBackend/Win32OpenGL/renderBackend.cpp +++ b/TheForceEngine/TFE_RenderBackend/Win32OpenGL/renderBackend.cpp @@ -732,9 +732,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; @@ -763,6 +761,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(); }; diff --git a/TheForceEngine/TFE_Ui/ui.cpp b/TheForceEngine/TFE_Ui/ui.cpp index d0d4b7a87..b15a65de6 100644 --- a/TheForceEngine/TFE_Ui/ui.cpp +++ b/TheForceEngine/TFE_Ui/ui.cpp @@ -70,6 +70,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 dcc219654..c045c3c77 100644 --- a/TheForceEngine/main.cpp +++ b/TheForceEngine/main.cpp @@ -37,6 +37,8 @@ // Replace with music system #include +#include "TFE_Ui/imGUI/imgui.h" + #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN 1 #include @@ -354,7 +356,7 @@ void setAppState(AppState newState, int argc, char* argv[]) } else { - TFE_Input::enableRelativeMode(true); + TFE_Input::setMouseCursorMode(MCURSORMODE_ABSOLUTE); } } else @@ -391,7 +393,7 @@ void setAppState(AppState newState, int argc, char* argv[]) } else { - TFE_Input::enableRelativeMode(true); + TFE_Input::setMouseCursorMode(MCURSORMODE_ABSOLUTE); } } } @@ -664,25 +666,30 @@ int main(int argc, char* argv[]) // Game loop u32 frame = 0u; bool showPerf = false; - bool relativeMode = false; + 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(); TFE_System::frameLimiter_begin(); - - bool enableRelative = TFE_Input::relativeModeEnabled(); - if (enableRelative != relativeMode) + + MouseCursorMode newMouseCursorMode = TFE_Input::getMouseCursorMode(); + if (newMouseCursorMode != mouseCursorMode) { - relativeMode = enableRelative; - SDL_SetRelativeMouseMode(relativeMode ? SDL_TRUE : SDL_FALSE); + mouseCursorMode = newMouseCursorMode; + SDL_SetRelativeMouseMode(mouseCursorMode == MCURSORMODE_RELATIVE ? SDL_TRUE : SDL_FALSE); + 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); } // Handle mouse state. + TFE_Input::setMouseInWindow(SDL_GetMouseFocus() == TFE_Ui::getSDLWindow()); s32 mouseX, mouseY; s32 mouseAbsX, mouseAbsY; u32 state = SDL_GetRelativeMouseState(&mouseX, &mouseY); @@ -751,7 +758,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 +767,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))