// Lieves!Tuore: Adnukes
// Compile with SDCC 2.8.0
// - Marq/L!T 2010

#include <stdlib.h>
#include <interrupt.h>
#include <ioport.h>
#include "../msxlib/msxlib.h"

#define MAXCOPY 2048 // The longest possible copy
#define MAXDATA 18000 // Biggest image file we have (+256 because of blocks)
#define BLANKTIME 1400

#define NEXTPLZ (50*8) // 7 seconds to next pic
#define FADEDURA 192 // Phases of fade
#define FADESTEP (768/FADEDURA)

#define wait_VB() juuh=0;while(juuh==0);

#define ORTNI // Show intro
//#define RASTER // Show raster meter

// Macros for code generator:
// Set VDP copy address
#define VDPADDR(draw,n,add) \
        draw[n++]=0x3e; \
        draw[n++]=(add)&0xff; \
        draw[n++]=0xd3; \
        draw[n++]=0x99; \
        draw[n++]=0x3e; \
        draw[n++]=((add)>>8)+0x40; \
        draw[n++]=0xd3; \
        draw[n++]=0x99;

// Set HL to source address
#define SRCADDR(draw,n,src) \
        draw[n++]=0x21; \
        draw[n++]=((unsigned)(src))&0xff; \
        draw[n++]=((unsigned)(src))>>8;

// Jump to OUTI table
#define FASTCOPY(draw,n,bytez) \
        draw[n++]=0xcd; \
        cad=(unsigned)&outi[(MAXCOPY-(bytez))*2]; \
        draw[n++]=cad&0xff; \
        draw[n++]=cad>>8;

// Jump to OUTI+NOP table
#define SLOWCOPY(draw,n,bytez) \
        draw[n++]=0xcd; \
        cad=(unsigned)&outinop[(MAXCOPY-(bytez))*4]; \
        draw[n++]=cad&0xff; \
        draw[n++]=cad>>8;

// Call the code array
void callist(void *p)
{
        p;
        _asm
        push    bc

        ld      bc,#BAKKIS
        push    bc
        ld      c,4(ix)
        ld      b,5(ix)
        push    bc
        ld      c,#0x98
        ret

BAKKIS:
        pop     bc
        _endasm;
}

volatile unsigned char juuh=0;

sfr at 0x99 vdp2;
void my_isr(void) interrupt __naked
{
	_asm
	push	af
	in	a,(0x99)
	ld	a,(_juuh)
	inc	a
	ld	(_juuh),a
	pop	af
	ei
	reti
	_endasm;
}

void vdp_blank(void)
{   
    vdp_register(VDP_MODE1,MODE1_IE+MODE1_VRAM+MODE1_SPRITE_SZ);
}

void vdp_unblank(void)
{
    vdp_register(VDP_MODE1,MODE1_IE+MODE1_VRAM+MODE1_BLANK+MODE1_SPRITE_SZ);
}

void main(void)
{
	int page,i,j,k,timeout,picidx=0;
	unsigned char continu=1,fadein,fadeout,l,vdp2;

	static unsigned char data[MAXDATA];
	static unsigned char draw1[512],draw2[512];
	static unsigned char outi[MAXCOPY*2+1],outinop[MAXCOPY*4+1],
                      	     *draw,*nt1,*nt2;

	unsigned *ofs=(unsigned *)data,cad,cplus,seepu,n,slice,slow,
		 *feidiptr;

	static char msx1[]={ // Approximate MSX1 palette
				0,0,0,
				3,6,3,
				4,7,4,
				3,3,6,
				4,4,7,

				6,2,2,
				4,7,7,
				7,3,3,
				7,4,4,
				6,5,2,

				6,6,3,
				1,5,1,
				6,3,6,
				6,6,6,
				7,7,7
				};

	static char *pics[]={	
				"volkkari.lt2",
				"vuorta.lt2",
				"otokka.lt2",
				"amppari.lt2",
				"tlaloc.lt2",

				"tequila.lt2",
				"taiwan.lt2",
				"taiwan2.lt2",
				"night.lt2",
				"graffity.lt2",

				"cards2.lt2",
				"tigger.lt2",
				"shroom.lt2",
				"lampara.lt2",
				"road.lt2",
				0};

        static char *sscr={
	"      Lieves!Tuore presents     "
	"            at MIU'10           "
	"                                "
	"      A slide show for MSX1:    "
	"             ADNUKES            "
	"                                "
	"       Yzi: gfx converter       "
	"        Marq: code, pics        "
        "            Man: pics           "
	"                                "
	};

	static unsigned feidi[768],feidiout[768];

	vdp2=isvdp2();

#ifdef ORTNI
	screen(1);
	vdp_register(VDP_COLOR,BLACK);
	DI;
	for(n=0;n<32;n++)
		vdp_poke(0x2000+n,0+16*WHITE);
	EI;
	for(n=0;n<50*2;n++)
		waitVB();

        // Scroll lines individually in
	for(n=0;n<9;n++)
	{
		if(n==1 || n==4 || n==7)
		{
		    for(i=0;i<33;i++)
		    {
			waitVB();
			DI;
			vdp_address(0x1800+32*8+(n<<5)+32-i);
			vdp_copy(&sscr[n<<5],i);
			EI;
		    }
		}
		else
		{
		    for(i=0;i<33;i++)
		    {
			waitVB();
			DI;
			vdp_address(0x1800+32*8+(n<<5));
			vdp_copy(&sscr[(n<<5)+32-i],i);
			EI;
		    }
		}
	}
#endif

	for(n=0;n<768;n++)
		feidi[n]=n;
	for(n=0;n<500;n++) // shake
	{
		i=rand()%768;
		j=rand()%768;
		k=feidi[i];
		feidi[i]=feidi[j];
		feidi[j]=k;
	}

	for(n=0;n<768;n++)
		feidiout[n]=n;
 	for(n=0;n<768;n++) // shake
 	{
 		i=n+(rand()&15); if (i>767) i=767; if (i<0) i=0;
 		j=n+(rand()&15); if (j>767) j=767; if (j<0) j=0;
 		k=feidiout[i];
 		feidiout[i]=feidiout[j];
 		feidiout[j]=k;
 	}

	// Code arrays for VDP copy
        for(n=0;n<MAXCOPY*2;n+=2)
        {
       	        outi[n]=0xed; // OUTI
               	outi[n+1]=0xa3;
        }
        outi[MAXCOPY*2]=0xc9; // RET
        for(n=0;n<MAXCOPY*4;n+=4)
        {
                outinop[n]=0xed; // OUTI
       	        outinop[n+1]=0xa3;
               	outinop[n+2]=0; // NOP
                outinop[n+3]=0;
       	}
        outinop[MAXCOPY*4]=0xc9; // RET

#ifdef ORTNI
        // Scroll screen out
	for(n=0;n<32;n++)
	{
		waitVB();
		DI;
		vdp_address(0x1800+32*8);
		vdp_copy(&sscr[n],32*9);
		EI;

		for(i=0;i<9;i++)
			sscr[(i<<5)+n]=' ';
	}	
#endif

	screen(2);
	vdp_register(VDP_COLOR,BLACK);
	//waitVB();

	DI;
	for(n=0;n<32;n++)
	{
		sprite_pos(n,0,208);
		sprite_col(n,0);
	}
	EI;

	// MSX2 palette to approximate MSX1 palette
/*	waitVB();
	if(vdp2)
	{
		DI;
		for(n=1,i=0;n<16;n++,i+=3)
			msx2_palette(n,msx1[i],msx1[i+1],msx1[i+2]);
		EI;
	}*/

	while(continu) // Main loop
	{
		DI;
		vdp_blank();
		EI;
		fadein=FADEDURA;
		fadeout=0;
		feidiptr=feidi;

		readfile(pics[picidx++],data);
		if(!pics[picidx])
			picidx=0;

		install_isr(my_isr);

		// Name tables
		nt1=&data[ofs[36]];
		nt2=&data[ofs[37]];

		// We start with 0xff because of the fade
		wait_VB();
		vdp_address(0x1800);
		vdp_set(0xff,768);
		wait_VB();
		vdp_address(0x3800);
		vdp_set(0xff,768);

		// Static patterns and colors
		for(n=0;n<3;n++)
		{
			wait_VB();
			vdp_address(n*2048);
			DI;
			vdp_slowcopy(&data[ofs[n*6]],ofs[n*6+1]);
			EI;
			wait_VB();
			vdp_address(0x2000+n*2048);
			DI;
			vdp_slowcopy(&data[ofs[18+n*6]],ofs[18+n*6+1]);
			EI;
		}

		// Clean character 255
		for(n=0;n<3;n++)
		{
			wait_VB();
			for(i=0;i<8;i++)
			{
				DI;
				vdp_poke(0x2000+255*8+n*2048+i,0);
				EI;
			}
			// MSX2 seems to suck
			//vdp_address(0x2000+255*8+n*2048);
			//vdp_set(0,8);
		}

		// Generate drawing code
		for(page=0;page<2;page++)
		{
			n=seepu=slow=0;
			if(!page)
				draw=draw1;
			else
				draw=draw2;
			for(i=0;i<3;i++)
			{	
				slice=i;
				cplus=ofs[page*2+slice*6+3];

				if(cplus) // Pattern data copied realtime
				{
    				    VDPADDR(draw,n,slice*2048+ofs[slice*6+1]); // Pattern
				    SRCADDR(draw,n,&data[ofs[page*2+slice*6+2]]);

				    if(!slow) // Still in blank
				    {
					if(cplus+seepu>BLANKTIME)
					{
						FASTCOPY(draw,n,BLANKTIME-seepu);
						SLOWCOPY(draw,n,cplus+seepu-BLANKTIME);
						slow=1;
					}
					else
					{
						FASTCOPY(draw,n,cplus);
					}
				    }
				    else
				    {
					SLOWCOPY(draw,n,cplus);
				    }
				}
				seepu+=cplus;

				cplus=ofs[page*2+slice*6+21];

				if(cplus) // Color data copied realtime
				{
				    VDPADDR(draw,n,0x2000+slice*2048+ofs[slice*6+19]); // Color
				    SRCADDR(draw,n,&data[ofs[page*2+slice*6+20]]);

				    if(!slow) // Still in blank
				    {
					if(cplus+seepu>BLANKTIME)
					{
						FASTCOPY(draw,n,BLANKTIME-seepu);
						SLOWCOPY(draw,n,cplus+seepu-BLANKTIME);
						slow=1;
					}
					else
					{
						FASTCOPY(draw,n,cplus);
					}
				   }
				   else
				   {
					SLOWCOPY(draw,n,cplus);
				   }
				}

				seepu+=cplus;
			}
			draw[n]=0xc9; // RET
		}

		wait_VB();
		vdp_unblank();

		timeout=0;
		while(1)
		{
			wait_VB(); // Page 1
#ifdef RASTER
			vdp_register(VDP_COLOR,DARK_BLUE);
#endif
			vdp_register(VDP_NAME_T,0x6);
			callist(draw1);
#ifdef RASTER
			vdp_register(VDP_COLOR,GRAY);
#endif

			if(fadein) // Kinda lazy to do this in C, but blah
			{
				fadein--;
				for(l=0;l<FADESTEP/2;l++,feidiptr++)
				{
					vdp_poke(0x1800+*feidiptr,nt1[*feidiptr]);
					vdp_poke(0x3800+*feidiptr,nt2[*feidiptr]);
					feidiptr++;
					vdp_poke(0x1800+*feidiptr,nt1[*feidiptr]);
					vdp_poke(0x3800+*feidiptr,nt2[*feidiptr]);
				}
				if(!fadein)
					feidiptr=feidiout;
			}
			if(fadeout)
			{
				fadeout--;
				for(l=0;l<FADESTEP/2;l++,feidiptr++)
				{
					vdp_poke(0x1800+*feidiptr,255);
					vdp_poke(0x3800+*feidiptr,255);
					feidiptr++;
					vdp_poke(0x1800+*feidiptr,255);
					vdp_poke(0x3800+*feidiptr,255);
				}
				if(fadeout==0)
				{
					vdp_register(VDP_COLOR,BLACK);
					break;
				}
			}

			timeout++;
			if(timeout==NEXTPLZ)
			{
				fadeout=FADEDURA;
			}

#ifdef RASTER
			vdp_register(VDP_COLOR,BLACK);
#endif

			wait_VB(); // Page 2
#ifdef RASTER
			vdp_register(VDP_COLOR,DARK_BLUE);
#endif
			vdp_register(VDP_NAME_T,0xe);
			callist(draw2);
#ifdef RASTER
			vdp_register(VDP_COLOR,GRAY);
#endif

			if(fadein)
			{
				fadein--;
				for(l=0;l<FADESTEP/2;l++,feidiptr++)
				{
					vdp_poke(0x1800+*feidiptr,nt1[*feidiptr]);
					vdp_poke(0x3800+*feidiptr,nt2[*feidiptr]);
					feidiptr++;
					vdp_poke(0x1800+*feidiptr,nt1[*feidiptr]);
					vdp_poke(0x3800+*feidiptr,nt2[*feidiptr]);
				}
				if(!fadein)
					feidiptr=feidiout;
			}
			if(fadeout)
			{
				fadeout--;
				for(l=0;l<FADESTEP/2;l++,feidiptr++)
				{
					vdp_poke(0x1800+*feidiptr,255);
					vdp_poke(0x3800+*feidiptr,255);
					feidiptr++;
					vdp_poke(0x1800+*feidiptr,255);
					vdp_poke(0x3800+*feidiptr,255);
				}
				if(fadeout==0)
				{
					vdp_register(VDP_COLOR,BLACK);
					break;
				}
			}

			if(space() && !fadein && !fadeout)
				timeout=NEXTPLZ-1;
			if(ispressed(K_ESC))
			{
				continu=0;
				break;
			}
			n=0;

#ifdef RASTER
			vdp_register(VDP_COLOR,BLACK);
#endif
		}

		uninstall_isr();
	}
	
	screen(0);
}
