Files
OpenRA3/docs/ARCHITECTURE.md
T
EnderTheCoder b6d619254d v0.3.0: display abstraction, map-browser menu, SAGE terrain tiling/blends
- ra3.client::display: shared interactive loops; SDL and Vulkan backends
  implement only the primitives (init/present/poll_event/window_size/
  key_down/present_terrain). ra3.display picks the backend.
- Menu: maps by localized name (gamestrings.csf), red/gold theme, hover
  highlight, mouse + keyboard, wheel scroll, fullscreen and FPS/vsync
  options, loading progress bar.
- Terrain: continuous tile sampling via a texture array (REPEAT, uv =
  cell/(2*cellSize)) removes per-cell grid seams; SAGE blend ramp for
  material transitions; FPS label + top-right minimap overlays.
- Skip the skirmish sim for map views; reuse the Vulkan texture; no idle
  terrain redraw.
2026-09-20 02:20:39 +08:00

132 lines
7.0 KiB
Markdown

# Architecture
OpenRA3 is organised as a stack of C++26 modules. Each layer may import the ones
below it, never the ones above. Every module uses `import std;` for the standard
library; the engine is built with Clang + libc++ on Linux and cross-compiled
with llvm-mingw for Windows.
```
┌───────────────────────────────────────┐
applications │ openra3 (apps/openra3) │
└───────────────────┬───────────────────┘
│ import ra3
┌───────────────────▼───────────────────┐
umbrella │ ra3 (re-exports everything) │
└───────────────────┬───────────────────┘
┌──────────────┬───────────────┼───────────────┬──────────────┐
▼ ▼ ▼ ▼ ▼
ra3.display ra3.render ra3.skirmish ra3.client ra3.game
backend pick framebuffer match rules display+loops RA3 sides
│ │ │ │ │
┌──┴───┐ │ └───────┬───────┘ │
▼ ▼ ▼ ▼ │
ra3.ui ra3.vulkan ra3.terrain ra3.logic │
SDL Vulkan heightmap/blends simulation │
┌──────────────────────┘
▼
ra3.map / ra3.fs
catalog / BIG4 + RefPack
```
## Presentation layer
`ra3.client::display` is the single seam between the engine and the windowing
stack. A backend implements only the low-level primitives (`init`, `present`,
`poll_event`, `window_size`, `key_down`, `shutdown`) and, optionally,
`present_terrain`; the interactive loops (menu, image viewer, camera viewer,
GPU terrain) and the native-to-`ui_event` mapping live once in the base class,
so the SDL and Vulkan paths cannot drift. SDL3 remains the platform layer (it
owns the window, input and the low-cost blit backend); Vulkan is the accelerated
backend. `ra3.display` selects the first backend that starts, and the app never
references a backend by name.
The Vulkan backend currently hand-rolls its pipelines. As materials, skybox and
HUD arrive, a thin RHI + render-graph belongs between `ra3.client` and the
Vulkan/SDL backends; `present_terrain` is the placeholder for that step.
## Module responsibilities
### `ra3.core`
The vocabulary every other module shares, mirroring SAGE's `GameEngine/Common`:
`real`/`int32`/`uint32`, `coord3d`/`coord2d`/`rgb_color`, `ascii_string` +
`make_name_key`, the deterministic `random` stream, and the `message_stream`
command bus (node layout derived from retail `MessageStream::appendMessage`,
`0x0060c4a0`).
### `ra3.logic`
The deterministic simulation, mirroring SAGE's `GameLogic`: `thing` → `object`
with pluggable `update_module`s, `player`/`player_list`, the `partition_manager`
spatial grid, and the 30 Hz `game_logic` driver (`prepare_new_game` /
`start_new_game` / `update`).
### `ra3.client`
The presentation boundary: the abstract `display` (low-level primitives plus the
shared interactive loops and `ui_event` mapping), a `headless_display` for
CPU-only runs, and `game_client`, the facade that owns the simulation and drives
the frame loop.
### `ra3.display`
Backend selection: tries Vulkan, then SDL, then reports failure so the caller can
fall back to an offscreen image. The only module that names a concrete backend.
### `ra3.terrain`
The real map terrain: parses `CkMp`'s `HeightMapData` and `BlendTileData`
(tiles, `Blends`/`ThreeWayBlends` and their `BlendDescription`s), loads the
`Terrain.big` tile textures, and rasterises the map (software `render`/`render3d`
and the GPU `gpu_terrain` for `present_terrain`).
### `ra3.game`
Red Alert 3 data that SAGE keeps in `PlayerTemplate`: the three sides
(`faction` flags `Empire=2`, `Allied=4`, `Soviet=8`, `Random=7`, recovered from
the retail skirmish setup) and skirmish defaults.
### `ra3.fs`
Reading the user's installation. Implements the `BIG4` archive container and
EA's RefPack codec, plus `find_game_dir` (`--game-dir` / `$RA3_GAME_DIR` /
`C:\Red Alert 3`). Only the archive index is held in memory; payloads are read
on demand.
### `ra3.map`
Map discovery and loading: scans `MapsMultiplayer.big` for main map entries,
unwraps the two compression layers (`BIG4` RefPack → `EAR\0` wrapper → RefPack →
`CkMp`), recovers `Player_N_Start` waypoint coordinates, and decodes the
localized display names from the install's `gamestrings.csf`. Degenerate
extractions are rejected so the caller can fall back.
### `ra3.skirmish`
The minimal match: two players, unit classes (harvester/infantry/tank/base),
passive + harvester income, a simple build AI, movement and combat on a fixed
30 Hz step, and a base-destruction win condition. Fully deterministic.
### `ra3.render`
A dependency-free software renderer: an ARGB8888 `image` framebuffer with
blit/line/circle/text primitives (an embedded 8x8 bitmap font), a TGA decoder for
the game's map art, a 24-bit BMP encoder for headless output, and `compose` which
overlays a world grid and markers (start positions, live units) onto the map art.
### `ra3.ui`
The SDL3 backend: `sdl_display` implements the `ra3.client::display` primitives
using an `SDL_Renderer` streaming texture. Cheap and dependency-light, it is the
fallback when Vulkan is unavailable. A null backend returns `false` so the build
still runs without SDL3.
### `ra3.vulkan`
The accelerated backend: `vulkan_display` implements the same primitives and
adds `present_terrain`, a GPU heightfield raymarcher (mipmapped tile atlas with a
replicated gutter and the retail SAGE blend ramp). A null backend reports failure
when no Vulkan loader is present.
## Design rules
1. **No raw owning pointers.** Ownership is `std::unique_ptr`; the partition
manager holds non-owning `thing *` views only.
2. **Portable simulation.** No platform APIs in `ra3.core` / `ra3.logic`. All
platform concerns live behind `display`.
3. **Determinism.** Anything that can diverge between runs (random, iteration
order) is explicit and seedable.
4. **RE-traceable.** Where a structure or constant comes from the retail
binary, the address is cited in the comment.
5. **No bundled assets, no online.** Game data is read from the user's install
and never committed; there is no networking or online service.