// Apple II hires bitplane for the scenery viewport. // // FS2's chunk5 line-drawing kernel sets BITS in a 280x192 monochrome // hires bitmap. Apple II hires display interprets adjacent bits as // colors via NTSC encoding: bits at "even" pixel columns become VIOLET // (palette 0) or BLUE (palette 1); bits at "odd" columns become GREEN // or ORANGE; two adjacent set bits combine to WHITE. // // The port stores the hires page in plain memory order (40 bytes per // row, 192 rows = 7680 bytes per page) instead of Apple II's scrambled // addressing -- chunk5's `HiresTableLo`/`HiresTableHi` is just an // optimisation; the bit semantics are independent of layout. #ifndef HIRES_H #define HIRES_H #include #include // One hires page = 40 bytes per row * 192 rows. #define HIRES_BYTES_PER_ROW 40 #define HIRES_ROWS 192 #define HIRES_PAGE_BYTES (HIRES_BYTES_PER_ROW * HIRES_ROWS) // chunk5 ToHiresColorTable codes (0..7). typedef enum HiresColorE { HIRES_BLACK1 = 0, HIRES_VIOLET = 1, HIRES_GREEN = 2, HIRES_WHITE1 = 3, HIRES_BLACK2 = 4, HIRES_BLUE = 5, HIRES_ORANGE = 6, HIRES_WHITE2 = 7, } HiresColorE; // chunk5 ToHiresColorTable entries (chunk5.s:3825). Indexed by the // scenery code byte (0..15) that follows the $12 SetColor opcode. extern const uint8_t kSceneryToHires[16]; // Reset every byte to BLACK1 ($00). void hiresClearPage(uint8_t *page); // Fill one viewport row with chunk5's solid-color pattern: sequential // bytes alternate `evenByte`/`oddByte`. For solid GREEN that's // $55/$2A; for SKY BLUE it's $D5/$AA. Unaffected: rows below the // viewport (= panel area). void hiresFillRow(uint8_t *page, int row, uint8_t evenByte, uint8_t oddByte); // Plot one pixel at color-pixel coords (xColor in 0..139, y in 0..191) // using the given hires color code. This mirrors chunk5's // `PlotColorPixel` (chunk5.s:3509) which plots the two sub-pixels of a // color pixel via `OrMaskTable1`/`OrMaskTable2`. void hiresPlotPixel(uint8_t *page, int xColor, int y, HiresColorE col); // Draw a Bresenham line in color-pixel coords, plotting each step via // hiresPlotPixel. void hiresDrawLine(uint8_t *page, int x1c, int y1, int x2c, int y2, HiresColorE col); // Draw a horizontal span of color pixels. Mirrors chunk5 DrawColorSpan // at $78E0 (chunk5.s:3446). Plots `length+1` color pixels starting at // color column `xRight` and walking LEFTWARD (matches the source // signature: A=length, $27=right edge). Each pixel is plotted via the // AND/OR mask technique: AND clears the opposite-palette bit at the // pixel position, OR sets the palette bit. With ground-pattern bytes // underneath, this produces the FS2 viewport-edge violet "water" pixels // observed in the captured MAME RAM ($4128=$29, $414F=$35). void hiresDrawColorSpan(uint8_t *page, int xRight, int length, int y, HiresColorE col); // Decode a hires page to a 280x192 RGB888 image (one packed uint32 // per pixel: 0x00RRGGBB). `out` must hold 280*192 uint32s. void hiresDecodeToRgb(const uint8_t *page, uint32_t *out); // Convenience: convert chunk5 hires code -> 0x00RRGGBB for solid // fills (sky/ground/etc). uint32_t hiresColorToRgb(HiresColorE col); // Get the (evenByte, oddByte) pair for a hires color code, suitable // for hiresFillRow. void hiresFillBytesFor(HiresColorE col, uint8_t *outEven, uint8_t *outOdd); // Copy 192 rows of hires bytes from an Apple II hires page (= scrambled // non-linear addressing per chunk4 HiresTableHi/Lo) at `appleHiresPage` // (= 8192 bytes starting at $2000) into our linear `page` (= 7680 // bytes). Used to import the captured RAM dump's hires page so the port // inherits MAME's pre-rendered viewport state (which on a real Apple II // persists frame-to-frame and contains init artifacts that the boot // dispatcher never overwrites -- this is where the violet pixels at the // viewport edges come from at boot Meigs). void hiresImportFromAppleII(uint8_t *page, const uint8_t *appleHiresPage); #endif