//******************************************************************************
//
// MIDITrail / MTNoteDesignRing
//
// ノートデザインリングクラス
//
// Copyright (C) 2019-2022 WADA Masashi. All Rights Reserved.
//
//******************************************************************************


#import "YNBaseLib.h"
#import "OGLUtil.h"
#import "MTParam.h"
#import "MTConfFile.h"
#import "MTNoteDesignRing.h"


//******************************************************************************
// コンストラクタ
//******************************************************************************
MTNoteDesignRing::MTNoteDesignRing(void)
{
	m_isLiveMode = false;
	m_NoteAngleStep = 360.0f / (float)SM_MAX_NOTE_NUM;
	m_RingRadius = 0.0f;
}

//******************************************************************************
// デストラクタ
//******************************************************************************
MTNoteDesignRing::~MTNoteDesignRing(void)
{
}

//******************************************************************************
// ライブモニタモード設定
//******************************************************************************
void MTNoteDesignRing::SetLiveMode(void)
{
	m_isLiveMode = true;
}

//******************************************************************************
// ノートボックス中心座標取得
//******************************************************************************
OGLVECTOR3 MTNoteDesignRing::GetNoteBoxCenterPosX(
		unsigned int curTickTime,
		unsigned char portNo,
		unsigned char chNo,
		unsigned char noteNo,
		short pitchBendValue,				//省略可：ピッチベンド
		unsigned char pitchBendSensitivity	//省略可：ピッチベンド感度
	)
{
	OGLVECTOR3 basePos;
	OGLVECTOR3 notePos;
	float angle = 0.0f;

	//ノート基準座標
	basePos = _GetNoteBasePos(curTickTime, portNo, chNo);

	//ノート番号で角度を決定
	angle = _GetNoteAngle(noteNo, pitchBendValue, pitchBendSensitivity);

	//X軸回転
	notePos = OGLH::RotateYZ(0.0f, 0.0f, basePos, angle);

	return notePos;
}

//******************************************************************************
// ノートボックス頂点座標取得
//******************************************************************************
void MTNoteDesignRing::GetNoteBoxVirtexPos(
		unsigned int curTickTime,
		unsigned char portNo,
		unsigned char chNo,
		unsigned char noteNo,
		OGLVECTOR3* pVector0,	//YZ平面+X軸方向を見て左上
		OGLVECTOR3* pVector1,	//YZ平面+X軸方向を見て右上
		OGLVECTOR3* pVector2,	//YZ平面+X軸方向を見て左下
		OGLVECTOR3* pVector3,	//YZ平面+X軸方向を見て右下
		short pitchBendValue,				//省略可：ピッチベンド
		unsigned char pitchBendSensitivity	//省略可：ピッチベンド感度

	)
{
	OGLVECTOR3 basePos0;
	OGLVECTOR3 basePos1;
	OGLVECTOR3 basePos2;
	float angle0 = 0.0f;
	float angle1 = 0.0f;
	float angle2 = 0.0f;

	//ノート基準座標
	basePos0 = _GetNoteBasePos(curTickTime, portNo, chNo);
	basePos1 = basePos0;
	basePos1.y -= GetNoteBoxWidth() / 2.0f;
	basePos2 = basePos0;
	basePos2.y += GetNoteBoxWidth() / 2.0f;

	//ノート番号で角度を決定
	angle0 = _GetNoteAngle(noteNo, pitchBendValue, pitchBendSensitivity);
	angle1 = angle0 - (m_NoteAngleStep / 2.0f);
	angle2 = angle0 + (m_NoteAngleStep / 2.0f);

	*pVector0 = OGLH::RotateYZ(0.0f, 0.0f, basePos2, angle1);
	*pVector1 = OGLH::RotateYZ(0.0f, 0.0f, basePos2, angle2);
	*pVector2 = OGLH::RotateYZ(0.0f, 0.0f, basePos1, angle1);
	*pVector3 = OGLH::RotateYZ(0.0f, 0.0f, basePos1, angle2);
}

//******************************************************************************
// 発音中ノートボックス頂点座標取得
//******************************************************************************
void MTNoteDesignRing::GetActiveNoteBoxVirtexPos(
		unsigned int curTickTime,
		unsigned char portNo,
		unsigned char chNo,
		unsigned char noteNo,
		OGLVECTOR3* pVector0,	//YZ平面+X軸方向を見て左上
		OGLVECTOR3* pVector1,	//YZ平面+X軸方向を見て右上
		OGLVECTOR3* pVector2,	//YZ平面+X軸方向を見て左下
		OGLVECTOR3* pVector3,	//YZ平面+X軸方向を見て右下
		short pitchBendValue,				//省略可：ピッチベンド
		unsigned char pitchBendSensitivity,	//省略可：ピッチベンド感度
		unsigned int elapsedTime			//省略可：経過時間（ミリ秒）
	)
{
	OGLVECTOR3 basePos0;
	OGLVECTOR3 basePos1;
	OGLVECTOR3 basePos2;
	float angle0 = 0.0f;
	float angle1 = 0.0f;
	float angle2 = 0.0f;
	float curSizeRatio = 1.0f;

	if (elapsedTime < (unsigned int)m_ActiveNoteDuration) {
		curSizeRatio = 1.0f + (m_ActiveNoteBoxSizeRatio - 1.0f) * (1.0f - (float)elapsedTime / (float)m_ActiveNoteDuration);
	}

	//ノート基準座標
	basePos0 = _GetNoteBasePos(curTickTime, portNo, chNo);
	basePos1 = basePos0;
	basePos1.y -= GetNoteBoxWidth() * curSizeRatio / 2.0f;
	basePos2 = basePos0;
	basePos2.y += GetNoteBoxWidth() * curSizeRatio / 2.0f;

	//ノート番号で角度を決定
	angle0 = _GetNoteAngle(noteNo, pitchBendValue, pitchBendSensitivity);
	angle1 = angle0 - (m_NoteAngleStep * curSizeRatio / 2.0f);
	angle2 = angle0 + (m_NoteAngleStep * curSizeRatio / 2.0f);

	*pVector0 = OGLH::RotateYZ(0.0f, 0.0f, basePos2, angle1);
	*pVector1 = OGLH::RotateYZ(0.0f, 0.0f, basePos2, angle2);
	*pVector2 = OGLH::RotateYZ(0.0f, 0.0f, basePos1, angle1);
	*pVector3 = OGLH::RotateYZ(0.0f, 0.0f, basePos1, angle2);
}

//******************************************************************************
// ライブモニタ用ノートボックス頂点座標取得
//******************************************************************************
void MTNoteDesignRing::GetNoteBoxVirtexPosLive(
		unsigned int elapsedTime,
		unsigned char portNo,
		unsigned char chNo,
		unsigned char noteNo,
		OGLVECTOR3* pVector0,	//YZ平面+X軸方向を見て左上
		OGLVECTOR3* pVector1,	//YZ平面+X軸方向を見て右上
		OGLVECTOR3* pVector2,	//YZ平面+X軸方向を見て左下
		OGLVECTOR3* pVector3,	//YZ平面+X軸方向を見て右下
		short pitchBendValue,				//省略可：ピッチベンド
		unsigned char pitchBendSensitivity	//省略可：ピッチベンド感度
	)
{
	OGLVECTOR3 basePos0;
	OGLVECTOR3 basePos1;
	OGLVECTOR3 basePos2;
	float angle0 = 0.0f;
	float angle1 = 0.0f;
	float angle2 = 0.0f;
	float x = 0.0f;
	unsigned int tickTimeDummy = 0;

	x = -(GetLivePosX(elapsedTime));

	//ノート基準座標
	basePos0 = _GetNoteBasePos(tickTimeDummy, portNo, chNo);
	basePos0.x = x;
	basePos1 = basePos0;
	basePos1.y -= GetNoteBoxWidth() / 2.0f;
	basePos2 = basePos0;
	basePos2.y += GetNoteBoxWidth() / 2.0f;

	//ノート番号で角度を決定
	angle0 = _GetNoteAngle(noteNo, pitchBendValue, pitchBendSensitivity);
	angle1 = angle0 - (m_NoteAngleStep / 2.0f);
	angle2 = angle0 + (m_NoteAngleStep / 2.0f);

	*pVector0 = OGLH::RotateYZ(0.0f, 0.0f, basePos2, angle1);
	*pVector1 = OGLH::RotateYZ(0.0f, 0.0f, basePos2, angle2);
	*pVector2 = OGLH::RotateYZ(0.0f, 0.0f, basePos1, angle1);
	*pVector3 = OGLH::RotateYZ(0.0f, 0.0f, basePos1, angle2);
}

//******************************************************************************
// グリッドリング基準座標取得
//******************************************************************************
void MTNoteDesignRing::GetGridRingBasePos(
		unsigned int tickTime,
		OGLVECTOR3* pBasePos
	)
{
	float chStep = 0.0f;
	
	chStep = GetChStep();
	*pBasePos = OGLVECTOR3(
					GetPlayPosX(tickTime),
					GetPortOriginY(0) + (chStep * (float)(SM_MAX_CH_NUM + 2)),
					GetPortOriginZ(0));
}

//******************************************************************************
// ライブモニタ用グリッドリング基準座標取得
//******************************************************************************
void MTNoteDesignRing::GetGridRingBasePosLive(
		OGLVECTOR3* pBasePosStart,
		OGLVECTOR3* pBasePosEnd
	)
{
	unsigned int elapsedTime = 0;
	float chStep = 0.0f;
	
	elapsedTime = GetLiveMonitorDisplayDuration();
	chStep = GetChStep();
	*pBasePosStart = OGLVECTOR3(
							GetPlayPosX(0),
							GetPortOriginY(0) + (chStep * (float)(SM_MAX_CH_NUM + 2)),
							GetPortOriginZ(0));
	*pBasePosEnd   = OGLVECTOR3(
							-(GetLivePosX(elapsedTime)),
							GetPortOriginY(0) + (chStep * (float)(SM_MAX_CH_NUM + 2)),
							GetPortOriginZ(0));
}

//******************************************************************************
// ポート原点Y座標取得
//******************************************************************************
float MTNoteDesignRing::GetPortOriginY(
		unsigned char portNo
	)
{
	float portIndex = 0.0f;
	float portWidth = 0.0f;

	portIndex = (float)(m_PortIndex[portNo]);
	portWidth = GetChStep() * (float)SM_MAX_CH_NUM;

	//   +y
	//    |
	//    @-- Note#0,127 @:Origin(for portB)
	//    |
	//    @-- Note#0,127 @:Origin(for portA)
	//    | |
	//    | | Radius
	//    | |
	// ---0----->+x(time)
	//    |
	//    |
	//    |
	//    *-- PortA
	//    |
	//    *-- PortB
	//    |
	//   -y

	return (m_RingRadius + (portWidth * portIndex));
}

//******************************************************************************
// ポート原点Z座標取得
//******************************************************************************
float MTNoteDesignRing::GetPortOriginZ(
		unsigned char portNo
	)
{
	//               +y
	//                |
	//           *****@*****      @:Origin(for portB)
	//         **     |     **
	//        *    ***@***    *   @:Origin(for portA)
	//       *   **   |   **   *
	//      *   *     |     *   *
	//      *  *      |      *  *
	// +z<--*--*------0------*--*-->-z
	//      *  *      |      *  *
	//      *   *     |     *   *
	//       *   **   |   **   *
	//        *    *******    *
	//         **     |     **
	//           ***********
	//                |
	//               -y

	return (0.0f);
}

//******************************************************************************
// 世界座標配置移動ベクトル取得
//******************************************************************************
OGLVECTOR3 MTNoteDesignRing::GetWorldMoveVector()
{
	OGLVECTOR3 vector;

	vector.x = 0.0f;
	vector.y = 0.0f;
	vector.z = 0.0f;

	return vector;
}

//******************************************************************************
// 世界座標配置移動ベクトル取得2
//******************************************************************************
OGLVECTOR3 MTNoteDesignRing::GetWorldMoveVector2(unsigned int curTickTime)
{
	OGLVECTOR3 vector;

	vector.x = - GetPlayPosX(curTickTime);
	vector.y = 0.0f;
	vector.z = 0.0f;

	return vector;
}

//******************************************************************************
// ノート基準座標取得
//******************************************************************************
OGLVECTOR3 MTNoteDesignRing::_GetNoteBasePos(
		unsigned int curTickTime,
		unsigned char portNo,
		unsigned char chNo
	)
{
	OGLVECTOR3 vector;

	//演奏位置
	vector.x = GetPlayPosX(curTickTime);

	//ポート番号・チャンネル番号で原点を決定
	vector.y = GetPortOriginY(portNo) + (GetChStep() * chNo);
	vector.z = GetPortOriginZ(portNo);

	return vector;
}

//******************************************************************************
// ノート角度取得
//******************************************************************************
float MTNoteDesignRing::_GetNoteAngle(
		unsigned char noteNo,
		short pitchBendValue,				//省略可：ピッチベンド
		unsigned char pitchBendSensitivity	//省略可：ピッチベンド感度
	)
{
	float angle = 0.0f;
	float pb = 0.0f;

	//ピッチベンドによる角度の増減
	if (pitchBendValue < 0) {
		pb = m_NoteAngleStep * pitchBendSensitivity * ((float)pitchBendValue / 8192.0f);
	}
	else {
		pb = m_NoteAngleStep * pitchBendSensitivity * ((float)pitchBendValue / 8191.0f);
	}

	//ノート番号で角度を決定
	angle = ((m_NoteAngleStep * noteNo) + (m_NoteAngleStep / 2.0f) + pb) * LH2RH(1.0f);

	//ライブモニタの場合は反転する
	if (m_isLiveMode) {
		angle = angle * (-1.0f);
	}

	return angle;
}

//******************************************************************************
// 設定ファイル読み込み
//******************************************************************************
int MTNoteDesignRing::_LoadConfFile(
		NSString* pSceneName
	)
{
	int result = 0;
	MTConfFile confFile;

	//設定ファイル読み込み
	result = MTNoteDesign::_LoadConfFile(pSceneName);
	if (result != 0) goto EXIT;

	result = confFile.Initialize(pSceneName);
	if (result != 0) goto EXIT;

	//----------------------------------
	//スケール情報
	//----------------------------------
	result = confFile.SetCurSection(@"Scale");
	if (result != 0) goto EXIT;
	result = confFile.GetFloat(@"RingRadius", &m_RingRadius, 5.0f);
	if (result != 0) goto EXIT;

EXIT:;
	return result;
}


