//------------------------------------------------------------------------------
// Lamp : Open source game middleware
// Copyright (C) 2004  Junpei Ohtani ( Email : junpee@users.sourceforge.jp )
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//------------------------------------------------------------------------------

/** @file
 * チュートリアル3 サウンド実装
 * @author Junpee
 */

#include <LampBasic.h>
#include <Framework/System/SceneFramework.h>
#include <Graphics/Scene/Scene.h>
#include <Graphics/SceneNode/SceneNodeManager.h>
#include <Animation/System/AnimationManager.h>
#include <Animation/System/Animation.h>
#include <Input/Pad/PS2Pad.h>
#include <Sound/System/LampSound.h>
#include <Sound/System/SoundManager.h>
#include <Sound/Stereo/StreamSound.h>
#include <Sound/3D/StaticSound3D.h>
#include <Sound/3D/SoundListener.h>
#include <Graphics/Camera/Camera.h>
#include <Sound/Utility/SoundCache.h>

// Lampのネームスペースを有効にする
using namespace Lamp;

//------------------------------------------------------------------------------
// クラス定義、通常はヘッダファイルに格納する
//------------------------------------------------------------------------------
/**
 * チュートリアル3 サウンド
 */
class Tutorial3_Sound : public SceneFramework{
public:
	/**
	 * コンストラクタ
	 */
	Tutorial3_Sound();

	/**
	 * 初期化
	 * @return 初期化に成功すればtrueを返す
	 */
	virtual bool initialize();

	/**
	 * 後始末
	 */
	virtual void finalize();

	/**
	 * 実行
	 */
	virtual void run();

protected:
	// キャラクタ移動ノード
	SceneNode* characterMoveNode_;
	// キャラクタ回転ノード
	SceneNode* characterRotationNode_;
	// アニメーション
	Animation* animation_;
	// BGM
	Sound* bgm_;
	// SE0
	StaticSound3D* se0_;
	// SE1
	StaticSound3D* se1_;
	// サウンドリスナ
	SoundListener* listener_;
	// サウンドキャッシュ
	SoundCache* soundCache_;

};
//------------------------------------------------------------------------------
// プログラムエントリポイント
//------------------------------------------------------------------------------
// メイン関数
int WINAPI WinMain(
	HINSTANCE instance, HINSTANCE previousInstance, LPSTR command, int show){
	Tutorial3_Sound tutorial;
	return tutorial.execute(instance);
}
//------------------------------------------------------------------------------
// クラス実装
//------------------------------------------------------------------------------
// コンストラクタ
Tutorial3_Sound::Tutorial3_Sound() :
	SceneFramework("Tutorial3_Sound"),
	characterMoveNode_(NULL), characterRotationNode_(NULL){
}
//------------------------------------------------------------------------------
// 初期化
bool Tutorial3_Sound::initialize(){
	// シーンのロード
	if(!loadScene("../Media/Tutorial.bsn")){ return false; }
	// 移動ノードの取得
	characterMoveNode_ =
		scene_->getSceneNodeManager()->search("MakotoMove");
	// 回転ノードの取得
	characterRotationNode_ =
		scene_->getSceneNodeManager()->search("MakotoRotation");
	// アニメーションの取得
	animation_ = animationManager_->search("Tutorial");

	// BGMの初期化
	SoundManager* soundManager = LampSound::getSoundManager();
	bgm_ = soundManager->createStreamSound("../Media/BGM.ogg");
	bgm_->setLoop(true);
	bgm_->fadeIn(2000.f);
	// SEの初期化
	soundManager->set3DAlgorithm(SoundManager::algorithmLightHRTF);
	se0_ = soundManager->createStaticSound3D("../Media/SE0.ogg");
	se0_->setLoop(true);
	se0_->setDistance(10.f, 1000.f);
	se1_ = soundManager->createStaticSound3D("../Media/SE1.ogg");
	se1_->setLoop(true);
	se1_->setDistance(10.f, 1000.f);
	// リスナの初期化
	listener_ = LampSound::getSoundListener();
	listener_->setDopplerFactor(5.f);
	// サウンドキャッシュの初期化
	soundCache_ = new SoundCache("../Media/", ".ogg");
	soundCache_->loadSoundList("SoundList.txt");

	return true;
}
//------------------------------------------------------------------------------
// 後始末
void Tutorial3_Sound::finalize(){
	// サウンドキャッシュの破棄
	SafeDelete(soundCache_);
	// 全サウンドの破棄
	LampSound::getSoundManager()->destroyAll();
}
//------------------------------------------------------------------------------
// 実行
void Tutorial3_Sound::run(){
	Vector3 addPosition(Vector3::zero);
	float moveSpeed = 0.4f;
	float runTime = 16.66666f;
	bool bgmFade = false;

	// パッド入力処理
	if(pad_ != NULL){
		Point2f leftAxis = pad_->getLeftAxis();
		leftAxis *= moveSpeed;
		addPosition += Vector3(leftAxis.x, 0.f, leftAxis.y);
		if(pad_->buttonDown(PS2Pad::buttonMaru)){ bgmFade = true; }
		if(pad_->buttonDown(PS2Pad::buttonBatu)){
			soundCache_->playSound("SE2", 0.75f);
		}
	}

	// キーボード入力処理
	if(keyboard_->pressed(Keyboard::keyUp)){ addPosition.z -= moveSpeed; }
	if(keyboard_->pressed(Keyboard::keyDown)){ addPosition.z += moveSpeed; }
	if(keyboard_->pressed(Keyboard::keyRight)){ addPosition.x += moveSpeed; }
	if(keyboard_->pressed(Keyboard::keyLeft)){ addPosition.x -= moveSpeed; }
	if(keyboard_->down(Keyboard::keyZ)){ bgmFade = true; }
	if(keyboard_->down(Keyboard::keyX)){ soundCache_->playSound("SE2", 0.75f); }

	// 位置の設定
	Vector3 position = characterMoveNode_->getTranslation();
	position += addPosition;
	characterMoveNode_->setTranslation(position);

	// 3Dサウンドの位置設定
	se0_->setPositionAndVelocity(position, runTime);
	se1_->setPositionAndVelocity(position, runTime);

	// リスナの位置設定
	listener_->setPositionAndVelocity(camera_->getPosition(), runTime);
	Matrix33 cameraRotationMatrix;
	cameraRotationMatrix.setRotationXYZ(camera_->getRotation());
	Vector3 cameraUp(0.f, 1.f, 0.f), cameraFront(0.f, 0.f, -1.f);
	cameraUp = cameraRotationMatrix * cameraUp;
	cameraFront = cameraRotationMatrix * cameraFront;
	listener_->setDirection(cameraFront, cameraUp);

	// 回転とアニメーションの設定
	if(!addPosition.isZero()){
		characterRotationNode_->setRotationXYZ(Vector3(0.f,
			Math::atan2(addPosition.x, addPosition.z), 0.f));
		if(animation_->getSequence() != 0){
			animation_->setSequence(0);
			se0_->play();
			se1_->stop();
		}
	}else{
		if(animation_->getSequence() != 3){
			animation_->setSequence(3);
			se1_->play();
			se0_->stop();
		}
	}

	// BGMフェード処理
	if(bgmFade){
		if(bgm_->getState() == Sound::statePlay){ bgm_->fadeOut(2000.f); }
		else{ bgm_->fadeIn(2000.f); }
	}

}
//------------------------------------------------------------------------------
