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

7.0 KiB

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_modules, 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 BlendDescriptions), 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.