/***************************************************************/
//
//
//		DirectX	[ meshfield.cpp ]
//
//											Author	kazuki tanaka
//											Date	2017 5/25
/*---------------------------------------------------------------
■Update : 2017/5/25
			meshfield.cppの作成

/*---------------------------------------------------------------
	Include File
---------------------------------------------------------------*/

#include "meshfield.h"

#include "mesh_rendererex.h"

#include "vertexbuffer_manager.h"
#include "texture_manager.h"

#include "indexbufferdx9.h"

#include "texturedx9_interface.h"
#include "castdx9.h"

#include "d_console.h"

/*---------------------------------------------------------------
	Macro Difinition
---------------------------------------------------------------*/


/*---------------------------------------------------------------
	Const Number Difinition
---------------------------------------------------------------*/


/*----------------------------------------------------------------
	static member variable Initialize 
----------------------------------------------------------------*/





// MeshField Constructor
MeshField::MeshField( )
	: pRenderer(nullptr)
	, pVtxBuf(nullptr)
	, pIdxBuf(nullptr)
	, pTexture(nullptr)
	, vertical(0)
	, horizonal(0)
	, size(0)
	, pos( Vector3(0,0,0) )
	, world( Matrix( ))
	, state(nullptr)
{

	// Menber Clear Process

}

// MeshField Destructor
MeshField::~MeshField( )
{

	// Do Nothing!!

}

// MeshField Create Instance 
MeshField* MeshField::Create( void )
{

	// Create Class Instance
	return new MeshField;

}

// MeshField Initialize
void MeshField::Init( void )
{

	// Initialize Process
	float** height = nullptr;

	vertical  = 10;
	horizonal = 10;
	size      = 10;

	world.Identity( ); 

	pVtxBuf = VertexBufferManager::PlatformSelect( );
	pIdxBuf = IndexBufferDX9::Create( );

	if( !pVtxBuf->CreateVertexBuffer( FVF_VERTEX_3D, (vertical+1)*(horizonal+1) ) ) return;
	if( !pIdxBuf->CreateIndexBuffer( ((2 + 2 * vertical)*horizonal + ( horizonal - 1 )*2) ) ) return;
	pTexture = TextureManager::LoadFromManager( "data\\texture\\field.jpg" );

	// Set Buffer < Vertex & Index >
	SetBuffer( );

	// Component Set
	pRenderer = MeshRendererEX::SetComponent( &pVtxBuf, &pIdxBuf, &pTexture, &world );


}

// MeshField Uninitialize
void MeshField::Uninit( void )
{

	// Uninitialize Process
	SAFE_DELETE_ARRAY( state )
	pVtxBuf->Release( );
	pIdxBuf->Release( );
	pTexture->Release( );

}

// MeshField Update
void MeshField::Update( void )
{
	
	// Update Process
	static float angle = 0;

	world.Identity( );
	
	Vector3 rot( 0, angle, 0 );

	//world.Rotate( rot );

	//angle += 0.1f/30;

}

// MeshField Draw
void MeshField::Draw( void )
{

	// Draw Process
	pRenderer->Render( );


}

// MeshField SetBuffer
void MeshField::SetBuffer( void )
{

	// Vertual Pointer
	Vertex3D*       pVtx;
	unsigned short* pIndex;
	Vector3 start = Vector3( -vertical*size*0.5f, 0, horizonal*size*0.5f );

	float height[11 * 11]={
		0, 1, 0, 2, 0, 1, 0, 12, 0, 12, 10,
		0, 21, 0, 2, 0, 3, 0, 21, 0, 11, 20,
		0, 21, 10, 2, 0, 3, 0, 21, 0, 12, 10,
		0, 1, 10, 2, 25, 10, 15, 12, 10, 1, 0,
		0, 1, 10, 2, 25, 30, 25, 12, 10, 1, 0,
		0, 1, 0, 12, 25, 20, 25, 12, 20, 1, 0,
		0, 1, 0, 2, 0, 3, 0, 1, 10, 11, 0,
		0, 1, 0, 2, 0, 3, 0, 1, 10, 21, 0,
		0, 21, 0, 2, 0, 3, 0, 1, 10, 21, 0,
		0, 21, 0, 2, 0, 3, 0, 1, 0, 11, 0,
	};

	state = new Vector3[(horizonal+1) * (vertical+1)];

	{ // 頂点バッファの設定

		pVtxBuf->Lock( &pVtx );

		for( int y = 0,x = 0; y < horizonal+1; y++ ){

			for( x = 0; x < vertical+1; x++ ){
		
				pVtx[ ((vertical+1))*y + (x) + 0 ].pos   = Vector3 ( start.x + ( size * x ), height[ ((vertical+1))*y + (x) ], start.z - ( size * y) );
				state[ ((vertical+1))*y + (x) ] = pVtx[ ((vertical+1))*y + (x) ].pos;
												  
				pVtx[ ((vertical+1))*y + (x) + 0 ].tex   = Vector2( (1.0f * x), (1.0f * y) );
												  
				pVtx[ ((vertical+1))*y + (x) + 0 ].color = Color( 1, 1, 1, 1 );												  
			}
		}

		// 法線の設定
		Vector3 dirX, dirZ,norX,norZ,nor;
		for( int y = 0,x = 0; y < horizonal+1; y++ ){

			for( x = 0; x < vertical+1; x++ ){


				dirX = pVtx[ ((vertical+1))*y + (x) + 1 ].pos - pVtx[ ((vertical+1))*y + (x) - 1 ].pos;
				if( x == 0 ){
					dirX = pVtx[ ((vertical+1))*y + (x) + 1 ].pos - pVtx[ ((vertical+1))*y + (x) ].pos;
				}else if( x == (vertical) ){
					dirX = pVtx[ ((vertical+1))*y + (x) ].pos - pVtx[ ((vertical+1))*y + (x) - 1 ].pos;
				}
				dirZ = pVtx[ ((vertical+1))*y + (x) - (vertical+1) ].pos - pVtx[ ((vertical+1))*y + (x) + (vertical+1) ].pos;
				if( y == 0 ){
					dirZ = pVtx[ ((vertical+1))*y + (x) ].pos - pVtx[ ((vertical+1))*y + (x) + (vertical+1) ].pos;
				}else if( y == (horizonal) ){
					dirZ =  pVtx[ ((vertical+1))*y + (x) - (vertical+1) ].pos - pVtx[ ((vertical+1))*y + (x) ].pos;
				}

				norX = Vector3( -dirX.y, dirX.x, 0.0f );
				norZ = Vector3( 0.0f, dirZ.z, -dirZ.y );

				nor = norX + norZ;
				nor = nor.Normalize( );

				pVtx[ ((vertical+1))*y + (x) ].nor = nor;
			}
		}

		pVtxBuf->Unlock( );

	} // -> END


	{ // 頂点インデックスの設定

		pIdxBuf->Lock( &pIndex );

		for( int y = 0,x = 0,alignNumber = 0,index = 0; y < horizonal; y++ ){

			// 縮退ポリゴンの作成
			if( y ){
			
				x = 0;
				pIndex[ ((vertical+1)*2)*y + (2*x) + 0 + alignNumber*2 ] = index - 1;
				pIndex[ ((vertical+1)*2)*y + (2*x) + 1 + alignNumber*2 ] = index + (vertical+1);
				alignNumber++;
			}
			for( x = 0; x < vertical+1; x++ ){

				pIndex[ ((vertical+1)*2)*y + (2*x) + 0 + alignNumber*2 ] = index + (vertical+1);
				pIndex[ ((vertical+1)*2)*y + (2*x) + 1 + alignNumber*2 ] = index;
				index++;
			}
		}

		pIdxBuf->Unlock( );

	} // -> END

}

// MeshField Resize
void MeshField::Resize( const int size, const int vertical, const int horizonal )
{

	// Reset Member Variable
	MeshField::size = size;
	MeshField::vertical  = vertical;
	MeshField::horizonal = horizonal;

	// MeshField SetBuffer
	SetBuffer( );

}

// MeshField GetHeight
float MeshField::GetHeight( Vector3 pos )
{


	// MeshField GetHeight
	for( int z = 0,x = 0; z < horizonal+1; z++ ){

		for( x = 0; x < vertical+1; x++ ){

			Vector3 p0, p1, p2, p3;
			p0 = state[ ((vertical+1))*z + (x) ];
			p1 = state[ ((vertical+1))*z + (x) + 1 ];
			p2 = state[ ((vertical+1))*z + (x) + vertical+1 ];
			p3 = state[ ((vertical+1))*z + (x) + vertical+2 ];


			Vector3 v0p, v0, v1, v2, vc0, vc1, vc2, vc3, vn, v;

			if( NormalCheck( pos, p0, p1, p2 ) ){
			
				/*
				v0 = p1 - p0; 
				v  = p2 - p0;
				vn = v0.Cross( v );
				vn = vn.Normalize();
				CDebugFont::Access()->SetRenderData( R_RENDER," nor[↑] : %f %f %f \n", vn.x, vn.y, vn.z );
				pos.y = p0.y - ((pos.x-p0.x)*vn.x + ( pos.z-p0.z )*vn.z)/vn.y;
				return pos.y;*/
				return SlopeHeight( pos, p0, p1, p2 );
			}

			if( NormalCheck( pos, p2, p1, p3 ) ){
				v  = p1 - p2;
				v2 = p3 - p2;
				vn = v.Cross( v2 );
				vn = vn.Normalize();
				pos.y = p3.y - ((pos.x-p3.x)*vn.x + ( pos.z-p3.z )*vn.z)/vn.y;
				CDebugFont::Access()->SetRenderData( R_RENDER," nor[↓] : %f %f %f \n", vn.x, vn.y, vn.z );
				return pos.y;
			}

		}
	}

	return pos.y;

}

// MeshField GetSlope
float MeshField::GetSlope( Vector3 pos )
{


	// MeshField GetHeight
	for( int z = 0,x = 0; z < horizonal+1; z++ ){

		for( x = 0; x < vertical+1; x++ ){

			Vector3 p0, p1, p2, p3;
			p0 = state[ ((vertical+1))*z + (x) ];
			p1 = state[ ((vertical+1))*z + (x) + 1 ];
			p2 = state[ ((vertical+1))*z + (x) + vertical+1 ];
			p3 = state[ ((vertical+1))*z + (x) + vertical+2 ];

			Vector3 v0p, v0, v1, v2, vc0, vc1, vc2, vc3, vn, v;

			if( NormalCheck( pos, p0, p1, p2 ) ){
			
				return SlopeHeight( pos, p0, p1, p2 );
			}

			if( NormalCheck( pos, p2, p1, p3 ) ){

				return SlopeHeight( pos, p3, p2, p1 );
			}

		}
	}

	return pos.y;

	
}

// MeshField Normal Check
bool MeshField::NormalCheck( Vector3& pos, Vector3& p0, Vector3& p1, Vector3& p2 )
{


	Vector3 v0p, v0, v1, v2, vc0, vc1, vc2, vc3, vn, v;

	v0  = p1  - p0;
	v0p = pos - p0;

	vc0 = v0.Cross( v0p );
	if( vc0.y < 0.0f ) return false;
			
	v1  = p2  - p1;
	v0p = pos - p1;

	vc1 = v1.Cross( v0p );
	if( vc1.y < 0.0f ) return false;
				
	v2  = p0  - p2;
	v0p = pos - p2;

	vc2 = v2.Cross( v0p );
	if( vc2.y < 0.0f ) return false;


	return true;


}

// MeshField 
float MeshField::SlopeHeight( Vector3& pos, Vector3& p0, Vector3& p1, Vector3& p2 )
{

	Vector3 v0, v1, vn;

	v0  = p1 - p0;
	v1  = p2 - p0;
	vn = v0.Cross( v1 );
	vn = vn.Normalize();
	pos.y = p0.y - ((pos.x-p0.x)*vn.x + ( pos.z-p0.z )*vn.z)/vn.y;
	CDebugFont::Access()->SetRenderData( R_RENDER," nor[↑] : %f %f %f \n", vn.x, vn.y, vn.z );
	return pos.y;

}




