Auto-fit the cockpit to the monitor; hide the plasma glass for now

The assembled shell could exceed the work area (1291px tall at default
scale) - on a 1080p monitor the whole lower row, map included, hung off
the bottom of the screen, which read as the map not rendering, and the
lamp-reactive preset buttons were unreachable down there. (The render
and click paths themselves were verified fine: a synthetic press on a
map preset button lights it through the game lamp command.)

The layout now measures SPI_GETWORKAREA and fits: the pane scale steps
down (to 20% minimum) and the viewscreen takes the leftover height at
the 3D aspect, shrinking below native when needed - Present stretches,
so the scene scales cleanly. Rows and viewscreen center in the shell,
which is sized to the work area. Verified: at 70% panes in a 1392-high
work area the viewscreen reduced to 609x457 with everything on screen.

The plasma glass sits out of the cockpit for the moment
(PlasmaScreen::Hide) per playtest direction.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-12 15:01:19 -05:00
co-authored by Claude Fable 5
parent aa24968c3d
commit 3b775e19d9
4 changed files with 120 additions and 60 deletions
+6 -3
View File
@@ -132,9 +132,12 @@ Two new environment options remove the hardware dependency entirely:
scene presents into the viewscreen pane via `Present`'s
`hDestWindowOverride` (`gMainPresentWindow`), so no swap-chain changes.
Mouse clicks over the viewscreen fall through to the game window
(STATIC pane hit-test transparency). `L4MFDSCALE` sets the MFD/map pane
size in percent of the gauge canvas (default 50). This replaces the
external BitBlt-mirror launcher wrapper.
(STATIC pane hit-test transparency). The shell **auto-fits the monitor
work area**: the pane scale steps down and the viewscreen shrinks (the
present stretches) until the whole cockpit is on screen. `L4MFDSCALE`
sets the *requested* MFD/map pane size in percent of the gauge canvas
(default 50). 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
+9
View File
@@ -103,6 +103,15 @@ void
);
}
void
PlasmaScreen::Hide()
{
if (activeInstance != NULL && activeInstance->window != NULL)
{
ShowWindow((HWND) activeInstance->window, SW_HIDE);
}
}
PlasmaScreen::PlasmaScreen():
Video8BitBuffered(plasmaWidth, plasmaHeight)
{
+4
View File
@@ -44,6 +44,10 @@ public:
static void
Position(void *parent, int x, int y, int client_width, int client_height);
// Hide the glass entirely (cockpit currently runs without it).
static void
Hide();
protected:
static PlasmaScreen
*activeInstance;
+101 -57
View File
@@ -3856,69 +3856,116 @@ SVGA16::SVGA16(
}
}
int cell_w = (init_width * scale_percent) / 100;
int cell_h = (init_height * scale_percent) / 100;
//---------------------------------------------------------------
// Assemble the pod interior in ONE window (the main game window
// becomes the cockpit shell; every display is a chrome-less
// child pane):
// [ MFD UL ] [ MFD UC ] [ MFD UR ]
// [ plasma (reduced) ][ viewscreen (centered) ]
// [ viewscreen (centered) ]
// [ MFD LL ] [ Map ] [ MFD LR ]
// The 3D scene presents into the viewscreen child via
// gMainPresentWindow.
// gMainPresentWindow. The whole shell AUTO-FITS the monitor work
// area: pane scale steps down and the viewscreen shrinks (the
// present stretches) until everything is on screen.
//---------------------------------------------------------------
int gap = 8;
// pane sizes mirror MFDSplitView::LayoutButtons (buttonGap = 4)
int strip_h = cell_h / 8;
if (strip_h < 18) strip_h = 18;
if (strip_h > 40) strip_h = 40;
int block_h = cell_h + 2 * (strip_h + 8);
int map_col_w = cell_h / 8;
if (map_col_w < 20) map_col_w = 20;
if (map_col_w > 40) map_col_w = 40;
int map_block_w = cell_h + 2 * (map_col_w + 8);
int map_block_h = cell_w;
int col_span = cell_w + gap;
int row_w = 3 * cell_w + 2 * gap;
int band_y = block_h + gap;
int main_w = (int) L4Application::GetScreenWidth();
int main_h = (int) L4Application::GetScreenHeight();
// center the viewscreen under the columns, but always leave the
// plasma glass at least 128px of space at its left
int main_x = (row_w - main_w) / 2;
int plasma_min = 128 + 2 * gap;
if (main_x < plasma_min) main_x = plasma_min;
HWND cockpit = ApplicationManager::GetCurrentManager()->GetHWnd();
int lower_y = band_y + main_h + gap;
int lower_h = (block_h > map_block_h) ? block_h : map_block_h;
int client_w = (row_w > main_x + main_w) ? row_w : (main_x + main_w);
int client_h = lower_y + lower_h;
int chrome_w = 16, chrome_h = 40;
if (cockpit != NULL)
{
RECT outer, inner;
GetWindowRect(cockpit, &outer);
GetClientRect(cockpit, &inner);
chrome_w = (outer.right - outer.left) - inner.right;
chrome_h = (outer.bottom - outer.top) - inner.bottom;
}
RECT work;
work.left = 0; work.top = 0; work.right = 1600; work.bottom = 900;
SystemParametersInfoA(SPI_GETWORKAREA, 0, &work, 0);
int avail_w = (work.right - work.left) - chrome_w;
int avail_h = (work.bottom - work.top) - chrome_h;
//---------------------------------------------------------------
// Fit: step the pane scale down until the rows fit the width
// and leave a usable viewscreen height. Pane sizes mirror
// MFDSplitView::LayoutButtons (buttonGap = 4).
//---------------------------------------------------------------
int scale = scale_percent;
int cell_w, cell_h, strip_h, block_h;
int map_col_w, map_block_w, map_block_h;
int row_w, col_span, lower_h;
int view_w, view_h;
for (;;)
{
cell_w = (init_width * scale) / 100;
cell_h = (init_height * scale) / 100;
strip_h = cell_h / 8;
if (strip_h < 18) strip_h = 18;
if (strip_h > 40) strip_h = 40;
block_h = cell_h + 2 * (strip_h + 8);
map_col_w = cell_h / 8;
if (map_col_w < 20) map_col_w = 20;
if (map_col_w > 40) map_col_w = 40;
map_block_w = cell_h + 2 * (map_col_w + 8);
map_block_h = cell_w;
col_span = cell_w + gap;
row_w = 3 * cell_w + 2 * gap;
lower_h = (block_h > map_block_h) ? block_h : map_block_h;
// viewscreen gets the leftover height, at most native size,
// keeping the 3D aspect
view_h = avail_h - block_h - lower_h - 2 * gap;
if (view_h > main_h) view_h = main_h;
view_w = (int)((__int64) main_w * view_h / main_h);
if (view_w > avail_w)
{
view_w = avail_w;
view_h = (int)((__int64) main_h * view_w / main_w);
}
if ((row_w <= avail_w && view_h >= 240) || scale <= 20)
{
break;
}
scale -= 5;
}
if (scale != scale_percent)
{
DEBUG_STREAM << "SVGA16: pane scale reduced to " << scale
<< "% to fit the " << (work.right - work.left) << "x"
<< (work.bottom - work.top) << " work area\n" << std::flush;
}
int client_w = (row_w > view_w) ? row_w : view_w;
int client_h = block_h + gap + view_h + gap + lower_h;
int rows_x = (client_w - row_w) / 2;
if (rows_x < 0) rows_x = 0;
int view_x = (client_w - view_w) / 2;
if (view_x < 0) view_x = 0;
int band_y = block_h + gap;
int lower_y = band_y + view_h + gap;
//---------------------------------------------------------------
// Grow the main window into the cockpit shell
//---------------------------------------------------------------
HWND cockpit = ApplicationManager::GetCurrentManager()->GetHWnd();
if (cockpit != NULL)
{
SetWindowLongPtrA(cockpit, GWL_STYLE,
GetWindowLongPtrA(cockpit, GWL_STYLE) | WS_CLIPCHILDREN);
RECT outer, inner;
GetWindowRect(cockpit, &outer);
GetClientRect(cockpit, &inner);
int chrome_w = (outer.right - outer.left) - inner.right;
int chrome_h = (outer.bottom - outer.top) - inner.bottom;
SetWindowPos(cockpit, NULL, 0, 0,
SetWindowPos(cockpit, NULL, work.left, work.top,
client_w + chrome_w, client_h + chrome_h,
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
}
//---------------------------------------------------------------
@@ -3930,30 +3977,30 @@ SVGA16::SVGA16(
//---------------------------------------------------------------
splitView[SplitMFDUpperLeft] = new MFDSplitView(
"MFD upper left", init_width, init_height,
cell_w, cell_h, 0, 0,
cell_w, cell_h, rows_x, 0,
MFDSplitView::MFDStrips, 0x2F, 0, cockpit);
splitView[SplitMFDUpperCenter] = new MFDSplitView(
"MFD upper center", init_width, init_height,
cell_w, cell_h, col_span, 0,
cell_w, cell_h, rows_x + col_span, 0,
MFDSplitView::MFDStrips, 0x27, 0, cockpit);
splitView[SplitMFDUpperRight] = new MFDSplitView(
"MFD upper right", init_width, init_height,
cell_w, cell_h, 2 * col_span, 0,
cell_w, cell_h, rows_x + 2 * col_span, 0,
MFDSplitView::MFDStrips, 0x37, 0, cockpit);
splitView[SplitMFDLowerLeft] = new MFDSplitView(
"MFD lower left", init_width, init_height,
cell_w, cell_h, 0, lower_y,
cell_w, cell_h, rows_x, lower_y,
MFDSplitView::MFDStrips, 0x0F, 0, cockpit);
splitView[SplitMFDLowerRight] = new MFDSplitView(
"MFD lower right", init_width, init_height,
cell_w, cell_h, 2 * col_span, lower_y,
cell_w, cell_h, rows_x + 2 * col_span, lower_y,
MFDSplitView::MFDStrips, 0x07, 0, cockpit);
// map is portrait: source rotated 90 degrees clockwise, its pane
// centered under the middle column
splitView[SplitMap] = new MFDSplitView(
"Map", init_height, init_width,
cell_h, cell_w,
col_span + (cell_w - map_block_w) / 2, lower_y,
rows_x + col_span + (cell_w - map_block_w) / 2, lower_y,
MFDSplitView::SideColumns, 0x10, 0x18, cockpit);
//---------------------------------------------------------------
@@ -3966,25 +4013,22 @@ SVGA16::SVGA16(
cockpitViewscreen = CreateWindowExA(
0, "STATIC", "",
WS_CHILD | WS_VISIBLE | SS_BLACKRECT,
main_x, band_y, main_w, main_h,
view_x, band_y, view_w, view_h,
cockpit, NULL, GetModuleHandleA(NULL), NULL);
if (cockpitViewscreen != NULL)
{
gMainPresentWindow = cockpitViewscreen;
}
// plasma glass, reduced to fill the space left of the
// viewscreen, vertically centered in the band
int glass_w = main_x - 2 * gap;
int glass_h = glass_w / 4;
PlasmaScreen::Position(cockpit,
gap, band_y + (main_h - glass_h) / 2,
glass_w, glass_h);
}
// the plasma glass sits out for now
PlasmaScreen::Hide();
DEBUG_STREAM << "SVGA16: single-window cockpit assembled ("
<< client_w << "x" << client_h << ", scale "
<< scale_percent << "%)\n" << std::flush;
<< client_w << "x" << client_h << " in "
<< (work.right - work.left) << "x" << (work.bottom - work.top)
<< " work area, scale " << scale << "%, viewscreen "
<< view_w << "x" << view_h << ")\n" << std::flush;
}
//STUBBED: VIDEO RB 1/15/07
# if defined(DEBUG)