/***************************************************************************/
/** @file       board.cpp
    @brief      drawing the board-polygon
    @author     shom
****************************************************************************/

#include "pch_core.h"

#include "board.h"

#ifdef DX
#include "core/graphic/render_dx.h"
#endif


using namespace board_def;


namespace
{
#ifdef DX
	enum{ MY_FVF_BOARD = D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1 };
#endif

	const board_vertex_t sc_vertex_original_tbl[4] =
	{
		//{ x,	  y,	  z,	rhw,  color,	   u,	 v },
		{ 100.0f, 0.0f,   0.0f, 1.0f, COLOR_WHITE, 1.0f, 0.0f },	//右下
		{ 100.0f, 100.0f, 0.0f, 1.0f, COLOR_WHITE, 1.0f, 1.0f },	//右上
#ifdef DX
		{ 0.0f,   0.0f,	  0.0f, 1.0f, COLOR_WHITE, 0.0f, 0.0f },	//左下
		{ 0.0f,	  100.0f, 0.0f, 1.0f, COLOR_WHITE, 0.0f, 1.0f },	//左上
#else	//if GL
		{ 0.0f,   100.0f, 0.0f, 1.0f, COLOR_WHITE, 0.0f, 1.0f },	//左下
		{ 0.0f,	  0.0f,   0.0f, 1.0f, COLOR_WHITE, 0.0f, 0.0f },	//左上
#endif
	};
	const b32 sc_uv_tbl[ 2 ][4][ 2/*u,v*/ ] =
	{
#ifdef DX
		{ { TRUE,  FALSE }, { TRUE,  TRUE  }, { FALSE, FALSE }, { FALSE, TRUE  }, },	//FALSE
		{ { FALSE, FALSE }, { FALSE, TRUE  }, { TRUE,  FALSE }, { TRUE,  TRUE  }, },	//TRUE
#else	//if GL
		{ { TRUE,  FALSE }, { TRUE,  TRUE  }, { FALSE, TRUE  }, { FALSE, FALSE }, },	//FALSE
		{ { FALSE, FALSE }, { FALSE, TRUE  }, { TRUE,  TRUE  }, { TRUE,  FALSE }, },	//TRUE
#endif
	};
}


/***************************************************************************
	cboard
****************************************************************************/

cboard::cboard()
:
m_vertex_tbl(),

#ifdef DX
m_p_buf_vertex( NULL ),
#endif

m_b_changed( FALSE ),
m_v3_pos( mm::zero_v3() ),
m_v3_size( mm::zero_v3() ),
m_rot_rad( 0.0f ),
m_v3_scale( mm::get_v3_all( 1.0f ) ),
m_v2_uv_start( mm::zero_v2() ),
m_v2_uv_end( mm::get_v2_all( 1.0f ) ),
m_b_inverse( FALSE ),
m_color( COLOR_WHITE ),
m_v2_pivot( mm::zero_v2() ),
m_bFadeIn( FALSE ),
m_bFadeOut( FALSE )//,
{
	memcpy(
		m_vertex_tbl,
		sc_vertex_original_tbl,
		sizeof( board_vertex_t ) * 4
		);

#if 0
	const f32 width_init  = SCAST<f32>( window_def::sc_client_width_init );
	const f32 height_init = SCAST<f32>( window_def::sc_client_height_init );
#else
	const f32 width_init = 0.f, height_init = 0.f;
#endif
	m_v3_size = vec3f( width_init, height_init, 0.0f );
	///<= initialization end
}

cboard::~cboard()
{
	release_all();
}

b32		cboard::Initialize()
{
#ifdef DX
	///--
	LPDIRECT3DDEVICE9 p_device = g_p_render->GetDevice();

	const HRESULT hr =
		p_device->CreateVertexBuffer(
			sizeof( board_vertex_t ) * 4,
			D3DUSAGE_WRITEONLY, MY_FVF_BOARD, D3DPOOL_MANAGED,
			&m_p_buf_vertex, NULL
			);
	if( FAILED( hr ) ) { DEBUG_BREAK(); return FALSE; }
	///--
#endif

	///--
	Update( TRUE );
	///--

	return TRUE;
}

void	cboard::Finalize()
{
	release_all();
}

void	cboard::Update( b32 b_force )
{
	update_fade();

	if( m_b_changed || b_force )
	{
		update_vertex();

		m_b_changed = FALSE;
	}
}

void	cboard::update_fade()
{
	if( m_bFadeIn )
	{
		if( get_color_a( m_color ) == 0xff )
		{
			m_bFadeIn = FALSE;
		}
		else
		{
			m_color = switch_color_a( m_color, mm::min_i( get_color_a( m_color ) + 5, 255 ) );
	
			if( get_color_a( m_color ) == 255 )
			{
				m_bFadeIn = FALSE;
			}
		}
	}
	else if( m_bFadeOut )
	{
		if( get_color_a( m_color ) == 0 )
		{
			m_bFadeOut = FALSE;
		}
		else
		{
			m_color = switch_color_a( m_color, mm::max_i( static_cast<s32>( get_color_a( m_color ) ) - 5, 0 ) );

			if( get_color_a( m_color ) == 0 )
			{
				m_bFadeOut = FALSE;
			}
		}
	}
}

void	cboard::update_vertex()
{
	///--	reset
	memcpy(
		m_vertex_tbl,
		sc_vertex_original_tbl,
		sizeof( board_vertex_t ) * 4
		);

#ifdef DX
	mm::matrix mtx_temp, mtx, mtx_s, mtx_r, mtx_t;

	mm::scaling_x( mtx_s, m_v3_scale );
	mm::rotation_z_x( mtx_r, m_rot_rad );
	mm::translation_x( mtx_t, m_v3_pos );
	D3DXMatrixMultiply( &mtx, D3DXMatrixMultiply( &mtx_temp, &mtx_s, &mtx_r ), &mtx_t );

	const f32 x_start = m_v3_size.x * m_v2_pivot.x * -1.0f;
	const f32 y_start = m_v3_size.y * m_v2_pivot.y * -1.0f;
	const f32 x_end = m_v3_size.x * ( 1.0f - m_v2_pivot.x );
	const f32 y_end = m_v3_size.y * ( 1.0f - m_v2_pivot.y );

	vec3f v3_result, v3_temp;

	for( u32 i=0; i<=3; ++i )
	{
		switch( i )
		{
			case 0:	v3_temp = mm::get_v( x_end, y_start, 0.0f );	break;
			case 1: v3_temp = mm::get_v( x_end, y_end, 0.0f );		break;
			case 2: v3_temp = mm::get_v( x_start, y_start, 0.0f );	break;
			case 3: v3_temp = mm::get_v( x_start, y_end, 0.0f );	break;
			default: DEBUG_BREAK(); break;
		}

		D3DXVec3TransformCoord( &v3_result, &v3_temp, &mtx );

		m_vertex_tbl[i].x = v3_result.x;
		m_vertex_tbl[i].y = v3_result.y;
	}
#else	//if GL
	struct local
	{
		static f32 convert_pos_x( f32 pos_x )
		{
			const u32 sc_uClientWidth = window::GetClientWidth();

			const f32 pos_x_on_ratio_of_screen =
				pos_x / SCAST<f32>( sc_uClientWidth );
			return ( pos_x_on_ratio_of_screen * 2.0f - 1.0f );
		}

		static f32 convert_pos_y( f32 pos_y )
		{
			const u32 sc_uClientHeight = window::GetClientHeight();

			const f32 pos_y_on_ratio_of_screen =
				1.0f - pos_y / SCAST<f32>( sc_uClientHeight );
			return ( pos_y_on_ratio_of_screen * 2.0f - 1.0f );
		}
	};

	const f32 x_start = local::convert_pos_x( m_v3_pos.x );
	const f32 y_start = local::convert_pos_y( m_v3_pos.y );
	const f32 x_end = local::convert_pos_x( m_v3_pos.x + m_v3_size.x );
	const f32 y_end = local::convert_pos_y( m_v3_pos.y + m_v3_size.y );

	m_vertex_tbl[0].x = x_end;
	m_vertex_tbl[0].y = y_start;
	m_vertex_tbl[1].x = x_end;
	m_vertex_tbl[1].y = y_end;
	m_vertex_tbl[2].x = x_start;
	m_vertex_tbl[2].y = y_end;
	m_vertex_tbl[3].x = x_start;
	m_vertex_tbl[3].y = y_start;
#endif

	for( u32 i=0; i<4; ++i )
	{
		m_vertex_tbl[i].color = m_color;
		
		m_vertex_tbl[i].u = ( sc_uv_tbl[ m_b_inverse ][i][0] ) ? m_v2_uv_end.x : m_v2_uv_start.x;
		m_vertex_tbl[i].v = ( sc_uv_tbl[ m_b_inverse ][i][1] ) ? m_v2_uv_end.y : m_v2_uv_start.y;
	}
	///--

#ifdef DX
	///--	re-write
	void *p_written = NULL;
	m_p_buf_vertex->Lock(
		0,
		sizeof( board_vertex_t ) * 4,
		SCAST< void** >( &p_written ),
		0
		);

	memcpy( p_written, m_vertex_tbl, sizeof( board_vertex_t ) * 4 );

	m_p_buf_vertex->Unlock();
	///--
#endif
}

void	cboard::Draw()
{
#ifdef DX
	LPDIRECT3DDEVICE9 p_device = g_p_render->GetDevice();

	p_device->SetStreamSource( 0, m_p_buf_vertex, 0, sizeof( board_vertex_t ) );
	p_device->SetFVF( MY_FVF_BOARD );

	p_device->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );
#else
	glBegin( GL_QUADS/*draw quad with 4 vertices*/ );
	{		
		for( int i=0; i<4; ++i )
		{
			glVertex2f( m_vertex_tbl[i].x, m_vertex_tbl[i].y );
		}
	}
	glEnd();
#endif
}

void	cboard::SetPos( const vec3f& in_v3_pos )
{
	m_v3_pos = in_v3_pos;

	m_b_changed = TRUE;	
}

void	cboard::SetPos( const vec2f& in_v2_pos )
{
	m_v3_pos = mm::v2_to_v3( in_v2_pos );

	m_b_changed = TRUE;		
}

void	cboard::SetPos( f32 in_pos_x, f32 in_pos_y )
{
	SetPos( mm::get_v( in_pos_x, in_pos_y ) );
}

void	cboard::GetPos( vec3f& out_v3 )	const
{
	out_v3 = m_v3_pos;
}

void	cboard::GetPos( vec2f& out_v2 )	const
{
	out_v2 = mm::v3_to_v2( m_v3_pos );
}

void	cboard::SetRot( f32 in_rad )
{
	m_rot_rad = in_rad;

	m_b_changed = TRUE;
}

f32		cboard::GetRot()	const
{
	return m_rot_rad;
}

void	cboard::SetScale( f32 in_scale )
{
	m_v3_scale = mm::get_v3_all( in_scale );
}

const vec3f&	cboard::GetScale()	const
{
	return m_v3_scale;
}

void	cboard::SetSize( const vec2f& v2_size )
{
	m_v3_size = mm::v2_to_v3( v2_size );

	m_b_changed = TRUE;
}

void	cboard::GetSize( vec2f& out_v2 )	const
{
	out_v2 = mm::v3_to_v2( m_v3_size );
}

void	cboard::SetUv( const vec2f& v2_uv_start, const vec2f& v2_uv_end )
{
	m_v2_uv_start = v2_uv_start;
	m_v2_uv_end = v2_uv_end;

	m_b_changed = TRUE;
}

const vec2f&	cboard::GetUvStart()	const
{
	return m_v2_uv_start;
}

const vec2f&	cboard::GetUvEnd()	const
{
	return m_v2_uv_end;
}

void	cboard::SetInverse( b32 in_b_inverse )
{
	m_b_inverse = in_b_inverse;

	m_b_changed = TRUE;
}

b32		cboard::GetInverse()	const
{
	return m_b_inverse;
}

void	cboard::SetColor( u32 color )
{
	m_color = color;

	m_b_changed = TRUE;
}

u32		cboard::GetColor()	const
{
	return m_color;
}

void	cboard::SetPivot( const vec2f& in_v2 )
{
	m_v2_pivot = in_v2;
}

const vec2f&	cboard::GetPivot()	const
{
	return m_v2_pivot;
}

void	cboard::GetPosLeftTop( vec2f& out_v2 )	const
{
	const f32 x_start = m_v3_size.x * m_v2_pivot.x * -1.0f;
	const f32 y_start = m_v3_size.y * m_v2_pivot.y * -1.0f;

	out_v2 = mm::add_v( mm::v3_to_v2( m_v3_pos ), vec2f( x_start, y_start ) );
}

void	cboard::FadeOut()
{
	m_bFadeOut = TRUE;
	m_bFadeIn = FALSE;
}

void	cboard::FadeIn()
{
	m_bFadeIn = TRUE;
	m_bFadeOut = FALSE;
}

b32		cboard::IsFadeOut()	const
{
	return m_bFadeOut;
}

b32		cboard::IsFadeIn()	const
{
	return m_bFadeIn;
}

void	cboard::release_all()
{
#ifdef DX
	my_safe_rel( m_p_buf_vertex );
#endif
}


