Files
CopilotandKenix3 8813b8233d Remove cross-layer includes from ship namespace (#1097)
* refactor: remove cross-layer includes from Ship namespace

- Remove unused consolevariablebridge.h include from MobileImpl.cpp
- Decouple Context.cpp from fast/debug/GfxDebugger.h by making
  InitGfxDebugger() accept a shared_ptr parameter (like InitWindow/InitControlDeck)
- Remove LUS::GfxDebuggerWindow instantiation from Gui.cpp (should be
  registered from the libultraship layer instead)
- Decouple Config.cpp from fast/backends/gfx_metal.h by using Window's
  available backends list for default fallback selection

Agent-Logs-Url: https://github.com/Kenix3/libultraship/sessions/cc9a3aa8-4ee7-48f2-aa6b-47c2832803a0

Co-authored-by: Kenix3 <18299654+Kenix3@users.noreply.github.com>

* fix: add null checks for GfxDebugger parameter and Window in Config

Agent-Logs-Url: https://github.com/Kenix3/libultraship/sessions/cc9a3aa8-4ee7-48f2-aa6b-47c2832803a0

Co-authored-by: Kenix3 <18299654+Kenix3@users.noreply.github.com>

* revert: restore Context.cpp/Context.h GfxDebugger changes to original state

Fast::GfxDebugger is still referenced in Context.h (forward declaration,
GetGfxDebugger return type, mGfxDebugger member), so the previous changes
did not actually decouple the ship layer from fast. Revert to original
InitGfxDebugger() with no parameters; will be addressed in the component
refactor instead.

Agent-Logs-Url: https://github.com/Kenix3/libultraship/sessions/72144527-4404-4a09-8ee6-97c61130d219

Co-authored-by: Kenix3 <18299654+Kenix3@users.noreply.github.com>

* fix: remove extra blank lines in Config.cpp (clang-format)

Agent-Logs-Url: https://github.com/Kenix3/libultraship/sessions/b4b91158-e788-4d5a-8121-89f36b69cde8

Co-authored-by: Kenix3 <18299654+Kenix3@users.noreply.github.com>

* fix: add WindowBackend::NONE and return it when no Window is available

Agent-Logs-Url: https://github.com/Kenix3/libultraship/sessions/3a67e462-03be-4cc7-ac96-b56ddbf5d78a

Co-authored-by: Kenix3 <18299654+Kenix3@users.noreply.github.com>

* refactor: move WindowBackend enum to Fast namespace; use int32_t in ship::Window API

Agent-Logs-Url: https://github.com/Kenix3/libultraship/sessions/526c1d54-6cac-4d86-b948-c31d3abae19f

Co-authored-by: Kenix3 <18299654+Kenix3@users.noreply.github.com>

* refactor: move all Fast3d ImGui backend dispatch to virtual methods on Window

Agent-Logs-Url: https://github.com/Kenix3/libultraship/sessions/22c50f87-dcd3-4c27-a1a0-cfa9c7a3145b

Co-authored-by: Kenix3 <18299654+Kenix3@users.noreply.github.com>

* refactor: create Fast3dGui class and restore Window.Backend.Name config string

Addresses review feedback:
1. Move ImGui backend dispatch from Window virtuals to Gui virtuals with
   a new Fast3dGui subclass (extends Ship::Gui). This removes all
   Fast::WindowBackend references from Gui.cpp and places backend-specific
   ImGui logic in the Fast namespace where it belongs.
2. Restore the Window.Backend.Name config string by adding a virtual
   GetWindowBackendName() on Window, overridden in Fast3dWindow.
3. Fast3dWindow default constructors now use Fast3dGui instead of Ship::Gui.

Agent-Logs-Url: https://github.com/Kenix3/libultraship/sessions/314d6c8c-e74d-4055-9d11-b6194fffe3a1

Co-authored-by: Kenix3 <18299654+Kenix3@users.noreply.github.com>

* style: fix clang-format-14 alignment issues

Agent-Logs-Url: https://github.com/Kenix3/libultraship/sessions/314d6c8c-e74d-4055-9d11-b6194fffe3a1

Co-authored-by: Kenix3 <18299654+Kenix3@users.noreply.github.com>

* refactor: move WindowEvent to Fast namespace; HandleWindowEvents only on Fast3dGui

Fixes issue #926 (ship including fast):
- WindowEvent was defined in Ship::Gui but only ever used in fast backends
  (gfx_sdl2.cpp, gfx_dxgi.cpp) and Fast3dGui. Moved to Fast::WindowEvent in
  include/fast/WindowEvent.h.
- HandleWindowEvents removed from Ship::Gui virtual interface; it is now a
  plain (non-virtual) method only on Fast3dGui.
- gfx_sdl2 and gfx_dxgi now dynamic_cast the Gui to Fast3dGui with SPDLOG_ERROR
  error handling before dispatching window events.

Agent-Logs-Url: https://github.com/Kenix3/libultraship/sessions/c2e05218-2994-4bc0-ad73-a2ca0dff25ec

Co-authored-by: Kenix3 <18299654+Kenix3@users.noreply.github.com>

* Move window backend persistence from Config to Window

Agent-Logs-Url: https://github.com/Kenix3/libultraship/sessions/4cb4a129-b887-4a82-8512-8383cff2fcba

Co-authored-by: Kenix3 <18299654+Kenix3@users.noreply.github.com>

* Add SetCurrentDimensions and GetPrimaryMonitorRect to Window/Fast3dWindow (PR #785)

Agent-Logs-Url: https://github.com/Kenix3/libultraship/sessions/4cb4a129-b887-4a82-8512-8383cff2fcba

Co-authored-by: Kenix3 <18299654+Kenix3@users.noreply.github.com>

* Push texture cache and Interpreter from Gui down to Fast3dGui

Agent-Logs-Url: https://github.com/Kenix3/libultraship/sessions/4cb4a129-b887-4a82-8512-8383cff2fcba

Co-authored-by: Kenix3 <18299654+Kenix3@users.noreply.github.com>

* Move audio backend persistence from Config to Audio

Agent-Logs-Url: https://github.com/Kenix3/libultraship/sessions/18622f13-a54b-4445-bcd2-7c786d413f81

Co-authored-by: Kenix3 <18299654+Kenix3@users.noreply.github.com>

* Fix migration save, throttle one-time log warnings in SDL2/DXGI backends

Agent-Logs-Url: https://github.com/Kenix3/libultraship/sessions/18622f13-a54b-4445-bcd2-7c786d413f81

Co-authored-by: Kenix3 <18299654+Kenix3@users.noreply.github.com>

* Move GetCurrentAudioChannelsSetting from Config to Audio; move GfxDebugger from Context to Fast3dWindow/Interpreter

Agent-Logs-Url: https://github.com/Kenix3/libultraship/sessions/b347a7d2-c361-44bf-a8fd-fadb3548368e

Co-authored-by: Kenix3 <18299654+Kenix3@users.noreply.github.com>

* Fix Gui.cpp missing GuiTexture.h include; fix GfxDebuggerWindow texture method calls; apply clang-format

Agent-Logs-Url: https://github.com/Kenix3/libultraship/sessions/b347a7d2-c361-44bf-a8fd-fadb3548368e

Co-authored-by: Kenix3 <18299654+Kenix3@users.noreply.github.com>

* Fix clang-format-14 formatting issues in interpreter.cpp and Gui.h

Agent-Logs-Url: https://github.com/Kenix3/libultraship/sessions/3af3f34e-fb61-46b9-afe8-22d4b972a116

Co-authored-by: Kenix3 <18299654+Kenix3@users.noreply.github.com>

* Move InputEditorWindow to libultraship layer (namespace LUS); remove auto-registration from Gui

Agent-Logs-Url: https://github.com/Kenix3/libultraship/sessions/aeb70820-2942-4146-b30a-578c94c0e96d

Co-authored-by: Kenix3 <18299654+Kenix3@users.noreply.github.com>

* Move GuiWindowInitData from Ship::Gui to Fast::Fast3dGui; fix Input Editor null dereference

Agent-Logs-Url: https://github.com/Kenix3/libultraship/sessions/c7448a65-b6af-4808-b92b-05d6a3b80b05

Co-authored-by: Kenix3 <18299654+Kenix3@users.noreply.github.com>

* Fix CI: add Ship:: qualifiers to InputEditorWindow (no using namespace)

Agent-Logs-Url: https://github.com/Kenix3/libultraship/sessions/d5c2b6d8-024a-4809-930d-c35733dd795d

Co-authored-by: Kenix3 <18299654+Kenix3@users.noreply.github.com>

* Fix CI: qualify remaining unqualified Ship:: types in InputEditorWindow

Agent-Logs-Url: https://github.com/Kenix3/libultraship/sessions/5f67d2e4-1fb8-4c76-98f3-aa034a32be9c

Co-authored-by: Kenix3 <18299654+Kenix3@users.noreply.github.com>

* Fix CI: qualify Ship::Mobile in Fast3dGui.cpp for Android/iOS builds

Agent-Logs-Url: https://github.com/Kenix3/libultraship/sessions/9812efcb-d1fc-4831-8ed1-db3ecad52b68

Co-authored-by: Kenix3 <18299654+Kenix3@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Kenix3 <18299654+Kenix3@users.noreply.github.com>
2026-05-04 00:00:23 -04:00

299 lines
12 KiB
C++

#pragma once
#include <memory>
#include <filesystem>
#include <string>
#include <vector>
#include <unordered_set>
#include <spdlog/spdlog.h>
#include "ship/window/gui/Gui.h"
#include "ship/window/MouseStateManager.h"
#include "ship/controller/controldevice/controller/mapping/keyboard/KeyboardScancodes.h"
namespace Ship {
/** @brief Identifies the graphics/windowing backend in use.
*
* Window backend IDs use the following convention:
* - Negative values indicate no Window backend is available (e.g. the Window is not initialized).
* - Zero indicates no Window backend is in use.
* - Positive values are backend IDs defined by the concrete Window subclass.
*/
/** @brief Integer pixel coordinates. */
struct Coords {
int32_t x;
int32_t y;
};
/** @brief Floating-point pixel coordinates. */
struct CoordsF {
float x;
float y;
};
/** @brief Screen-space rectangle in integer pixels. */
struct WindowRect {
int32_t Left;
int32_t Top;
int32_t Right;
int32_t Bottom;
};
class Config;
/**
* @brief Abstract base class for the application window and rendering surface.
*
* Window owns the platform-specific window handle, the render loop, and the
* ImGui/GUI layer. Concrete subclasses (e.g. an SDL+OpenGL window) implement the
* pure virtual methods to integrate with specific graphics APIs.
*
* The window is created by Context::InitWindow() and is accessible via
* Context::GetWindow().
*/
class Window {
friend class Context;
public:
Window();
/**
* @brief Constructs a Window and pre-registers a list of GUI windows.
* @param guiWindows GUI overlay windows to register with the Gui layer.
*/
Window(std::vector<std::shared_ptr<GuiWindow>> guiWindows);
/**
* @brief Constructs a Window backed by a pre-constructed Gui instance.
* @param gui Gui layer to use.
*/
Window(std::shared_ptr<Gui> gui);
/**
* @brief Constructs a Window with both a Gui and a MouseStateManager.
* @param gui Gui layer to use.
* @param mouseStateManager Mouse state tracker to use.
*/
Window(std::shared_ptr<Gui> gui, std::shared_ptr<MouseStateManager> mouseStateManager);
virtual ~Window();
/** @brief Opens the window and initializes the graphics backend. */
virtual void Init() = 0;
/** @brief Requests that the window and application close. */
virtual void Close() = 0;
/** @brief Runs a single GUI-only tick without executing game logic. */
virtual void RunGuiOnly() = 0;
/** @brief Begins a new render frame; clears the back buffer and sets up state. */
virtual void StartFrame() = 0;
/** @brief Ends the current render frame and presents it to the display. */
virtual void EndFrame() = 0;
/** @brief Returns true if the renderer is ready to begin a new frame. */
virtual bool IsFrameReady() = 0;
/** @brief Processes pending OS/input events. */
virtual void HandleEvents() = 0;
/**
* @brief Shows or hides the OS mouse cursor over the window.
* @param visible true to show, false to hide.
*/
virtual void SetCursorVisibility(bool visible) = 0;
/** @brief Returns the current width of the window client area in pixels. */
virtual uint32_t GetWidth() = 0;
/** @brief Returns the current height of the window client area in pixels. */
virtual uint32_t GetHeight() = 0;
/** @brief Returns the current aspect ratio (width / height) of the window. */
virtual float GetAspectRatio() = 0;
/** @brief Returns the X position of the window's top-left corner on the desktop. */
virtual int32_t GetPosX() = 0;
/** @brief Returns the Y position of the window's top-left corner on the desktop. */
virtual int32_t GetPosY() = 0;
/**
* @brief Moves the mouse cursor to the given window-relative coordinates.
* @param pos Target position in window pixels.
*/
virtual void SetMousePos(Coords pos) = 0;
/** @brief Returns the current mouse cursor position relative to the window. */
virtual Coords GetMousePos() = 0;
/** @brief Returns the mouse movement delta since the last frame. */
virtual Coords GetMouseDelta() = 0;
/** @brief Returns the mouse wheel scroll delta for the current frame. */
virtual CoordsF GetMouseWheel() = 0;
/**
* @brief Returns whether the given mouse button is currently pressed.
* @param btn Mouse button to query.
*/
virtual bool GetMouseState(MouseBtn btn) = 0;
/**
* @brief Enables or disables mouse capture (relative/locked mouse mode).
* @param capture true to capture, false to release.
*/
virtual void SetMouseCapture(bool capture) = 0;
/** @brief Returns true if the mouse is currently captured. */
virtual bool IsMouseCaptured() = 0;
/** @brief Returns the display's current refresh rate in Hz. */
virtual uint32_t GetCurrentRefreshRate() = 0;
/** @brief Returns true if the backend supports a windowed-fullscreen (borderless) mode. */
virtual bool SupportsWindowedFullscreen() = 0;
/** @brief Returns true if vertical sync can be disabled on this backend. */
virtual bool CanDisableVerticalSync() = 0;
/**
* @brief Sets the internal rendering resolution multiplier.
* @param multiplier Values > 1 super-sample; < 1 sub-sample.
*/
virtual void SetResolutionMultiplier(float multiplier) = 0;
/**
* @brief Sets the MSAA sample count.
* @param value Number of MSAA samples (e.g. 1, 2, 4, 8).
*/
virtual void SetMsaaLevel(uint32_t value) = 0;
/**
* @brief Switches between fullscreen and windowed mode.
* @param isFullscreen true to enter fullscreen, false to return to windowed.
*/
virtual void SetFullscreen(bool isFullscreen) = 0;
/** @brief Returns true if the window is currently in fullscreen mode. */
virtual bool IsFullscreen() = 0;
/** @brief Returns true while the window / render loop is running. */
virtual bool IsRunning() = 0;
/**
* @brief Returns the human-readable name for a keyboard scancode.
* @param scancode Platform scancode value.
* @return C-string name, or an empty string if unknown.
*/
virtual const char* GetKeyName(int32_t scancode) = 0;
/** @brief Returns a handle to the graphics API framebuffer object. */
virtual uintptr_t GetGfxFrameBuffer() = 0;
/**
* @brief Sets the window dimensions (size and position) and applies them immediately.
* @param width New client-area width in pixels.
* @param height New client-area height in pixels.
*/
virtual void SetCurrentDimensions(uint32_t width, uint32_t height) = 0;
/**
* @brief Sets the window dimensions and position and applies them immediately.
* @param width New client-area width in pixels.
* @param height New client-area height in pixels.
* @param posX Left edge of the window in screen coordinates.
* @param posY Top edge of the window in screen coordinates.
*/
virtual void SetCurrentDimensions(uint32_t width, uint32_t height, int32_t posX, int32_t posY) = 0;
/**
* @brief Switches fullscreen state and sets the window dimensions.
* @param isFullscreen true to enter fullscreen, false for windowed.
* @param width New client-area width in pixels.
* @param height New client-area height in pixels.
*/
virtual void SetCurrentDimensions(bool isFullscreen, uint32_t width, uint32_t height) = 0;
/**
* @brief Switches fullscreen state and sets the window dimensions and position.
* @param isFullscreen true to enter fullscreen, false for windowed.
* @param width New client-area width in pixels.
* @param height New client-area height in pixels.
* @param posX Left edge of the window in screen coordinates.
* @param posY Top edge of the window in screen coordinates.
*/
virtual void SetCurrentDimensions(bool isFullscreen, uint32_t width, uint32_t height, int32_t posX,
int32_t posY) = 0;
/**
* @brief Returns the bounding rectangle of the primary monitor.
* @return WindowRect containing Left, Top, Right, Bottom of the primary display.
*/
virtual WindowRect GetPrimaryMonitorRect() = 0;
/** @brief Returns the current graphics backend identifier.
*
* See the window backend ID convention in the comment above this class:
* negative = no backend available, 0 = no backend in use, positive = defined by subclass.
*/
int32_t GetWindowBackend();
/**
* @brief Returns a human-readable name for the current window backend.
*
* The base implementation returns an empty string. Concrete subclasses (e.g. Fast3dWindow)
* override this to return backend-specific names such as "OpenGL", "Metal", or "DirectX 11".
*/
virtual std::string GetWindowBackendName();
/** @brief Returns the list of backends available on this platform. */
std::shared_ptr<std::vector<int32_t>> GetAvailableWindowBackends();
/**
* @brief Returns true if the backend with the given ID is available on this platform.
* @param backendId Backend identifier to check.
*/
bool IsAvailableWindowBackend(int32_t backendId);
/** @brief Returns the scancode of the last key event received. */
int32_t GetLastScancode();
/**
* @brief Records the most recently received keyboard scancode.
* @param scanCode Platform scancode value.
*/
void SetLastScancode(int32_t scanCode);
/** @brief Toggles between fullscreen and windowed mode. */
void ToggleFullscreen();
/** @brief Returns the current aspect ratio, recomputed from GetWidth() / GetHeight(). */
float GetCurrentAspectRatio();
/** @brief Persists window geometry and backend settings to the Config. */
void SaveWindowToConfig();
/** @brief Returns the GUI overlay layer. */
std::shared_ptr<Gui> GetGui();
/** @brief Returns true if the window should automatically capture the mouse when focused. */
bool ShouldAutoCaptureMouse();
/**
* @brief Enables or disables automatic mouse capture on window focus.
* @param capture true to enable auto-capture.
*/
void SetAutoCaptureMouse(bool capture);
/** @brief Returns true if the cursor should always be visible regardless of capture state. */
bool ShouldForceCursorVisibility();
/**
* @brief Forces the cursor to remain visible even when captured.
* @param visible true to force visibility.
*/
void SetForceCursorVisibility(bool visible);
/** @brief Returns the scancode bound to the fullscreen toggle action. */
int32_t GetFullscreenScancode();
/** @brief Returns the scancode bound to the mouse-capture toggle action. */
int32_t GetMouseCaptureScancode();
/**
* @brief Binds a scancode to the fullscreen toggle action.
* @param scancode Platform scancode.
*/
void SetFullscreenScancode(int32_t scancode);
/**
* @brief Binds a scancode to the mouse-capture toggle action.
* @param scancode Platform scancode.
*/
void SetMouseCaptureScancode(int32_t scancode);
/** @brief Returns the MouseStateManager used to track mouse button and position state. */
std::shared_ptr<MouseStateManager> GetMouseStateManager();
protected:
/**
* @brief Records the active graphics backend. Called by subclass constructors.
* @param backend The backend ID in use.
*/
void SetWindowBackend(int32_t backend);
/**
* @brief Adds a backend to the list of backends available on this platform.
* @param backend Backend ID to mark as available.
*/
void AddAvailableWindowBackend(int32_t backend);
/**
* @brief Reads the saved window backend identifier from the config.
*
* Reads Window.Backend.Id, validates it against the available backends, and falls back to
* the first registered backend if the saved value is not available.
*/
int32_t GetSavedWindowBackend();
private:
std::shared_ptr<Gui> mGui;
int32_t mLastScancode = -1;
int32_t mWindowBackend;
std::shared_ptr<MouseStateManager> mMouseStateManager;
std::shared_ptr<std::vector<int32_t>> mAvailableWindowBackends;
// Hold a reference to Config because Window has a Save function called on Context destructor, where the singleton
// is no longer available.
std::shared_ptr<Config> mConfig;
int32_t mFullscreenScancode;
int32_t mMouseCaptureScancode;
};
} // namespace Ship