program Rotating_text;
var  

@define dPos0 $8000
@define dPos1 $1F00
@define splitChar 18
@define useKernal 0
@define spriteLoc $4800

@requireFile "data/textsprites0.bin" "Please run example12_rotating_text.fjo before compiling this file"

/*

	In this example, we pre-render 28 character as rotating sprites with 16 frames each. We then display
	the sprites in a funky wavy pattern that it totally scientific and stuff. 


*/

	// Text data
	data1: incbin("data/textsprites0.bin", @dPos0);
	data2: incbin("data/textsprites1.bin", @dPos1);
	// Array to store som values
	vals : array[8] of byte;
	

	xadd,i,k, m,y,time,l,aadd,keep,tt, lStart: byte=0;
	// y-placement of sprites
	ypos: byte=128;
	// Text to display
	text : string=("TORTILLA");
	// Colors for text
	colors : array[8] of byte = (1,2,3,4,5,6,7,8);


	itmp:integer;
	zp,p1, p2,tp : pointer;
	// Empty sprites, used for space 
	zero:array[64] of byte;

/*
	This is the "main" method of the effect, which copies 64 bytes of sprite data
	to the sprite pointer location. The hard part is finding the current frame of the current letter:
	- each frame is 64 bytes (1 sprite)
	- 1 letter has 16 pre-rendered sprites, so 16*64 bytes = 1024 bytes of data per letter
	So in order to find "frame no N of letter L", you need to find L*1024 + N*64
	The "64" is multiplied directly, but we use a trick to obtain the *1024: since 
	adding a 1 to a high byte is the same as 256, then adding 4 bytes to the high byte counts as 1024. Therefore, we
	can obtain the high byte of the position by : adding 4*L. This is all performed in the following lines:

	// Set p2 to 64*current frame	
	p2:=ss_frame*64;
	// Then add current character (1024 bytes each, representing 16 frames * 64 bytes)
	p1:=p2 + toPointer(ss_char*4+m ,0);

	here, "m" represents the base high byte of the memory address of the data.
	
*/
procedure SetSprite(ss_i, ss_char, ss_frame:byte);
begin
	zp:=@spriteLoc + 64*ss_i;
	if (ss_char=$20) then begin
		memcpyfast(zero,0,zp,63);
		return();
	end;
	ss_char:=ss_char-65;
	// Sprites are split between two data sets. If above, set the other one
	m:=hi(^@dPos0);
	if (ss_char>=@splitChar) then begin
		ss_char:=ss_char-@splitChar;
		m:=hi(^@dPos1);
	end;
	// Set current frame
	p2:=ss_frame*64;
	// Then add current character (1024 bytes each, representing 16 frames * 64 bytes)
	p1:=p2 + toPointer(ss_char*4+m ,0);
	keep:=peek(^$01,0);
	enableallram();
	// Copy 64 bytes of data!
	// We can use "fast" since the count of bytes is less than 127
	memcpyfast(p1,0,zp,63);
	poke(^$01,0,keep);
end;
/*
	Magical method that does some funky stuff. Basically
	calculates both the position and angles. Can be switched out to something very more basic, but this looks way cooler. 
*/
procedure UpdateSpritePos();
begin
	tt:=time;
	aadd:=sine[64-tt]/12 + 16;
	l:=lStart;
	lStart:=lStart+2;
	xadd:=16+sine[time*2]/12;
	tt:=tt*3;
	i:=sine[time]/2;
	itmp:=i;
	// Set x/y pos
	for i:=0 to 8 do begin
		m:=l-tt*2;
		k:=sine[m]/4;
			
		y:=ypos+k-49;
		spritepos(itmp,y,i);
		k:=sine[m+64-9]/16;			
		vals[i]:=k;

		itmp:=itmp+xadd;
		l:=l+aadd;		
	
	end;
	// Set rotation and sprites
	for i:=0 to 8 do begin
		k:=vals[i];
		m:=(time+i)&1;
		if (m=0) then 
			SetSprite(i,tp[i],k);

	end;
end;

// Sets up the sprites, pointer position and colors 
procedure InitSprites();
begin
	sprite_bitmask:=$ff;
	zp:=text;
	memcpy(colors,0,sprite_color,8);
	sprite_stretch_X:=$FF;
	sprite_stretch_Y:=$FF;
	setbank(vic_bank1);
	for i:=0 to 8 do 
		setspriteloc(i, (@spriteLoc-bank_size)/64+i,1);

	sprite_multicolor:=0;
	fill(zero,0,64);

end;

// Main raster, only calls UpdateSpritePos
interrupt Raster();
begin
	startirq(@useKernal);
	UpdateSpritePos();
	inc(time);
	closeIRQ();
end;


// Main block
begin	
	screen_bg_col:=black;
	screen_fg_col:=black;
	clearscreen(black, screen_char_loc2);	
	clearscreen(black, screen_col_loc);	
	tp:=text;
	InitSprites();
	disableciainterrupts();
	setmemoryconfig(1,@useKernal,0);
	startrasterchain(Raster(),0,@useKernal);
	Loop();
end.

