Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
8813b82
Remove cross-layer includes from ship namespace (#1097)
Copilot May 4, 2026
42ecb8e
fixed building on GCC 16 (#1100)
Pepper0ni May 6, 2026
f30fe0e
Add fixedAspect flag to framebuffers (#1109)
Pepper0ni May 22, 2026
1d98291
Untangle various parts from the Context destructor (#1103)
louist103 Jun 1, 2026
026bbc2
fix windows arm CI failure (#1127) (#1130)
briaguya0 Jun 13, 2026
2cc049d
Fix warnings (#1126)
Pepe20129 Jun 14, 2026
ec194d6
Skip some clamps and stride calculations for replacement textures (#1…
JeodC Jun 16, 2026
2c63e7e
Only populate event callers map in debug builds (#1131)
JeodC Jun 17, 2026
e8a1618
fast3d: clamp masked over-loaded textures to their wrap period (#1151)
JeodC Jul 17, 2026
f0837c0
gsSPPopMatrix xml command (#1124)
Jameriquiah Jul 21, 2026
8a67fa4
Bind imgui's gamepad backend to the controller libultraship is using …
JeodC Jul 21, 2026
2bfbde3
Add Palette4bpp Support for Texture Loading into ImGui (#1157)
Caladius Jul 22, 2026
97d8e30
fix: round interpolated texture tile sizes (#1164)
banteg Jul 23, 2026
621f09b
Fix Metal crash when LoadBlock uploads a texture as one giant line (#…
serprex Jul 23, 2026
1289e28
Fix NullAudioPlayer::Buffered() returning 0 (audio-thread spin/hang) …
bassdr Jul 24, 2026
c57da1b
Add G_SETTILESIZE_LERP for constant-size texture scroll interpolation…
serprex Jul 24, 2026
0eae41a
fix undefined symbol in `NON_PORTABLE` builds (#1170)
ProverbialPennance Jul 24, 2026
f57f4d2
Add ImGui FileBrowserWindow as a fallback file dialog (#1139)
JeodC Jul 26, 2026
60c9bb7
fix(fast3d): treat an undefined tile region as zero size (#1135)
bassdr Jul 28, 2026
1d85123
Add Nintendo Switch support on top of port-maintenance
Project516 Oct 7, 2026
b40c276
Give libultraship the SDL2 include path on Switch
Project516 Oct 7, 2026
ecbdf84
Merge main-nx into port-maintenance-switch
Project516 Oct 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ jobs:
path: build-cmake-x64/src/**/*.lib
if-no-files-found: error
build-windows-arm64:
runs-on: windows-latest
runs-on: windows-2022
steps:
- name: Install dependencies
run: |
Expand Down
4 changes: 0 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,6 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
include(cmake/dependencies/windows.cmake)
endif()

if (CMAKE_SYSTEM_NAME STREQUAL "NintendoSwitch")
include(cmake/dependencies/switch.cmake)
endif()

# === Platform Specific Configuration ===
if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
include(cmake/ios-toolchain-populate.cmake)
Expand Down
6 changes: 5 additions & 1 deletion cmake/dependencies/switch.cmake
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)

#=================== SDL2 ===================
find_package(SDL2 REQUIRED)
target_link_libraries(ImGui PUBLIC SDL2::SDL2)

# ========= ImGui =========
target_include_directories(ImGui PRIVATE ${DEVKITPRO}/portlibs/switch/include/ ${DEVKITPRO}/portlibs/switch/include/SDL2)
target_include_directories(ImGui PUBLIC ${DEVKITPRO}/portlibs/switch/include/ ${DEVKITPRO}/portlibs/switch/include/SDL2)

#=================== nlohmann-json ===================
find_package(nlohmann_json QUIET)
Expand Down
177 changes: 177 additions & 0 deletions include/fast/Fast3dGui.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
#pragma once
#include <SDL2/SDL.h>

#include "Fast3dWindow.h"
#include "ship/window/gui/Gui.h"
#include "fast/WindowEvent.h"
#include "fast/resource/type/Texture.h"
#include "ship/window/gui/resource/GuiTexture.h"

// Fixes issue #926: HandleWindowEvents is only ever called from Fast3D backend code
// (gfx_sdl2.cpp, gfx_dxgi.cpp) and must not be a virtual method on Ship::Gui.
// The WindowEvent type has been moved to the Fast namespace so that ship code does
// not depend on any Fast3D or platform-specific types.

namespace Fast {
class Interpreter;

/**
* @brief Backend-specific data required to initialise the ImGui rendering context.
*
* The active union member is selected based on the graphics backend:
* - Dx11 for DirectX 11 (Windows).
* - Opengl for OpenGL (Linux/macOS via SDL).
* - Metal for Metal (macOS via SDL).
* - Gx2 for the GX2 API (Wii U / Café OS).
*/
typedef struct {
union {
struct {
void* Window; ///< HWND
void* DeviceContext; ///< ID3D11DeviceContext*
void* Device; ///< ID3D11Device*
} Dx11;
struct {
void* Window; ///< SDL_Window*
void* Context; ///< SDL_GLContext
} Opengl;
struct {
void* Window; ///< SDL_Window*
SDL_Renderer* Renderer; ///< SDL_Renderer* (for Metal layer)
} Metal;
struct {
uint32_t Width; ///< Framebuffer width in pixels.
uint32_t Height; ///< Framebuffer height in pixels.
} Gx2;
};
WindowBackend Backend;
} GuiWindowInitData;

/**
* @brief Concrete Gui subclass for the Fast3D rendering backend.
*
* Overrides the virtual ImGui backend methods defined by Ship::Gui with
* implementations that dispatch to the appropriate platform/renderer backend
* (SDL+OpenGL, SDL+Metal, or DXGI+DX11) based on the active WindowBackend.
*
* Also owns the Fast3D-specific rendering resources: texture cache and the
* Interpreter weak reference used for viewport and resolution calculations.
*/
class Fast3dGui : public Ship::Gui {
public:
Fast3dGui();
Fast3dGui(std::vector<std::shared_ptr<Ship::GuiWindow>> guiWindows);
~Fast3dGui() override = default;

bool SupportsViewports() override;

/**
* @brief Initialises the ImGui context with the given backend-specific handles.
* @param windowImpl Backend-specific handles required by the ImGui backend.
*/
void Init(GuiWindowInitData windowImpl);

/**
* @brief Forwards a platform window event to the active ImGui backend.
*
* Only Fast3D backends (gfx_sdl2, gfx_dxgi) construct and dispatch WindowEvents.
* Callers retrieve the Gui via Window::GetGui() and dynamic_cast to Fast3dGui.
* @param event Platform event (SDL or Win32) wrapped in a Fast::WindowEvent.
*/
void HandleWindowEvents(Fast::WindowEvent event);

/**
* @brief Loads an image from an archive path and caches it under the given name.
* @param name Path/texture name used to reference the texture in GetTextureByName().
* @param path Virtual resource path of the source image.
* @param tint RGBA tint multiplied over the image (use ImVec4(1,1,1,1) for no tint).
*/
void LoadGuiTexture(const std::string& name, const std::string& path, const std::string& palettePath = "",
const ImVec4& tint = ImVec4(1.0f, 1.0f, 1.0f, 1.0f));

/**
* @brief Returns true if a texture with the given name is already cached.
* @param name Texture cache key.
*/
bool HasTextureByName(const std::string& name);

/**
* @brief Uploads a Fast::Texture object to the GPU and caches it under @p name.
* @param name Texture cache key.
* @param tex Source texture data.
* @param tint RGBA tint.
*/
void LoadGuiTexture(const std::string& name, const Fast::Texture& tex, const std::string& palettePath = "",
const ImVec4& tint = ImVec4(1.0f, 1.0f, 1.0f, 1.0f));

/**
* @brief Removes the texture with the given name from the cache and frees GPU resources.
* @param name Texture cache key to remove.
*/
void UnloadTexture(const std::string& name);

/**
* @brief Returns the ImGui texture handle for the given cache key.
* @param name Texture cache key.
* @return ImTextureID suitable for ImGui::Image(), or nullptr if not found.
*/
ImTextureID GetTextureByName(const std::string& name);

/**
* @brief Returns the pixel dimensions of the cached texture.
* @param name Texture cache key.
* @return ImVec2 with the texture's width and height, or (0, 0) if not found.
*/
ImVec2 GetTextureSize(const std::string& name);

/**
* @brief Loads a raw image file from the filesystem (not the archive) and caches it.
* @param name Cache key.
* @param path Absolute filesystem path to the image file (e.g. a PNG).
*/
void LoadTextureFromRawImage(const std::string& name, const std::string& path);

/**
* @brief Uploads a pre-loaded GuiTexture resource to the GPU and caches it.
* @param name Cache key.
* @param texture Loaded GuiTexture resource.
*/
void LoadTextureFromResource(const std::string& name, std::shared_ptr<Ship::GuiTexture> texture);

void RefreshImGuiGamepads() override;

protected:
void ImGuiWMInit() override;
void ImGuiWMShutdown() override;
void ImGuiBackendInit() override;
void ImGuiBackendShutdown() override;
void ImGuiBackendNewFrame() override;
void ImGuiWMNewFrame() override;
void ImGuiRenderDrawData(ImDrawData* data) override;
void DrawFloatingWindows() override;
void CalculateGameViewport() override;
void DrawGame() override;

/**
* @brief Returns the ImTextureID for a texture identified by its integer ID.
* @param id Internal texture registry ID.
* @return ImTextureID for use with ImGui::Image().
*/
ImTextureID GetTextureById(int32_t id);

std::weak_ptr<Interpreter> mInterpreter; ///< Weak reference to the Fast3D scripting interpreter.
GuiWindowInitData mImpl; ///< Backend-specific window/context handles passed to Init().

private:
/** @brief Applies any pending resolution or MSAA changes to the render target. */
void ApplyResolutionChanges();

/**
* @brief Returns the integer scaling factor applied to the game viewport.
* @return Scaling multiplier (1 = native, 2 = 2×, etc.).
*/
int16_t GetIntegerScaleFactor();

std::unordered_map<std::string, Ship::GuiTextureMetadata> mGuiTextures; ///< Cached GPU texture registry.
};
} // namespace Fast
29 changes: 29 additions & 0 deletions include/fast/Fast3dWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,28 @@
#include "ship/window/gui/Gui.h"
#include "ship/controller/controldevice/controller/mapping/keyboard/KeyboardScancodes.h"
#include "FastMouseStateManager.h"
#include "fast/debug/GfxDebugger.h"

union Gfx;
#include "interpreter.h"

namespace Fast {

/**
* @brief Identifies the graphics/windowing backend used by Fast3dWindow.
*
* These are the positive backend IDs registered by Fast3dWindow.
* The general convention for window backend IDs (int32_t) is:
* negative — no Window backend available (e.g. Window is not initialized)
* zero — no Window backend in use
* positive — backend defined by the Window subclass
*/
enum WindowBackend {
FAST3D_DXGI_DX11 = 1,
FAST3D_SDL_OPENGL = 2,
FAST3D_SDL_METAL = 3,
};

class Fast3dWindow : public Ship::Window {
public:
Fast3dWindow();
Expand Down Expand Up @@ -47,6 +64,14 @@ class Fast3dWindow : public Ship::Window {
uintptr_t GetGfxFrameBuffer() override;
const char* GetKeyName(int32_t scancode) override;

std::string GetWindowBackendName() override;

void SetCurrentDimensions(uint32_t width, uint32_t height) override;
void SetCurrentDimensions(uint32_t width, uint32_t height, int32_t posX, int32_t posY) override;
void SetCurrentDimensions(bool isFullscreen, uint32_t width, uint32_t height) override;
void SetCurrentDimensions(bool isFullscreen, uint32_t width, uint32_t height, int32_t posX, int32_t posY) override;
Ship::WindowRect GetPrimaryMonitorRect() override;

void InitWindowManager();
int32_t GetTargetFps();
void SetTargetFps(int32_t fps);
Expand All @@ -60,6 +85,9 @@ class Fast3dWindow : public Ship::Window {

std::weak_ptr<Interpreter> GetInterpreterWeak() const;

/** @brief Returns the graphics debugger for this Fast3D window. */
std::shared_ptr<GfxDebugger> GetGfxDebugger() const;

protected:
static bool KeyDown(int32_t scancode);
static bool KeyUp(int32_t scancode);
Expand All @@ -72,5 +100,6 @@ class Fast3dWindow : public Ship::Window {
GfxRenderingAPI* mRenderingApi;
GfxWindowBackend* mWindowManagerApi;
std::shared_ptr<Interpreter> mInterpreter = nullptr;
std::shared_ptr<GfxDebugger> mGfxDebugger;
};
} // namespace Fast
32 changes: 32 additions & 0 deletions include/fast/WindowEvent.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#pragma once

// Fixes issue #926: ship/window/gui/Gui.h previously defined WindowEvent in the Ship namespace,
// but this type is only ever constructed and consumed by Fast3D backend code (gfx_sdl2.cpp,
// gfx_dxgi.cpp) and processed by Fast3dGui::HandleWindowEvents. Moving it to the Fast namespace
// enforces the correct include hierarchy: fast can include fast, ship cannot include fast.

namespace Fast {

/**
* @brief Platform-agnostic wrapper around a window system event.
*
* Constructed by the Fast3D backends (gfx_sdl2, gfx_dxgi) and passed to
* Fast3dGui::HandleWindowEvents() so that the ImGui backend can process input
* events without the ship layer depending on any Fast3D or platform-specific type.
*/
typedef union {
struct {
void* Handle; ///< HWND
int Msg; ///< Windows message ID.
int Param1; ///< WPARAM
int Param2; ///< LPARAM
} Win32;
struct {
void* Event; ///< SDL_Event*
} Sdl;
struct {
void* Input; ///< GX2 input structure pointer.
} Gx2;
} WindowEvent;

} // namespace Fast
2 changes: 2 additions & 0 deletions include/fast/backends/gfx_dxgi.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ class GfxWindowBackendDXGI final : public GfxWindowBackend {
void SetMouseCapture(bool capture) override;
bool IsMouseCaptured() override;
void GetDimensions(uint32_t* width, uint32_t* height, int32_t* posX, int32_t* posY) override;
void SetDimensions(uint32_t width, uint32_t height, int32_t posX, int32_t posY) override;
Ship::WindowRect GetPrimaryMonitorRect() override;
void HandleEvents() override;
bool IsFrameReady() override;
void SwapBuffersBegin() override;
Expand Down
2 changes: 2 additions & 0 deletions include/fast/backends/gfx_sdl.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class GfxWindowBackendSDL2 final : public GfxWindowBackend {
void SetMouseCapture(bool capture) override;
bool IsMouseCaptured() override;
void GetDimensions(uint32_t* width, uint32_t* height, int32_t* posX, int32_t* posY) override;
void SetDimensions(uint32_t width, uint32_t height, int32_t posX, int32_t posY) override;
Ship::WindowRect GetPrimaryMonitorRect() override;
void HandleEvents() override;
bool IsFrameReady() override;
void SwapBuffersBegin() override;
Expand Down
3 changes: 3 additions & 0 deletions include/fast/backends/gfx_window_manager_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <stdint.h>
#include <stdbool.h>
#include "ship/window/Window.h"
namespace Fast {
class GfxWindowBackend {
public:
Expand All @@ -24,6 +25,8 @@ class GfxWindowBackend {
virtual void SetMouseCapture(bool capture) = 0;
virtual bool IsMouseCaptured() = 0;
virtual void GetDimensions(uint32_t* width, uint32_t* height, int32_t* posX, int32_t* posY) = 0;
virtual void SetDimensions(uint32_t width, uint32_t height, int32_t posX, int32_t posY) = 0;
virtual Ship::WindowRect GetPrimaryMonitorRect() = 0;
virtual void HandleEvents() = 0;
virtual bool IsFrameReady() = 0;
virtual void SwapBuffersBegin() = 0;
Expand Down
Loading