-
Notifications
You must be signed in to change notification settings - Fork 129
ReXApp
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.
ReXApp::OnInitialize() runs four phases in order. Steps marked -> are virtual hooks your subclass can override.
Resolves paths, initializes logging, loads any user-supplied config TOML.
- Compute path defaults: positional CLI argument or
exe_dir/assetsforgame_data_root, platform user directory foruser_data_root. CVars foruser_data_root/update_data_rootoverride. -
->
OnConfigurePaths(PathConfig&). Adjust path defaults programmatically before any UI is shown. - Initialize logging from CVars (
log_level,log_file,log_verbose). Attach log capture sink for the console overlay. -
->
OnPostInitLogging(). Add custom log sinks now that logging is up.
Builds the render config, opens the window, stands up ImGui. Runs before Runtime construction so OnFinalizePaths can prompt the user from a real window.
-
->
OnPreSetup(RuntimeConfig&). Customize backends, enabletool_mode, swap graphics backends, etc. The config is consumed by graphics setup next. - Initialize the graphics backend (D3D12 or Vulkan) and create the window (1280x720 default).
- Create the ImGui drawer.
-
->
OnConfigureFonts(ImFontAtlas*)is invoked from inside the drawer's font setup, after the default font is registered and before the atlas is built. - Create built-in overlays (debug, console, settings).
-
->
OnCreateDialogs(ImGuiDrawer*). Register custom overlays.
-
->
OnFinalizePaths(defaults, resume). Last chance to resolve paths from a UI prompt, since the window is now live. Return aPathConfigsynchronously, or returnstd::nulloptand callresume(path_config)later (e.g. from a wizard completion handler) to continue asynchronously.
- Construct Runtime with the finalized paths.
-
->
OnLoadXexImage(std::string& xex_image). Override the XEX image path/identifier before it's loaded. - Load the XEX image (see Virtual File System for guest path resolution).
-
->
OnPostLoadXexImage(). The XEX is mapped into guest memory; the module has not launched. Patch loaded data here. - Initialize ReXCRT heap if the generated code includes
[rexcrt]heap modules. Size controlled by therexcrt_heap_size_mbCVar. -
->
OnPostSetup(). Runtime is fully initialized.
-
->
OnPreLaunchModule(). Last chance to patch guest memory or code before the main thread starts. - Create the main guest thread targeting the XEX entry point. The thread is suspended.
-
->
OnPostLaunchModule(XThread*). Attach debuggers or monitors before the thread runs. - Resume the thread; it begins executing recompiled code.
-
->
OnGuestThreadExit(XThread*)when the main guest thread exits. The runtime is still alive, so cleanup that depends on runtime resources should happen here.
When the window closes, OnDestroy() tears everything down in reverse order.
-
->
OnShutdown(). Release custom resources before cleanup begins.
| 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.
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 |
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.
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.
The generated rexglue.cmake provides:
-
rexglue_configure_target(<target>): adds the platform-specific entry point source (windowed_app_main_win.cppor_posix.cpp) and theReXAppbase 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.
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
RuntimeConfigpopulation (backends, kernel init callback) - Calling
Runtime::Setup()with function mappings - Managing
LoadXexImage()andLaunchModule()yourself - Handling window creation, presenter setup, and ImGui independently (if needed)
See include/rex/runtime.h for the full API.
ReXGlue SDK
CLI Reference
Recompilation Pipeline
Runtime Architecture
Technical Reference