Files
DOOM/linuxdoom-1.10/README.macos.md
gronod 6aaf73d70c
Build macOS app / Build DOOM.app (push) Canceled after 0s
macOS port: add app build workflow
2026-09-18 20:01:16 +01:00

161 lines
6.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# linuxdoom 1.10 — macOS port
This tree is the original linuxdoom 1.10 source, ported to build and run
natively on macOS (12.0+, x86_64). X11/MIT-SHM video and Linux OSS audio
were replaced with SDL2 and Apple AudioToolbox while keeping the original
software renderer and sound mixer.
There are two ways to build:
| | Output | SDL2 | IWAD |
|---|---|---|---|
| **App bundle** (recommended) | `DOOM.app` | vendored `SDL2.framework`, embedded | bundled FreeDoom, runs standalone |
| **CLI binary** | `linuxdoom-1.10/macos/doom` | Homebrew `sdl2` | bring your own via `DOOMWADDIR` |
## App bundle: `DOOM.app`
The committed `DOOM.xcodeproj` (at the repo root) builds a self-contained
`DOOM.app`: it embeds a real SDL2 2.30.x `SDL2.framework` (not
sdl2-compat, so no SDL3 dependency) and an IWAD, so the result runs on
any macOS 12+ x86_64 machine with no Homebrew install.
### One-time dependency fetch
```sh
macos-app/Scripts/fetch-deps.sh
```
This downloads `SDL2.framework` into `macos-app/Frameworks/` (pinned to
2.30.12) and makes sure at least one IWAD is in `macos-app/Resources/`:
any `*.wad` in the repo's `wads/` dir is copied first, otherwise
`freedoom2.wad` is downloaded (pinned to FreeDoom 0.13.0). The script is
idempotent and also runs as the first Xcode build phase, so it's safe to
skip this step and let the build do it — it only needs the network once.
### Build
```sh
open DOOM.xcodeproj # then ⌘R
# or
xcodebuild -scheme DOOM -configuration Release
```
The product lands in the usual DerivedData location
(`.../Build/Products/Release/DOOM.app`).
### Where things live at runtime
When launched as a bundle (Finder or `open DOOM.app`), the working
directory is `/`, so the app `chdir()`s to its data directory:
- **Savegames / screenshots**: `~/Library/Application Support/DOOM/`
- **Config**: `$HOME/.doomrc` (absolute path, unchanged upstream)
### IWAD search order
The engine checks each IWAD filename across all search dirs before moving
to the next name, so a higher-priority IWAD anywhere wins:
- Filenames (high → low): `doom2f` (French), `doom2`, `plutonia`, `tnt`,
`doomu`, `doom`, `doom1`, `freedoom2`, `freedoom1`
- Directories (high → low): `$DOOMWADDIR`, bundle `Contents/Resources`,
`~/Library/Application Support/DOOM`, `.`
Consequences:
- `doom.wad` in `macos-app/Resources/` beats the bundled `freedoom2.wad`.
- A `doom2.wad` dropped in `~/Library/Application Support/DOOM` beats a
bundled `freedoom2.wad` (filenames are compared before directories).
- To bundle your own IWAD, drop it in `macos-app/Resources/` (or `wads/`
before running `fetch-deps.sh`) and rebuild.
### Command-line arguments
The scheme ships with no arguments. To add some (`-3`, `-warp 1 1`,
`-file foo.wad`), edit the scheme in Xcode (Product ▸ Scheme ▸ Edit
Scheme ▸ Run ▸ Arguments). Equivalent from a terminal:
```sh
DOOM.app/Contents/MacOS/DOOM -warp 1 1
```
### Signing
The target signs ad-hoc (`CODE_SIGN_IDENTITY = "-"`). That's fine on the
machine that built it; on other Macs Gatekeeper will complain — either
right-click ▸ Open, or re-sign with a Developer ID for real distribution.
## CLI binary: `make`
```sh
brew install sdl2 # sdl2-compat (SDL3-backed) also works
cd linuxdoom-1.10 && make
```
Produces `linuxdoom-1.10/macos/doom`. Needs an IWAD via `DOOMWADDIR`
or cwd:
```sh
DOOMWADDIR=/path/to/wads ./macos/doom
```
The same IWAD search order above applies (App Support dir included), so
IWADs are shared between the app and the CLI binary.
## Useful options
| Option | Effect |
|---|---|
| `-2` / `-3` / `-4` | Start at 640×480, 960×720, or 1280×960 |
| `-fullscreen` | Fullscreen (scaled desktop mode) |
| `-grabmouse` | Grab the mouse (relative mouse mode) |
| `-warp E M` | Warp to episode/map, e.g. `-warp 1 1` |
| `-nomouse` / `-nojoy` | Disable input devices |
The window is freely resizable down to 640×480. DOOM keeps its original
320×200 internal framebuffer and scales it with nearest-neighbour filtering
into the largest centered 4:3 area, adding black bars for wider or taller
windows. SDL's renderer output size is used so the presentation also stays
correct on Retina displays.
A new configuration starts at 960×720. Normal window resizing updates the
`window_width` and `window_height` settings in `.doomrc`, and that windowed
size is restored on the next launch. Fullscreen size changes and the `-2`,
`-3`, and `-4` startup presets do not overwrite the remembered size unless
the window is subsequently resized by the user.
## Porting notes
- `i_video.c` — resizable, high-DPI SDL2 window/renderer/streaming ARGB8888
texture; the 320x200 indexed framebuffer is palette-expanded each frame
and aspect-corrected to 4:3 for presentation.
Keyboard/mouse SDL events are translated to DOOM `event_t`s.
- `i_sound.c` — original software mixer retained; output is queued to
an SDL2 audio device (11025 Hz s16 stereo) instead of `/dev/dsp`.
Music lumps are converted by `mus2mid.c` (MUS→MIDI; already-MIDI
lumps pass through) and played with AudioToolbox
`MusicSequence`/`MusicPlayer` through the system DLS synth —
no SDL_mixer or soundfont needed. Track looping uses
`kSequenceTrackProperty_LoopInfo`.
- `i_mac.c` — bundle detection (`CFBundleGetIdentifier`), resource-dir
and `~/Library/Application Support/DOOM` lookup, and the bundled-app
`chdir()` that redirects all relative-path writes (savegames,
screenshots) somewhere writable.
- 64-bit fixes: pointer-size casts in the renderer, savegame code,
zone allocator and `m_misc` defaults; WAD `maptexture_t` layout
corrected (`columndirectory` is a 4-byte offset, not a pointer);
`*4`-sized allocations for pointer arrays fixed; unsequenced
`eventhead`/`eventtail` updates made well-defined.
- Networking (`i_net.c`) still uses UDP/BSD sockets and should work
for `-net` play; it is unchanged apart from byte-order/socket fixes.
## Known limitations
- Embedded demo lumps recorded for other engine versions print
"Demo is from a different game version" — use `-warp` to skip the
title-screen demo loop if the IWAD's demos mismatch (e.g. FreeDoom).
- Music volume slider is tracked but not applied to the MusicPlayer
(AudioToolbox has no per-sequence gain at this API level).
- x86_64 only; no arm64 slice. `sndserv/`, `ipx/`, `sersrc/` are
unused by this port.