/***************************************************************/
//
//
//		DirectX	[particle.cpp]
//
//										Author	kazuki tanaka
//										Date	2016 11/28
/*---------------------------------------------------------------
■Update : 2016/11/28
			particle.cppの作成
			func : InitParticleの追加
			func : UninitParticleの追加
			func : UpdateParticleの追加
			func : DrawParticleの追加
			func : MakeVertexParticleの追加
			func : SetVertexParticleCoordの追加
			func : SetVertexParticleColorの追加
			func : SetVertexParticleSpriteUVの追加
			func : SetVertexParticleNormalの追加
			func : SetParticleの追加

			Update : UpdateParticle 
						-> Zソートの追加

■Update : 2016/11/28


/*---------------------------------------------------------------
	ヘッダーファイル
---------------------------------------------------------------*/

#define _CRT_SECURE_NO_WARNINGS_
#include <Windows.h>
#include <stdio.h>
#include <time.h>
#include "main.h"
#include "particle.h"

#include "photo.h"
#include "camera.h"

/*---------------------------------------------------------------
	マクロ定義
---------------------------------------------------------------*/

#define NUM_VERTEX (4)										// 頂点数
#define NUM_INDEX  (6)										// 頂点インデックス数

#define NUM_POLYGON (2)										// ポリゴン数

#define NUM_PARTICLE (4096)									// 粒子最大数
#define NUM_TEXTURE  ( 13 )

#define PARTICLE_RADIUS (5)									// 粒子半径

/*---------------------------------------------------------------
	プロトタイプ宣言
---------------------------------------------------------------*/

HRESULT MakeVertexParticle( LPDIRECT3DDEVICE9 pDevice );	// 頂点の作成

void SetVertexParticleCoord(								// 頂点座標の設定
	VERTEX_3D *pVtx,
	const int index );
void SetVertexParticleColor(								// 頂点色の設定
	VERTEX_3D *pVtx,
	const int index );
void SetVertexParticleSpriteUV(								// 頂点UV値の設定
	VERTEX_3D *pVtx,
	const int index  );
void SetVertexParticleNormal(								// 頂点法線設定 
	VERTEX_3D* pVtx,
	const int index );

												
/*----------------------------------------------------------------
	スタティックメンバ変数宣言
----------------------------------------------------------------*/

int PARTICLE::PARTICLE_MAX = NUM_PARTICLE;						// パーティクル最大数
int PARTICLE::LOAD_TEXTURE  = 0;

/*----------------------------------------------------------------
	グローバル変数
----------------------------------------------------------------*/

LPDIRECT3DTEXTURE9      g_pTextureParticle[256];				// テクスチャ-インターフェ-ス用
LPDIRECT3DVERTEXBUFFER9 g_pVtxBufferParticle    = nullptr;		// 頂点バッファインターフェースへのポインタ

PARTICLE                particle[ NUM_PARTICLE ] = {};

bool addCalcFlag = true;
bool subCalcFlag = false;
bool rotationFlag = false;

//　ファイルネーム定数

char* TEXTURE_NAME[ NUM_TEXTURE ] = {

	"data\\TEXTURE\\effect000.jpg",
	"data\\TEXTURE\\effect001.jpg",
	"data\\TEXTURE\\effect002.jpg",
	"data\\TEXTURE\\effect003.jpg",
	"data\\TEXTURE\\effect004.jpg",
	"data\\TEXTURE\\effect005.jpg",
	"data\\TEXTURE\\effect006.jpg",
	"data\\TEXTURE\\effect007.jpg",
	"data\\TEXTURE\\effect008.jpg",
	"data\\TEXTURE\\effect009.jpg",
	"data\\TEXTURE\\effect010.jpg",
	"data\\TEXTURE\\effect011.jpg",
	"data\\TEXTURE\\effect012.jpg",
};





// PARTICLEの初期化
void InitParticle( void )
{

	// デバイス受け取り用関数
	LPDIRECT3DDEVICE9 pDevice = GetDevice( );


	// ランダムの初期化
	srand( ( unsigned int ) time( NULL ) );

	// パーティクルステータスの初期化
	for( int index = 0; index < PARTICLE::PARTICLE_MAX ; index++ ){

		particle[ index ].center   = D3DXVECTOR3( 10.0f, 10.0f, 100.0f );
		particle[ index ].speed    = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
		particle[ index ].velocity = D3DXVECTOR3( 1.0f, 1.0f, 1.0f );
		particle[ index ].scale    = D3DXVECTOR3( 1.0f, 1.0f, 1.0f );

		particle[ index ].life     = 0; 
		particle[ index ].age      = 0;
		particle[ index ].radius   = PARTICLE_RADIUS;
		particle[ index ].color    = D3DXCOLOR( 0.5f, 0.2f, 0.8f, 1.0f ); 

		particle[ index ].ambientPower = D3DXVECTOR3( 0, 0 ,0 );
		particle[ index ].texIndex = 0;				// TEXTUREデフォルト設定

	} // -> INTIALIZE PARTICLE


	// 頂点バッファの作成
	MakeVertexParticle( pDevice );

	// テクスチャの読み込み 
	for( int index = 0; index < NUM_TEXTURE; index++ ){
		HRESULT hres = D3DXCreateTextureFromFile( pDevice, TEXTURE_NAME[index], &g_pTextureParticle[index] );
		if( FAILED( hres )){
			#ifdef _DEBUG
			MessageBox( NULL, "テクスチャファイルの読み込みに失敗しました!" , "TEXTURE LOAD ERROR!!", MB_OK | MB_ICONWARNING );
			#endif	// _DEBUG
		}else{
			PARTICLE::LOAD_TEXTURE++;
		}
	}
	


}

// PARTICLEの終了処理
void UninitParticle( void )
{

	// PARTICLE_TEXTUREの解放
	for( int index = 0; index < PARTICLE::LOAD_TEXTURE; index++ ){
		SAFE_RELEASE( g_pTextureParticle[index] )
	}
	PARTICLE::LOAD_TEXTURE = 0;

	// PARTICLE_VTXBUFFERの解放
	SAFE_RELEASE( g_pVtxBufferParticle )

}

// PARTICLEの更新
void UpdateParticle( void )
{

	VERTEX_3D* pVtx;

	// バッファをロックし仮想アドレスを取得する
	g_pVtxBufferParticle -> Lock(0,0,(void**)&pVtx,0 );


	// パーティクルの更新
	for( int index = 0; index < PARTICLE::PARTICLE_MAX; index++ ){

		if( particle[ index ].life ){


			{ // パーティクルパラメーターの更新

				// パーティクル存在フレームの更新
				particle[ index ].life -= 1 ;
				particle[ index ].age  += 1;

				// 色の設定
				particle[ index ].color.r -= particle[ index ].amountOfChangeInColor.r;
				particle[ index ].color.g -= particle[ index ].amountOfChangeInColor.g;
				particle[ index ].color.b -= particle[ index ].amountOfChangeInColor.b;
				particle[ index ].color.a -= particle[ index ].amountOfChangeInColor.a;
				if( particle[ index ].color.a < 0.0f ){
					particle[ index ].color.a = 0.0f;
				}

				// 加速度の加算
				particle[ index ].speed.x *= particle[ index ].velocity.x;
				particle[ index ].speed.y *= particle[ index ].velocity.y;
				particle[ index ].speed.z *= particle[ index ].velocity.z;

				// パーティクルの移動
				particle[ index ].center.x += particle[ index ].speed.x*sinf( particle[index].theta )*cosf( particle[index].phy );
				particle[ index ].center.y += particle[ index ].speed.y*cosf( particle[index].theta );
				particle[ index ].center.z += particle[ index ].speed.z*sinf( particle[index].theta )*sinf( particle[index].phy );

				// 環境力によるベクトル変換
				/*if( particle[ index ].age > 10 ){
					particle[ index ].center += particle[ index ].ambientPower;
				}*/

				// エフェクトの設置
				SetVertexParticleColor( pVtx, index );
				SetVertexParticleCoord( pVtx, index );

			} // -> END ( PARTICLE UPDATE )
		}	// if( particle[ index ].life ) -> END
	}	// for -> END



	// バッファのアンロック
	g_pVtxBufferParticle->Unlock();


}

// PARTICLEの描画
void DrawParticle( void )
{


	// デバイスの受け取り
	LPDIRECT3DDEVICE9 pDevice = GetDevice( );

	// 座標変換ワールド行列
	D3DXMATRIX mtxWorld;
	D3DXMATRIX mtxTranslation;
	D3DXMATRIX mtxRotarion;
	//DXMATRIX mtxScale;

	// ライト無効処理
	pDevice ->SetRenderState( D3DRS_LIGHTING, false );

	// 加算合成の設定
	if( addCalcFlag ){
		pDevice->SetRenderState( D3DRS_BLENDOP, D3DBLENDOP_ADD );		
		pDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );	
		pDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
	}

	if( subCalcFlag ){
		pDevice ->SetRenderState( D3DRS_BLENDOP, D3DBLENDOP_REVSUBTRACT );
		pDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );	
		pDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
	}

	pDevice ->SetRenderState( D3DRS_ZWRITEENABLE, false );

	// ストリーム
	pDevice->SetStreamSource(0,					
		g_pVtxBufferParticle,								
		0,													
		sizeof( VERTEX_3D ));						

	// 頂点フォーマットの設定
	pDevice->SetFVF( FVF_VERTEX_3D );


	// パーティクルの描画
	for( int index = 0; index < PARTICLE::PARTICLE_MAX; index++ ){

		if( particle[ index ].life ){

			// 単位行列への初期化( 行列を単位行列にする )
			D3DXMatrixIdentity( &mtxWorld );

			D3DXMatrixTranslation( &mtxTranslation, particle[index].center.x, particle[index].center.y, particle[index].center.z );

			mtxWorld = CPhoto::GetMtxView( ) * mtxTranslation;

			// デバイスにワールド変換行列を設定
			pDevice ->SetTransform( D3DTS_WORLD, &mtxWorld );

			// テクスチャの設定
			pDevice->SetTexture( 0, g_pTextureParticle[particle[index].texIndex] );
		
			// 描画処理
			pDevice ->DrawPrimitive( D3DPT_TRIANGLESTRIP, NUM_VERTEX*index, NUM_POLYGON );
		
		}
	}

	// 元の状態に戻す
	pDevice ->SetRenderState( D3DRS_ZWRITEENABLE, true );

	//pDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
	pDevice->SetRenderState( D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA );

	if( subCalcFlag ){
		pDevice->SetRenderState( D3DRS_BLENDOP, D3DBLENDOP_ADD );		
	}
	pDevice ->SetRenderState( D3DRS_LIGHTING, true );

}

// 頂点の作成
HRESULT MakeVertexParticle( LPDIRECT3DDEVICE9 pDevice )
{


	VERTEX_3D *pVtx;												// 仮想アドレス

	if(FAILED(pDevice->CreateVertexBuffer(
		sizeof(VERTEX_3D) * NUM_VERTEX * PARTICLE::PARTICLE_MAX,	// 確保するバッファサイズ(頂点数分確保) 単位:バイト
			D3DUSAGE_WRITEONLY,										// 使用方法
			FVF_VERTEX_3D,											// 使用する頂点フォーマット(特殊な処理をしない限り参照されないので0でよい)
			D3DPOOL_MANAGED,										// バッファの管理方法(バッファの中に書き込んだものの管理方法)
			&g_pVtxBufferParticle,									// 格納するポインタ先
			NULL)))
	{
		#ifdef _DEBUG
		MessageBox(NULL,"バッファへの書き込みに失敗しました!!","vertex buffer ERROR!!",MB_OK);
		#endif	// _DEBUG
		return E_FAIL;
	}


	// バッファをロックし仮想アドレスを取得する
	g_pVtxBufferParticle -> Lock(0,0,(void**)&pVtx,0);				// GPUからのVRAMへの操作をロックする


	// 頂点バッファーの設定
	for( int index = 0; index < PARTICLE::PARTICLE_MAX; index++ ){

		// 頂点座標の設定
		SetVertexParticleCoord( pVtx , index );

		// 頂点色の設定
		SetVertexParticleColor( pVtx , index );

		// 頂点UV値の設定
		SetVertexParticleSpriteUV( pVtx , index );

		// 法線情報の設定
		SetVertexParticleNormal( pVtx, index );


	} // ->VTX SETTING END

	// バッファのアンロック
	g_pVtxBufferParticle->Unlock( );

	return S_OK;

}

// パーティクル座標設置
void SetVertexParticleCoord( VERTEX_3D *pVtx , const int index )
{


	// pVtx     >> 仮想アドレス
	// arryycenter >> どの番目のエフェクトか...


	D3DXVECTOR2 start,end;			//始点と終点


	// 座標計算particle
	start.x = -particle[ index ].radius;
	start.y = +particle[ index ].radius;
	end.x   = +particle[ index ].radius;
	end.y   = -particle[ index ].radius;


	// 頂点座標の設定
	pVtx[ 0 + (index * NUM_VERTEX) ].pos = D3DXVECTOR3( start.x, start.y, 0.0f);
	pVtx[ 1 + (index * NUM_VERTEX) ].pos = D3DXVECTOR3( end.x,   start.y, 0.0f);
	pVtx[ 2 + (index * NUM_VERTEX) ].pos = D3DXVECTOR3( start.x, end.y,   0.0f);
	pVtx[ 3 + (index * NUM_VERTEX) ].pos = D3DXVECTOR3( end.x,   end.y,   0.0f);


}

// パーティクル色変更関数
void SetVertexParticleColor( VERTEX_3D *pVtx , const int index )
{
	
	// αの変更
	pVtx[ 0 + (index * NUM_VERTEX) ].color = particle[ index ].color;
	pVtx[ 1 + (index * NUM_VERTEX) ].color = particle[ index ].color;
	pVtx[ 2 + (index * NUM_VERTEX) ].color = particle[ index ].color;
	pVtx[ 3 + (index * NUM_VERTEX) ].color = particle[ index ].color;
	

}

// パーティクルUV値のセット
void SetVertexParticleSpriteUV( VERTEX_3D *pVtx , const int index  )
{

	pVtx[ 0 + (index * NUM_VERTEX) ].tex = D3DXVECTOR2( 0.0f, 0.0f );
	pVtx[ 1 + (index * NUM_VERTEX) ].tex = D3DXVECTOR2( 1.0f, 0.0f );
	pVtx[ 2 + (index * NUM_VERTEX) ].tex = D3DXVECTOR2( 0.0f, 1.0f );
	pVtx[ 3 + (index * NUM_VERTEX) ].tex = D3DXVECTOR2( 1.0f, 1.0f );

}

// パーティクルの法線設定
void SetVertexParticleNormal( VERTEX_3D* pVtx, const int index )
{

	pVtx[0 + NUM_VERTEX*index ].normal = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
	pVtx[1 + NUM_VERTEX*index ].normal = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
	pVtx[2 + NUM_VERTEX*index ].normal = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
	pVtx[3 + NUM_VERTEX*index ].normal = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );

}

// パーティクルの設置
void SetParticle( const LPD3DXVECTOR3 center, const LPD3DXVECTOR3 velocity, const LPD3DXCOLOR color, const float radius, const unsigned int life )
{

	// 粒子の設置
	for( int index = 0; index < PARTICLE::PARTICLE_MAX; index++ ){

		if( !particle[ index ].life ){
			

			{ // パーティクルパラメーターの設定


				// パーティクル中心座標
				particle[ index ].center   = *center;

				// パーティクルの速度
				//particle[ index ].speed    = D3DXVECTOR3( ((rand()%100)-50)*0.01f, ((rand()%100)-50)*0.01f, ((rand()%100)-50)*0.01f ); 
				particle[ index ].speed    = *velocity;

				// パーティクルの加速度
				particle[ index ].velocity = *velocity;

				// パーティクル放出角度設定
				particle[ index ].theta   = ((( rand( )%628 ) + 157 ) - 314 ) * 0.01f;
				particle[ index ].phy     = ((( rand( )%628 ) + 314 ) - 314 + 157 ) * 0.01f;

				// パーティクル色の設定
				particle[ index ].color    = *color;

				// パーティクル半径
				particle[ index ].radius   =  radius;

				// パーティクルの存在フレーム数
				particle[ index ].life     =  life;				

				// パーティクル変化量定数
				particle[ index ].amountOfChangeInColor.a  = particle[ index ].color.a / particle[ index ].life;
				particle[ index ].amountOfChangeInColor.a  *= 0.1f;
				particle[ index ].amountOfChangeInColor.r  = particle[ index ].color.r / particle[ index ].life;
				particle[ index ].amountOfChangeInColor.g  = particle[ index ].color.g / particle[ index ].life;
				particle[ index ].amountOfChangeInColor.b  = particle[ index ].color.b / particle[ index ].life;
				particle[ index ].amountOfChangeInRadius   = particle[ index ].radius / particle[ index ].life;
			
			} // -> END ( PARTICLE SET )

			break;
		}
	}

}

// パーティクルの設置
void SetParticleEx( const LPD3DXVECTOR3 center, const LPD3DXVECTOR3 speed, const LPD3DXVECTOR3 velocity, const LPD3DXCOLOR color, const float radius, const int theta, const int theta_offset, const int phy, const int phy_offset, const unsigned int life, const int texIndex )
{

	// 粒子の設置
	for( int index = 0; index < PARTICLE::PARTICLE_MAX; index++ ){

		if( !particle[ index ].life ){
			

			{ // パーティクルパラメーターの設定


				// パーティクル中心座標
				particle[ index ].center   = *center;

				// パーティクルの速度
				//particle[ index ].speed    = D3DXVECTOR3( ((rand()%100)-50)*0.01f, ((rand()%100)-50)*0.01f, ((rand()%100)-50)*0.01f ); 
				particle[ index ].speed    = *speed;

				// パーティクルの加速度
				particle[ index ].velocity = *velocity;

				// パーティクル放出角度設定
				particle[ index ].theta   = ((( rand( )%theta ) + theta_offset + 157 ) - 314 )       * 0.01f;
				particle[ index ].phy     = ((( rand( )%phy )   + phy_offset + 314 )   - 314 + 157 ) * 0.01f;

				// パーティクル色の設定
				particle[ index ].color    = *color;

				// パーティクル半径
				particle[ index ].radius   =  radius;

				// パーティクルの存在フレーム数
				particle[ index ].life     =  life;		

				// パーティクルテクスチャのインデックス
				particle[ index ].texIndex = texIndex;

				// パーティクル変化量定数
				particle[ index ].amountOfChangeInColor.a  = particle[ index ].color.a / particle[ index ].life;
				particle[ index ].amountOfChangeInColor.a  *= 0.1f;
				particle[ index ].amountOfChangeInColor.r  = particle[ index ].color.r / particle[ index ].life;
				particle[ index ].amountOfChangeInColor.g  = particle[ index ].color.g / particle[ index ].life;
				particle[ index ].amountOfChangeInColor.b  = particle[ index ].color.b / particle[ index ].life;
				particle[ index ].amountOfChangeInRadius   = particle[ index ].radius / particle[ index ].life;
			
			} // -> END ( PARTICLE SET )

			break;
		}
	}


}

// パーティクルテクスチャの取得
char** GetTextureParticle( void )
{

	return TEXTURE_NAME;

}

// テクスチャの読み込み
void TextureLoad( const LPTSTR TEXTURE_FILE_NAME )
{

	// デバイス受け取り用関数
	LPDIRECT3DDEVICE9 pDevice = GetDevice( );

	HRESULT hres = D3DXCreateTextureFromFile( pDevice, TEXTURE_FILE_NAME, &g_pTextureParticle[PARTICLE::LOAD_TEXTURE] );
	if( FAILED( hres )){
		#ifdef _DEBUG
		MessageBox( NULL, "テクスチャファイルの読み込みに失敗しました!" , "TEXTURE LOAD ERROR!!", MB_OK | MB_ICONWARNING );
		#endif	// _DEBUG
	}else{

		char filename[255] = { };		// ファイルネーム
		char extension[255] ={ };		// 拡張子
	
		// パスの切り出し
		_splitpath( TEXTURE_FILE_NAME, NULL, NULL, filename, extension );
		
		// ファイルネームの書き出し
		sprintf(  TEXTURE_FILE_NAME, "%s%s", filename , extension );

		sprintf( &TEXTURE_NAME[PARTICLE::LOAD_TEXTURE][0], "%s", TEXTURE_FILE_NAME );
		
		//MessageBox( NULL, *buf, "TEXTURE LOAD ERROR!!", MB_OK | MB_ICONWARNING );
		PARTICLE::LOAD_TEXTURE++;
	}

}

// 加算フラグの取得
void SetAddCalcRender( const bool flag )
{
	addCalcFlag = flag;
}

// 減算フラグの取得
void SetSubCalcRender( const bool flag )
{
	subCalcFlag = flag;
}

// 爆発型パーティクル
void EmitExplosion( D3DXVECTOR3 center, const float radius, D3DXVECTOR3 speed, const D3DXVECTOR3 velocity, const D3DXCOLOR color, const D3DXCOLOR colorValue, const int life, const int scale )
{


	//srand( ( unsigned int ) time( NULL ) );

	// エフェクトの設置
	for ( int index = 0; index < NUM_PARTICLE; index++ ) {

		if ( !particle[index].life ) {


			{ // パーティクルパラメーターの設定

				// パーティクルの存在フレーム数
				particle[index].life = life;

				// パーティクル中心座標
				float angle  = ((rand() % 628) - 314) * 0.01f;
				float phy    = ((rand() % 628) - 314) * 0.01f;
				float length = ( float )( rand( )%scale );

				center.x = center.x + scale * sinf( angle )*cosf( phy ); 
				center.y = center.y + scale * cosf( angle );
				center.z = center.z + scale * sinf( angle )*sinf( phy );

				particle[index].center = center;

				// パーティクルの速度
				speed += D3DXVECTOR3(1.0f + (((rand() % 200) - 100) * 0.001f), 1.0f + (((rand() % 200) - 100) * 0.001f), 1.0f + (((rand() % 200) - 100) * 0.001f) );


				particle[index].speed  = speed;

				// パーティクルの加速度
				particle[index].velocity = velocity;

				// パーティクル移動方向の設定
				particle[index].theta = ( (rand( ) % 628 ) - 314) * 0.01f;
				particle[index].phy   = ( (rand( ) % 628 ) - 314) * 0.01f;

				// パーティクル色
				particle[index].color = color;

				// パーティクル半径
				particle[index].radius = radius;

				// パーティクル変化量定数
				particle[index].amountOfChangeInColor.a = particle[ index ].color.a / particle[index].life;
				particle[index].amountOfChangeInRadius = (particle[ index ].radius - 10) / particle[index].life;

				// 環境力の追加
				//particle[ index ].ambientPower = D3DXVECTOR2( 1.7f, 0.5f );
			
				// 存在フレームの初期化
				particle[ index ].age  = 0;


			} // -> END ( PARTICLE SET )

			break;

		}
	}


}





