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.
This commit is contained in:
@@ -18,13 +18,21 @@ Ghidra.
|
||||
|
||||
## Status
|
||||
|
||||
OpenRA3 is at **v0.2.0**. The engine compiles and runs headless, and a **minimal
|
||||
OpenRA3 is at **v0.3.0**. The engine compiles and runs headless, and a **minimal
|
||||
skirmish** is playable: it reads a real multiplayer map out of your install,
|
||||
recovers the player start waypoints, and simulates two sides earning credits,
|
||||
training units and fighting until one base falls. The map and match state can be
|
||||
**rendered** to a window (SDL3) or to an image. The whole tree builds for
|
||||
**Linux** (clang + libc++) and cross-compiles to **Windows** (`openra3.exe` +
|
||||
`SDL3.dll`) with llvm-mingw — both using C++26 modules and `import std;`.
|
||||
recovers the player start waypoints, and simulates two sides building a base,
|
||||
extracting ore and fighting until one side is wiped out. The balance is the
|
||||
**retail Red Alert 3 balance**, pinned in `ra3.data` from EA's open RA3 XML:
|
||||
damage types, `ArmorTemplate` percentages, weapon target masks, build costs and
|
||||
the ore economy. Presentation is a **Vulkan** backend (`ra3.vulkan`) with a null
|
||||
fallback; the software renderer still produces headless images. Terrain tiles
|
||||
cross-fade the way the retail `Terrain.fx` does (a per-cell blend ramp plus a
|
||||
gutter-padded atlas), so material boundaries are smooth instead of a grid of
|
||||
hard lines. An in-window **menu** lists the maps by their localized name and
|
||||
exposes every render/skirmish option for tweaking before launch. The whole tree
|
||||
builds for **Linux** (clang + libc++) and cross-compiles to **Windows**
|
||||
(`openra3.exe` + `SDL3.dll`) with llvm-mingw — both using C++26 modules and
|
||||
`import std;`.
|
||||
|
||||
```text
|
||||
$ openra3 skirmish --game-dir "/game" --map map_mp_2_feasel4
|
||||
@@ -32,9 +40,9 @@ OpenRA3 skirmish map=map_mp_2_feasel4 source=archive:map_mp_2_feasel4 seed=1
|
||||
start positions:
|
||||
P0 (1338, 1940)
|
||||
P1 (1291, 1404)
|
||||
result: decided winner=0 frames=3397 (113.2 s)
|
||||
P0 Commander Allied money= 129 units=19 kills=21 losses=3
|
||||
P1 AI Soviet money= 840 units= 0 kills=3 losses=21
|
||||
result: decided winner=0 frames=9293 (309.8 s)
|
||||
P0 Commander Allied money= 700 units=15 kills=21 losses=15
|
||||
P1 AI Soviet money= 376 units= 0 kills=15 losses=21
|
||||
```
|
||||
|
||||
## Offline only
|
||||
@@ -47,15 +55,25 @@ tested without any external service.
|
||||
|
||||
## Assets
|
||||
|
||||
The engine reads the retail game from your local install:
|
||||
The runtime reads a portable `assets/` folder **next to the executable** — there
|
||||
is no `--game-dir` at run time. The build extracts it from your install:
|
||||
|
||||
- default path `C:\Red Alert 3`, or `--game-dir DIR`, or `$RA3_GAME_DIR`;
|
||||
- `Data\MapsMultiplayer.big` is read for the map catalog;
|
||||
- maps are unpacked from `BIG4` + RefPack and their start waypoints recovered.
|
||||
- `openra3_assets` (build target) runs `cmake/extract_assets.cmake`, which
|
||||
- extracts every map (double-unwrapped `CkMp`) and terrain TGA into `assets/`
|
||||
via the engine's own `openra3 extract`;
|
||||
- with `-DOPENRA3_EXTRACT_ALL=ON` (default) also dumps **every** `.big` entry
|
||||
plus models, textures (`.png`), sound effects/voice and movie audio via the
|
||||
[`ra3-headless/ra3tools`](https://github.com/) scripts.
|
||||
- CMake cache vars: `RA3_GAME_DIR` (default `C:/Red Alert 3`), `RA3TOOLS_DIR`
|
||||
(the `ra3tools` scripts), `PYTHON_EXECUTABLE`.
|
||||
- The step is skipped when the exe cannot run on the build host (a Windows
|
||||
cross-build in a Linux container); the exe then extracts maps/terrain on first
|
||||
launch, and the full dump can be run explicitly:
|
||||
`cmake --build <build> --target openra3_assets` on a native host, or
|
||||
`openra3 extract --game-dir DIR --out DIR`.
|
||||
|
||||
**No game data is committed or distributed.** `reference/` (the GPLv3 Generals
|
||||
source) and any extracted assets are git-ignored; `tools/fetch_reference.sh`
|
||||
fetches the former on demand. Without an install, the engine falls back to a
|
||||
**No game data is committed or distributed.** `reference/`, `assets/` and the
|
||||
ra3tools checkout are git-ignored. Without an install the engine falls back to a
|
||||
built-in test map so the project still builds and runs in CI.
|
||||
|
||||
## Layout
|
||||
@@ -64,15 +82,19 @@ built-in test map so the project still builds and runs in CI.
|
||||
| --- | --- |
|
||||
| `src/core/ra3.core.cppm` | fundamental types, math, strings, random, message stream |
|
||||
| `src/logic/ra3.logic.cppm` | objects, players, teams, spatial partition, game loop |
|
||||
| `src/client/ra3.client.cppm` | display abstraction + client facade / frame loop |
|
||||
| `src/client/ra3.client.cppm` | `display` abstraction + shared interactive loops + client facade |
|
||||
| `src/display/ra3.display.cppm` | picks the backend (Vulkan, then SDL) for the app |
|
||||
| `src/game/ra3.game.cppm` | RA3 sides, player templates, skirmish defaults |
|
||||
| `src/data/ra3.data.cppm` | retail RA3 balance: damage types, armour, weapons, units, economy |
|
||||
| `src/fs/ra3.fs.cppm` | `BIG4` archives, RefPack codec, local install locator |
|
||||
| `src/map/ra3.map.cppm` | map catalog, `EAR`/RefPack unwrap, start waypoints |
|
||||
| `src/skirmish/ra3.skirmish.cppm` | units, economy, AI, combat, win condition |
|
||||
| `src/render/ra3.render.cppm` | ARGB framebuffer, TGA decode, BMP encode, map compositing |
|
||||
| `src/ui/ra3.ui.*.cppm` | SDL3 window viewer (null backend when SDL3 is absent) |
|
||||
| `src/map/ra3.map.cppm` | map catalog, `EAR`/RefPack unwrap, start waypoints, `gamestrings.csf` display names |
|
||||
| `src/skirmish/ra3.skirmish.cppm` | base building, economy, AI, combat, win condition |
|
||||
| `src/terrain/ra3.terrain.cppm` | `CkMp` terrain: `HeightMapData`, `BlendTileData` (tiles + blends), `Terrain.big` tiles |
|
||||
| `src/render/ra3.render.cppm` | ARGB framebuffer, TGA decode, BMP encode, map compositing, bitmap-font text |
|
||||
| `src/ui/ra3.ui.*.cppm` | SDL3 window viewer and menu (null backend when SDL3 is absent) |
|
||||
| `src/vulkan/ra3.vulkan.*.cppm` | Vulkan presentation backend and menu (null fallback without a loader) |
|
||||
| `src/ra3.cppm` | umbrella module re-exporting the SDK |
|
||||
| `apps/openra3/main.cpp` | `maps` / `skirmish` CLI |
|
||||
| `apps/openra3/main.cpp` | `menu` / `maps` / `skirmish` / `render` CLI |
|
||||
| `tests/ra3_tests.cpp` | smoke tests (run via `ctest`) |
|
||||
| `tools/` | reference fetch + Ghidra-driven reconstruction helpers |
|
||||
| `docs/` | architecture, reverse-engineering notes, roadmap |
|
||||
@@ -122,6 +144,18 @@ docker run --rm -v "$PWD:/work" -w /work openra3-windows:local cmake --build bui
|
||||
|
||||
Behind a slow or blocked mirror, pass `--build-arg APT_MIRROR=<url>`.
|
||||
|
||||
The two images are deliberately separate so the Linux (clang + libc++) and
|
||||
Windows (llvm-mingw + MinGW SDL3) toolchains never interfere. The Windows demo
|
||||
is `build/windows/bin/openra3.exe` next to `SDL3.dll`:
|
||||
|
||||
```powershell
|
||||
# show a real map in a Vulkan window
|
||||
openra3.exe render --game-dir "C:\Red Alert 3" --vulkan
|
||||
```
|
||||
|
||||
Vulkan is provided by **vendored volk + headers** (`third_party/`), resolved at
|
||||
runtime, so neither image needs a Vulkan SDK.
|
||||
|
||||
## Running a skirmish
|
||||
|
||||
```bash
|
||||
@@ -140,10 +174,33 @@ it from `cmd`/PowerShell, e.g. `openra3.exe skirmish --game-dir "C:\Red Alert 3"
|
||||
`--frames N` caps the simulation length (default 15 minutes of game time at
|
||||
30 Hz). The result is deterministic for a given map and seed.
|
||||
|
||||
## Menu
|
||||
|
||||
Run `openra3` with no arguments (or `openra3 menu`) to open a window listing the
|
||||
maps by their **localized display name** (read from the install's
|
||||
`gamestrings.csf`, e.g. `map_mp_2_feasel4` → "Battlebase Beta") with their id
|
||||
below. The `Options` column exposes every `render`/`skirmish` parameter — mode
|
||||
(3D terrain / top-down / skirmish), window size, camera pitch/yaw/height, FOV,
|
||||
zoom, terrain scale, terrain pitch, world size, seed, frame cap, the overview
|
||||
thumbnail toggle and a BMP output path. `Up`/`Down` selects, `Left`/`Right`
|
||||
changes a value (or moves the text caret on the BMP field), `Tab` switches
|
||||
between the map list and the options, `Enter` starts and `Esc` quits. Starting a
|
||||
3D or top-down view opens the viewer; closing it returns to the menu. When no
|
||||
window backend is available the same flow falls back to a console picker, and
|
||||
`openra3 menu-preview` renders one menu frame to a BMP for inspection.
|
||||
|
||||
## Rendering the map
|
||||
|
||||
The renderer draws the map's own overview art, a world grid and the match state
|
||||
(start markers in yellow, player 0 in blue, player 1 in red).
|
||||
`render` draws the **real terrain**: it parses the map's `HeightMapData`
|
||||
(elevation grid) and `BlendTileData` (per-cell tile index plus the per-cell
|
||||
`Blends`/`ThreeWayBlends` and their `BlendDescription`s), loads the tile
|
||||
textures from `Data\Terrain.big` (RefPack + TGA), and rasterises the map with an
|
||||
elevation shade. Each cell cross-fades into its blend neighbour with the same
|
||||
linear ramp the retail `Terrain.fx` uses, so material transitions are smooth; on
|
||||
the GPU path the tile atlas is padded with a replicated gutter so filtering
|
||||
never bleeds between tiles. Match state is overlaid (start markers in yellow,
|
||||
player 0 in blue, player 1 in red). `--thumbnail` uses the old `<map>_art.tga`
|
||||
overview instead.
|
||||
|
||||
**Offscreen image** (works anywhere, no display needed):
|
||||
|
||||
@@ -155,8 +212,11 @@ docker run --rm -v "/path/to/Red Alert 3:/game:ro" -v "$PWD/out:/out" openra3-li
|
||||
On Windows the same command runs natively: `openra3.exe render --game-dir
|
||||
"C:\Red Alert 3" --map map_mp_2_feasel4` opens an SDL3 window.
|
||||
|
||||
**Interactive window** (SDL3; drag to pan, wheel to zoom, Esc to quit). In a
|
||||
container you need an X server on the host — on Windows run
|
||||
**Interactive window** (Vulkan with `--vulkan`, otherwise SDL3). The camera
|
||||
follows the retail tactical view: it opens centred on the first player's start,
|
||||
the wheel zooms, pushing the cursor against a screen edge scrolls, dragging with
|
||||
the left button pans, and Esc quits. `--zoom Z` sets the initial zoom (1 fits
|
||||
the whole map). In a container you need an X server on the host — on Windows run
|
||||
[VcXsrv](https://sourceforge.net/projects/vcxsrv/) and launch it with "Disable
|
||||
access control", then:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user