//===========================================================================// // File: l4riobank.h // // Project: MUNGA_L4 Brick: cockpit RIO button-bank geometry // // Contents: the ONE layout rule for the buttons around a pod display // //---------------------------------------------------------------------------// // Copyright (C) 1994-1995, Virtual World Entertainment, Inc. // // PROPRIETARY AND CONFIDENTIAL // //===========================================================================// #ifndef _L4RIOBANK_H_ #define _L4RIOBANK_H_ //########################################################################### // Every pod secondary display carries a bank of illuminated RIO pushbuttons // mounted around its glass. We render that field TWICE -- once composited // into the main window (the COCKPIT SURROUND, L4VB16.cpp) and once per // display in its own desktop window (the EXPLODED view, L4GLASSWIN.cpp) -- // and until 2026-07-26 each renderer carried its own copy of the geometry. // They drifted: the exploded windows put the buttons UNDER the glass (a big // click target, only a thin lamp strip clearing the edge) while the surround // left the MFD lamps entirely outside the surface, so the same button was a // 156x138 target in one mode and a 76x24 sliver in the other. // // This is that geometry, once. A caller supplies a display rect and the // bank's anchor address(es); it gets back the button rects IN THAT SAME // SPACE plus the bounding box the bank needs. Placement -- WHERE each // display sits -- stays with the renderer, because that genuinely differs // (one composited canvas vs seven desktop windows). // // THE UNDER-GLASS RULE (ported from RP412 L4MFDVIEW, which took it from the // pod): a button reaches half the display in BEHIND the glass and only // `strip` clears the edge. The renderer draws the buttons FIRST and the // display imagery OVER them, so the lamp reads as a slim bar while // practically the whole display is the press target. Nothing is occluded -- // the picture wins every pixel it covers. // // Addresses per [[pod-hardware]] "The button space + lamps"; the anchors are // the caller's -- this file never hardcodes a bank address. //########################################################################### enum BTRioBankStyle { BTRioBankMfd = 0, // 4 buttons above the glass + 4 below, addresses // DESCENDING from anchorA row-major (0x2F..0x28) BTRioBankRadar // 6 down each side (anchorA left, anchorB right) // + an optional 4 along the bottom }; enum { BTRioBankMaxButtons = 24 }; struct BTRioButton { int address; // RIO buttonGroup address (0x00-0x47) int x, y, w, h; // caller-space rect (the FULL hit target) int colorClass; // 0 red (MFD) / 1 yellow (radar) / 2 blue (flight) int inert; // 1 = no authored .CTL mapping -> drawn greyed const char *label; // non-NULL -> the face is drawn + labelled }; //--------------------------------------------------------------------------- // How much of a button shows, and how the field is spaced. Both renderers // work at different scales (the surround halves the glass; the exploded // windows are native), so this is DERIVED from the display size -- the pod // rule applied at whatever size you hand it. //--------------------------------------------------------------------------- struct BTRioBankMetrics { int strip; // how much of a button clears the display edge (the lamp) int gap; // gap between neighbouring buttons in a row/column int cellW, cellH; // the labelled no-glass cell (flight bank, map foot row) }; struct BTRioBank { BTRioButton buttons[BTRioBankMaxButtons]; int buttonCount; // The bank + display bounding box, in the caller's space. A window // caller sizes its client to boundsW/H and passes an origin that puts // boundsX/Y at zero; the composited caller ignores these and just uses // the button rects, which are already in canvas space. int boundsX, boundsY, boundsW, boundsH; }; //--------------------------------------------------------------------------- // The pod rule at a given display size. The lamp strip scales off the SHORT // axis against the native 480 (an MFD is 640x480 landscape, the map 480x640 // portrait -- both have a 480 short axis) and never drops below a readable // floor, because a 5px lamp on a half-scale surround MFD is a smudge. //--------------------------------------------------------------------------- void BTRioBankMetricsFor(int displayW, int displayH, BTRioBankMetrics *out); //--------------------------------------------------------------------------- // Lay out one display's bank. originX/Y is the DISPLAY's top-left; button // rects come back around it, reaching `strip` outside the glass (so they can // land at negative coordinates relative to the origin -- see boundsX/Y). // anchorA/B bank base addresses (style-dependent; see BTRioBankStyle) // bottomAddrs BTRioBankRadar only: the 4 foot-row addresses, or NULL //--------------------------------------------------------------------------- void BTRioBankLayout( BTRioBankStyle style, int originX, int originY, int displayW, int displayH, int anchorA, int anchorB, const BTRioBankMetrics *metrics, const int *bottomAddrs, BTRioBank *out ); //--------------------------------------------------------------------------- // The no-display bank (throttle/panic 0x38-0x3F, joystick/fire 0x40-0x47): // a grid of labelled cells, drawn in full since there is no glass to hide // behind. APPENDS to `out` (so both columns share one bank) and grows its // bounds; zero `out` before the first call. `labels`/`inert` are `count` // long and may be NULL. // // These cells carry TEXT, so their size is the caller's call, not a scale of // some glass -- fill metrics->cellW/cellH yourself (the surround runs bigger // cells than the exploded window because its canvas is half-scale and the // labels still have to read). //--------------------------------------------------------------------------- void BTRioBankFlightGrid( int originX, int originY, int baseAddress, int count, int columns, const char *const *labels, const int *inert, const BTRioBankMetrics *metrics, BTRioBank *out ); //--------------------------------------------------------------------------- // One-shot geometry dump: `BT_RIOBANK_LOG=1` prints every button's address and // rect as the banks are built, so the field can be checked for coverage and // address shadowing without driving a mouse. Capped at the first few banks so // a per-frame caller (the surround recomputes its layout every draw) prints // one pass and then goes quiet. //--------------------------------------------------------------------------- void BTRioBankDump(const char *tag, const BTRioBank *bank); #endif