#include <stdio.h>
#include <stdlib.h>
#include <kernel.h>
#include <swis.h>

#include "tpf/tpf.h"
#include "screen.c"
#include "osspr.c"

#define colconv(c) (((c & 33)<<2)+((c & 14)<<3)+((c & 16)>>1)+((c & 192)>>6))

int main(int argc,char **argv)
{
	char n[256];
	int *sprblock;
	tpfTex s[6]; /* 6 sprites */
	int x,y;
	tpfMap *map;
	tpfScreen *scrn;
	tpfVec cam,dir;
	tpfAng dirl,dirr,diru,dird;
	tpfAng change;
	int frames;
	_kernel_swi_regs regs;
	int frametime;
	int z;
	tpfObj *obj;
	/* Get sprites to use... */
	printf("Sprite file?\n");
	scanf("%s255",n);
	sprblock = (int *) OSSpr_LoadFile(n);
	for (x=0;x<64;x++)
		for (y=0;y<64;y++)
		{
			TpfTex_Write(&s[0],x,y,colconv(OSSpr_ReadPixel(sprblock,"0",x,y)));
			TpfTex_Write(&s[1],x,y,colconv(OSSpr_ReadPixel(sprblock,"1",x,y)));
			TpfTex_Write(&s[2],x,y,colconv(OSSpr_ReadPixel(sprblock,"2",x,y)));
			TpfTex_Write(&s[3],x,y,colconv(OSSpr_ReadPixel(sprblock,"3",x,y)));
			TpfTex_Write(&s[4],x,y,colconv(OSSpr_ReadPixel(sprblock,"4",x,y)));
			TpfTex_Write(&s[5],x,y,colconv(OSSpr_ReadPixel(sprblock,"5",x,y)));
		}
	OSSpr_CloseFile(sprblock);
	/* Now set up the level map */
	map = TpfMap_New(8,8);
	for (x=0;x<8;x++)
	{
		TpfMap_SetSide(map,x,0,TPFMAP_WALL_N,1); /* Walls at the edge */
		TpfMap_SetSide(map,x,7,TPFMAP_WALL_S,2); /* North sprite (#2) goes on south side of the northern wall */
		TpfMap_SetSide(map,0,x,TPFMAP_WALL_E,3); /* West sprite (#3) goes on east side of western wall */
		TpfMap_SetSide(map,7,x,TPFMAP_WALL_W,4); /* etc */
	}
	TpfMap_SetSide(map,1,0,TPFMAP_WALL_N,5); /* Put dirty blocks in where the corners should be */
	TpfMap_SetSide(map,1,7,TPFMAP_WALL_S,5);
	TpfMap_SetSide(map,6,0,TPFMAP_WALL_N,5);
	TpfMap_SetSide(map,6,7,TPFMAP_WALL_S,5);
	TpfMap_SetSide(map,0,1,TPFMAP_WALL_E,5);
	TpfMap_SetSide(map,0,6,TPFMAP_WALL_E,5);
	TpfMap_SetSide(map,7,1,TPFMAP_WALL_W,5);
	TpfMap_SetSide(map,7,6,TPFMAP_WALL_W,5);
	TpfMap_SetSide(map,4,4,TPFMAP_WALL_N,6); /* A block in the centre */
	TpfMap_SetSide(map,4,5,TPFMAP_WALL_S,6);
	TpfMap_SetWallFlags(map,1,TPFWALL_STOPRAY + TPFWALL_TEXTURE);
	TpfMap_SetWallFlags(map,2,TPFWALL_STOPRAY + TPFWALL_TEXTURE);
	TpfMap_SetWallFlags(map,3,TPFWALL_STOPRAY + TPFWALL_TEXTURE);
	TpfMap_SetWallFlags(map,4,TPFWALL_STOPRAY + TPFWALL_TEXTURE);
	TpfMap_SetWallFlags(map,5,TPFWALL_STOPRAY + TPFWALL_TEXTURE);
	TpfMap_SetWallFlags(map,6,TPFWALL_TEXTURE);
	TpfMap_SetWallTex(map,1,&s[0]); /* Set texture: South sprite */
	TpfMap_SetWallTex(map,2,&s[1]); /* North sprite */
	TpfMap_SetWallTex(map,3,&s[2]); /* West sprite */
	TpfMap_SetWallTex(map,4,&s[3]); /* East sprite */
	TpfMap_SetWallTex(map,5,&s[4]); /* Messy wall */
	TpfMap_SetWallTex(map,6,&s[5]); /* Half wall */
	obj = TpfObj_New();
	cam.x = cam.y = f1616_FromFloat(4.5);
	cam.z = 0;
	TpfObj_SetPos(obj,cam);
	TpfObj_SetAng(obj,0);
	TpfObj_SetSides(obj,4);
	TpfObj_SetSide(obj,0,&s[3]);
	TpfObj_SetSide(obj,1,&s[1]);
	TpfObj_SetSide(obj,2,&s[2]);
	TpfObj_SetSide(obj,3,&s[0]);
	TpfObj_SetFlags(obj,TPFOBJ_STOPRAY);
	/* Now set screen mode... */
	screen_oldmode(13);
	screen_createbanks(2);
	frames=0;
	/* Main loop */
	cam.x = f1616_FromInt(3); cam.y = f1616_FromInt(3); cam.z = f1616_FromFloat(0.6);
	dirl = TpfAng_FromDeg(110);
	dirr = TpfAng_FromDeg(20);
	diru = TpfAng_FromDeg(30); /* Only show 60 degrees up/down */
	dird = TpfAng_FromDeg(-30);
	scrn = TpfScreen_New();
	_kernel_swi(OS_Mouse,&regs,&regs);
	x=regs.r[0];
	y=regs.r[1];
	z=regs.r[2];
	screen_getdata();
	_kernel_swi(OS_ReadMonotonicTime,&regs,&regs);
	frametime = regs.r[0];
	while (z != 7)
	{
		_kernel_swi(OS_Mouse,&regs,&regs);
		x=regs.r[0]-512; /* Get displacement */
		y=regs.r[1]-512;
		z=regs.r[2];
		regs.r[0]=21;
		regs.r[1]=(int) &regs.r[2]; /* Point to own register block */
		regs.r[2]=0x00020003;
		regs.r[3]=0x02;
		_kernel_swi(OS_Word,&regs,&regs);
		change = TpfAng_FromDeg(-x/2);
		dirl = TpfAng_Add(dirl,change);
		dirr = TpfAng_Add(dirr,change);
		change = TpfAng_Sub(dirl,TpfAng_FromDeg(45));
		dir.x = TpfAng_cos(change);
		dir.y = TpfAng_sin(change);
		dir.z = 0;
		TpfVec_Mul2(&dir,f1616_FromInt(y));
		TpfVec_Div2(&dir,f1616_FromInt(200));
		TpfVec_Add(&cam,&dir);
		screen_vsync();
		if (frames > 100)
			screen_swap(); /* Only change banks after the first frame or two to make sure any startup errors are visible */
		screen_getdata();
		screen_cls();
		TpfScreen_SetScreen(scrn,screen.width+1,screen.height+1,0,screen.vdu);
		TpfScreen_SetViewPos(scrn,&cam);
		TpfScreen_SetFov(scrn,dirl,dirr,diru,dird);
		/* Draw! */
		TpfDraw_Draw(scrn,map);
		TpfDraw_DrawObj(scrn,obj);
		TpfDraw_DoDrawList(scrn);
		frames+=100;
		_kernel_swi(OS_ReadMonotonicTime,&regs,&regs);
		printf("%ffps\n",(float) frames/(regs.r[0]-frametime));
	}
	/* Quit */
	screen_setbank(1);
	TpfMap_Delete(map);
	TpfScreen_Delete(scrn);
	return 0;
}
