0a657b59989df52255a3c19d5c9aeda96735b437
-tmfds 4 splits the 1280x480 MFD span into two independent 640x480 monitors so
the span hardware is no longer required. It rendered correctly but stuttered
rhythmically and constantly, making the game unplayable. -tmfds 1 on the same
binary was flawless.
Root cause: a cross-DirectDraw-object texture read, twice every 7-frame cycle.
CHSH_Device::InitFirst with no pOtherHSHD peer creates its OWN IDirectDraw7 (via
wDirectDrawCreateEx on that monitor's device GUID) and InitSecond creates its OWN
primary flip chain and IDirect3DDevice7. CMFDRight_Device::InitFirst passes no
peer, so the right MFD is an entirely separate DirectDraw object.
EndChannel then did, for channels 3-4:
target->pD3DDevice->SetTexture(0, pDDSTarget);
where target->pD3DDevice belonged to the RIGHT device but pDDSTarget was the LEFT
device's render-target texture. The old code comment asserted "both devices are
on the same GPU so VRAM textures are mutually accessible" -- that premise is
wrong. In DirectDraw 7 a surface belongs to the IDirectDraw7 that created it, not
to the physical GPU, so it is not a valid texture on another object's D3D device.
The MFDs still displayed, which means the runtime was emulating the access with a
VRAM -> system-memory readback and re-upload of the 1024x512 16-bit render target.
That forces a full GPU pipeline stall, and it happened on channels 3 and 4 (that
is, sh_step 5 and 6) -- twice per 7-frame cycle, on the same GPU drawing the main
view. Hence a fixed-period hitch in the whole game, forever.
This also explains why the earlier stagger work (eaa5fd3, BeginSceneRight) did not
help: it only moved a Flip from sh_step 0 to 1, and the flips already used
DDFLIP_DONOTWAIT|DDFLIP_NOVSYNC and never blocked. The flips were never the
problem.
Fix: give the right device everything it draws with, and render channels 3-4
entirely on it.
- New HSH_CreateMFDTextures() builds the mech image atlas and the MFD sprite atlas
on a caller-supplied IDirectDraw7. Both devices now call it, so each owns a
complete independent texture set. CMFD_Device::InitSecond was refactored onto it.
- CMFDRight_Device gained its own pDDSMechTexture / pDDSDamageTexture /
pDDSTargetTexture plus a Release() override, and its InitSecond now sets up
tw/th and the material/render state exactly like the left device.
- New CMFD_Device::SwapRightState() exchanges this object's DATA members with the
right device's. BeginChannel swaps in when channel >= 3 in mode 4; EndChannel
swaps back. This routes all existing drawing to the correct monitor without
touching the ~233 mfd_device.* call sites in hudchat/huddamage/hudweapon/
GUIRadarManager. The vtable pointer is deliberately never swapped, so virtual
dispatch is unaffected; CHSHFont has no virtual functions so its array is
swapped bytewise to avoid ctor/dtor side effects on a temporary.
- EndChannel's composite is now a single path for all modes. Mode 4 composites
full 640 width at x=0 (each device is a standalone panel); modes 1-3 keep the
half-width (ch/3)*w packing into one backbuffer.
Side effects: startup builds the 65-bitmap mech atlas twice (once per device), and
VRAM use rises by a few MB. Modes 0-3 are behaviourally unchanged.
Known cosmetic leftover, deliberately not changed: huddamage.cpp lines ~1319 and
~1901 call LoadTargetTexture outside the channel-3 block, so those loads land on
the left device and go unused. The in-channel call at ~2209 runs every frame in
that branch and correctly populates the right device's copy, so behaviour is
correct -- it is just a redundant load on target change.
Requires rebuild: MW4.exe (GameOS changes recompile the engine library).
Verified: compiles clean, console launches. Two-monitor testing pending.
Co-authored-by: Claude Opus 5 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
BattleTech: FireStorm — workspace layout
⚠️ Setting up a new machine? Read
RECOVERY.mdBEFORE cloning this repo. The clone only comes out byte-exact if long paths,core.autocrlf=false, and Git LFS are configured first — cloning without them silently corrupts line endings, truncates deep VC98/MFC paths, and leaves LFS placeholders instead of the real binaries.
This is the working tree for the FireStorm total-conversion built on the MechWarrior 4
(Gameleap / GameOS) engine. Only three trees feed the build/deploy; everything else is
output (regenerable), design reference, or archived clutter. See CLAUDE.md for the full
build/runtime reconstruction notes.
Folder map
C:\VWE\firestorm\
├─ Gameleap\ The MW4/Gameleap 5.03 engine + game (the two live trees)
│ ├─ code\ ⭐ SOURCE CODE — build mw4\Code\MechWarrior4.dsw in VC6
│ │ ├─ CoreTech\ Reusable engine layer: GameOS, MLR renderer, gosFX,
│ │ │ GOSScript, Stuff, Network, blade + engine tools
│ │ ├─ mw4\Code\ The game itself: MW4 lib (AI, mechlab, HUD, shell),
│ │ │ MW4Application (→MW4.exe), MW4GameEd2 (mission editor),
│ │ │ scriptstrings/MissionLang (string DLLs), dedicated UI
│ │ ├─ mw4\Libraries\ mw4-local libs: Adept, stlport (build first), MLR,
│ │ │ Compost, ImageLib, gosfx, server, stuff …
│ │ ├─ mw4\Binaries\ 3DS Max export plug-ins (mech/prop .erf pipeline)
│ │ └─ rel.bin\ pro.bin\ Build OUTPUT: Release (MW4.exe, MW4pro.exe) / Profile
│ │ arm.bin\ dbg.bin\ (editor MW4Ed2.exe) / Armor / Debug — regenerable
│ └─ mw4\ ⭐ GAME DATA source tree (editor also runs here in place
│ │ via run-editor.bat; tool exes MapCreator/Tctd/NFOEditor…)
│ ├─ Content\ All content sources: Mechs\, Maps\, Missions\, Skies\,
│ │ Weapons\, WeaponSubsystems\, Subsystems\, Buildings\,
│ │ Vehicles\, Effects\, textures\, Campaigns\, Tables\,
│ │ Defines\, ABLScripts\ (mission/AI language),
│ │ ShellScripts\ (menu/mechlab UI), *.build manifests
│ ├─ Resource\ Packed .mw4 packages (output of `MW4pro -build`) +
│ │ Missions\*.nfo (MP registration) + UserMissions\
│ ├─ hsh\ Loose 2D art loaded at runtime: mech portraits, MFD
│ │ target images, HUD/radar bitmaps, decals, fonts
│ ├─ Assets\ Stats\ Runtime support data (cursors, world stats)
│ └─ Movies\ fonts\ Notes\ Cinematics / font sources / dev notes (not deployed)
├─ build-env\ ⭐ TOOLCHAIN — self-contained VC6 (VisualStudio6\),
│ │ DX 7.0a + DX Media 6 SDKs, stlnative\ headers,
│ │ ddrawcompat\ (editor viewport fix), .reg env files,
│ │ build/deploy scripts (see below), build logs
├─ MW4\ Runnable game deploy (output of deploy-mw4.ps1) —
│ regenerable; copy this to production
├─ BTFrstrm\ FireStorm design data: MechInfo_5.04.xls (stat source
│ of truth), scriptaddmech.xls (add-mech row generator)
├─ Finished HUDS from J&J\ Per-mech HUD source art (MFD + Radar) awaiting
│ integration, ~13 chassis
├─ _UNUSED\ Archived clutter — nothing read by the build (EXCEPT
│ worth knowing: Gameleap\EditorDocs\ = original map/
│ terrain/NFO/ABL tutorials)
├─ CLAUDE.md Full build/runtime reconstruction notes (the history)
├─ README.md This file — orientation + fresh-machine restore
├─ RECOVERY.md Disaster-recovery notes
├─ ADDING-A-MECH.md Workflow: add a new 'Mech chassis
└─ ADDING-A-MAP.md Workflow: add a new map/mission
The folders that matter (build inputs)
| Folder | Role | Notes |
|---|---|---|
Gameleap\code\ |
Source code + compiled binaries | C++ engine/game source (mw4\Code, CoreTech, mw4\Libraries). Build mw4\Code\MechWarrior4.dsw in VC6. Outputs land in rel.bin\ (Release MW4.exe, MW4pro.exe), pro.bin\ (editor MW4Ed2.exe), arm.bin\/dbg.bin\. |
Gameleap\mw4\ |
Game data source | The content tree the resource packer reads (Content\, and the generated resource\*.mw4, plus hsh\, Assets\, Stats\, runtime DLLs). This is the live data set — not GameleapCode5_03\Content (that was an old 2005 duplicate, now in _UNUSED). |
build-env\ |
Toolchain + scripts | Self-contained VC6 (VisualStudio6\), DirectX 7.0a + DX Media 6 SDKs, stlnative\, the .reg env files, and the deploy scripts. |
Build / deploy scripts (in build-env\)
deploy-mw4.ps1— packs resources from source (build-resources.ps1) then assembles the runnable game intoc:\VWE\firestorm\MW4. Trims dev bloat, ships only the canonical game packages, optimizes mech BMPs to 256-color, applies the DirectDraw compat shim.build-resources.ps1— (re)packsresource\*.mw4fromGameleap\mw4\Contentusing the in-exe compiler (MW4pro.exe -build). Called by the deploy; can be run standalone.deploy-editor.ps1— installs the mission editor in place intoGameleap\mw4(the data tree it edits): dropsMW4Ed2.exe+ DDrawCompat there, neutralizes the DDraw-breaking DLLs, sets the shim, writesrun-editor.bat. No separate editor directory. (build-resources.ps1moves DDrawCompat aside while the builder runs, since it's fatal toMW4pro.exe.)RESOURCE-BUILD.md— how the.mw4packaging works.
Outputs (regenerable — safe to delete and rebuild)
MW4\— runnable game deploy (fromdeploy-mw4.ps1). Move/copy this to production.- The editor has no separate output dir — it runs in place from
Gameleap\mw4viaGameleap\mw4\run-editor.bat(installed bydeploy-editor.ps1).
Design / reference (not build inputs)
BTFrstrm\— FireStorm design data: mech stat workbooks (MechInfo_*.xls, etc.).Finished HUDS from J&J\— per-mech HUD source art (MFD + Radar).
_UNUSED\ — archived clutter (nothing here is read by the build)
Moved here to reduce confusion. Safe to delete once you're comfortable. Contents:
Gameleap\{Archive, Drivers, EditorDocs, Notes, batch, utilities}— historical / original-machine utility data (the build only ever usedGameleap\mw4).GameleapCode5_03\{Content, hsh}— stale 2005 duplicate data trees (superseded byGameleap\mw4).resource_fullbak\— a one-off backup of the devresource\set taken during the from-scratch rebuild; redundant now that the dev tree is rebuilt.
TL;DR build flow
- Compile code: VC6 build
Gameleap\code\mw4\Code\MechWarrior4.dsw→rel.bin\/pro.bin\. - Deploy game:
build-env\deploy-mw4.ps1→MW4\(packs resources, assembles, optimizes). - (Optional) Install editor:
build-env\deploy-editor.ps1→ runs in place fromGameleap\mw4(run-editor.bat).
On a fresh Windows machine
- Install Git for Windows (includes Git LFS) — or Git +
git-lfsseparately. - Enable long paths before cloning (this tree has deep VC98/MFC paths > 260 chars):
(Also enable the OS setting:
git config --global core.longpaths true git config --global core.autocrlf false git lfs installHKLM\SYSTEM\CurrentControlSet\Control\FileSystem\LongPathsEnabled = 1.) - Clone to the same location so the absolute paths baked into the toolchain config resolve:
git clone https://gitea.mysticmachines.com/VWE/firestorm.git C:\VWE\firestormgit clonepulls LFS objects automatically. If any are missing:cd C:\VWE\firestorm && git lfs pull.
After restore — make it buildable / runnable
- Build toolchain (VC6): import the registry config (ELEVATED), per
build-env\README.md:Then buildreg import C:\VWE\firestorm\build-env\vc6-hklm-registration.reg reg import C:\VWE\firestorm\build-env\vc6-directories.regGameleap\code\mw4\Code\MechWarrior4.dsw(seeCLAUDE.mdSTEP 1/3), or just use the already-mirroredGameleap\code\rel.bin/pro.binbinaries. - Run the game:
build-env\deploy-mw4.ps1reassemblesC:\VWE\firestorm\MW4and applies the Win11 DirectDraw compat shim; or run the already-mirroredC:\VWE\firestorm\MW4\MW4.exeafter re-applying the shim (AppCompat is keyed on exe path, so a new machine needs it re-set — the deploy script does this). - Editor:
Gameleap\mw4\run-editor.bat(installed in place; seeCLAUDE.mdSTEP 9).
Notes
core.autocrlf=false— line endings are preserved byte-for-byte; keep it that way.- The mirror includes machine-specific bits (registry exports, deploy AppCompat). They restore the files, but registry/AppCompat state must be re-imported on the new machine (steps above).
- See
CLAUDE.mdfor the full build/runtime reconstruction history andREADME.mdfor the layout.
Languages
C
48.8%
C++
36.9%
Rich Text Format
12.2%
HTML
0.6%
Visual Basic 6.0
0.5%
Other
0.5%