Files
RP412/MUNGA_L4/L4MFDVIEW.cpp
T
CydandClaude Fable 5 214a8e079c Un-pack the 7-display cockpit in-engine (L4MFDSPLIT=1)
The pod drove five monochrome MFDs from the color channels of two video
outputs - SVGA16 packs bit-slices of the shared gauge canvas into R/G/B
of gauge window 3 (upper MFDs) and R/G of window 4 (lower MFDs), with the
map palettized on the secondary and physically mounted portrait. The
desktop reconstruction previously required an external BitBlt-mirror
wrapper.

With L4MFDSPLIT=1, SVGA16 renders each display into its own window
(MFDSplitView, plain GDI) straight from the canvas + port bit-masks:
five green-screen MFD windows and the 90CW-rotated Map, tiled in the pod
grid to the right of the main view (L4MFDSCALE percent, default 50). The
packed D3D windows stay hidden but keep presenting off-screen, leaving
the original path untouched. Handles spanning mode (2-window setups).

Also: the plasma glass now opens directly below the main view (clamped
to the work area; L4PLASMAPOS=x,y overrides) per playtest feedback.

Verified: window grid comes up as main + 5 MFDs + Map + plasma with the
packed windows hidden; screenshots confirm a green MFD score readout and
the portrait tactical map rendering correctly. dist packer and BUILD.md
updated; the launcher wrapper is obsolete for split-mode use.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 14:10:52 -05:00

169 lines
3.5 KiB
C++

#include "mungal4.h"
#pragma hdrstop
#include "l4mfdview.h"
namespace
{
const char mfdViewClass[] = "RPMFDView";
const char mfdViewProp[] = "RPMFDViewBlit";
struct MFDViewBlit
{
BITMAPINFOHEADER header;
void *pixels;
int sourceWidth;
int sourceHeight;
};
LRESULT CALLBACK
MFDViewWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
const MFDViewBlit *blit =
(const MFDViewBlit *) GetPropA(hwnd, mfdViewProp);
if (blit != NULL && blit->pixels != NULL)
{
RECT client;
GetClientRect(hwnd, &client);
SetStretchBltMode(hdc, COLORONCOLOR);
StretchDIBits(
hdc,
0, 0, client.right, client.bottom,
0, 0, blit->sourceWidth, blit->sourceHeight,
blit->pixels, (const BITMAPINFO *) &blit->header,
DIB_RGB_COLORS, SRCCOPY
);
}
EndPaint(hwnd, &ps);
}
return 0;
case WM_CLOSE:
// Part of the cockpit; just hide it.
ShowWindow(hwnd, SW_HIDE);
return 0;
case WM_ERASEBKGND:
return 1;
}
return DefWindowProcA(hwnd, message, wParam, lParam);
}
}
MFDSplitView::MFDSplitView(
const char *title,
int source_width,
int source_height,
int client_width,
int client_height,
int x,
int y
)
{
Check_Pointer(this);
sourceWidth = source_width;
sourceHeight = source_height;
pixels = new unsigned long[source_width * source_height];
memset(pixels, 0, source_width * source_height * sizeof(unsigned long));
MFDViewBlit *blit = new MFDViewBlit;
memset(blit, 0, sizeof(MFDViewBlit));
blit->header.biSize = sizeof(BITMAPINFOHEADER);
blit->header.biWidth = source_width;
blit->header.biHeight = -source_height; // top-down
blit->header.biPlanes = 1;
blit->header.biBitCount = 32;
blit->header.biCompression = BI_RGB;
blit->pixels = pixels;
blit->sourceWidth = source_width;
blit->sourceHeight = source_height;
blitInfo = blit;
HINSTANCE instance = GetModuleHandleA(NULL);
static Logical class_registered = False;
if (!class_registered)
{
class_registered = True;
WNDCLASSA window_class;
memset(&window_class, 0, sizeof(window_class));
window_class.style = CS_HREDRAW | CS_VREDRAW;
window_class.lpfnWndProc = MFDViewWndProc;
window_class.hInstance = instance;
window_class.hCursor = LoadCursor(NULL, IDC_ARROW);
window_class.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
window_class.lpszClassName = mfdViewClass;
RegisterClassA(&window_class);
}
DWORD style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
RECT bounds;
bounds.left = 0;
bounds.top = 0;
bounds.right = client_width;
bounds.bottom = client_height;
AdjustWindowRect(&bounds, style, FALSE);
window = CreateWindowExA(
0,
mfdViewClass,
title,
style,
x, y,
bounds.right - bounds.left,
bounds.bottom - bounds.top,
NULL, NULL, instance, NULL
);
if (window != NULL)
{
SetPropA((HWND) window, mfdViewProp, blitInfo);
ShowWindow((HWND) window, SW_SHOWNOACTIVATE);
}
else
{
DEBUG_STREAM << "MFDSplitView: window creation failed (" << title << ")\n" << std::flush;
}
}
MFDSplitView::~MFDSplitView()
{
Check_Pointer(this);
if (window != NULL)
{
RemovePropA((HWND) window, mfdViewProp);
DestroyWindow((HWND) window);
window = NULL;
}
delete (MFDViewBlit *) blitInfo;
blitInfo = NULL;
delete [] pixels;
pixels = NULL;
}
Logical
MFDSplitView::TestInstance() const
{
return pixels != NULL;
}
void
MFDSplitView::Repaint()
{
Check_Pointer(this);
if (window != NULL)
{
InvalidateRect((HWND) window, NULL, FALSE);
}
}