/*************************************************************************************************/
/*!
   	@file		Misc.h
	@author 	Fanzo
 	@date 		2008/5/11
*/
/*************************************************************************************************/
#pragma		once

///////////////////////////////////////////////////////////////////////////////////////////////////
//include files


#pragma pack( push , 8 )		//set align

namespace shared
{
using namespace icubic;
///////////////////////////////////////////////////////////////////////////////////////////////////
// preprocessor deifne

///////////////////////////////////////////////////////////////////////////////////////////////////
// type define
enum TextAlign
{
	Top_TextAlign , 
	Center_TextAlign , 
	Base_TextAlign , 
	Bottom_TextAlign
};
///////////////////////////////////////////////////////////////////////////////////////////////////
// classes define

///////////////////////////////////////////////////////////////////////////////////////////////////
// global variable define

///////////////////////////////////////////////////////////////////////////////////////////////////
// global functions define

//=================================================================================================
#ifdef cb_windows
cb_inline
wstring GetModuleFolder
		(
		HINSTANCE		hinst
		)
{
	wchar_t		path[_MAX_PATH];
	wchar_t		drive[_MAX_DRIVE];
	wchar_t		dir[_MAX_DIR];
	wchar_t		fname[_MAX_FNAME];
	wchar_t		ext[_MAX_EXT];
	DWORD	size = GetModuleFileNameW( hinst , path , _MAX_PATH );
	_wsplitpath_s( path , drive , _MAX_DRIVE , dir , _MAX_DIR , fname , _MAX_FNAME , ext , _MAX_EXT );
	_wmakepath_s( path , _MAX_PATH , drive , dir , L"" , L"");
	return wstring( path );
}
#else
	#error		unknown os.
#endif

//=================================================================================================
#ifdef cb_windows
cb_inline
void MessageBox
		(
		const wstring&	msg , 
		const wstring&	title
		)
{
	::MessageBoxW( NULL , msg.c_str() , title.c_str() , MB_OK );
}
#else
	#error		unknown os.
#endif


//=================================================================================================
//!	DrawLine
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void DrawLine
		(
		iSurfaceDest&	surface , 
		const fvector2	pnt[] , 
		int				pntnum , 
		float			w , 
		const rgba&		color , 
		bool			loop	= false
		)
{
	if( pntnum <= 1 )
		return;
	static
	instance<Outline>				outline;
	static
	instance< OutlineGenStroke >		gen;
	static
	instance<PathSegmentToOutline>	path;
	static
	instance<BlenderOverlap>			blender;
	static
	instance<PaintSolidColor>		source;
	static
	instance< RendererOutline >		renderer;
	static
	instance<EdgemapOutline>			map;

	gen->SetStrokeWidth( w );
	outline->Reset();
	path->Begin( (iOutline)outline , (iOutlineGen)gen );
	path->Move( pnt[0] , faffine() , loop );
	path->Line( pntnum-1 , &pnt[1] );
/*
	if( loop == true )
	{
		fvector2	ll[2] ={ pnt[ pntnum-1 ] , pnt[0] };
		path->Line( 2 , ll );
	}
*/
	path->End();

	irect							area( surface->GetDestAvailableArea() );
	{
		map->Initialize( x4_antialias , area );
		map->BeginOutline();
		map->SetOutline( ( iOutline )outline , faffine() );
		map->EndOutline( Winding_PathFillRule );
	}

	source->SetColor( color );
	renderer->SetBlender( ( iBlender )blender );
	renderer->SetPaint( ( iPaint )source );

	renderer->Render( ( iSurfaceDest )surface , (iEdgemapOutlineInfo)map , &area , 1 );
}
//=================================================================================================
//!	DrawLine
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void DrawLine
		(
		iSurfaceDest&	surface , 
		const fvector2&	start , 
		const fvector2&	target , 
		float			w , 
		const rgba&		color
		)
{
	fvector2	pnt[2] = { start , target };
	DrawLine( surface , pnt , 2 , w , color );
}
//=================================================================================================
//!	draw circle
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void DrawCircle
		(
		iSurfaceDest&	surface , 
		const fvector2&	cp , 
		float			r , 
		const rgba&		color
		)
{
	static
	instance<OutlineGenPaint>		gen;
	static
	instance<PathSegmentToOutline>	path;
	static
	instance<Outline>				outline;
	static
	instance<EdgemapOutline>			map;
	static
	instance<BlenderOverlap>			blender;
	static
	instance<PaintSolidColor>		source;
	static
	instance< RendererOutline >		renderer;

	outline->Reset();
	path->Begin( (iOutline)outline , (iOutlineGen)gen );
	path->Move( fvector2( cp.x - r , cp.y ) , faffine() , true );
	path->Arc( cp , 1.0f , PI_2_f );
	path->End();

	irect		area( surface->GetDestAvailableArea() );
	map->Initialize( x4_antialias , area );
	map->BeginOutline();
	map->SetOutline( (iOutline)outline , faffine() );
	map->EndOutline( Winding_PathFillRule );

	source->SetColor( color );
	renderer->SetBlender( ( iBlender )blender );
	renderer->SetPaint( ( iPaint )source );

	renderer->Render( ( iSurfaceDest )surface , (iEdgemapOutlineInfo)map , &area , 1 );
}
//=================================================================================================
//!	draw circle
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void DrawCircleStroke
		(
		iSurfaceDest&	surface , 
		const fvector2&	cp , 
		float			r , 
		float			w , 
		const rgba&		color
		)
{
	static
	instance<OutlineGenStroke>		gen;
	static
	instance<PathSegmentToOutline>	path;
	static
	instance<Outline>				outline;
	static
	instance<EdgemapOutline>			map;
	static
	instance<BlenderOverlap>			blender;
	static
	instance<PaintSolidColor>		source;
	static
	instance< RendererOutline >		renderer;

	gen->SetStrokeWidth( w );
	outline->Reset();
	path->Begin( (iOutline)outline , (iOutlineGen)gen );
	path->Move( fvector2( cp.x - r , cp.y ) , faffine() , true );
	path->Arc( cp , 1.0f , PI_2_f );
	path->End();

	irect		area( surface->GetDestAvailableArea() );
	map->Initialize( x4_antialias , area );
	map->BeginOutline();
	map->SetOutline( (iOutline)outline , faffine() );
	map->EndOutline( Winding_PathFillRule );

	source->SetColor( color );
	renderer->SetBlender( ( iBlender )blender );
	renderer->SetPaint( ( iPaint )source );

	renderer->Render( ( iSurfaceDest )surface , (iEdgemapOutlineInfo)map , &area , 1 );
}
//=================================================================================================
//!	draw rectangle
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void DrawRectStroke
		(
		iSurfaceDest&	surface , 
		const irect&	r , 
		float			w , 
		const rgba&		color
		)
{
	static
	instance<OutlineGenStroke>		gen;
	static
	instance<PathSegmentToOutline>	path;
	static
	instance<Outline>				outline;
	static
	instance<EdgemapOutline>			map;
	static
	instance<BlenderOverlap>			blender;
	static
	instance<PaintSolidColor>		source;
	static
	instance< RendererOutline >		renderer;
	static
	instance< JointMiter >			joint;

	fvector2	p[] = 
			{ 
			fvector2( ( float )r.xmin + w/2.0f , ( float )r.ymin + w/2.0f ) ,  
			fvector2( ( float )r.xmax - w/2.0f , ( float )r.ymin + w/2.0f ) ,  
			fvector2( ( float )r.xmax - w/2.0f , ( float )r.ymax - w/2.0f ) ,  
			fvector2( ( float )r.xmin + w/2.0f , ( float )r.ymax - w/2.0f )
			};

	gen->SetJoint( ( iJoint )joint );
	gen->SetStrokeWidth( w );
	outline->Reset();
	path->Begin( (iOutline)outline , (iOutlineGen)gen );
	path->Move( p[ 0 ] , faffine() , true );
	path->Line( _countof( p ) - 1 , &p[ 1 ] );
	path->End();

	irect		area( surface->GetDestAvailableArea() );
	map->Initialize( x4_antialias , area );
	map->BeginOutline();
	map->SetOutline( (iOutline)outline , faffine() );
	map->EndOutline( Winding_PathFillRule );

	source->SetColor( color );
	renderer->SetBlender( ( iBlender )blender );
	renderer->SetPaint( ( iPaint )source );

	renderer->Render( ( iSurfaceDest )surface , (iEdgemapOutlineInfo)map , &area , 1 );
}
//=================================================================================================
//!	draw rectangle
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void DrawRect
		(
		iSurfaceDest&	surface , 
		const irect&	r , 
		const rgba&		color
		)
{
	ColorBlt( surface , r , color , Overlap_BltBlendType );
}
//=================================================================================================
//!	draw outline point
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void DrawOutline
		(
		iSurfaceDest&	surface , 
		iOutline&		s_outline , 
		float			w , 
		const rgba&		color
		)
{
	static
	instance<Outline>				outline;
	static
	instance< OutlineEffectStroke >	outline_eff;
	static
	instance<BlenderOverlap>			blender;
	static
	instance<PaintSolidColor>		source;
	static
	instance< RendererOutline >		renderer;

	outline_eff->SetWidth( w );
	outline_eff->SetClose( false );
	outline->Reset();
	outline_eff->Effect( (iOutline)outline , s_outline );
	
	irect							area( surface->GetDestAvailableArea() );
	instance<EdgemapOutline>		map;
	{
		map->Initialize( x4_antialias , area );
		map->BeginOutline();
		map->SetOutline( ( iOutline )outline , faffine() );
		map->EndOutline( Winding_PathFillRule );
	}

	source->SetColor( color );
	renderer->SetBlender( ( iBlender )blender );
	renderer->SetPaint( ( iPaint )source );

	renderer->Render( ( iSurfaceDest )surface , (iEdgemapOutlineInfo)map , &area , 1 );
}
//=================================================================================================
//!	draw outline point
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void DrawOutlinePoint
		(
		iSurfaceDest&	surface , 
		iOutline&		outline , 
		const rgba&		color
		)
{
	static
	instance<OutlineGenPaint>		gen;
	static
	instance<PathSegmentToOutline>	path;
	static
	instance<Outline>				t_outline;
	static
	instance<EdgemapOutline>			map;
	static
	instance<BlenderOverlap>			blender;
	static
	instance<PaintSolidColor>		source;
	static
	instance< RendererOutline >		renderer;

	float		r = 1.5f;
	t_outline->Reset();
	path->Begin( (iOutline)t_outline , (iOutlineGen)gen );

	OutlineInfo		oi;
	if( false == outline->GetOutlineInfo( &oi ) )
		return;
	const OutlineSeg* i = oi.m_first;
	while( i != 0 )
	{
		OutlineNode*	n = i->m_node;
		while( n != 0 )
		{
			path->Move( fvector2( n->x - r , n->y ) , faffine() , true );
			float	p[] = { n->x , n->y , 1.0f , PI_2_f };
			path->Arc( fvector2( n->x , n->y ) , 1.0f , PI_2_f );
			n = n->m_next;
		}
		i = i->m_next;
	}
	path->End();

	irect							area( surface->GetDestAvailableArea() );
	map->Initialize( x4_antialias , area );
	map->BeginOutline();
	map->SetOutline( (iOutline)t_outline , faffine() );
	map->EndOutline( Winding_PathFillRule );

	source->SetColor( color );
	renderer->SetBlender( ( iBlender )blender );
	renderer->SetPaint( ( iPaint )source );

	renderer->Render( ( iSurfaceDest )surface , (iEdgemapOutlineInfo)map , &area , 1 );
}
//=================================================================================================
//!	textout
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void DrawText
		(
		iSurfaceDest&		surface , 
		const fvector2&		pos , 
		const wstring&		str , 
		iFont&				font , 
		const rgba&			color = rgba( 0 , 0 , 0 , 255 ) , 
		TextAlign			align = Base_TextAlign
		)
{
	// font
	float	x	= pos.x;
	float	y;
	if( align == Top_TextAlign )
		y = pos.y + font->GetAscent();
	else if( align == Center_TextAlign )
		y = pos.y + ( font->GetAscent() - font->GetDescent() ) / 2.0f;
	else if( align == Base_TextAlign )
		y = pos.y;
	else
		y = pos.y - font->GetDescent();
	font->DrawString( surface , str.c_str() , str.length() , fvector2( x , y ) , color , 0 );
/*		
	for( off = 0 ; off < num ; off++ )
	{
		wchar_t	ch1 = off == 0 ? L'\0' : str.at( off - 1 );
		wchar_t	ch2 = str.at( off );
		
		FontAlphaInfo	info;
		iSurface		alphamap;
		{
			alphamap	= font->CreateFontAlphamap( ch2 , &info );
			if( ch1 != L'\0' )
				x += font->GetKerningPair( ch1 , ch2 );
		}
		sourcectrl->SetSurface( alphamap );
		SurfaceBlt( surface , ivector2( ( int )x + info.m_pos.x , ( int )y + info.m_pos.y ) , (iSurfaceSource)sourcectrl , color , alpha_aaa() , Overlap_BltBlendType );
		
		x += font->GetCharWidth( ch2 );
	}
*/
}
//=================================================================================================
//!	textout
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
irect GetTextRect
		(
		const wstring&		str , 
		iFont&				font , 
		TextAlign			align = Base_TextAlign
		)
{
	// font
	irect	r( 0 , 0 , 0 , 0 );
	int		off , num = str.length();
	float	x	= 0;
	if( align == Top_TextAlign )
	{
		r.ymin	= 0;
		r.ymax= ( int )( font->GetAscent() + font->GetDescent() );
	}
	else if( align == Center_TextAlign )
	{
		r.ymin	= -( int )( ( font->GetAscent() + font->GetDescent() ) / 2.0f );
		r.ymax= -r.ymin;
	}
	else if( align == Base_TextAlign )
	{
		r.ymin	= -(int)font->GetAscent();
		r.ymax= (int)font->GetDescent();
	}
	else
	{
		r.ymin	= -(int)( font->GetAscent() + font->GetDescent() );
		r.ymax= 0;
	}
	for( off = 0 ; off < num ; off++ )
	{
		wchar_t	ch1 = off == 0 ? L'\0' : str.at( off - 1 );
		wchar_t	ch2 = str.at( off );
		
//		x += font->GetKerningPair( ch1 , ch2 );
		float	w;
		font->GetCharWidth( &ch2 , 1 , &w );
		x += w;
	}
	r.xmax = ( int )x;
	return r;
}
//=================================================================================================
//!	draw slider knob
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void DrawSliderKnob
		(
		iSurfaceDest&	surface , 
		const fvector2&	pos , 
		float			r , 
		const rgba&		color , 
		const rgba&		color_edge
		)
{
	DrawCircle( surface , pos , r , color );
	DrawCircleStroke( surface , pos , r , 1.0f , color_edge );
}
//=================================================================================================
//!	draw slider rail
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void DrawSliderRail
		(
		iSurfaceDest&	surface , 
		const irect&	rect , 
		const rgba&		color , 
		const rgba&		color_edge
		)
{
	fvector2	m( ( float )rect.xmin , ( float )rect.ymax );
	float	l[]	= 
	{
		( float )rect.xmin , 
		( float )( rect.ymin + rect.ymax ) / 2.0f , 
		1.0f , 
		-PI_f		
	};
	float	t[] = 
	{
		( float )rect.xmin , 
		( float )rect.ymin , 
		( float )rect.xmax , 
		( float )rect.ymin
	};
	float	r[]	= 
	{
		( float )rect.xmax , 
		( float )( rect.ymin + rect.ymax ) / 2.0f , 
		1.0f , 
		-PI_f		
	};
	float	b[] = 
	{
		( float )rect.xmax , 
		( float )rect.ymax , 
		( float )rect.xmin , 
		( float )rect.ymax
	};
	static
	instance<OutlineGenPaint>		gen_p;
	static
	instance<OutlineGenStroke>		gen_s;
	static
	instance<PathSegmentToOutline>	path;
	static
	instance<Outline>				outline;
	static
	instance<EdgemapOutline>			map;
	static
	instance<BlenderOverlap>			blender;
	static
	instance<PaintSolidColor>		source;
	static
	instance< RendererOutline >		renderer;

	irect		area( surface->GetDestAvailableArea() );

	// paint
	outline->Reset();
	path->Begin( (iOutline)outline , (iOutlineGen)gen_p );
	path->Move( m , faffine() , true );
	path->Arc( fvector2(l[0],l[1]) , l[2] , l[3] );
	path->Line( _countof( t ) , t );
	path->Arc( fvector2(r[0],r[1]) , r[2] , r[3] );
	path->Line( _countof( b ) , b );
	path->End();

	map->Initialize( x4_antialias , area );
	map->BeginOutline();
	map->SetOutline( (iOutline)outline , faffine() );
	map->EndOutline( Winding_PathFillRule );

	source->SetColor( color );
	renderer->SetBlender( ( iBlender )blender );
	renderer->SetPaint( ( iPaint )source );

	renderer->Render( ( iSurfaceDest )surface , (iEdgemapOutlineInfo)map , &area , 1 );

	// stroke
/*	
	gen_s->SetWidth( 1.0f );
	outline->Reset();
	path->Initialize( (iOutline)outline , (iOutlineGen)gen_s );
	path->Move( m , faffine() , Loop_StrokeType );
	path->Arc( l , _countof( l ) );
	path->Line( t , _countof( t ) );
	path->Arc( r , _countof( r ) );
	path->Line( b , _countof( b ) );
	path->Finalize();

	map->Initialize( x4_antialias , area );
	map->BeginOutline();
	map->SetOutline( (iOutline)outline );
	map->EndOutline( Winding_PathFillRule );

	source->SetColor( color_edge );
	renderer->SetBlender( ( iBlender )blender );
	renderer->SetPaintGen( ( iSourceGen )source );

	renderer->BeginRender( area );
	renderer->Render( map->GetOutlineEdgeinfo() , ( iSurfaceDest )surface , area );
*/
}
//=================================================================================================
//!	draw check
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void DrawCheck
		(
		iSurfaceDest&	surface , 
		const irect&	r , 
		float			w , 
		const rgba&		color
		)
{
	static
	instance<OutlineGenStroke>		gen;
	static
	instance<PathSegmentToOutline>	path;
	static
	instance<Outline>				outline;
	static
	instance<EdgemapOutline>			map;
	static
	instance<BlenderOverlap>			blender;
	static
	instance<PaintSolidColor>		source;
	static
	instance< RendererOutline >		renderer;
	static
	instance< CapRound >				cap;

	fvector2	p1[] = 
			{ 
			fvector2( ( float )r.xmin , ( float )r.ymin ) ,  
			fvector2( ( float )r.xmax , ( float )r.ymax )
			};
	fvector2	p2[] = 
			{ 
			fvector2( ( float )r.xmax , ( float )r.ymin ) ,  
			fvector2( ( float )r.xmin , ( float )r.ymax )
			};

	gen->SetCap( ( iCap )cap , ( iCap )cap );
	gen->SetStrokeWidth( w );
	outline->Reset();
	path->Begin( (iOutline)outline , (iOutlineGen)gen );
	path->Move( p1[ 0 ] , faffine() , true );
	path->Line( _countof( p1 ) - 1 , &p1[ 1 ] );
	path->Move( p2[ 0 ] , faffine() , true );
	path->Line( _countof( p2 ) - 1 , &p2[ 1 ] );
	path->End();

	irect		area( surface->GetDestAvailableArea() );
	map->Initialize( x4_antialias , area );
	map->BeginOutline();
	map->SetOutline( (iOutline)outline , faffine() );
	map->EndOutline( Winding_PathFillRule );

	source->SetColor( color );
	renderer->SetBlender( ( iBlender )blender );
	renderer->SetPaint( ( iPaint )source );

	renderer->Render( ( iSurfaceDest )surface , (iEdgemapOutlineInfo)map , &area , 1 );
}
//=================================================================================================
//!	draw config back
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void DrawConfigBack
		(
		iSurfaceDest&	surface , 
		const isize&	size
		)
{
	irect	base( irect( ivector2( 0 , 0 ) , size ) );
	DrawRect( surface , base , rgba( 255 , 255 , 200 , 200 ) );
	DrawRectStroke( surface , base , 1.0f , rgb( 0 , 0 , 0 ) );
}
//=================================================================================================
//!	draw normalized back
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void DrawNormalizedBack
		(
		iSurfaceDest&	surface , 
		const isize&	size , 
		int				r , 
		bool			center = false
		)
{
	irect	base( irect( ivector2( r , r ) , isize( size.width - r * 2 , size.height - r * 2 ) ) );
	DrawRect( surface , base , rgba( 255 , 255 , 255 , 200 ) );
	DrawRectStroke( surface , base , 1.0f , rgb( 0 , 0 , 0 ) );
	if( center == true )
	{
		DrawLine( surface , fvector2( ( base.xmin + base.xmax ) / 2.0f , (float)base.ymin ) , fvector2( ( base.xmin + base.xmax ) / 2.0f , (float)base.ymax ) , 1.0f , rgb( 0 , 0 , 0 ) );
		DrawLine( surface , fvector2( (float)base.xmin , ( base.ymin + base.ymax ) / 2.0f ) , fvector2( (float)base.xmax , ( base.ymin + base.ymax ) / 2.0f ) , 1.0f , rgb( 0 , 0 , 0 ) );
	}
}

};	//namespace

//using namespace Misc;		

#pragma pack( pop )			//release align
