MFD rendering: HALFTONE downscale, plus the exploded diagnostic view

Two pieces of MFD work that had been sitting in the tree (already in
every build and dist since).

The compact cockpit glass shows the full 640x480 gauge canvas at about
half size, and COLORONCOLOR did that by dropping every other row and
column - which shredded the 1-bit vector strokes and small text.
HALFTONE area-averages instead (with the brush origin set, as MSDN
requires) so the downscaled MFDs stay legible.

L4MFDSPLIT=2 adds an exploded diagnostic view: every display in its
own full-size desktop window at native resolution, decoded exactly as
the pod VDB split them from the single gauge canvas, with no cockpit
compositing and no downscale. It makes an individual MFD readable and
screenshottable at full resolution for comparison against the
emulator per-channel reference windows. L4MFDSPLIT=1 keeps the
composited glass cockpit and stays the default.

Also: .gitignore now covers the packaged RedPlanet-*.zip releases,
which live on the Gitea release page rather than in the tree.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-24 20:10:14 -05:00
co-authored by Claude Fable 5
parent 1ba3bde36a
commit 1bd6dd83e2
3 changed files with 67 additions and 2 deletions
+3
View File
@@ -67,3 +67,6 @@ assets/RP411/startrp-800x600.ps1
# ...but never the spool runtime output or Windows thumbnail caches.
assets/**/*.spl
assets/**/last.spl
# packaged releases (attached to Gitea releases, not tracked)
RedPlanet-*.zip
+6 -1
View File
@@ -342,7 +342,12 @@ void
FillRect(mem, &client, (HBRUSH) GetStockObject(BLACK_BRUSH));
SetStretchBltMode(mem, COLORONCOLOR);
// HALFTONE area-averages the downscale (the compact glass shows the
// full 640x480 canvas at ~half size); COLORONCOLOR dropped every other
// row/column, which shredded the 1-bit vector strokes and small text.
// HALFTONE requires the brush origin be set (MSDN).
SetStretchBltMode(mem, HALFTONE);
SetBrushOrgEx(mem, 0, 0, NULL);
StretchDIBits(
mem,
displayX, displayY, displayW, displayH,
+58 -1
View File
@@ -3842,11 +3842,19 @@ SVGA16::SVGA16(
//------------------------------------------------------------------
splitViews = False;
cockpitViewscreen = NULL;
Logical explodedViews = False;
{
const char *split_string = getenv("L4MFDSPLIT");
if (split_string != NULL && atoi(split_string) != 0)
{
splitViews = True;
// L4MFDSPLIT=2+ : exploded diagnostic view - each display
// in its own native-resolution desktop window instead of
// the composited glass cockpit.
if (atoi(split_string) >= 2)
{
explodedViews = True;
}
}
}
for (int view = 0; view < SplitViewCount; ++view)
@@ -3856,7 +3864,56 @@ SVGA16::SVGA16(
BuildWindows(init_width,init_height,windowed, secondaryIndex, aux1Index, aux2Index);
if (splitViews)
if (splitViews && explodedViews)
{
//---------------------------------------------------------------
// Exploded diagnostic view: every display in its own full-size
// desktop window (MFDs native 640x480, map 480x640 rotated),
// decoded exactly as the pod's VDB split them from the single
// gauge canvas - no cockpit compositing, no downscale. Each MFD
// can be read and screenshotted at full resolution, matching the
// emulator's per-channel reference windows. Laid out in the pod
// arrangement (top row / bottom row) across the work area; the
// windows are draggable (dragging a title bar briefly pauses the
// game's single-per-frame message pump, as expected).
//---------------------------------------------------------------
RECT work;
work.left = 0; work.top = 0; work.right = 1920; work.bottom = 1080;
SystemParametersInfoA(SPI_GETWORKAREA, 0, &work, 0);
int work_w = work.right - work.left;
int work_h = work.bottom - work.top;
int mid_x = (work_w - init_width) / 2; if (mid_x < 0) mid_x = 0;
int right_x = work_w - init_width; if (right_x < 0) right_x = 0;
int bottom_y = work_h - init_height; if (bottom_y < 0) bottom_y = 0;
splitView[SplitMFDUpperLeft] = new MFDSplitView(
"MFD upper left", init_width, init_height,
init_width, init_height, work.left, work.top,
MFDSplitView::NoButtons, 0, 0, 0);
splitView[SplitMFDUpperCenter] = new MFDSplitView(
"MFD upper center", init_width, init_height,
init_width, init_height, work.left + mid_x, work.top,
MFDSplitView::NoButtons, 0, 0, 0);
splitView[SplitMFDUpperRight] = new MFDSplitView(
"MFD upper right", init_width, init_height,
init_width, init_height, work.left + right_x, work.top,
MFDSplitView::NoButtons, 0, 0, 0);
splitView[SplitMFDLowerLeft] = new MFDSplitView(
"MFD lower left", init_width, init_height,
init_width, init_height, work.left, work.top + bottom_y,
MFDSplitView::NoButtons, 0, 0, 0);
splitView[SplitMFDLowerRight] = new MFDSplitView(
"MFD lower right", init_width, init_height,
init_width, init_height, work.left + right_x, work.top + bottom_y,
MFDSplitView::NoButtons, 0, 0, 0);
// map is portrait-mounted: source rotated to 480x640
splitView[SplitMap] = new MFDSplitView(
"Map", init_height, init_width,
init_height, init_width, work.left + mid_x, work.top + bottom_y,
MFDSplitView::NoButtons, 0, 0, 0);
}
else if (splitViews)
{
//---------------------------------------------------------------
// The 1920x1080 internal cockpit canvas.