# Building Red Planet 4.12 (Win32)

This is the Win32 source for the pod-racing game **Red Planet**, built on the
in-house **MUNGA** engine and its **L4** (Win32 / DirectX 9) platform layer.
As of RP 4.12 the build targets **Visual Studio 2022 (v143)**; the legacy
VS 2005/2008 projects are retained for reference (see §5).

> ✅ **Verified build (2026-07-12):** all 4 projects build clean (`Release|Win32`)
> with **VS2022 Build Tools 17.14** (MSVC 14.44, v143) + **Windows 11 SDK
> (10.0.26100)** + **DirectX SDK (June 2010)**. Outputs: `Release\rpl4opt.exe`
> (the game), `Release\RPL4TOOL.exe`, `lib\Munga_l4.lib`, `lib\DivLoader.lib`.
> Runtime-verified against the VC9 baseline built from the same tree: identical
> log output and behavior at every checkpoint, including RIO init against vRIO
> and mission load (see §4 for the pre-existing crash both builds share).

---

## 1. Requirements

| Component | Version | Notes |
|-----------|---------|-------|
| **VS2022 Build Tools** (or any VS2022 with C++ workload) | 17.x, MSVC v143 | Installed at `C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools`. Install via `winget install Microsoft.VisualStudio.2022.BuildTools --override "--quiet --wait --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended"`. |
| **Windows 10/11 SDK** | any recent (26100 verified) | Comes with the VCTools workload. |
| **DirectX SDK (June 2010)** | — | Still needed for **d3dx9** and **dxerr** only; everything else now comes from the Windows SDK. The projects reference it via `$(DXSDK_DIR)`, which the SDK installer sets machine-wide. The DXSDK include/lib paths are appended **after** the Windows SDK paths (see the `IncludePath`/`LibraryPath` properties in the projects) so modern headers win — do not move them to `AdditionalIncludeDirectories`. |

### Bundled third-party libraries (already in the repo)

Committed under [lib/](lib/), no install needed: `OpenAL32.lib`, `libsndfile-1.lib`
(import libs). At **run time** the game needs `OpenAL32.dll` (system-wide install —
`assets/RP411/oalinst.exe` — or beside the exe) and `libsndfile-1.dll` (beside the
exe; a copy ships in `assets/RP411/`).

## 2. Building

```powershell
& "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\MSBuild\Current\Bin\MSBuild.exe" `
    WinTesla.sln /p:Configuration=Release /p:Platform=Win32 /m
```

`Debug|Win32` also builds. `x64` is not configured — this is a 32-bit build.
The solution is [WinTesla.sln](WinTesla.sln) with four v143 projects:

| Project | Type | Output |
|---------|------|--------|
| [MUNGA_L4/Munga_L4.vcxproj](MUNGA_L4/Munga_L4.vcxproj) | Static lib | `lib\Munga_l4.lib` |
| [RP_L4/RP_L4.vcxproj](RP_L4/RP_L4.vcxproj) | App (Windows) | `Release\rpl4opt.exe` — **the game** |
| [RP_L4/RPL4TOOL.vcxproj](RP_L4/RPL4TOOL.vcxproj) | App (Console) | `Release\RPL4TOOL.exe` |
| [DivLoader/DivLoader.vcxproj](DivLoader/DivLoader.vcxproj) | Static lib | `lib\DivLoader.lib` (Release) |

Build order is resolved by `ProjectReference` (RP_L4 and RPL4TOOL both reference
Munga_L4).

**Packaging:** [pack-dist.ps1](pack-dist.ps1) assembles a runnable game into
`dist\` (exe + PDB, game data, OpenAL/libsndfile runtimes, desktop
`environ.ini`, `start-windowed.bat`, README). Pass `-Zip` to also produce
`dist\RedPlanet412-prototype.zip` for handing to someone else.

## 3. VS2022 migration notes (what changed and why)

Settings preserved from the VC9 projects: **`/Zp1` struct packing** in Munga_L4
and RP_L4 (the engine's on-disk/on-wire binary formats depend on it — RPL4TOOL
and DivLoader never had it), Unicode, subsystems, x86, `/DYNAMICBASE:NO`,
optimization levels, and `/FORCE:MULTIPLE` (see below). Deliberate changes:

- **CRT unified to `/MD` (Release) / `/MDd` (Debug).** The VC9 build mixed
  `/MT` (Munga_L4, RPL4TOOL) with `/MD` (RP_L4) and forced the link.
- **Import libs are no longer merged into `Munga_L4.lib`** by the librarian;
  the exes link OpenAL32/d3d9/d3dx9/dinput8/dxguid/ws2_32 directly.
- `WINDOWS_IGNORE_PACKING_MISMATCH` is defined: the modern Windows SDK
  `static_assert`s against `/Zp1`; the VC9 build always compiled Windows
  headers at `/Zp1`, so this preserves those exact semantics. Un-`/Zp1`-ing
  the engine (pragma-pack only the serialized structs) is future work.
- `_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS` is defined: the code still uses
  `stdext::hash_map`; porting to `std::unordered_map` is future work.
- `legacy_stdio_definitions.lib` is linked: the June-2010 `dxerr.lib`
  references pre-UCRT stdio symbols.
- **Source fixes** (behavior-preserving): standard copy-ctor/assignment
  overloads added to `Time` (rvalues can't bind to `volatile&` in standard
  C++); `operator==(SOCKADDR_IN&,...)` in `NETWORK.h` made `inline`; the
  L4DINPUT callbacks renamed `DIEnum*` (they collided with L4CTRL's under
  LTCG); `std::ios.in` → `std::ios::in` in `CAMMGR.cpp`.
- `/FORCE:MULTIPLE` is still required: `gOpNames`, `gReplacementData`
  (hash_maps defined in a header) and `GlobalEggFileName` are genuinely
  defined in multiple TUs (LNK4006 warnings, same as the VC9 build). Moving
  them to a single TU is future cleanup.

## 4. Runtime notes

**Fixed (2026-07-12):** standalone mission load used to crash with an access
violation in `d3d_OBJECT::LoadTexture` ([MUNGA_L4/L4D3D.cpp](MUNGA_L4/L4D3D.cpp)):
`D3DXCreateTextureFromFileA` failures were never checked and the NULL texture
was cached and `AddRef()`ed. It crashed identically on VC9 — a latent defect
in the 2007 DPL→D3D9 port, exposed by the pod-skin textures (`VIDEO\player1–8`)
that a bare working copy doesn't contain (they normally come from the
replacement-material/presets path, `WTPresets` → `VIDEO\<name>.png`). Missing
textures now log `L4D3D.cpp couldn't load texture …` and render untextured;
the game boots to a running window with `-windowed -res 640 480 -egg TEST.EGG`
from a working copy like `assets/RP411/`.

For runtime debugging the v143 build produces full PDBs — run
`cdb -g -G -lines -y Release rpl4opt.exe ...` from the working directory
(cdb ships in this machine's Windows Kits).

### Running without the cockpit (Workstream A prototype)

Two new environment options remove the hardware dependency entirely:

- **`L4CONTROLS=PAD;KEYBOARD`** — selects **PadRIO**
  ([MUNGA_L4/L4PADRIO.cpp](MUNGA_L4/L4PADRIO.cpp)), an in-process RIO that
  speaks the full RIO control surface (buttons, axes, lamps) from an XInput
  controller + the PC keyboard. The stock `VTVRIOMapper` path runs unchanged.
  Hot-plugging works; with no controller it falls back to keyboard only.
- **`L4PLASMA=SCREEN`** — renders the 128×32 plasma display as its own
  desktop window ("Plasma Display", plasma orange, `L4PLASMASCALE` sets the
  pixel size, default 4). It opens directly below the main view;
  `L4PLASMAPOS=x,y` overrides. No COM port. Closing the window hides it.
- **`L4MFDSPLIT=1`** — assembles the **whole pod interior in one window**.
  The pod hardware drove five monochrome MFDs from the color channels of
  two video outputs (window 3 = upper MFDs in R/G/B, window 4 = lower
  MFDs in R/G) and mounted the map display portrait. In split mode the
  main game window becomes the cockpit shell and every display is a
  chrome-less child pane, arranged as in the pod:

  ```
  [ MFD UL ] [ MFD UC ] [ MFD UR ]
  [ plasma (reduced) ][ viewscreen (centered) ]
  [ MFD LL ] [   Map  ] [ MFD LR ]
  ```

  The cockpit is a fixed **1920×1080 internal canvas** (scaled down
  uniformly on smaller work areas): the viewscreen fills the whole
  canvas (launch with `-res 1920 1080` for native 1:1 3D), with compact
  320×240 MFD glasses in the four corners, the score glass top-center,
  and the portrait map bottom-center. The panes deliberately **overlap
  the viewscreen and render over it** — in the pod the MFD bezels
  partially occluded the viewport, and the same trick gives a
  full-screen 3D view with the cockpit floating over its edges. MFDs render green-screen and the map full-color/rotated,
  CPU-side from the shared gauge canvas (the packed D3D windows stay
  hidden); the 3D scene presents into the viewscreen pane via
  `Present`'s `hDestWindowOverride` (`gMainPresentWindow`), clipped
  around the panes (viewscreen pinned to the bottom of the z-order).
  Mouse clicks over the viewscreen fall through to the game window
  (STATIC pane hit-test transparency). The plasma glass is currently
  hidden in cockpit mode. This replaces the external BitBlt-mirror
  launcher wrapper.

  Each split window also carries its display's **physical button bank**
  (geometry per vRIO's `CockpitLayout`): 4 red buttons above and below
  each MFD glass (RIO addresses descending from the cluster anchor —
  upper left 0x2F, upper center 0x27, upper right 0x37, lower left 0x0F,
  lower right 0x07), and 6 amber buttons down each side of the map
  (Secondary 0x10–0x15 left, Screen 0x18–0x1D right; the columns' other
  addresses are Tesla relays, not buttons). They **light from the lamp
  states the game commands** (dim/bright, flash modes animate) and press
  the corresponding RIO unit with the mouse — active when `PadRIO` is the
  control device, dark and inert with real serial hardware.

Bindings (vRIO's default profile, condensed):

| Input | Pod control |
|-------|-------------|
| Left stick / WASD | joystick X/Y |
| LT / RT, Q / E | left / right pedal |
| Right stick Y, PgUp / PgDn | throttle (rate; position holds) |
| A / Space | joystick trigger |
| B / R | reverse thrust (ButtonThrottle1) |
| DPad / arrows | joystick hat (look) |
| X, Y, LB, RB | pinky / thumb-low / thumb-low / thumb-high |
| Start / F1, Back / F2 | config buttons (AuxUpperRight 1 / 2) |

`L4PADFLIP=XY` (or `X` / `Y`) inverts the stick axes if the feel is wrong.
Example desktop `environ.ini`:

```ini
L4CONTROLS=PAD;KEYBOARD
DPLARG=1
L4DPLCFG=RPDPL.INI
L4GAUGE=640x480x16
L4PLASMA=SCREEN
L4MFDSPLIT=1
TARGETFPS=60
```

Lamp commands land in `PadRIO::lampState[]` — the hook for the planned
on-screen cockpit panel (vRIO buttons arranged around the displays).

Also note: `Fail()` compiles to `abort()` in release (`MUNGA/DEBUGOFF.h`) —
e.g. running with `L4CONTROLS=KEYBOARD` alone aborts at VTV creation because
no keyboard-only pod mapper exists (the old CRT showed a blocking R6010
dialog; the UCRT fail-fasts). Use `L4CONTROLS=RIO;KEYBOARD` with vRIO serving
the RIO side, exactly like the arcade config.

## 5. Legacy VS2005/2008 build

The original `.vcproj` files and solution are kept as
[WinTesla_vc9.sln](WinTesla_vc9.sln) and still build with VC++ 2008 Express
SP1 + DXSDK June 2010:

```bat
@echo off
call "C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\Tools\vsvars32.bat"
set "DXSDK_DIR=C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\"
vcbuild /nologo /rebuild WinTesla_vc9.sln "Release|Win32"
```

See [docs/BUILD-NOTES.md](docs/BUILD-NOTES.md) for the original repository
cleanup history and the findings behind the legacy build.
