Skip to content
Tom edited this page Apr 27, 2026 · 1 revision

ReXApp is the base class for windowed recompiled game applications. It handles window creation, ImGui integration, backend initialization, and the full runtime lifecycle. Projects generated by rexglue init subclass it.

For overriding individual recompiled functions, see Function Overrides and Mid-ASM Hooks. For headless or custom-window scenarios, see Using Runtime Directly below.

Lifecycle

ReXApp::OnInitialize() runs four phases in order. Steps marked -> are virtual hooks your subclass can override.

1. SetupEnvironment

Resolves paths, initializes logging, loads any user-supplied config TOML.

  1. Compute path defaults: positional CLI argument or exe_dir/assets for game_data_root, platform user directory for user_data_root. CVars for user_data_root / update_data_root override.
  2. -> OnConfigurePaths(PathConfig&). Adjust path defaults programmatically before any UI is shown.
  3. Initialize logging from CVars (log_level, log_file, log_verbose). Attach log capture sink for the console overlay.
  4. -> OnPostInitLogging(). Add custom log sinks now that logging is up.

2. SetupPresentation

Builds the render config, opens the window, stands up ImGui. Runs before Runtime construction so OnFinalizePaths can prompt the user from a real window.

  1. -> OnPreSetup(RuntimeConfig&). Customize backends, enable tool_mode, swap graphics backends, etc. The config is consumed by graphics setup next.
  2. Initialize the graphics backend (D3D12 or Vulkan) and create the window (1280x720 default).
  3. Create the ImGui drawer.
  4. -> OnConfigureFonts(ImFontAtlas*) is invoked from inside the drawer's font setup, after the default font is registered and before the atlas is built.
  5. Create built-in overlays (debug, console, settings).
  6. -> OnCreateDialogs(ImGuiDrawer*). Register custom overlays.

3. Path finalization

  1. -> OnFinalizePaths(defaults, resume). Last chance to resolve paths from a UI prompt, since the window is now live. Return a PathConfig synchronously, or return std::nullopt and call resume(path_config) later (e.g. from a wizard completion handler) to continue asynchronously.

4. ConstructRuntime

  1. Construct Runtime with the finalized paths.
  2. -> OnLoadXexImage(std::string& xex_image). Override the XEX image path/identifier before it's loaded.
  3. Load the XEX image (see Virtual File System for guest path resolution).
  4. -> OnPostLoadXexImage(). The XEX is mapped into guest memory; the module has not launched. Patch loaded data here.
  5. Initialize ReXCRT heap if the generated code includes [rexcrt] heap modules. Size controlled by the rexcrt_heap_size_mb CVar.
  6. -> OnPostSetup(). Runtime is fully initialized.

5. LaunchModule

  1. -> OnPreLaunchModule(). Last chance to patch guest memory or code before the main thread starts.
  2. Create the main guest thread targeting the XEX entry point. The thread is suspended.
  3. -> OnPostLaunchModule(XThread*). Attach debuggers or monitors before the thread runs.
  4. Resume the thread; it begins executing recompiled code.
  5. -> OnGuestThreadExit(XThread*) when the main guest thread exits. The runtime is still alive, so cleanup that depends on runtime resources should happen here.

Shutdown

When the window closes, OnDestroy() tears everything down in reverse order.

  1. -> OnShutdown(). Release custom resources before cleanup begins.

Hooks Reference

Hook Phase Use For
OnConfigurePaths(PathConfig&) SetupEnvironment Adjust path defaults programmatically
OnPostInitLogging() SetupEnvironment Add log sinks
OnPreSetup(RuntimeConfig&) SetupPresentation Modify backend config, enable tool_mode
OnConfigureFonts(ImFontAtlas*) SetupPresentation Add custom ImGui fonts
OnCreateDialogs(ImGuiDrawer*) SetupPresentation Register custom overlays
OnFinalizePaths(defaults, resume) Path finalization Prompt user for paths via UI (sync or async)
OnLoadXexImage(std::string&) ConstructRuntime Swap the XEX image path before loading
OnPostLoadXexImage() ConstructRuntime Patch XEX data after load, before launch
OnPostSetup() ConstructRuntime Post-initialization work
OnPreLaunchModule() LaunchModule Patch guest memory or code before launch
OnPostLaunchModule(XThread*) LaunchModule Attach debuggers; thread is suspended
OnGuestThreadExit(XThread*) LaunchModule Cleanup while runtime is still alive
OnShutdown() Shutdown Release custom resources

The four Init phase methods (SetupEnvironment, ConstructRuntime, SetupPresentation, LaunchModule) are themselves virtual and can be overridden if you need to replace an entire phase rather than just inject behavior at a hook point.

PathConfig

struct PathConfig {
  std::filesystem::path game_data_root;    // Game files (ROM data, default.xex)
  std::filesystem::path user_data_root;    // Save files, user data
  std::filesystem::path update_data_root;  // DLC / title updates
};
Field Default CVar Override
game_data_root First positional arg, or exe_dir/assets (none)
user_data_root Platform user directory / app name user_data_root
update_data_root Empty (opt-in) update_data_root

Generated Project Structure

rexglue init --app_name "foobar" --app_root ./foobar produces:

foobar/
├── CMakeLists.txt          # Build config with SDK discovery and platform settings
├── CMakePresets.json       # Platform presets (win-amd64, linux-amd64)
├── foobar_config.toml      # Codegen configuration template
├── src/
│   ├── main.cpp            # Entry point: REX_DEFINE_APP macro
│   └── foobar_app.h        # ReXApp subclass with override stubs
└── generated/
    └── rexglue.cmake       # SDK integration script (auto-managed by rexglue migrate)

src/main.cpp includes the generated headers and defines the application entry point:

#include "generated/foobar_init.h"
#include "foobar_app.h"

REX_DEFINE_APP(foobar, FoobarApp::Create)

src/foobar_app.h contains the ReXApp subclass. The Create factory passes PPCImageConfig (code base, code size, image base, image size, function mappings) from the generated headers:

class FoobarApp : public rex::ReXApp {
 public:
  using rex::ReXApp::ReXApp;

  static std::unique_ptr<rex::ui::WindowedApp> Create(
      rex::ui::WindowedAppContext& ctx) {
    return std::unique_ptr<FoobarApp>(new FoobarApp(ctx, "foobar",
        PPCImageConfig));
  }

  // Override hooks here: OnPreSetup, OnPostSetup, OnCreateDialogs, etc.
};

generated/rexglue.cmake is regenerated by rexglue migrate on SDK version upgrades. Do not edit it manually.

Built-in Overlays

ReXApp creates three debug overlays automatically:

Overlay Class Default Key Description
Debug DebugOverlayDialog F3 Host/guest FPS, thread info, memory stats, performance counters
Console ConsoleDialog ` (backtick) Log viewer with level/category filters and CVar System command input
Settings SettingsDialog F4 Visual CVar System editor with search, categories, and save-to-TOML

Register custom overlays in OnCreateDialogs:

void OnCreateDialogs(rex::ui::ImGuiDrawer* drawer) override {
  drawer->AddDialog(std::make_unique<MyCustomDialog>(drawer));
}

All overlays are ImGui-based. The ImGuiDrawer manages draw order and input routing.

CMake Helpers

The generated rexglue.cmake provides:

  • rexglue_configure_target(<target>): adds the platform-specific entry point source (windowed_app_main_win.cpp or _posix.cpp) and the ReXApp base class source (rex_app.cpp) to the target. This is the primary integration point between your project and the SDK.

The top-level CMakeLists.txt generated by rexglue init handles SDK discovery (via REXSDK cache variable or FetchContent), compiler settings, and links the generated recompiled code. See SDK Install Modes for the full discovery chain.

Using Runtime Directly

ReXApp is optional. Advanced users can construct rex::Runtime directly for headless tools, custom window management, or non-standard lifecycles. See Runtime Architecture Overview for the subsystem diagram and initialization sequence. This requires:

  • Manual RuntimeConfig population (backends, kernel init callback)
  • Calling Runtime::Setup() with function mappings
  • Managing LoadXexImage() and LaunchModule() yourself
  • Handling window creation, presenter setup, and ImGui independently (if needed)

See include/rex/runtime.h for the full API.

Clone this wiki locally