Emulator: VDB heads mirror TEXT mode -- boot scroll + suite menus, like the
real cockpit The splitter passed the analog VGA signal through whenever the game's packed mode wasn't driving it: a person in the cockpit watched the PC boot sequence scroll across every secondary display, and the test suite's menus were readable on the heads. pal_draw now rasterizes M_TEXT (80x25 through the live font tables + attribute palette -> VGA DAC, 8-dot cells, centered 640x400) with the mono MFD windows showing single-wire green-phosphor luminance. Two DOSBox-X planar-layout lessons encoded in comments: text cells live in linear_base as one latch DWORD per character address (char/attr = plane 0/1 bytes, cell stride 4<<addr_shift, lvida = vidstart<<2), and font_tables index PLANAR vram too -- one font byte per dword, so the glyph fetch is ((chr<<5)+line)*4. Plus a 2s textdiag line (row-0 decode) in the vpx log for future text-path debugging. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1396,7 +1396,78 @@ static void pal_draw(HDC dc, int g, int cw, int ch, bool dump) {
|
||||
if (lin8) stride = (vga.draw.address_add >= (Bitu)W &&
|
||||
vga.draw.address_add <= (Bitu)W * 4)
|
||||
? vga.draw.address_add : (Bitu)W;
|
||||
if (fb) {
|
||||
if (fb && vga.mode == M_TEXT) {
|
||||
/* Pass-through, TEXT mode: the real splitter mirrored the analog VGA
|
||||
* signal always -- someone in the cockpit saw the PC BOOT SEQUENCE
|
||||
* scroll across every secondary display, and the test suite's menus
|
||||
* are only identifiable on the heads because of it. Rasterize the
|
||||
* 80x25 text screen through the live font tables + attribute palette,
|
||||
* 8-dot cells = 640x400 centered in the 480-line head. */
|
||||
memset(img, 0, sizeof img);
|
||||
const unsigned cols = 80, chh = 16;
|
||||
const int chn0 = (g > 4) ? ((g <= 6) ? g - 5 : g - 7) : -1;
|
||||
/* EGA/VGA text lives in linear_base as 32-bit planar latches: one
|
||||
* DWORD per character address, char = plane-0 byte, attr = plane-1
|
||||
* byte (see EGAVGA_TEXT_Combined_Draw_Line: lvida = vidstart<<2,
|
||||
* cell skip = 4<<addr_shift). NOT the CGA 2-byte layout. */
|
||||
const uint8_t *vram = vga.draw.linear_base;
|
||||
const Bitu vidmask = vga.draw.linear_mask;
|
||||
const Bitu cell_vs = (Bitu)1u << vga.config.addr_shift;
|
||||
if (vpx_fp && g == 0) { /* decode diagnostic: row 0 as we read it */
|
||||
static double last_txt = 0.0; double nowt = (double)GetTickCount();
|
||||
if (nowt - last_txt > 2000.0) {
|
||||
last_txt = nowt;
|
||||
fprintf(vpx_fp, "# VDB textdiag addr_shift=%u addr_add=%u start=0x%X row0: ",
|
||||
(unsigned)vga.config.addr_shift,
|
||||
(unsigned)vga.draw.address_add,
|
||||
(unsigned)vga.config.real_start);
|
||||
for (unsigned c = 0; c < 40; c++) {
|
||||
Bitu vs0 = vga.config.real_start + (Bitu)c * cell_vs;
|
||||
unsigned ch0 = vram[(vs0 << 2) & vidmask];
|
||||
fputc((ch0 >= 32 && ch0 < 127) ? (int)ch0 : '.', vpx_fp);
|
||||
}
|
||||
fprintf(vpx_fp, "\n"); fflush(vpx_fp);
|
||||
}
|
||||
}
|
||||
for (unsigned r = 0; r < 25; r++) {
|
||||
for (unsigned c = 0; c < cols; c++) {
|
||||
Bitu vs = vga.config.real_start +
|
||||
(Bitu)r * vga.draw.address_add + (Bitu)c * cell_vs;
|
||||
Bitu addr = (vs << 2) & vidmask;
|
||||
unsigned chr = vram[addr];
|
||||
unsigned attr = vram[addr + 1];
|
||||
unsigned fgi = vga.attr.palette[attr & 0xFu] & 0x3Fu;
|
||||
unsigned bgi = vga.attr.palette[(attr >> 4) & 0x7u] & 0x3Fu;
|
||||
/* font_tables point into PLANAR vram: one font byte per
|
||||
* latch DWORD (plane-2 lane), hence the *4 stride -- same
|
||||
* as the real renderer's ((chr<<5)+line)*4 */
|
||||
const uint8_t *ftab = vga.draw.font_tables[(attr >> 3) & 1u];
|
||||
for (unsigned ln = 0; ln < chh; ln++) {
|
||||
int y = 40 + (int)(r * chh + ln);
|
||||
if (y >= H) break;
|
||||
unsigned char *d = &img[((size_t)y * W + c * 8u) * 3];
|
||||
unsigned bits = ftab[((Bitu)chr * 32u + ln) * 4u];
|
||||
for (unsigned b = 0; b < 8; b++, d += 3) {
|
||||
unsigned di = (bits & (0x80u >> b)) ? fgi : bgi;
|
||||
unsigned char r6 = (unsigned char)vga.dac.rgb[di].red;
|
||||
unsigned char g6 = (unsigned char)vga.dac.rgb[di].green;
|
||||
unsigned char b6 = (unsigned char)vga.dac.rgb[di].blue;
|
||||
if (chn0 < 0) {
|
||||
d[0] = (unsigned char)((r6 << 2) | (r6 >> 4));
|
||||
d[1] = (unsigned char)((g6 << 2) | (g6 >> 4));
|
||||
d[2] = (unsigned char)((b6 << 2) | (b6 >> 4));
|
||||
} else {
|
||||
unsigned char c6 = (chn0 == 0) ? r6 : (chn0 == 1) ? g6 : b6;
|
||||
unsigned char v = (unsigned char)((c6 << 2) | (c6 >> 4));
|
||||
d[0] = (unsigned char)(v >> 3);
|
||||
d[1] = v;
|
||||
d[2] = (unsigned char)(v >> 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (fb) {
|
||||
/* win0 = framebuffer LOW byte (bits 0-7) through pal0; win3/win4 =
|
||||
* framebuffer HIGH byte (bits 8-15) through pal1/pal2. All as 8-bit
|
||||
* RGB (6-bit VGA-DAC expanded to 8-bit). pal0 is dynamic; pal1/pal2
|
||||
|
||||
Reference in New Issue
Block a user