diff --git a/BUILD.md b/BUILD.md index e0a021a..d5a1c06 100644 --- a/BUILD.md +++ b/BUILD.md @@ -127,17 +127,23 @@ Two new environment options remove the hardware dependency entirely: [ MFD LL ] [ Map ] [ MFD LR ] ``` - MFDs render green-screen and the map full-color/rotated, CPU-side from - the shared gauge canvas (the packed D3D windows stay hidden); the 3D - scene presents into the viewscreen pane via `Present`'s - `hDestWindowOverride` (`gMainPresentWindow`), so no swap-chain changes. + The cockpit is a fixed **1920×1080 internal canvas** (scaled down + uniformly on smaller work areas): the top row is three + native-resolution 640×480 glasses spanning exactly 1920, the 800×600 + viewscreen (launch with `-res 800 600`) sits centered, and the lower + MFDs (corners) + portrait map (bottom center) anchor to the bottom + edge. The panes deliberately **overlap the viewscreen and render over + it** — in the pod the MFD bezels partially occluded the viewport, and + the same trick lets a big 3D view and full-size gauges share the + canvas. MFDs render green-screen and the map full-color/rotated, + CPU-side from the shared gauge canvas (the packed D3D windows stay + hidden); the 3D scene presents into the viewscreen pane via + `Present`'s `hDestWindowOverride` (`gMainPresentWindow`), clipped + around the panes (viewscreen pinned to the bottom of the z-order). Mouse clicks over the viewscreen fall through to the game window - (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. + (STATIC pane hit-test transparency). 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 diff --git a/MUNGA_L4/L4MFDVIEW.cpp b/MUNGA_L4/L4MFDVIEW.cpp index abd6d07..c29404e 100644 --- a/MUNGA_L4/L4MFDVIEW.cpp +++ b/MUNGA_L4/L4MFDVIEW.cpp @@ -165,8 +165,9 @@ MFDSplitView::MFDSplitView( if (parent != NULL) { - // chrome-less pane inside the cockpit window - style = WS_CHILD | WS_VISIBLE; + // chrome-less pane inside the cockpit window; clips siblings so + // overlapping panes and the viewscreen never paint over it + style = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS; window_w = client_width; window_h = client_height; } @@ -253,9 +254,9 @@ void // 4 buttons above the glass, 4 below; RIO addresses descend // from the anchor, row-major (vRIO CockpitLayout::Mfd). //----------------------------------------------------------- - int strip_h = display_height / 8; - if (strip_h < 18) strip_h = 18; - if (strip_h > 40) strip_h = 40; + int strip_h = display_height / 16; + if (strip_h < 9) strip_h = 9; + if (strip_h > 20) strip_h = 20; int button_w = (display_width - 5 * buttonGap) / 4; @@ -279,15 +280,16 @@ void else if (button_style == SideColumns) { //----------------------------------------------------------- - // 6 buttons down each side of the glass (the pod wires only - // 6 of each column's 8 addresses to buttons; the rest are - // Tesla relays). Left = anchorA ascending, right = anchorB. + // 6 buttons down each side of the glass, stacked contiguous + // like the pod's strips (the pod wires only 6 of each + // column's 8 addresses to buttons; the rest are Tesla + // relays). Left = anchorA ascending, right = anchorB. //----------------------------------------------------------- int col_w = display_width / 8; if (col_w < 20) col_w = 20; if (col_w > 40) col_w = 40; - int button_h = (display_height - 7 * buttonGap) / 6; + int button_h = display_height / 6; displayX = col_w + 2 * buttonGap; *client_width = display_width + 2 * (col_w + 2 * buttonGap); @@ -298,7 +300,7 @@ void left->unit = anchorA + i; left->amber = 1; left->x = buttonGap; - left->y = buttonGap + i * (button_h + buttonGap); + left->y = i * button_h; left->w = col_w; left->h = button_h; @@ -397,6 +399,17 @@ void // one message per frame, and queued WM_PAINTs (lowest priority) starve // behind it - panes would freeze on their first frame. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +void + MFDSplitView::SetPosition(int x, int y) +{ + Check_Pointer(this); + if (window != NULL) + { + SetWindowPos((HWND) window, NULL, x, y, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + } +} + void MFDSplitView::Repaint() { diff --git a/MUNGA_L4/L4MFDVIEW.h b/MUNGA_L4/L4MFDVIEW.h index 6c3f5cd..86aa8a2 100644 --- a/MUNGA_L4/L4MFDVIEW.h +++ b/MUNGA_L4/L4MFDVIEW.h @@ -59,6 +59,12 @@ public: ClientHeight() const { return clientHeight; } + // Move the pane (child mode: parent client coords). Panes overlap + // the viewscreen like the pod's bezels, so exact placement happens + // after construction from the measured client sizes. + void + SetPosition(int x, int y); + ~MFDSplitView(); Logical diff --git a/MUNGA_L4/L4VB16.cpp b/MUNGA_L4/L4VB16.cpp index fcd9cd7..8ad85d8 100644 --- a/MUNGA_L4/L4VB16.cpp +++ b/MUNGA_L4/L4VB16.cpp @@ -3839,38 +3839,20 @@ SVGA16::SVGA16( if (splitViews) { //--------------------------------------------------------------- - // One window per cockpit display. L4MFDSCALE is the view size in - // percent of the gauge canvas (default 50). Default layout is the - // pod grid to the right of the main view: - // [ main ] [ UL ] [ C ] [ UR ] - // [ LL ] [ map ] [ LR ] + // The 1920x1080 internal cockpit canvas. + // + // [ MFD UL 640 ][ MFD UC 640 ][ MFD UR 640 ] <- native glass, + // exactly 1920 + // [ viewscreen 800x600, centered ] + // [ MFD LL ] [ Map ] [ MFD LR ] <- bottom edge + // + // The panes layer OVER the viewscreen like the pod's bezels - + // the MFDs partially occlude the main display by design, just + // as in the original cockpit. The whole canvas scales down + // uniformly on monitors smaller than 1920x1080. //--------------------------------------------------------------- - int scale_percent = 50; - const char *scale_string = getenv("L4MFDSCALE"); - if (scale_string != NULL) - { - int requested = atoi(scale_string); - if (requested >= 10 && requested <= 200) - { - scale_percent = requested; - } - } - - //--------------------------------------------------------------- - // 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 ] - // [ viewscreen (centered) ] - // [ MFD LL ] [ Map ] [ MFD LR ] - // The 3D scene presents into the viewscreen child via - // 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; - int main_w = (int) L4Application::GetScreenWidth(); - int main_h = (int) L4Application::GetScreenHeight(); + const int canvas_w = 1920; + const int canvas_h = 1080; HWND cockpit = ApplicationManager::GetCurrentManager()->GetHWnd(); @@ -3885,75 +3867,28 @@ SVGA16::SVGA16( } RECT work; - work.left = 0; work.top = 0; work.right = 1600; work.bottom = 900; + work.left = 0; work.top = 0; work.right = 1920; work.bottom = 1080; 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 (;;) + int scale_num = 100; + if (avail_w < canvas_w || avail_h < canvas_h) { - cell_w = (init_width * scale) / 100; - cell_h = (init_height * scale) / 100; + int fit_w = (avail_w * 100) / canvas_w; + int fit_h = (avail_h * 100) / canvas_h; + scale_num = (fit_w < fit_h) ? fit_w : fit_h; + if (scale_num < 25) scale_num = 25; - 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" + DEBUG_STREAM << "SVGA16: cockpit canvas scaled to " << scale_num + << "% for 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; +#define COCKPIT_CANVAS(v) (((v) * scale_num) / 100) + + int client_w = COCKPIT_CANVAS(canvas_w); + int client_h = COCKPIT_CANVAS(canvas_h); //--------------------------------------------------------------- // Grow the main window into the cockpit shell @@ -3969,51 +3904,22 @@ SVGA16::SVGA16( } //--------------------------------------------------------------- - // Button banks per display (addresses per vRIO CockpitLayout, - // bank-to-display placement per the pod cockpit): - // upper left MFD 0x2F.. / upper center 0x27.. / upper right - // 0x37.. / lower left 0x0F.. / lower right 0x07.. and the map - // flanked by Secondary 0x10-0x15 / Screen 0x18-0x1D. + // The viewscreen: created FIRST so every pane sits above it in + // the z-order, and clipped by those siblings so the 3D present + // never draws over them. STATIC hit-tests transparent, so mouse + // input over the 3D view reaches the game window as before. + // 800x600 (the -res native size), centered on the canvas. //--------------------------------------------------------------- - splitView[SplitMFDUpperLeft] = new MFDSplitView( - "MFD upper left", init_width, init_height, - 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, 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, 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, rows_x, lower_y, - MFDSplitView::MFDStrips, 0x0F, 0, cockpit); - splitView[SplitMFDLowerRight] = new MFDSplitView( - "MFD lower right", init_width, init_height, - 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, - rows_x + col_span + (cell_w - map_block_w) / 2, lower_y, - MFDSplitView::SideColumns, 0x10, 0x18, cockpit); + int view_w = COCKPIT_CANVAS(800); + int view_h = COCKPIT_CANVAS(600); - //--------------------------------------------------------------- - // The viewscreen: a black STATIC pane the 3D scene presents - // into. STATIC hit-tests transparent, so mouse input over the - // 3D view still reaches the game window as before. - //--------------------------------------------------------------- if (cockpit != NULL) { cockpitViewscreen = CreateWindowExA( 0, "STATIC", "", - WS_CHILD | WS_VISIBLE | SS_BLACKRECT, - view_x, band_y, view_w, view_h, + WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SS_BLACKRECT, + (client_w - view_w) / 2, (client_h - view_h) / 2, + view_w, view_h, cockpit, NULL, GetModuleHandleA(NULL), NULL); if (cockpitViewscreen != NULL) { @@ -4021,14 +3927,100 @@ SVGA16::SVGA16( } } + //--------------------------------------------------------------- + // Button banks per display (addresses per vRIO CockpitLayout, + // bank-to-display placement per the pod cockpit): + // upper left MFD 0x2F.. / upper center 0x27.. / upper right + // 0x37.. / lower left 0x0F.. / lower right 0x07.. and the map + // flanked by Secondary 0x10-0x15 / Screen 0x18-0x1D. + //--------------------------------------------------------------- + int top_glass_w = COCKPIT_CANVAS(640); + int top_glass_h = COCKPIT_CANVAS(480); + int bot_glass_w = COCKPIT_CANVAS(320); + int bot_glass_h = COCKPIT_CANVAS(240); + int map_glass_w = COCKPIT_CANVAS(240); + int map_glass_h = COCKPIT_CANVAS(320); + + splitView[SplitMFDUpperLeft] = new MFDSplitView( + "MFD upper left", init_width, init_height, + top_glass_w, top_glass_h, 0, 0, + MFDSplitView::MFDStrips, 0x2F, 0, cockpit); + splitView[SplitMFDUpperCenter] = new MFDSplitView( + "MFD upper center", init_width, init_height, + top_glass_w, top_glass_h, 0, 0, + MFDSplitView::MFDStrips, 0x27, 0, cockpit); + splitView[SplitMFDUpperRight] = new MFDSplitView( + "MFD upper right", init_width, init_height, + top_glass_w, top_glass_h, 0, 0, + MFDSplitView::MFDStrips, 0x37, 0, cockpit); + splitView[SplitMFDLowerLeft] = new MFDSplitView( + "MFD lower left", init_width, init_height, + bot_glass_w, bot_glass_h, 0, 0, + MFDSplitView::MFDStrips, 0x0F, 0, cockpit); + splitView[SplitMFDLowerRight] = new MFDSplitView( + "MFD lower right", init_width, init_height, + bot_glass_w, bot_glass_h, 0, 0, + MFDSplitView::MFDStrips, 0x07, 0, cockpit); + // map is portrait: source rotated 90 degrees clockwise + splitView[SplitMap] = new MFDSplitView( + "Map", init_height, init_width, + map_glass_w, map_glass_h, 0, 0, + MFDSplitView::SideColumns, 0x10, 0x18, cockpit); + + //--------------------------------------------------------------- + // Place the panes from their measured sizes: top row edge to + // edge across the canvas, bottom cluster on the bottom edge. + //--------------------------------------------------------------- + if (splitView[SplitMFDUpperLeft] != NULL) + { + splitView[SplitMFDUpperLeft]->SetPosition(0, 0); + } + if (splitView[SplitMFDUpperCenter] != NULL) + { + splitView[SplitMFDUpperCenter]->SetPosition( + (client_w - splitView[SplitMFDUpperCenter]->ClientWidth()) / 2, 0); + } + if (splitView[SplitMFDUpperRight] != NULL) + { + splitView[SplitMFDUpperRight]->SetPosition( + client_w - splitView[SplitMFDUpperRight]->ClientWidth(), 0); + } + if (splitView[SplitMFDLowerLeft] != NULL) + { + splitView[SplitMFDLowerLeft]->SetPosition( + 0, client_h - splitView[SplitMFDLowerLeft]->ClientHeight()); + } + if (splitView[SplitMFDLowerRight] != NULL) + { + splitView[SplitMFDLowerRight]->SetPosition( + client_w - splitView[SplitMFDLowerRight]->ClientWidth(), + client_h - splitView[SplitMFDLowerRight]->ClientHeight()); + } + if (splitView[SplitMap] != NULL) + { + splitView[SplitMap]->SetPosition( + (client_w - splitView[SplitMap]->ClientWidth()) / 2, + client_h - splitView[SplitMap]->ClientHeight()); + } + + // The panes go OVER the main display (pod bezel occlusion): pin + // the viewscreen to the bottom of the sibling z-order so the 3D + // present clips around every pane. + if (cockpitViewscreen != NULL) + { + SetWindowPos(cockpitViewscreen, HWND_BOTTOM, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + } + // the plasma glass sits out for now PlasmaScreen::Hide(); DEBUG_STREAM << "SVGA16: single-window cockpit assembled (" - << 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; + << client_w << "x" << client_h << " canvas at " << scale_num + << "%, viewscreen " << view_w << "x" << view_h + << " centered)\n" << std::flush; + +#undef COCKPIT_CANVAS } //STUBBED: VIDEO RB 1/15/07 # if defined(DEBUG)