VDB decode SOLVED: six displays bit-packed in the 16bpp pixel

The gauge framebuffer is an encoded stream: each 16bpp pixel packs all six
cockpit displays. Decoded live into per-display windows:
  bits 0-5   = the COLOR radar/tactical display, as 6-bit RGB (2 bits/channel)
  bits 6-7   = mono display 1 (nav scope)
  bits 8-9   = mono display 2 (weapons/systems)
  bits 10-11 = mono display 3 (sensor cluster)
  bits 12-13 = mono display 4
  bits 14-15 = mono display 5
That's 6 + 5x2 = 16 bits exactly -> six displays (1 color + 5 mono), matching
the pod hardware. A 7th window (bits 16-17) confirms the budget: it's black.

Each display now renders in its own 640x480 window from the shared framebuffer
(vga.mem.linear). Mono screens show as brightness; the three VDB palettes are
the per-display color maps (next: apply them).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-03 20:09:36 -05:00
co-authored by Claude Opus 4.8
parent 1b973917fa
commit 7a615449c5
+29 -14
View File
@@ -669,20 +669,30 @@ static void pal_draw(HDC dc, int g, int cw, int ch) {
Bitu start = vga.config.real_start; /* visible page start (bytes) */
Bitu stride = (Bitu)W * 2; /* 16bpp */
if (fb) {
/* The six displays are bit-packed into each 16bpp pixel:
* window 0 = the COLOR radar = bits 0-5 as 6-bit RGB (2 bits/chan)
* window g>=1 = a mono display = the 2-bit field at bit (4 + 2*g)
* (g=1 -> bits 6-7, ... g=5 -> bits 14-15)
* rendered as brightness. */
unsigned shift = 4u + 2u * (unsigned)g; /* used for g>=1 */
for (int y = 0; y < H; y++) {
Bitu ofs = start + (Bitu)y * stride;
unsigned char *d = &img[(size_t)y * W * 3];
for (int x = 0; x < W; x++, ofs += 2, d += 3) {
uint16_t px = *(const uint16_t *)(fb + (ofs & mask));
d[0] = (unsigned char)(((px >> 11) & 0x1F) * 255 / 31);
d[1] = (unsigned char)(((px >> 5) & 0x3F) * 255 / 63);
d[2] = (unsigned char)(( px & 0x1F) * 255 / 31);
if (g == 0) {
d[0] = (unsigned char)(( px & 0x3u) * 85u); /* R: bits 0-1 */
d[1] = (unsigned char)(((px >> 2u) & 0x3u) * 85u); /* G: bits 2-3 */
d[2] = (unsigned char)(((px >> 4u) & 0x3u) * 85u); /* B: bits 4-5 */
} else {
unsigned char v = (unsigned char)(((px >> shift) & 0x3u) * 85u);
d[0] = d[1] = d[2] = v;
}
}
}
} else {
memset(img, 0, sizeof img);
}
(void)g;
glViewport(0, 0, cw, ch);
glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST); glDisable(GL_TEXTURE_2D); glDisable(GL_LIGHTING);
@@ -732,15 +742,20 @@ static DWORD WINAPI rt_main(LPVOID) {
if (!make_gl_window("VPX VelociRender (emulated)", 832, 512, 40, 40,
&wnd, &dc, &gl)) return 1;
/* three 640x480 windows, one per VDB display palette */
static const char *pal_titles[3] = {
"VDB palette 0 - secondary", "VDB palette 1 - aux1",
"VDB palette 2 - aux2" };
HWND pwnd[3]; HDC pdc[3]; HGLRC pgl[3];
bool phave[3] = { false, false, false };
for (int g = 0; g < 3; g++)
/* one 640x480 window per decoded display: window 0 = color radar
* (bits 0-5 RGB), windows 1-6 = the mono displays (2-bit fields). */
const int NPAL = 7;
static const char *pal_titles[7] = {
"display 0 - radar (bits 0-5 RGB)", "display 1 (bits 6-7)",
"display 2 (bits 8-9)", "display 3 (bits 10-11)",
"display 4 (bits 12-13)", "display 5 (bits 14-15)",
"display 6 (bits 16-17)" };
HWND pwnd[7]; HDC pdc[7]; HGLRC pgl[7];
bool phave[7] = { false, false, false, false, false, false, false };
for (int g = 0; g < NPAL; g++)
phave[g] = make_gl_window(pal_titles[g], 640, 480,
920, 40 + g * 500, &pwnd[g], &pdc[g], &pgl[g]);
880 + (g % 3) * 650, 30 + (g / 3) * 470,
&pwnd[g], &pdc[g], &pgl[g]);
VFrame cur;
for (;;) {
@@ -765,8 +780,8 @@ static DWORD WINAPI rt_main(LPVOID) {
rt_frames++;
}
}
/* redraw the palette windows every tick (live) */
for (int g = 0; g < 3; g++) {
/* redraw the display windows every tick (live) */
for (int g = 0; g < NPAL; g++) {
if (!phave[g]) continue;
wglMakeCurrent(pdc[g], pgl[g]);
RECT cr; GetClientRect(pwnd[g], &cr);