program Tutorial6_DYCP_scroller;
var
	@define charmap "$3800"
	@define cmem "$2800"
	@define cm2 "$6800"
	index,a,i,val,yy,yn, xx, time, shift, k,j,x,y,c,l: byte;
	scroll: byte;
	text: string = "                        COMMODORE 128 DYCP SCROLLER TEST        DOESN'T WORK PROPERLY YET BUT YOU GET THE IDEA";

	// Put image in bank $8000+
	charset : IncBin("charsets/charset_8x8.bin", @charmap);
	image_color: IncBin("images/jack_color.bin", "$7000");
	image_data: IncBin("images/jack_data.bin", "$A000");

	zpc,z : byte=0;

	zeropage2, zeropage3, zeropage5, zeropage4: pointer;

	//charset: IncBin("charsets/tutorial3.bin","@charmap");

// Uses banking	
@include "../RasLib/banking.ras"

// Turn the defines on / off in order to test optimized/unoptimized versions

@define DYCP   "DYCP_Optimized"
//@define DYCP   "DYCP_Unoptimized"



/*
	Original unoptimized version
	NB doesn't work anymore fix fix
*/
procedure DYCP_Unoptimized();
begin
	// Set current drawing bank: zeropage2 is used as target charmap, either $2 or $4000
	if g_currentBank=0 then		
		zeropage2 := @cmem
	else
		zeropage2 := @cm2;

	// init shift
	shift:=time;
	// Init character position x (4*8=32, so 64 becomes x=2)
	zpc:=64;
	zeropage3:=@charmap;
	inc(zeropage5);
	// Loop through 36 chars in the text
	for i:=1 to 36 do begin 
		// Calculate y value
		y:=sine[shift]+zpc;
		// Fetch text character value
		val := zeropage5[i]; // text value
		// Only draw letters (>64)
		if val>64 then begin
			// Calculate position in character map: (val-64)*8 bytes
			val:=(val-64)*8;
			
			// Copy 8 bytes from the original character location to the char memory space
			for j:=0 to 8 do begin
				zeropage2[y]:=zeropage3[val];
				inc(val);
				inc(y);
			end;

			// Fill in two blank bytes above and below (for clearing)
			zeropage2[y]:=0;
			zeropage2[y+1]:=0;
			zeropage2[y-10]:=0;
			zeropage2[y-11]:=0;
		end;
		zpc:=zpc+32; 
		// inczp is kinda slow, so try to only call when absolutely necessary, here at every 7 steps
		if zpc=224 then begin
			inczp(zeropage2, 224);
			zpc:=0;
		end;
		shift:=shift +7;
	end;
	
end;


/*
	Optimized version of the same method above: Inner loop is rewritten in assembler 
*/
procedure DYCP_Optimized();
begin

	if g_currentBank=0 then		
		zeropage2 := @cmem
	else
		zeropage2 := @cm2;

	shift:=0;
	zpc:=64;
	shift:=shift + time;
	for i:=00 to 26 offpage do begin // 197 cycles! Force onpage
		y:=sine[shift]+zpc;
		val := zeropage5[i]; // text value
		if val>64 then begin
			val:=(val-64)*8;

			k:=val+8;
			asm("
			; First clear the two first bytes on top
			ldy y
			lda #0
			sta (zeropage2),y
			iny
			sta (zeropage2),y
			iny
			; load val
			ldx val ; loop val times
innerlabbe:
			lda @charmap,x    ; copy data
			sta (zeropage2),y
			iny
			inx
			cpx k
			bne innerlabbe
			
			; aftewards, clear the two last bytes
			lda #0
			sta (zeropage2),y
			iny
			sta (zeropage2),y

			");

		end;
		zpc:=zpc+32;
		if zpc=224 then begin
			inczp(zeropage2, 224);
			zpc:=0;
		end;
		shift:=shift +7;
	end;
	
end;

/*
	Main raster routine

*/
procedure RasterUpdate();
begin
	// Make sure raster is at 0
	waitforraster(0);
	
	time:=time+7;
	// Display bitmap
	setbitmapmode();
	setbank(VIC_BANK2);
	setmulticolormode();
	// Make sure no scroll while bitmap is displayed
	scrollx(0);

	// Start doing DYCP magick (while waiting for raster..)
	if scroll = 7  then begin
		
		if g_currentBank=0 then g_currentBank:=1
		else g_currentBank := 0;
		// Kinda ugly fix. When scroll is at its last position, start drawing on the next bank
		@DYCP();

		if g_currentBank=0 then g_currentBank:=1
		else g_currentBank := 0;

	end
	else
		@DYCP(); // Else just draw on the current bank


	/* I need a way to set high/low bytes directly for zeropages. 

	This next step is for clearing purposes: Since cleaning the entire charset in a single bulk is way
	too slow, I'm only cleaning 256 bytes for each scrollx in 0..7
	 Therefore, for each scroll in values 0..7, add this to the high bit of zeropage4 (which points to the previous
	character set and fill at this position). 

*/

	asm("
	lda scroll
	adc zeropage4+1
	sta zeropage4+1
	");
	if scroll<>7 then
		fill(zeropage4, 0, 0);


	// Only clear when not on special scroll location (7)


	// Puh! Optimize enough so that everything can be completed before we hit rasterline 210
	waitforraster(210);
	// Switch back to regular text & color modes
	setregularcolormode();
	settextmode();
	// Make sure we are pointing to correct bank, either 0 or 1
	if g_currentBank=1 then begin
		zeropage4:=@cmem;
		setbank(VIC_BANK1);
	end
	else begin
		zeropage4:=@cm2;
		setbank(VIC_BANK0);
	end;
	// If we're on special scroll x, switch banks
	if scroll=7 then SwitchBank();
	scrollx(scroll);

	scroll:=scroll-1;
	// If scroll <0, then fill special, increase text counter (zeropage5+1) and reset scroll
	if scroll>128 then begin
		fill(zeropage4, 0, 0);
		scroll:=7;
		inczp(zeropage5, 1);
	end;
	
end;


/*
	This method sets up the screen on bank 0 and 1. Basically, the pattern for DYCP is

	0  4  8  12
	1  5  9  ..
	2  6 10
	3  7 11  

	where all characters are in a narrow 4-row strip.

*/
procedure InitScreenChars();
begin
	yy:=20;
	k:=0;
	moveto(0,yy,$04);
	zeropage5 := text;
	scroll := 7;
	i:=0;
	for i:=0 to 40 do begin
		screenmemory[i]:=k;
		screenmemory[i+40]:=k+1;
		screenmemory[i+80]:=k+2;
		screenmemory[i+120]:=k+3;
		k:=k+4;
	end;
	copyfullscreen(^$0400,^$4400);
		
end;

/*
	Copy charset from rom, sets up sine table (divide by 12), charset loc, clearing screens and colors
	also fills some greenish colors to the color memory of the scroller
	copies color memory for image displaying

*/
procedure InitAll();
begin
	
//	zeropage1:=@charmap;
//	copycharsetfromrom(^@charmap);
	setmemoryconfig(0,1,1,1,0);
	for a:=0 to 255 do sine[a]:=sine[a]/12;
	sine[255] := sine[0];
	SetCharsetLocation($2800);
//	poke(VIC_DATA_LOC, 0,$1A);
	hideborderx(1);
	
	//setmulticolormode();
	clearscreen(GREEN,^$D800);
	clearscreen(161,^$0400);
	clearscreen(161,^$4400);

//	clearbitmap(^$2000,16);
//	clearbitmap(^$6000,16);

	SCREEN_BG_COL:=BLACK;
	SCREEN_FG_COL:=BLACK;

	//	clearscreen(0,^$3B00); // Clear charset
	time := 0;
	InitScreenChars();
	// Banking data loc
	g_dataLoc := $1A;
//	togglebit(^$1, 0, 0);
	copyimagecolordata(image_color,2);

	moveto(0,20,$D8);
	for i:=0 to 40 do begin
		screenmemory[i]:=GREEN;
		screenmemory[i+40]:=LIGHT_GREEN;
		screenmemory[i+80]:=WHITE;
		screenmemory[i+120]:=GREY;
	end;



end;

/*
	Main method. Plain.
*/
begin
	InitAll();
	while 1=1 do
		RasterUpdate();

	Loop();
end.




