#include "screens.h"
#include <c64/vic.h>
#include <c64/cia.h>
#include <string.h>

// Embedded screen data.  In Phase 2 only the title screen is wired in;
// the other 4 will be added in Phase 4 (state machine) when we need
// them.  The arrays are const so they live in the ROM/load-image part
// of the .prg, not in BSS.
//
// Screen memory layout (in multicolor bitmap mode) per
// cebix-vic-article §3.7.3.4:
//   "00" pixel  -> $D021 (background, per-screen)
//   "01" pixel  -> high nibble of screen memory byte
//   "10" pixel  -> low nibble of screen memory byte
//   "11" pixel  -> color RAM nibble (we set to 0 = black)
//
// convert_screens.py's .attr file stores the screen memory byte:
//   bits 0-3 = "10" color
//   bits 4-7 = "01" color
// (the "11" color is not stored; color RAM defaults to black at boot).

const char ScreenTitleBin[] = {
	#embed "data/processed/title.bin"
};

const char ScreenTitleAttr[] = {
	#embed "data/processed/title.attr"
};

// The $D021 background color for the title screen.  Generated by
// tools/convert_screens.py as a separate .d021 sidecar, but the value
// is a single small integer (0..15) and we hardcode it here rather
// than read the file at runtime.  When we add the other 4 screens in
// Phase 4 we'll fold the d021 value into a per-screen descriptor
// struct so the compiler can't constant-fold it.
#define SCREEN_TITLE_D021	0

// Copy `len` bytes from `src` to `dst`.
//
// Both source and destination are 16-bit-addressed memory regions in
// the C64.  Using a simple byte-by-byte copy (rather than the c64
// memcpy helper, which is in the runtime and pulls in more code) keeps
// the .prg small.  The compiler turns this into a tight loop; for
// 8000 bytes that's well under a frame at 1 MHz.
static void copy_bytes(const char *src, char *dst, unsigned len)
{
	for (unsigned i = 0; i < len; i++)
		dst[i] = src[i];
}

void show_screen(int n)
{
	// 1. Write the new pixel/attribute data into the destination
	//    while the VIC is still in its old mode.  This avoids a
	//    visible garbage frame during the mode switch.
	//
	// 2. Then flip the VIC into multicolor bitmap mode pointing at
	//    the new data.  The VIC's line buffer absorbs the transition
	//    cleanly enough for our purposes.
	if (n == SCREEN_TITLE)
	{
		copy_bytes(ScreenTitleBin, (char *)0xE000, sizeof(ScreenTitleBin));
		copy_bytes(ScreenTitleAttr, (char *)0xD000, sizeof(ScreenTitleAttr));

		// Color RAM (the "11" color per cell).  We don't have per-cell
		// "11" data in the .attr file, so zero it (= black).  This
		// reduces each cell from 4 to 3 distinct colors but matches
		// what convert_screens.py produces.
		__asm
		{
			lda #0
			ldx #4
			ldy #0
			L0:	sta $d800, y
				sta $d900, y
				sta $da00, y
				sta $db00, y
				iny
				bne L0
				dex
				bne L0
		}

		// Background color ($D021, the "00" color).  The title screen
		// uses color 0 (black); per-screen .d021 files are
		// documentation, the value is inlined here.
		vic.color_back = SCREEN_TITLE_D021;
		vic.color_border = 0;

		// 3. Now flip the VIC into multicolor bitmap mode.
		//
		// We set the registers explicitly rather than calling
		// vic_setmode() so the yscroll/xscroll bits stay 0
		// (vic_setmode() hardcodes yscroll=3, which we don't want
		// for a non-scrolling display).
		//
		//   ctrl1 = BMM(1) | DEN(1) | RSEL(1) | yscroll(0) = 0x38
		//   ctrl2 = MCM(1) | CSEL(1) | xscroll(0)         = 0x18
		//
		// CIA2 PRA low 2 bits = 0  -> VIC bank 0 = CPU $C000-$FFFF
		// (both our $D000 screen and $E000 bitmap live there).
		//
		// memptr (D018) = 0x48
		//   bits 7-4 = (0xD000 >> 6) & 0xF0 = 0x40  -> screen at $D000
		//   bits 3-1 = (0xE000 >> 10) & 0x0E = 0x08 -> bitmap upper 8K
		//   bit  0   = 0                          -> unused in BMM
		vic.ctrl1 = VIC_CTRL1_BMM | VIC_CTRL1_DEN | VIC_CTRL1_RSEL;
		vic.ctrl2 = VIC_CTRL2_MCM | VIC_CTRL2_CSEL;
		cia2.pra  = (cia2.pra & 0xfc) | 0x00;
		vic.memptr = 0x48;
	}
	// Other SCREEN_* IDs: reserved for Phase 4.
}
