//******************************************************************************
//
// MIDITrail / MTPictBoardRing
//
// ピクチャボードリング描画クラス
//
// Copyright (C) 2019 WADA Masashi. All Rights Reserved.
//
//******************************************************************************

#import "YNBaseLib.h"
#import "MTParam.h"
#import "MTConfFile.h"
#import "MTPictBoardRing.h"


//******************************************************************************
// コンストラクタ
//******************************************************************************
MTPictBoardRing::MTPictBoardRing(void)
{
	m_CurTickTime = 0;
	m_isPlay = false;
	m_isEnable = true;
	m_isClipImage = false;
}

//******************************************************************************
// デストラクタ
//******************************************************************************
MTPictBoardRing::~MTPictBoardRing(void)
{
	Release();
}

//******************************************************************************
// ピクチャボード生成
//******************************************************************************
int MTPictBoardRing::Create(
		OGLDevice* pOGLDevice,
		NSString* pSceneName,
		SMSeqData* pSeqData,
		bool isReverseMode
	)
{
	int result = 0;
	SMBarList barList;
	GLsizei vertexNum = 0;
	GLsizei indexNum = 0;
	MTPICTBOARD_VERTEX* pVertex = NULL;
	unsigned int* pIndex = NULL;

	Release();

	//ノートデザインオブジェクト初期化
	result = m_NoteDesign.Initialize(pSceneName, pSeqData);
	if (result != 0) goto EXIT;

	//テクスチャ読み込み
	result = _LoadTexture(pOGLDevice, pSceneName);
	if (result != 0) goto EXIT;

	//プリミティブ初期化
	result = m_Primitive.Initialize(
					sizeof(MTPICTBOARD_VERTEX),	//頂点サイズ
					_GetFVFFormat(),			//頂点FVFフォーマット
					GL_TRIANGLE_STRIP			//プリミティブ種別
				);
	if (result != 0) goto EXIT;

	//頂点バッファ生成
	vertexNum = (SM_MAX_NOTE_NUM + 1) * 2;
	result = m_Primitive.CreateVertexBuffer(pOGLDevice, vertexNum);
	if (result != 0) goto EXIT;

	//インデックスバッファ生成
	indexNum = SM_MAX_NOTE_NUM * 3 * 2;
	result = m_Primitive.CreateIndexBuffer(pOGLDevice, indexNum);
	if (result != 0) goto EXIT;

	//バッファのロック
	result = m_Primitive.LockVertex((void**)&pVertex);
	if (result != 0) goto EXIT;
	result = m_Primitive.LockIndex(&pIndex);
	if (result != 0) goto EXIT;

	//バッファに頂点とインデックスを書き込む
	result = _CreateVertexOfBoard(
					pVertex,		//頂点バッファ書き込み位置
					pIndex,			//インデックスバッファ書き込み位置
					isReverseMode
				);
	if (result != 0) goto EXIT;

	//バッファのロック解除
	result = m_Primitive.UnlockVertex();
	if (result != 0) goto EXIT;
	result = m_Primitive.UnlockIndex();
	if (result != 0) goto EXIT;

EXIT:;
	return result;
}

//******************************************************************************
// 移動
//******************************************************************************
int MTPictBoardRing::Transform(
		OGLDevice* pD3DDevice,
		OGLVECTOR3 camVector,
		float rollAngle
	)
{
	int result = 0;
	float curPos = 0.0f;
	OGLVECTOR3 moveVector;
	OGLTransMatrix transMatrix;

	//回転
	transMatrix.RegistRotationX(rollAngle);

	//演奏位置
	curPos = m_NoteDesign.GetPlayPosX(m_CurTickTime);

	//移動
	moveVector = m_NoteDesign.GetWorldMoveVector();
	transMatrix.RegistTranslation(moveVector.x + curPos, moveVector.y, moveVector.z);

	//左手系(DirectX)=>右手系(OpenGL)の変換
	transMatrix.RegistScale(1.0f, 1.0f, LH2RH(1.0f));

	//変換行列設定
	m_Primitive.Transform(&transMatrix);

	return result;
}

//******************************************************************************
// 描画
//******************************************************************************
int MTPictBoardRing::Draw(
		OGLDevice* pOGLDevice
	)
{
	int result = 0;

	if (!m_isEnable) goto EXIT;

	//テクスチャステージ設定
	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
	//  カラー演算：引数1を使用  引数1：テクスチャ
	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
	// アルファ演算：引数1を使用  引数1：テクスチャ
	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);

	//テクスチャフィルタ
	//なし

	//描画
	result = m_Primitive.Draw(pOGLDevice, &m_Texture);
	if (result != 0) goto EXIT;

EXIT:;
	return result;
}

//******************************************************************************
// 解放
//******************************************************************************
void MTPictBoardRing::Release()
{
	m_Primitive.Release();
	m_Texture.Release();
}

//******************************************************************************
// ピクチャボード頂点生成
//******************************************************************************
int MTPictBoardRing::_CreateVertexOfBoard(
		MTPICTBOARD_VERTEX* pVertex,
		unsigned int* pIndex,
		bool isReverseMode
	)
{
	int result = 0;
	unsigned int i = 0;
	unsigned int virtexIndex = 0;
	unsigned int virtexIndexStart = 0;
	OGLVECTOR3 basePos;
	OGLVECTOR3 rotatedPos;
	float clipAreaHeight = 0.0f;
	float clipAreaWidth = 0.0f;
	float boardHeight = 0.0f;
	float boardWidth = 0.0f;
	float chStep = 0.0f;
	float angle = 0.0f;
	float direction = 0.0f;
	OGLVECTOR2 clipAreaP1;
	OGLVECTOR2 clipAreaP2;
	OGLVECTOR2 textureP1;
	OGLVECTOR2 textureP2;
	
	//テクスチャクリップ領域の座標
	if (m_isClipImage) {
		clipAreaP1 = m_ClipAreaP1; //左上
		clipAreaP2 = m_ClipAreaP2; //右下
	}
	else {
		clipAreaP1 = OGLVECTOR2(0.0f, 0.0f); //左上
		clipAreaP2 = OGLVECTOR2(m_Texture.GetWidth(), m_Texture.GetHeight()); //右下
	}
	
	//テクスチャX座標
	if (isReverseMode) {
		textureP1.x = clipAreaP1.x;
		textureP1.y = clipAreaP2.y;
		textureP2.x = clipAreaP2.x;
		textureP2.y = clipAreaP1.y;
		direction = -1.0f;
	}
	else {
		textureP1.x = clipAreaP2.x;
		textureP1.y = clipAreaP1.y;
		textureP2.x = clipAreaP1.x;
		textureP2.y = clipAreaP2.y;
		direction = 1.0f;
	}
	
	//基準座標
	chStep = m_NoteDesign.GetChStep();
	basePos = OGLVECTOR3(
				m_NoteDesign.GetPlayPosX(0),
				m_NoteDesign.GetPortOriginY(0) + (chStep * (float)SM_MAX_CH_NUM) + chStep + 0.01f,
				m_NoteDesign.GetPortOriginZ(0));
	clipAreaHeight = clipAreaP2.y - clipAreaP1.y;
	clipAreaWidth  = clipAreaP2.x - clipAreaP1.x;
	boardHeight = 2.0f * 3.1415926f * basePos.y;
	boardWidth  = boardHeight * (clipAreaWidth / clipAreaHeight);
	basePos.x -= (boardWidth * m_NoteDesign.GetPictBoardRelativePos());
	
	//頂点作成：X軸回りの円筒
	virtexIndexStart = virtexIndex;
	pVertex[virtexIndex].p = basePos;
	pVertex[virtexIndex].n = OGLVECTOR3(-1.0f, 0.0f, 0.0f);
	pVertex[virtexIndex].c = OGLCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
	pVertex[virtexIndex].t = OGLVECTOR2(textureP1.x, textureP1.y);
	virtexIndex++;
	pVertex[virtexIndex].p = basePos;
	pVertex[virtexIndex].p.x += boardWidth;
	pVertex[virtexIndex].n = OGLVECTOR3(-1.0f, 0.0f, 0.0f);
	pVertex[virtexIndex].c = OGLCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
	pVertex[virtexIndex].t = OGLVECTOR2(textureP2.x, textureP1.y);
	for (i = 1; i < SM_MAX_NOTE_NUM; i++) {
		virtexIndex++;
		
		//回転後の頂点
		angle = (360.0f / (float)SM_MAX_NOTE_NUM) * (float)i;
		rotatedPos = OGLH::RotateYZ(0.0f, 0.0f, basePos, angle);
		pVertex[virtexIndex].p = rotatedPos;
		pVertex[virtexIndex].n = OGLVECTOR3(-1.0f, 0.0f, 0.0f);
		pVertex[virtexIndex].c = OGLCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
		pVertex[virtexIndex].t = OGLVECTOR2(textureP1.x, textureP1.y + (direction * clipAreaHeight * (float)i / (float)SM_MAX_NOTE_NUM));
		virtexIndex++;
		pVertex[virtexIndex].p = rotatedPos;
		pVertex[virtexIndex].p.x += boardWidth;
		pVertex[virtexIndex].n = OGLVECTOR3(-1.0f, 0.0f, 0.0f);
		pVertex[virtexIndex].c = OGLCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
		pVertex[virtexIndex].t = OGLVECTOR2(textureP2.x, textureP1.y + (direction * clipAreaHeight * (float)i / (float)SM_MAX_NOTE_NUM));
		
		//インデックスバッファ
		//  直前の頂点0,1と追加した頂点2,3で三角形0-1-3と0-3-2を追加
		//  1+--+3-+--+--+--
		//   | /| /| /| /|  ..
		//   |/ |/ |/ |/ |  ..
		//  0+--+2-+--+--+--
		pIndex[(i-1)*6 + 0] = (i-1)*2 + 0;  //0 1つ目の三角形
		pIndex[(i-1)*6 + 1] = (i-1)*2 + 1;  //1 1つ目の三角形
		pIndex[(i-1)*6 + 2] = (i-1)*2 + 3;  //3 1つ目の三角形
		pIndex[(i-1)*6 + 3] = (i-1)*2 + 0;  //0 2つ目の三角形
		pIndex[(i-1)*6 + 4] = (i-1)*2 + 3;  //3 2つ目の三角形
		pIndex[(i-1)*6 + 5] = (i-1)*2 + 2;  //2 2つ目の三角形
	}
	//最後の頂点2,3は最初0,1の頂点と同じ（リングを閉じる）
	virtexIndex++;
	pVertex[virtexIndex] =pVertex[0];
	pVertex[virtexIndex].t = OGLVECTOR2(textureP1.x, textureP2.y);
	virtexIndex++;
	pVertex[virtexIndex] =pVertex[1];
	pVertex[virtexIndex].t = OGLVECTOR2(textureP2.x, textureP2.y);

	//インデックスバッファ（リングを閉じる）
	pIndex[(i-1)*6 + 0] = (i-1)*2 + 0;  //0 1つ目の三角形
	pIndex[(i-1)*6 + 1] = (i-1)*2 + 1;  //1 1つ目の三角形
	pIndex[(i-1)*6 + 2] = (i-1)*2 + 3;  //3 1つ目の三角形
	pIndex[(i-1)*6 + 3] = (i-1)*2 + 0;  //0 2つ目の三角形
	pIndex[(i-1)*6 + 4] = (i-1)*2 + 3;  //3 2つ目の三角形
	pIndex[(i-1)*6 + 5] = (i-1)*2 + 2;  //2 2つ目の三角形

	return result;
}

//******************************************************************************
// テクスチャ画像読み込み
//******************************************************************************
int MTPictBoardRing::_LoadTexture(
		OGLDevice* pOGLDevice,
		NSString* pSceneName
	)
{
	int result = 0;
	NSString* pImgFilePath = nil;
	NSString* pBmpFileName = nil;
	MTConfFile confFile;
	int clipImage = 0;
	
	result = confFile.Initialize(pSceneName);
	if (result != 0) goto EXIT;
	
	//ビットマップファイル名
	result = confFile.SetCurSection(@"Bitmap");
	if (result != 0) goto EXIT;
	result = confFile.GetStr(@"Board", &pBmpFileName, MT_IMGFILE_BOARD);
	if (result != 0) goto EXIT;
	
	//描画対象領域の座標
	//  Mac OS X 10.5.8 + Mac mini (GMA 950) の環境において、任意画像サイズの
	//  テクスチャ処理(GL_TEXTURE_RECTANGLE_EXT)が正常に動作しない。
	//  本来なら 2^n 以外の画像サイズも扱えるはずだが、テクスチャが崩れて描画される。
	//  画像の幅が640pixelなら崩れないという不可解な動作をするので不具合らしい。
	//  この問題を回避するため、余白を付けて描画が崩れないサイズで画像ファイルを作成する。
	//  さらに余白を描画しないように、画像全体ではなく特定の領域だけ描画する処理を追加する。
	//  ここでは領域の座標を設定ファイルから取得する。
	result = confFile.SetCurSection(@"Board");
	if (result != 0) goto EXIT;
	result = confFile.GetInt(@"ClipImage", &clipImage, 0.0f);
	if (result != 0) goto EXIT;
	if (clipImage > 0) {
		m_isClipImage = true;
	}
	result = confFile.GetFloat(@"ClipAreaX1", &(m_ClipAreaP1.x), 0.0f);
	if (result != 0) goto EXIT;
	result = confFile.GetFloat(@"ClipAreaY1", &(m_ClipAreaP1.y), 0.0f);
	if (result != 0) goto EXIT;
	result = confFile.GetFloat(@"ClipAreaX2", &(m_ClipAreaP2.x), 0.0f);
	if (result != 0) goto EXIT;
	result = confFile.GetFloat(@"ClipAreaY2", &(m_ClipAreaP2.y), 0.0f);
	if (result != 0) goto EXIT;
	
	//画像ファイルパス
	pImgFilePath = [NSString stringWithFormat:@"%@/%@",
									[YNPathUtil resourceDirPath], pBmpFileName];
	
	//任意画像サイズを有効化
	m_Texture.EnableRectanbleExt(true);
	
	//画像ファイル読み込み
	result = m_Texture.LoadImageFile(pImgFilePath);
	if (result != 0) goto EXIT;
	
EXIT:;
	return result;
}

//******************************************************************************
// チックタイム設定
//******************************************************************************
void MTPictBoardRing::SetCurTickTime(
		unsigned int curTickTime
	)
{
	m_CurTickTime = curTickTime;
}

//******************************************************************************
// リセット
//******************************************************************************
void MTPictBoardRing::Reset()
{
	m_CurTickTime = 0;
}

//******************************************************************************
// 演奏開始
//******************************************************************************
void MTPictBoardRing::OnPlayStart()
{
	m_isPlay = true;
}

//******************************************************************************
// 演奏終了
//******************************************************************************
void MTPictBoardRing::OnPlayEnd()
{
	m_isPlay = false;
}

//******************************************************************************
// 表示設定
//******************************************************************************
void MTPictBoardRing::SetEnable(
		bool isEnable
	)
{
	m_isEnable = isEnable;
}


