#include "FKUT/FKUT.h"


// プログラムが始まるmain関数
int main(int argc, char *argv[])
{
	// ウィンドウ準備しまーす
	fkut_SimpleWindow	window;			// すごい変数「3DCGが描けるウィンドウになる変数」
	// サブウィンドウの作成
	// fkut_SimpleWindow	subWin(window);	// 変数名(ここに先に作った親ウィンドウの変数を入れる)

	window.setSize(800, 600);			// ウィンドウの大きさはお好みで
	window.setBGColor(0.3, 0.6, 0.8);	// 背景色はR, G, Bの色成分を0.0〜1.0でブレンドして作るよ
	window.showGuide();					// グリッドと軸の表示
	window.open();						// ウィンドウ自体を表示するよ

	// サブウィンドウを作った場合の設定
	/*
	window.setInnerSize(0, 0, 400, 600);	// 親ウィンドウの表示領域を、左上の座標と幅と大きさで指定
	subWin.setInnerSize(400, 0, 400, 600);	// サブウィンドウの表示領域を、左上の座標と幅と大きさで指定
	subWin.setBGColor(0.3, 0.6, 0.8);		// 背景色はR, G, Bの色成分を0.0〜1.0でブレンドして作るよ
	subWin.open();							// ウィンドウ自体を表示するよ
	*/
	// ウィンドウ準備ここまで

	// ここから表示するものを用意している部分
	fk_Model			baseModel;
	fkut_GuideObject	baseGuide;

	fkut_SphereModel	body;

	body.create(8, 10.0);
	body.setMaterial(Yellow);
	body.glMoveTo(0.0, 5.0, 0.0);
	body.setParent(baseModel, true);
	window.entry(body);
	baseGuide.setScale(1.0);
	baseGuide.setNum(30);
	window.entry(baseModel, baseGuide);
	// entry時にGuideObjectの変数を一緒に渡すと軸と床がついてくる

	fkut_BlockModel		floor;			// 床をあらわすブロックモデル

	floor.create(1000.0, 1.0, 1000.0);
	floor.glMoveTo(0.0, -0.51, 0.0);	// ちょいと低めにしておく
	floor.setMaterial(Brown);
	window.entry(floor);
	// 表示用意部分ここまで

	// カメラを自前で定義するよ
	fk_Model	camera;

	window.setCameraModel(camera);
	camera.glMoveTo(0.0, 100.0, 400.0);
	camera.glFocus(0.0, 0.0, 0.0);
	// カメラ定義ここまで

	// 状態管理用の変数
	fk_Vector	vSpd, vPos;	// 速度ベクトル、位置取得用変数
	int			iState = 0;	// 0: ふつう, 1: 上昇中, 2: 下降中

	// ぐるぐる回る前に、変数を用意
	fk_Vector	vFwd;			// 前進する向きを表す変数
	vFwd.set(0.0, 0.0, -1.0);	// これが前進方向だよ

	int	iTripleTime = 0;		// 3倍速タイムを表す変数
	// 変数準備ここまで

	// ぶつかれるブロックを用意する
	fkut_BlockModel		hitBlk[10];
	fk_Vector			back, prevPos;

	// 配列と繰り返しを利用して、まとめて設定
	for(int i = 0; i < 10; i++) {
		hitBlk[i].create(30.0, 60.0, 30.0);
		hitBlk[i].glMoveTo(-100.0 + i*60.0, 0.0, -50.0);
		hitBlk[i].setMaterial(Green);
		window.entry(hitBlk[i]);
	}
	prevPos = baseModel.getPosition();

	// サブウィンドウに表示させたいものはサブウィンドウの変数に対して別個にentryする
	/*
	subWin.setTrackBallMode(true);
	subWin.entry(body);
	subWin.entry(baseModel, baseGuide);
	subWin.entry(floor);
	for(int i = 0; i < 10; i++) {
		subWin.entry(hitBlk[i]);
	}
	*/

	// 絵を出すよ
	fkut_SpriteModel	spr, text, numSpr;

	// 読み込んで
	if(spr.readPNG("grp/hit.png") == false) fl_alert("画像読み込み失敗でごんす");
	// 表示(カメラは先に設定しておかないとだめ)
	window.entry(spr);

	// 読み込んで
	if(numSpr.readPNG("grp/pop_font.png") == false) fl_alert("画像読み込み失敗でごんす");
	// 切り出して
	numSpr.setSpriteArea(0, 0, 28, 38);
	// 移動して
	numSpr.setPositionLT(-400.0, 300.0);
	// 表示
	window.entry(numSpr);

	// 文字を準備して
	if(text.initFont("C:/WINDOWS/Fonts/Meiryo.ttc") == false) fl_alert("フォント読み込み失敗でごんす");
	// 描いて
	text.drawText("もじもじだー");
	// 移動して
	text.glTranslate(100.0, 0.0, 0.0);
	// 表示
	window.entry(text);

	// 通常のモデル変数は、1つの変数を2つのウィンドウに突っ込むことができるが、
	// スプライトに関してはできないので注意
	// (同じ画像をそれぞれのウィンドウに表示させたいなら、別個に変数を用意すること)

	////////////////////////////////////////////////////////////////////////////////////
	// モーション再生用クラスの変数を用意
	CMotionCharactor	chara;

	// モーション制御用の変数(使用例なので必須ではない)
	int motionID = -1;

	// メタセコのデータを読み込む
	if(!chara.loadObjectData("girl/girl.mqo")) fl_alert("Object Read Error.");
	// セットアップデータを読み込む
	if(!chara.loadJointData("girl/girl_setup.fkc")) fl_alert("Joint Read Error.");
	// モーションデータを読み込みたいだけ読み込む
	if(!chara.loadMotionData("girl/walk_new.fkm")) fl_alert("Motion Read Error.");
	if(!chara.loadMotionData("girl/punch2_new.fkm")) fl_alert("Motion Read Error.");
	if(!chara.loadMotionData("girl/kick2_new.fkm")) fl_alert("Motion Read Error.");

	// 表示
	window.entry(chara);
	////////////////////////////////////////////////////////////////////////////////////


	// ぐるぐる回るよー
	while(window.update()) {

		////////////////////////////////////////////////////////////////////////////////////
		// キー操作によって再生しているモーションの状態を変化させる
		if(window.getKeyStatus('1') == FKUT_SW_DOWN) {
			motionID = 0;
		} else if(window.getKeyStatus('2') == FKUT_SW_DOWN) {
			motionID = 1;
		} else if(window.getKeyStatus('3') == FKUT_SW_DOWN) {
			motionID = 2;
		} else if(window.getKeyStatus('0') == FKUT_SW_DOWN) {
			motionID = -1;
		}

		// モーション ID によって、再生するモーションの種類を分岐する

		// ループ1回ごとに playMotion(再生番号) を呼ぶと1フレームずつモーションが進む
		// 再生番号は loadMotionData() で読み込んだ順(0スタート)
		if(motionID == 0) {
			// ずっと呼び続けると繰り返し再生される
			chara.playMotion(0);
		} else if(motionID == 1 || motionID == 2) {
			// 1回きりの再生で止めたい場合は、終了を検出して対処する
			if(chara.isMotionFinished(motionID) == true) {
				// モーションが終了していた場合は何もしないようにしたり、
				// 次のモーションへ繋げたりすればよい

				// この例だと最初のフレーム巻き戻した後、
				// IDを-1にして再生処理は止めるようにしている
				// もう一度2を押せば再生される
				chara.setNowFrame(motionID, 0);
				motionID = -1;
			} else {
				chara.playMotion(motionID);
			}
		}
		////////////////////////////////////////////////////////////////////////////////////

		// ピックの使い方
		// ウィンドウの変数.isModelPicked(調べたいモデルの変数, 何ピクセルまでを当たりとして判定するか);
		// これで、現在のマウスカーソルが指している位置が、モデルを指しているかどうかを判定できます
		// getMouseStatus()と組み合わせれば、クリックしている時に反応、ということもできます
		if(window.isModelPicked(body, 5)) {
			cout << "刺さっております" << endl;
		}

		// キー操作で前進後退＆左右旋回
		if(window.getSpecialKeyStatus(FK_UP) == FKUT_SW_PRESS) {
			baseModel.loTranslate(vFwd);	// vFwdの方向へ進め
		}
		if(window.getSpecialKeyStatus(FK_DOWN) == FKUT_SW_PRESS) {
			baseModel.loTranslate(-vFwd);	// vFwdと反対方向へ進め
		}
		if(window.getSpecialKeyStatus(FK_LEFT) == FKUT_SW_PRESS) {
			baseModel.loFocus(-0.1, 0.0, -1.0);
		}
		if(window.getSpecialKeyStatus(FK_RIGHT) == FKUT_SW_PRESS) {
			baseModel.loFocus(0.1, 0.0, -1.0);
		}
		// キー操作処理ここまで

		// 3倍モードシステム
		if(iTripleTime == 0) {	// まだ通常状態のときに
			// Xキーを押したら3倍モードにする
			if(window.getKeyStatus('x') == FKUT_SW_DOWN) {
				iTripleTime = 300;		// 残り時間を5秒(300フレーム)にする
				body.setMaterial(Red);	// 赤くする
				vFwd.z = -3.0;			// 3倍にする
			}
		} else if(iTripleTime >= 1) {	// 3倍タイム発動中なら
			iTripleTime--;	// 残り時間を1フレーム減らす
			if(iTripleTime == 0) {	// 減らした結果時間終了なら
				body.setMaterial(Yellow);	// 色を元に戻す
				vFwd.z = -1.0;				// 速度も元に戻す
			}
		}
		// 3倍モードシステムここまで

		// 今時？風ジャンプ
		if(iState == 0) {			// 通常モード
			// zキーを押された瞬間、上昇モードへ移行
			if(window.getKeyStatus('z') == FKUT_SW_DOWN) {
				iState = 1;
				vSpd.y = 8.0;		// ジャンプの初速度を与える
			}
			// 足場がなくなってるかの判定
			for(int i = 0; i < 10; i++) {
				if(hitBlk[i].checkToMovingSphere(body, fk_Vector(0.0, -1.0, 0.0), back)) {
					if(back.y <= 0.0) {		// 床にめり込んでいたら
						vSpd.y = 0.0;		// 速度リセット
						iState = 2;			// 足場がなくなったので落下モード
						break;
					}
				}
			}
		} else if(iState == 1) {	// 上昇モード
			// 速度を変化させる(擬似的な重力加速度を与える)
			if(vSpd.y > 4.0) {
				// 上向きの速度があるうちはきつめに減らす
				vSpd.y -= 1.0;
			} else if(vSpd.y > 0.0) {
				// 速度が少なくなったら減らす量を減らす
				vSpd.y -= 0.5;
			} else {
				// 速度が下向きに反転したら下降モードへ移行
				iState = 2;
			}
			// 変化させた速度によってモデルを移動
			baseModel.glTranslate(vSpd);
		} else if(iState == 2) {	// 下降モード
			// 速度を変化させる(擬似的な重力加速度を与える)
			if(vSpd.y > -4.0) {
				// 下向きの速度が少ないうちはゆるめに加速
				vSpd.y -= 0.5;
			} else {
				// 速度がきつくなってきたらきつめに加速
				vSpd.y -= 1.0;
			}
			// 変化させた速度によってモデルを移動
			baseModel.glTranslate(vSpd);
			// 床との当たり判定処理
			vPos = baseModel.getPosition();	// 現在位置を取ってくる
			if(vPos.y <= 0.0) {				// 床にめり込んでいたら
				vSpd.y = 0.0;				// 速度リセット
				vPos.y = 0.0;				// Y座標を0.0に固定
				baseModel.glMoveTo(vPos);	// 固定した座標に強制転送
				// 通常モードへ移行
				iState = 0;
			}
		}
		// 今時風ジャンプここまで

		// ブロックとの当たり判定
		for(int i = 0; i < 10; i++) {
			// 当たっていたらtrueが返る
			if(hitBlk[i].checkToSphere(body, back) == true) {
				// ブロックから見ためりこみ具合なので、
				// プレイヤー側を動かして調整する場合は逆方向になる
				baseModel.glTranslate(-back);
				// 乗っかり判定処理
				if(back.y <= 0.0) {		// 乗っかっためり込みを感知したら
					vSpd.y = 0.0;		// 速度リセット
					iState = 0;			// 通常モードへ移行
				}
			}
		}
		prevPos = baseModel.getPosition();

	}
	// おつかれさまでした

	return 0;
}
