Glass cockpit: per-display windows (BT_GLASS_PANELS)
Break the desktop glass cockpit's secondary displays out of the single combined pad panel + D3D gauge strip into ONE window per pod display, each carrying that display's surface with its RIO button bank, arranged pod-faithfully around the main view. New TU engine/MUNGA_L4/L4GLASSWIN.* (BT_GLASS-only), selected by the -platform glass preset via the new runtime gate BT_GLASS_PANELS (=0 falls back to the legacy single panel + dock). - Surfaces are CPU-expanded from the shared gauge buffer (SVGA16::ExpandPlaneToBGRA, no D3D) and StretchDIBits'd in -- the D3D dev-composite path (dock / window / overlay) stands down while active. - Buttons sit UNDER the imagery: big hidden click targets that reach into the display, with only a small protruding edge showing as a lamp light. Red MFD banks tile the top/bottom; radar rails run the sides + a bottom row; a Flight Controls window hosts the no-display banks. - Windows: Heat / Engineering / Comm / Left Weapons / Right Weapons / radar + Flight Controls; edge-to-edge (no in-client margin/title; OS caption labels each). - Fix blank surfaces: application/ghWnd are duplicate-defined and bind non-deterministically under /FORCE, so the fresh L4GLASSWIN TU read NULL. Reach the renderer/window via BTResolveGaugeRenderer/BTResolveMainWindow defined in btl4main.cpp off the real btl4App/hWnd pointers. New gotcha: reconstruction-gotchas.md S6 duplicate-GLOBAL corollary. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,14 @@
|
||||
#include "L4VIDEO.h"
|
||||
#include "DXUtils.h"
|
||||
|
||||
#ifdef BT_GLASS
|
||||
#include "l4glasswin.h" // BTGlassPanelsActive(): the per-display windows own the surfaces
|
||||
#endif
|
||||
// BTResolveGaugeRenderer()/BTResolveMainWindow() (l4vb16.h) are DEFINED in
|
||||
// game/btl4main.cpp off the real app/window pointers -- NOT here: an engine TU
|
||||
// can bind the NULL /FORCE-duplicate copy of `application`/`ghWnd`, and which
|
||||
// copy an obj binds is non-deterministic per link.
|
||||
|
||||
#if defined(TRACE_SCREEN_COPY)
|
||||
static BitTrace Screen_Copy("Screen Copy");
|
||||
#define SET_SCREEN_COPY() Screen_Copy.Set()
|
||||
@@ -153,6 +161,18 @@ static bool DevGaugeDocked()
|
||||
return v != 0 || gBTGaugeDockBottom != 0;
|
||||
}
|
||||
|
||||
// GLASS per-display windows (L4GLASSWIN) own the instrument surfaces in their OWN
|
||||
// GDI windows -- when active, the whole D3D dev-composite path (dock / separate
|
||||
// window / overlay) must stand down so nothing double-draws into the main window.
|
||||
static bool GlassPanelsOwnSurfaces()
|
||||
{
|
||||
#ifdef BT_GLASS
|
||||
return BTGlassPanelsActive() != 0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
//===========================================================================//
|
||||
// DEV-COMPOSITE (option B) -- draw the woken gauge renderer's SECONDARY/radar
|
||||
// surface as an inset in the MAIN window. The gauge widgets have already
|
||||
@@ -260,6 +280,89 @@ void SVGA16::DrawDevSurface(LPDIRECT3DDEVICE9 device, int slot, int mask, int pa
|
||||
device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, sizeof(InsetVert));
|
||||
}
|
||||
|
||||
//===========================================================================//
|
||||
// GLASS per-display windows -- the CPU (no-D3D) analog of DrawDevSurface: expand
|
||||
// one bit-plane of the shared gauge pixelBuffer into a 32-bit BGRA image that the
|
||||
// GDI window blits with StretchDIBits (L4GLASSWIN.cpp). The rotation the D3D path
|
||||
// did via texture-UV remap is baked in here by transposing into `dst`.
|
||||
//===========================================================================//
|
||||
void SVGA16::ExpandPlaneToBGRA(int mask, int paletteID, int monoTint, int rotateQuadrant,
|
||||
unsigned long *dst, int *outW, int *outH)
|
||||
{
|
||||
int w = pixelBuffer.Data.Size.x; // 640
|
||||
int h = pixelBuffer.Data.Size.y; // 480
|
||||
if (dst == NULL || w <= 0 || h <= 0)
|
||||
{
|
||||
if (outW) *outW = 0;
|
||||
if (outH) *outH = 0;
|
||||
return;
|
||||
}
|
||||
Word *base = pixelBuffer.Data.MapPointer;
|
||||
SVGA16Palette *pal = &palette[paletteID];
|
||||
|
||||
if (rotateQuadrant == 0)
|
||||
{
|
||||
// Native orientation, top-down straight copy.
|
||||
for (int y = 0; y < h; y++)
|
||||
{
|
||||
Word *src = base + y * w;
|
||||
unsigned long *d = dst + y * w;
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
Word s = src[x];
|
||||
if (monoTint < 0)
|
||||
{
|
||||
PaletteTriplet *pe = &(pal->paletteData.Color[s & mask]);
|
||||
d[x] = ((unsigned long)pe->Red << 16) |
|
||||
((unsigned long)pe->Green << 8) | (unsigned long)pe->Blue;
|
||||
}
|
||||
else
|
||||
{
|
||||
d[x] = (s & mask) ? (unsigned long)monoTint : 0UL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (outW) *outW = w;
|
||||
if (outH) *outH = h;
|
||||
return;
|
||||
}
|
||||
|
||||
// 90-degree rotation: output is transposed (ow = h, oh = w). rotate 3 = CW,
|
||||
// rotate 1 = CCW (the DrawDevSurface convention; BT_GAUGE_SEC_ROT picks it).
|
||||
int ow = h, oh = w;
|
||||
for (int oy = 0; oy < oh; oy++)
|
||||
{
|
||||
unsigned long *d = dst + oy * ow;
|
||||
for (int ox = 0; ox < ow; ox++)
|
||||
{
|
||||
int sx, sy;
|
||||
if (rotateQuadrant == 3) // 90 CW: out(ox,oy) = src(oy, h-1-ox)
|
||||
{
|
||||
sx = oy;
|
||||
sy = h - 1 - ox;
|
||||
}
|
||||
else // 90 CCW: out(ox,oy) = src(w-1-oy, ox)
|
||||
{
|
||||
sx = w - 1 - oy;
|
||||
sy = ox;
|
||||
}
|
||||
Word s = base[sy * w + sx];
|
||||
if (monoTint < 0)
|
||||
{
|
||||
PaletteTriplet *pe = &(pal->paletteData.Color[s & mask]);
|
||||
d[ox] = ((unsigned long)pe->Red << 16) |
|
||||
((unsigned long)pe->Green << 8) | (unsigned long)pe->Blue;
|
||||
}
|
||||
else
|
||||
{
|
||||
d[ox] = (s & mask) ? (unsigned long)monoTint : 0UL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (outW) *outW = ow;
|
||||
if (outH) *outH = oh;
|
||||
}
|
||||
|
||||
//
|
||||
// The pod's SIX instrument surfaces, all bit-plane views of the ONE shared 640x480
|
||||
// gauge buffer (masks/positions from content/GAUGE/L4GAUGE.CFG MechInit @4395):
|
||||
@@ -401,6 +504,7 @@ void BTDrawGaugeSurfaces(LPDIRECT3DDEVICE9 device, float px, float py, float pw,
|
||||
void BTDrawGaugeInset(LPDIRECT3DDEVICE9 device)
|
||||
{
|
||||
if (!DevGaugeComposite() || !DevGaugeDocked() || device == NULL) return;
|
||||
if (GlassPanelsOwnSurfaces()) return; // the per-display glass windows draw the surfaces
|
||||
if (gBTGaugeDockBottom)
|
||||
{
|
||||
// DOCK-BOTTOM: the strip owns the bottom band of the target (the world
|
||||
@@ -544,6 +648,7 @@ static bool BTGaugeWindowEnsure(LPDIRECT3DDEVICE9 device)
|
||||
void BTGaugeWindowRenderAndPresent(LPDIRECT3DDEVICE9 device)
|
||||
{
|
||||
if (!DevGaugeComposite() || DevGaugeDocked() || device == NULL) return;
|
||||
if (GlassPanelsOwnSurfaces()) return; // the per-display glass windows draw the surfaces
|
||||
if (!BTGaugeWindowEnsure(device)) return;
|
||||
|
||||
IDirect3DSurface9 *gaugeBB = NULL;
|
||||
|
||||
Reference in New Issue
Block a user