#include "knes.h"

// include stuff

#include "sine_lut.h"
#include "testvideo.h"
#include "testvideo2.h"

void set_demo_palette(void);
void set_nt(void);
void update_frame(void);
void upload_ppu_buffers(void);
void play_dpcm_sample(void);
void show_logo(void);
void upload_dynamic_palette(void);

#pragma bss-name(push, "ZEROPAGE")
#pragma data-name(push, "ZEROPAGE")

// static byte ego_alive;

static byte framecount;

static byte nt_buffer[28];
static byte nt_buffer_full;
static byte attr_buffer[8];
static byte attr_buffer_full;

static byte i, j; // couple of generic loop counters

static word frame_offset = 0;
static byte scanline_offset = 0;

static word ppu_addr;
static word nam_addr;
	
static byte tile = 0;
static byte clonecount = 0;
static byte framesl = 0;

extern void __fastcall__ INIT( void );
extern void __fastcall__ PLAY( void );

int main(void)
{
    // init music
    OAM_DMA();
    INIT();
    
    // keep NMI on at all times
    PPU.ctrl = BASE_NT0|ADDRINC_1|SPR_CHR0|BG_CHR0|SPR_8X8|NMI_ON;

    set_demo_palette();

	/*
	ppu_addr = 0x2000;
	nam_addr = nosfe_nam;
	set_nt();
*/


	frame_offset = 0;
    
		PPU.mask = GRAYSCL_OFF|BGCLIP_OFF|SPRCLIP_OFF|BGREND_ON|SPRREND_ON|
				   TINTRED_OFF|TINTGRN_OFF|TINTBLU_OFF;
    for(;;) {

		ppu_addr = 0x2000;
        update_frame();

	// play music
       	PLAY(); 
        wait_vblank();
		PPU_SCROLL(0,0);
		PPU.mask = GRAYSCL_OFF|BGCLIP_OFF|SPRCLIP_OFF|BGREND_ON|SPRREND_ON|
				   TINTRED_OFF|TINTGRN_OFF|TINTBLU_OFF;
		PPU.ctrl = BASE_NT0|ADDRINC_1|SPR_CHR0|BG_CHR0|SPR_8X8|NMI_ON;
    }
    
    return 0;
}
void upload_dynamic_palette(void)
{
/*
    PPU_ADDR(0x3F0D);
    PPU.data = coin_color;
*/
}
void set_demo_palette(void)
{
    #define BGCOLOR 0x0D
    static const byte palette[] = {
        // background palette
        BGCOLOR, 0x00, 0x10, 0x20,
        BGCOLOR, 0x00, 0x10, 0x20,
        BGCOLOR, 0x00, 0x10, 0x20,
        BGCOLOR, 0x00, 0x10, 0x20,
        // sprite palette
        BGCOLOR, 0x16, 0x27, 0x18,
    };
    #undef BGCOLOR

    // avoid artifacts by only writing palette in vblank
    wait_vblank();

    PPU_ADDR(0x3F00);
    for(i = 0; i < sizeof palette; ++i) {
        PPU.data = palette[i];
    }
}

void set_nt()
{

    // write attributes
    PPU_ADDR(0x23C0);
    for(j = 0; j < 7; ++j) {
        for(i = 0; i < 8; ++i) {
			PPU.data = 255;
		}
	}
}

void decode_video_frame()
{
	const byte *p = testvideo+frame_offset;
	
	framesl = 0;


	PPU_ADDR(ppu_addr);
	while (framesl < 32) {	
		// byte == escape
		if (*p == 255) {
			++p;
			tile = *p;
			if (tile != 255) {
				// clone tile
				++p;
				frame_offset+=3;
				clonecount = *p;
				i = 0;
				while (i < clonecount) {
					PPU.data = tile;
					++scanline_offset;
					i++;
					if (scanline_offset == 32) {
						framesl++;
					    if (framesl == 3) { PLAY(); wait_vblank(); }
					    if (framesl == 6) { PLAY(); wait_vblank(); }
					    if (framesl == 9) { PLAY(); wait_vblank(); }
					    if (framesl == 12) { PLAY(); wait_vblank(); }
					    if (framesl == 15) { PLAY(); wait_vblank(); }
					    if (framesl == 18) { PLAY(); wait_vblank(); } 
					    if (framesl == 21) { PLAY(); wait_vblank(); }
					    if (framesl == 24) { PLAY(); wait_vblank(); }
					    if (framesl == 27) { PLAY(); wait_vblank(); }
						scanline_offset = 0;
						ppu_addr+=32;
						PPU_ADDR(ppu_addr);
						PPU.mask = GRAYSCL_OFF|BGCLIP_OFF|SPRCLIP_OFF|BGREND_ON|SPRREND_ON|
						TINTRED_OFF|TINTGRN_OFF|TINTBLU_OFF;
					    PPU_SCROLL(0,0);	
						if (framesl == 29) goto out;
					} 
				}
				++p;

			} else {
				// delta from last frame
			}
		} else {
			// byte == tile
			PPU.data = *p;
			++p;
			frame_offset++;
			++scanline_offset;
			if (scanline_offset == 32) { 
				framesl++;
				if (framesl == 3) { PLAY(); wait_vblank(); }
				if (framesl == 6) { PLAY(); wait_vblank(); }
				if (framesl == 9) { PLAY(); wait_vblank(); }
				if (framesl == 12) { PLAY(); wait_vblank(); }
				if (framesl == 15) { PLAY(); wait_vblank(); }
				if (framesl == 18) { PLAY(); wait_vblank(); } 
				if (framesl == 21) { PLAY(); wait_vblank(); }
				if (framesl == 24) { PLAY(); wait_vblank(); }
				if (framesl == 27) { PLAY(); wait_vblank(); }
				scanline_offset = 0;
				ppu_addr+=32;
				PPU_ADDR(ppu_addr);
				PPU.mask = GRAYSCL_OFF|BGCLIP_OFF|SPRCLIP_OFF|BGREND_ON|SPRREND_ON|
				TINTRED_OFF|TINTGRN_OFF|TINTBLU_OFF;
				PPU_SCROLL(0,0);	
				if (framesl == 29) goto out;
			} 
		}
	}
out:
	{}
	if (frame_offset >= sizeof testvideo) frame_offset = 0;
}

void update_frame(void)
{
	decode_video_frame();
    ++framecount;
}

void upload_ppu_buffers(void)
{
/*
    word attraddr;

    if(nt_buffer_full) {
        // calculate nametable address based on valid_tilecol
        // for first NT it is $2000+valid_tilecol
        // after valid_tilecol%64 is >=32 address is $2400+valid_tilecol
        // also need to switch on inc32 mode in PPU.ctrl
        
        PPU.ctrl = BASE_NT0|ADDRINC_32|SPR_CHR0|BG_CHR1|SPR_8X8|NMI_ON;
        
        if((valid_tilecol & 63) < 32) {
            // upload to 0x2000+valid_tilecol
            PPU_ADDR(0x2000 + (valid_tilecol & 31));
        } else {
            // upload to 0x2400+valid_tilecol
            PPU_ADDR(0x2400 + (valid_tilecol & 31));
        }
        for(i = 0; i < 28; ++i) {
            PPU.data = nt_buffer[i];
        }
        nt_buffer_full = 0;
    }
    
    if(attr_buffer_full) {
        PPU.ctrl = BASE_NT0|ADDRINC_1|SPR_CHR0|BG_CHR1|SPR_8X8|NMI_ON;
        
        if((valid_attrcol & 15) < 8) {
            // upload to 0x23C0+valid_tilecol
            attraddr = 0x23C0 + (valid_attrcol & 7);
        } else {
            // upload to 0x27C0+valid_tilecol
            attraddr = 0x27C0 + (valid_attrcol & 7);
        }
        for(i = 0; i < 8; ++i) {
            PPU_ADDR(attraddr);
            PPU.data = attr_buffer[i];
            attraddr += 8;
        }
        attr_buffer_full = 0;
    }
*/ 
}

void play_dpcm_sample(void)
{
    CPU.apu.dmc.freq  = 0xE;  // frequency
    CPU.apu.dmc.raw   = 63;   // starting value for the counter
    CPU.apu.dmc.start = 0xC0; // sample at 0xF000
    CPU.apu.dmc.len   = 0xFE; // sample length is 4065 bytes
    CPU.apu_chn       = 0xF;  // stop old sample
    CPU.apu_chn       = 0x1F; // start sample
}

void show_logo(void)
{
/*
    word i; // NOTE: overrides the global variable "byte i"
    signed logo_scroll_x;
    const char *text = "PRESS START";
    byte text_flash_timer = 0;
    
    set_logo_palette();
    
    // clear both nametables (vertical mirroring)
    // 0x40 is empty in both CHR banks
    PPU_ADDR(0x2000);
    for(i = 0; i < 2048; ++i) {
        PPU.data = 0x40;
    }

    // copy logo nametable to ppu memory
    PPU_ADDR(0x20E0);
    for(i = 0; i < 256; ++i) {
        PPU.data = gfx_index_logo[i] + 0x40; // indices in file are off by 0x40
    }
    // set the attribute table for NT1
    PPU_ADDR(0x23C0);
    for(j = 0; j < 40; ++j) {
        PPU.data = 0;
    }
    // rest of the attribute table to use the 2nd palette set (for text)
    for(j = 0; j < 24; ++j) {
        PPU.data = _B(01010101);
    }
    
    PPU_ADDR(0x22AA);
    while(j = *text++) {
        PPU.data = j - ' ' + 0xC0;
    }
    
    // main logo loop
    for(logo_scroll_x = 256; logo_scroll_x <= 512; logo_scroll_x += 8) {
        wait_vblank();
        // critical PPU updates
        // ...
        // set the MSB of scroll in PPU.ctrl
        PPU.ctrl = ADDRINC_1|SPR_CHR0|BG_CHR1|SPR_8X8|NMI_ON|
            (logo_scroll_x & 0x100) >> 8;
        PPU.mask = GRAYSCL_OFF|BGCLIP_OFF|SPRCLIP_OFF|BGREND_ON|SPRREND_ON|
            TINTRED_OFF|TINTGRN_OFF|TINTBLU_OFF;
        PPU_SCROLL(logo_scroll_x, 0);
    }
    
    // setup sprite #0 hit
    wait_vblank();
    OAM[0].x      = 211;
    OAM[0].y      = 119 - 1;
    OAM[0].tile   = 0xFB;
    OAM[0].attrib = 0;
    OAM_DMA();

    play_dpcm_sample();
    
    // wait for the sample to end
    while((CPU.apu_chn & (byte)_B(00010000)));
    
    for(;;) {
        ++text_flash_timer;
        
        // wait for player to push start...
        if(read_joy(0) & JOY_START) {
            break;
        }
    
        wait_vblank();
        // critical PPU updates
        // flash the text palette
        PPU_ADDR(0x3F05);
        if(text_flash_timer & 0x20) {
            PPU.data = PPU.data = PPU.data = 0x0F;
        } else {
            PPU.data = 0x07;
            PPU.data = 0x17;
            PPU.data = 0x27;
        }
        
        PPU.ctrl = BASE_NT0|ADDRINC_1|SPR_CHR0|BG_CHR1|SPR_8X8|NMI_ON;
        PPU_SCROLL(0, 0);
        
        // use sprite 0 hit to change charset after the logo
        
        // since we're still in vblank, wait for sprite 0 hit flag to be cleared
        //   it happens at the end of the vblank
        while(PPU.status & (byte)_B(01000000));
        // now wait for it to be set
        while(!(PPU.status & (byte)_B(01000000)));
        
        PPU.ctrl = BASE_NT0|ADDRINC_1|SPR_CHR0|BG_CHR0|SPR_8X8|NMI_ON;
    }
    
    wait_vblank();
    PPU.mask = GRAYSCL_OFF|BGCLIP_OFF|SPRCLIP_OFF|BGREND_OFF|SPRREND_OFF|
        TINTRED_OFF|TINTGRN_OFF|TINTBLU_OFF;   
*/
}

