fs2port/port/include/hires.h
2026-05-13 21:32:05 -05:00

92 lines
3.9 KiB
C

// 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 <stdbool.h>
#include <stdint.h>
// 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