Add -tmon switch to hard-assign display devices

Display roles are auto-detected in FindVideoCards(): the main view takes the
first hardware-rasterizing device that is not a 1280x480-capable span, the radar
takes the next, and mode 4's two MFD panels take the two after that. That works
until DirectDraw enumerates the adapters in an unexpected order, at which point
the wrong content appears on the wrong monitor with no way to correct it.

Adds an override that keeps auto-detection as the default:

    -tmon <main>,<radar>,<mfd1>,<mfd2>

Values are 1-based, so the normal case is "-tmon 1,2,3,4". A value of 0 leaves
that slot auto-detected, so "-tmon 2,1,0,0" swaps only main and radar. Separators
may be ',' '/' or ':'. mfd1/mfd2 are only meaningful with -tmfds 4. Omitting the
switch entirely preserves existing behaviour exactly.

Implementation:

- Parsed in MW4Application's WinMain alongside -tmfds. That runs before GameOS
  calls FindVideoCards(), so the values are in place for device selection.
- Stored in g_naMonitorOverride[4] (VideoCard.cpp), extern'd in MW4Application.cpp.
- ApplyMonitorOverride() validates the index against NumDevices, so a stale -tmon
  on a machine with fewer monitors falls back to auto-detection rather than
  breaking startup.
- Ordering matters and is deliberate: main and radar are applied BEFORE the mode 4
  MFD search so that search still skips whichever devices the operator picked;
  mfd1/mfd2 are applied after it. Partial overrides therefore compose correctly.

Role map: main = Environment.FullScreenDevice, radar = g_nNonDualHead,
mfd1 = g_nMFD1, mfd2 = g_nMFD2. The mode 1 span (g_nDualHead) is intentionally
not overridable -- it is detected by 1280x480 mode support, which only the span
card advertises, so that detection is reliable.

Also adds a SPEW line logging the final role -> device map and device count.
Note this is only visible in Profile/LAB builds; SPEW compiles out in Release
(gos2X/Gos.h), so in Release the order is determined by observation.

Verified: compiles clean, console launches. Multi-monitor testing pending.

Co-authored-by: Claude Opus 5 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
This commit is contained in:
2026-07-24 23:39:59 -05:00
co-authored by Claude Opus 5 GitHub Copilot
parent 0a657b5998
commit 9ba2d594b1
2 changed files with 60 additions and 1 deletions
@@ -85,7 +85,10 @@ extern Time g_PlasmaClearTime;
extern Time g_TOC_ADT;
extern Time g_AUX_ADT;
extern bool g_UseMSRSP;
extern int g_nTypeOfMFDs; // 0 - no MFDs, 1 - orginal(5+1=dual & single), 2 - B&W(3 + 1=1 dual), 3 - color(3 + 1=2 dual)
extern int g_nTypeOfMFDs; // 0 - no MFDs, 1 - orginal(5+1=dual & single), 2 - B&W(3 + 1=1 dual), 3 - color(3 + 1=2 dual), 4 - split dual 640x480
// [tmon] Display-device override in Main/Radar/MFD1/MFD2 order; -1 = auto-detect.
// Defined in CoreTech GameOS VideoCard.cpp and consumed by FindVideoCards().
extern int g_naMonitorOverride[4];
extern int g_nRIOType;
extern DWORD g_dwRIOBaud; // [tbaud]
extern LONG g_ThrottleDir;
@@ -1443,6 +1446,34 @@ int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int n
if ((0 <= n) && (n <= 4)) // 0 - no MFDs, 1 - orginal(5+1=dual & single), 2 - B&W(3 + 1=1 dual), 3 - color(3 + 1=2 dual), 4 - split dual 640x480
g_nTypeOfMFDs = n;
}
// [tmon] Hard-assign the display devices when DirectDraw enumerates them in an
// unexpected order. Syntax: -tmon <main>,<radar>,<mfd1>,<mfd2>
// Values are 1-based (the normal case is "-tmon 1,2,3,4"); a value of 0 leaves that
// slot to auto-detection, so "-tmon 2,1,0,0" only swaps main and radar. Separators
// may be ',' '/' or ':'. mfd1/mfd2 are only used by -tmfds 4.
token = strstr(all_lower, "-tmon ");
if (token)
{
const char* p = &token[6];
int slot = 0;
while (slot < 4)
{
while (*p == ' ')
p++;
if ((*p < '0') || ('9' < *p))
break;
int v = atoi(p);
while (('0' <= *p) && (*p <= '9'))
p++;
// 0 = leave auto-detected, otherwise convert 1-based to a 0-based device index
g_naMonitorOverride[slot] = (0 < v) ? (v - 1) : -1;
slot++;
if ((*p == ',') || (*p == '/') || (*p == ':'))
p++;
else
break;
}
}
token = strstr(all_lower, "-trio ");
if (token && token[6])
{