#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <egb.h>
#include <snd.h>
#include <fmcfrb.h>

#include "tornado.h"
#include "concorde.h"

/* 表示関連は,プログラム全体から見えるようにグローバルに確保する */
PAGE *wp,vp0,vp1;
char egb[EgbWorkSize];

void InitBios();
void SwapConcordePage();

void RollingBoxMain();
void DrawBox(PROJ *prj,IPNTANG *eye,IPNTANG *box);
void DrawLine(PROJ *prj,IPOINT *vtx,int v0,int v1,int col);

int Inkey();
void EyeMove(IPNTANG *eye);

int main()
{
	InitBios();
	RollingBoxMain();
	EGB_init(egb,EgbWorkSize);
	return 0;
}

void RollingBoxMain()
{
	int i,x,y,z;
	PROJ prj;       /* 投影画面情報 */
	IPNTANG eye;    /* 視点/目の角度 */
	IPNTANG box[27];/* 箱の位置/角度 */

	prj.cx  = 160;  /* 描画中心点 X=256 */
	prj.cy  = 120;  /* 描画中心点 X=240 */
	prj.mag =  64;  /* 拡大率 = 64 */
	prj.cpz = 100;  /* クリップ平面 Z = 100 */
	prj.lx  = 320;  /* 画面サイズ X=512 */
	prj.ly  = 240;  /* 画面サイズ Y=480 */

	SetIpoint(&eye.p, 0,0,0);  /* 視点(原点) */
	SetIangle(&eye.a, 0,0,0);  /* 視線角度(真北) */

	/* 箱の位置/角度 */
	i=0;
	for(z= 1; z<=3; z++)
	{
		for(y=-1; y<=1; y++)
		{
			for(x=-1; x<=1; x++)
			{
				SetIpoint(&box[i].p, x*2000,y*2000,z*2000);
				SetIangle(&box[i].a, 0,0,0);
				i++;
			}
		}
	}

	Inkey();           /* キーバッファクリア */
	while(Inkey()==0)
	{
		YGH_clearPage(wp,0);
		for(i=0; i<27; i++)
		{
			DrawBox(&prj,&eye,&box[i]);
			box[i].a.b += i*50+50;
			PitchUp(&box[i].a,&box[i].a, i*25+25);
		}

		EyeMove(&eye);

		YGH_color(wp,32767);
		YGH_print8font(wp,0,239,"Hit Any Key To End.");

		SwapConcordePage();
	}
}

/* 箱を書く */
void DrawBox(PROJ *prj,IPNTANG *eye,IPNTANG *box)
{
	static IPOINT boxVtx[8]=
	{
		{ 500, 500, 500},{-500, 500, 500},{-500, 500,-500},{ 500, 500,-500},
		{ 500,-500, 500},{-500,-500, 500},{-500,-500,-500},{ 500,-500,-500},
	};
	IPOINT vec,tmpVtx[8];

	/* モデル座標→世界座標変換 */
	RotLtoG(8, tmpVtx,boxVtx, &box->a);
	Move3  (8, tmpVtx,tmpVtx, &box->p);

	/* 世界座標→視野座標変換 */
	SetIpoint(&vec, 0,0,0);
	SubIpoint(&vec, &vec,&eye->p);
	Move3  (8, tmpVtx,tmpVtx, &vec);
	RotGtoL(8, tmpVtx,tmpVtx, &eye->a);

	DrawLine(prj, tmpVtx,0,1, 0x001f);
	DrawLine(prj, tmpVtx,1,2, 0x03e0);
	DrawLine(prj, tmpVtx,2,3, 0x03ff);
	DrawLine(prj, tmpVtx,3,0, 0x7c00);
	DrawLine(prj, tmpVtx,4,5, 0x7c1f);
	DrawLine(prj, tmpVtx,5,6, 0x7fe0);
	DrawLine(prj, tmpVtx,6,7, 0x7fff);
	DrawLine(prj, tmpVtx,7,4, 0x001f);
	DrawLine(prj, tmpVtx,0,4, 0x03e0);
	DrawLine(prj, tmpVtx,1,5, 0x03ff);
	DrawLine(prj, tmpVtx,2,6, 0x7c00);
	DrawLine(prj, tmpVtx,3,7, 0x7c1f);
}

void DrawLine(PROJ *prj,IPOINT *vtx,int v0,int v1,int col)
{
	IPOINT linPnt[2],cutPnt[2];
	IPOINT2 scr[2];

	YGH_color(wp,col);

	/* 頂点テーブルから直線端点を生成 */
	linPnt[0]=vtx[v0];
	linPnt[1]=vtx[v1];

	/* クリップ平面の処理 */
	if(ClipLine3(cutPnt,linPnt, prj->cpz)!=0)
	{
		/* 画面座標変換 */
		ProjectToScreen(2, scr,cutPnt  ,prj);
		/* 描画 */
		YGH_line(wp, scr[0].x,scr[0].y, scr[1].x,scr[1].y);
	}
}

/* Bios初期化 */
void InitBios()
{
	SND_elevol_init();  /* PADを使えるようにする */

	EGB_init(egb,EgbWorkSize);

	EGB_resolution(egb,0,10);  /* レイア0 画面モード10 (320×240) 32K色 */
	EGB_resolution(egb,1,10);  /* レイア1 画面モード10 (320×240) 32K色 */

	EGB_writePage(egb,0);      /* レイア0 表示開始位置/倍率の設定 */
	EGB_displayStart(egb,0,0,0);
	EGB_displayStart(egb,2,2,2);
	EGB_displayStart(egb,3,320,240);
	EGB_color(egb,1,0x8000);
	EGB_clearScreen(egb);

	EGB_writePage(egb,1);     /* レイア1 表示開始位置/倍率の設定 */
	EGB_displayStart(egb,0,0,0);
	EGB_displayStart(egb,2,2,2);
	EGB_displayStart(egb,3,320,240);
	EGB_color(egb,1,0x8000);
	EGB_clearScreen(egb);

	EGB_displayPage(egb,1,2); /* 初期状態 レイア1のみ表示ON */

	YGH_initPage(&vp0,SEG_VRAMP,0x00000,512,240); /* レイア0のPAGE */
	YGH_initPage(&vp1,SEG_VRAMP,0x40000,512,240); /* レイア1のPAGE */
	wp = &vp1;  /* 最初の書き込みページはレイア1ということにする */
}

void SwapConcordePage()
{
	if(wp==&vp0)  /* それまでレイア0に書き込んでいたなら */
	{
		EGB_displayPage(egb,0,1);  /* 書き込んだ内容を表示する */
		wp=&vp1;                   /* これからはレイア1に書き込む */
	}
	else          /* それまでレイア1に書き込んでいたなら */
	{
		EGB_displayPage(egb,1,2);  /* 書き込んだ内容を表示する */
		wp=&vp0;                   /* これからはレイア0に書き込む */
	}
}

int Inkey()
{
	unsigned key,encode;
	key=KYB_read(1,&encode);
	if((key & 0xff00)==0)
	{
		return key & 0xff;
	}
	return 0;
}

void EyeMove(IPNTANG *eye)
{
	int pad,vp,vh;
	IPOINT vec;

	vh=0;
	vp=0;
	SND_joy_in_2(0,&pad);
	pad = ~pad;
	if(pad & 0x01){ vp= 800; }  /* 上向き回転 */
	if(pad & 0x02){ vp=-800; }  /* 下向き回転 */
	if(pad & 0x04){ vh= 800; }  /* 左向き回転 */
	if(pad & 0x08){ vh=-800; }  /* 右向き回転 */
	PitchUp(&eye->a, &eye->a, vp);
	YawLeft(&eye->a, &eye->a, vh);

	SetIpoint(&vec,0,0,60);
	RotLtoG(1,&vec,&vec,&eye->a);
	if(pad & 0x10){ AddIpoint(&eye->p, &eye->p, &vec); }
	if(pad & 0x20){ SubIpoint(&eye->p, &eye->p, &vec); }

	if(pad & 0x40){ eye->a.b += 800; } /* 左横転 */
	if(pad & 0x80){ eye->a.b -= 800; } /* 右横転 */
}
