/*************************************************************************************************/
/*!
   	@file		main.h
	@author 	Fanzo
 	@date 		2008/5/13
*/
/*************************************************************************************************/
#pragma		once

///////////////////////////////////////////////////////////////////////////////////////////////////
//include files
#include	<windows.h>
#include	<math.h>

using namespace icubic;
using namespace shared;


///////////////////////////////////////////////////////////////////////////////////////////////////
// preprocessor deifne

#define create_item( obj_name , title_obj_name , title , view_height )																								\
	title_obj_name->SetString( title );																																\
	title_obj_name->Create( ( rViewParentCtrl )( reference )this_object() , irect( ivector2( m_es , y ) , isize( p->m_rect.Width() - m_es * 2 , m_ts ) ) );			\
	y += title_obj_name->GetRect().Height();																														\
	obj_name->Create( ( rViewParentCtrl )( reference )this_object() , irect( ivector2( m_es , y ) , isize( p->m_rect.Width() - m_es * 2 , view_height ) ) );		\
	obj_name->SetMsgCallback( ( rControlMsg )( reference )this_object() , 0 );																						\
	y += obj_name->GetRect().Size().height;

///////////////////////////////////////////////////////////////////////////////////////////////////
// type define

///////////////////////////////////////////////////////////////////////////////////////////////////
// classes define

/**************************************************************************************************
"ControlView" class 
**************************************************************************************************/
class ControlView : public View , public IControlMsg
{
	query_begin()
	iface_hook( IControlMsg , IControlMsg_IID )	
	query_end( View )

	msg_view_map_begin()
	msg_view_hook( Create , OnCreate )
	msg_view_hook( Update , OnUpdate )
	msg_view_map_end( View )

// variable member
public:
	instance<SeparateView>			m_affine_t;
	instance<AffineCfgView>			m_affine;
	instance<SeparateView>			m_anti_t;
	instance<AntiCfgView>			m_anti;
	instance<SeparateView>			m_samplescale_t;
	instance<SampleScaleCfgView>		m_samplescale;
	instance<SeparateView>			m_fillrule_t;
	instance<FillruleCfgView>		m_fillrule;
	instance<SeparateView>			m_disp_state_t;
	instance<DispOutlineCfgView>		m_disp_state;
	instance<SeparateView>			m_angle_t;
	instance<AngleCfgView>			m_angle;
	instance<SeparateView>			m_blender_t;
	instance<BlenderCfgView>			m_blender;
	instance<SeparateView>			m_processor_t;
	instance<ProcessorCfgView>		m_processor;

private:
	rControlMsg							m_msg;
	int									m_id;
	
	const int							m_es;
	const int							m_ts;
	
// "IControlMsg" msg	
//=================================================================================================
void cb_call ValueChanged_controlmsg
		(
		int		id
		)
{
	iControlMsg	ck = m_msg.lock();
	if( ck == true )
		ck->ValueChanged_controlmsg( m_id );
}
// msg functions
protected:
//=================================================================================================
void OnCreate
		(
		Create_ViewPM*	p
		)
{
	int		y = m_es;
	create_item( m_affine , m_affine_t , L"affine" , 80 );
	create_item( m_anti , m_anti_t , L"antialias" , 40 );
	create_item( m_samplescale , m_samplescale_t , L"samplescale" , 20 );
	create_item( m_fillrule , m_fillrule_t , L"fillrule" , 35 );
	create_item( m_disp_state , m_disp_state_t , L"disp switch" , 50 );
	create_item( m_angle , m_angle_t , L"arc angle" , 20 );
	create_item( m_blender , m_blender_t , L"blender" , 20 );
	create_item( m_processor , m_processor_t , L"processor" , 20 );
	m_angle->SetValue( PI_R2_f );
}
//=================================================================================================
void OnUpdate
		(
		Update_ViewPM*	p
		)
{
	DrawConfigBack( (iSurfaceDest)p->m_surface , GetRect().Size() );
}

// public functions
public:
//=================================================================================================
ControlView() : m_id( 0 ) , m_es( 5 ) , m_ts( 11 )
{
}
//=================================================================================================
void SetMsgCallback
		(
		rControlMsg&		msg , 
		int					id
		)
{
	m_msg	= msg;
	m_id	= id;
}
};
/**************************************************************************************************
"SourceGenView" class 
**************************************************************************************************/
class SourceGenView : public View , public IControlMsg
{
	query_begin()
	iface_hook( IControlMsg , IControlMsg_IID )	
	query_end( View )

	msg_view_map_begin()
	msg_view_hook( Create , OnCreate )
	msg_view_hook( Update , OnUpdate )
	msg_view_map_end( View )

// variable member
public:
	instance<SeparateView>			m_source_t;
	instance<SourceGenCfgView>		m_source;

private:
	rControlMsg							m_msg;
	int									m_id;
	
	const int							m_es;
	const int							m_ts;
	
// "IControlMsg" msg	
//=================================================================================================
void cb_call ValueChanged_controlmsg
		(
		int		id
		)
{
	iControlMsg	ck = m_msg.lock();
	if( ck == true )
		ck->ValueChanged_controlmsg( m_id );
}
// msg functions
protected:
//=================================================================================================
void OnCreate
		(
		Create_ViewPM*	p
		)
{
	int		y = m_es;
	create_item( m_source , m_source_t , L"source" , 130 );
}
//=================================================================================================
void OnUpdate
		(
		Update_ViewPM*	p
		)
{
	DrawConfigBack( (iSurfaceDest)p->m_surface , GetRect().Size() );
}

// public functions
public:
//=================================================================================================
SourceGenView() : m_id( 0 ) , m_es( 5 ) , m_ts( 11 )
{
}
//=================================================================================================
void SetMsgCallback
		(
		rControlMsg&		msg , 
		int					id
		)
{
	m_msg	= msg;
	m_id	= id;
}
};
/**************************************************************************************************
"GammaView" class 
**************************************************************************************************/
class GammaView : public View , public IControlMsg
{
	query_begin()
	iface_hook( IControlMsg , IControlMsg_IID )	
	query_end( View )

	msg_view_map_begin()
	msg_view_hook( Create , OnCreate )
	msg_view_hook( Update , OnUpdate )
	msg_view_map_end( View )

// variable member
public:
	instance<SeparateView>	m_gamma_t;
	instance<GammaCfgView>	m_gamma;

private:
	rControlMsg					m_msg;
	int							m_id;
	
	const int					m_es;
	const int					m_ts;
	
// "IControlMsg" msg	
//=================================================================================================
void cb_call ValueChanged_controlmsg
		(
		int		id
		)
{
	iControlMsg	ck = m_msg.lock();
	if( ck == true )
		ck->ValueChanged_controlmsg( m_id );
}
// msg functions
protected:
//=================================================================================================
void OnCreate
		(
		Create_ViewPM*	p
		)
{
	int		y = m_es;
	create_item( m_gamma , m_gamma_t , L"edge gamma" , p->m_rect.Height() - m_es * 2 - m_ts );
}
//=================================================================================================
void OnUpdate
		(
		Update_ViewPM*	p
		)
{
	DrawConfigBack( (iSurfaceDest)p->m_surface , GetRect().Size() );
}

// public functions
public:
//=================================================================================================
GammaView() : m_id( 0 ) , m_es( 5 ) , m_ts( 11 )
{
}
//=================================================================================================
void SetMsgCallback
		(
		rControlMsg&		msg , 
		int					id
		)
{
	m_msg	= msg;
	m_id	= id;
}
};
/**************************************************************************************************
"MainView" class 
**************************************************************************************************/
class MainView : public View , public IControlMsg
{
	query_begin()
	iface_hook( IControlMsg , IControlMsg_IID )
	query_end( View )

	msg_view_map_begin()
	msg_view_hook( Create , OnCreate )
	msg_view_hook( Update , OnUpdate )
	msg_view_hook( Size , OnSize )
	msg_view_hook( LDragStart , OnLDragStart )
	msg_view_hook( LDrag , OnLDrag )
	msg_view_hook( LDragEnd , OnLDragEnd )
	msg_view_hook( LDragCancel , OnLDragCancel )
	msg_view_map_end( View )

// variable member
private:
	instance<ControlView>			m_control;
	instance<GammaView>				m_gamma;
	instance<SourceGenView>			m_sourcegen;
	instance<TimeCfgView>			m_time;

	instance<PathSegmentToOutline>	m_path;
	instance<Outline>				m_outline;
	instance<OutlineGenPaint>		m_gen;
	instance<EdgemapOutline>		m_map;
	instance< RendererOutline >		m_renderer;

	int									m_edit_type;
	int									m_edit_pnt;
	fvector2							m_pnt[8];

	const int							m_handle_r;
	const rgb							m_bc;
	const rgb							m_oc;
	const rgb							m_hc;
	
// msg functions
private:
//=================================================================================================
void cb_call ValueChanged_controlmsg
		(
		int		id
		)
{
	RequireUpdate( irect( ivector2( 0 , 0 ) , GetRect().Size() ) , false );
}
// control
private:
//=================================================================================================
int GetPointNum()
{
	return 8;
}
//=================================================================================================
fvector2 GetPoint
		(
		int				off
		)
{
	isize		size	= GetRect().Size();
	faffine		aff		= faffine::GetMove( fvector2( ( float )size.width / 2.0f , ( float )size.height / 2.0f ) ) * m_control->m_affine->GetValue();
	return aff.Transform( m_pnt[ off ] );
}
//=================================================================================================
void SetPoint
		(
		int				off , 
		fvector2		pnt
		)
{
	isize		size	= GetRect().Size();
	faffine		aff		= faffine::GetMove( fvector2( ( float )size.width / 2.0f , ( float )size.height / 2.0f ) ) * m_control->m_affine->GetValue();
	faffine		raff	= aff.Inverse();
	m_pnt[ off ] = raff.Transform( pnt );
}	
//=================================================================================================
bool Search
		(
		const ivector2&		pnt , 
		int*				pntoff
		)
{
	int		off , num = GetPointNum();
	for( off = 0 ; off < num ; off++ )
	{
		fvector2	pp = GetPoint( off );
		ivector2	p( ( int )pp.x , ( int )pp.y );
		irect		r( p.x - m_handle_r , p.y - m_handle_r , p.x + m_handle_r , p.y + m_handle_r );
		if( true == r.IsInside( pnt ) )
		{
			*pntoff	= off;
			return true;
		}
	}
	return false;
}
//=================================================================================================
void DrawHandle
		(
		iSurfaceDest&	surface
		)
{
	isize		size= GetRect().Size();			
	faffine		aff = faffine::GetMove( fvector2( ( float )size.width / 2.0f , ( float )size.height / 2.0f ) ) * m_control->m_affine->GetValue();

	fvector2	pnt[_countof( m_pnt )];
	int	i;
	for( i = 0 ; i < _countof( m_pnt ) ; i++ )
		pnt[i] = aff.Transform( m_pnt[i] );

	DrawLine( surface , pnt[1] , pnt[2] , 1.0f , m_hc );
	DrawLine( surface , pnt[2] , pnt[3] , 1.0f , m_hc );
	DrawLine( surface , pnt[3] , pnt[4] , 1.0f , m_hc );
	DrawLine( surface , pnt[5] , pnt[6] , 1.0f , m_hc );
	for( i = 0 ; i < _countof( pnt ) ; i++ )
		DrawCircle( surface , pnt[i] , ( float )m_handle_r , m_hc );
}

// msg functions
private:
//=================================================================================================
void OnCreate
		(
		Create_ViewPM*	p
		)
{
	m_control->Create( ( rViewParentCtrl )( reference )this_object() , irect( ivector2( 1 , 1 ) , isize( 130 , 380 ) ) );
	m_control->SetMsgCallback( ( rControlMsg )( reference )this_object() , 0 );

	m_time->Create( ( rViewParentCtrl )( reference )this_object() , irect( ivector2( 135 , 0 ) , isize( 300 , 16 ) ) );
	m_time->SetMsgCallback( ( rControlMsg )( reference )this_object() , 0 );

	m_sourcegen->Create( ( rViewParentCtrl )( reference )this_object() , irect( ivector2( 1 , p->m_rect.Size().height - 1 - 150 ) , isize( 400 , 150 ) ) );
	m_sourcegen->SetMsgCallback( ( rControlMsg )( reference )this_object() , 0 );

	m_gamma->Create( ( rViewParentCtrl )( reference )this_object() , irect( ivector2( 1 + 400 + 1 , p->m_rect.Size().height - 1 - 150 ) , isize( 170 , 150 ) ) );
	m_gamma->SetMsgCallback( ( rControlMsg )( reference )this_object() , 0 );
}
//=================================================================================================
void OnUpdate
		(
		Update_ViewPM*	p
		)
{
	ColorBlt( (iSurfaceDest)p->m_surface , p->m_rect , m_bc , Onezero_BltBlendType );	

	m_time->BeginMeasure();
	m_outline->Reset();
	
	isize		size= GetRect().Size();			
	faffine		aff = faffine::GetMove( fvector2( ( float )size.width / 2.0f , ( float )size.height / 2.0f ) );
	m_gen->SetSampleScale( m_control->m_samplescale->GetValue() );
	m_path->Begin( (iOutline)m_outline , (iOutlineGen)m_gen );

	m_path->Move( m_pnt[0] , aff * m_control->m_affine->GetValue() , true );
	m_path->Line( 1 , &m_pnt[1] );
	m_path->BezierQ( 2 , &m_pnt[2] );
	m_path->BezierC( 3 , &m_pnt[4] );
	m_path->Arc( m_pnt[7] , 2.0f , m_control->m_angle->GetValue() );
	m_path->End();

	m_map->Initialize( m_control->m_anti->GetValue() , p->m_rect );
	m_map->BeginOutline();
	m_map->SetOutline( (iOutline)m_outline , faffine() );
	m_map->EndOutline( m_control->m_fillrule->GetValue() );

	m_renderer->SetBlender( m_control->m_blender->GetValue() );
	m_renderer->SetPaint( ( iPaint )m_sourcegen->m_source->GetSourcePaint( p->m_surface->GetDPI() , aff ) );
	m_renderer->SetGamma( m_gamma->m_gamma->GetValue_i16() );
	
	m_renderer->Render( (iSurfaceDest)p->m_surface , (iEdgemapOutlineInfo)m_map , &p->m_rect , 1 );
	m_time->EndMeasure();

	if( m_control->m_disp_state->GetOutlineState() == true )
		DrawOutline( (iSurfaceDest)p->m_surface , ( iOutline )m_outline , 1.0f , m_oc );
	if( m_control->m_disp_state->GetSampleState() == true )
		DrawOutlinePoint( (iSurfaceDest)p->m_surface , ( iOutline )m_outline , m_oc );
	if( m_control->m_disp_state->GetHandleState() == true )
		DrawHandle( (iSurfaceDest)p->m_surface );
	if( m_control->m_disp_state->GetHandleState() == true )
		m_sourcegen->m_source->DrawEditHandle( aff , (iSurfaceDest)p->m_surface );
}
//=================================================================================================
void OnSize
		(
		Size_ViewPM*	p
		)
{
	m_sourcegen->Move( irect( ivector2( 1 , p->m_rect.Size().height - 150 - 1 ) , isize( 400 , 150 ) ) );
	m_gamma->Move( irect( ivector2( 1 + 400 + 1 , p->m_rect.Size().height - 1 - 150 ) , isize( 170 , 150 ) ) );
}
//=================================================================================================
void OnLDragStart
		(
		LDragStart_ViewPM*	p
		)
{
	if( m_control->m_disp_state->GetHandleState() == false )
		return;
	isize	size = GetRect().Size();
	if( true == m_sourcegen->m_source->SearchEditPoint( faffine::GetMove( fvector2( -size.width / 2.0f , -size.height / 2.0f ) ).Transform( p->m_pos ) , &m_edit_pnt ) )
	{
		m_edit_type	= 1;
		return;
	}
	if( true == Search( p->m_pos , &m_edit_pnt ) )
	{
		m_edit_type	= 0;
		return;
	}
}
//=================================================================================================
void OnLDrag
		(
		LDrag_ViewPM*	p
		)
{
	if( m_edit_pnt == -1 )
		return;
	if( m_edit_type == 0 )
		SetPoint( m_edit_pnt , p->m_pos );
	else if( m_edit_type == 1 )
	{
		isize	size = GetRect().Size();
		m_sourcegen->m_source->SetEditPoint( m_edit_pnt , faffine::GetMove( fvector2( -size.width / 2.0f , -size.height / 2.0f ) ).Transform( p->m_pos ) );
	}
	RequireUpdate( irect( ivector2( 0 , 0 ) , GetRect().Size() ) , false );
}
//=================================================================================================
void OnLDragEnd
		(
		LDragEnd_ViewPM*	p
		)
{
	m_edit_type	= -1;
	m_edit_pnt	= -1;
}
//=================================================================================================
void OnLDragCancel
		(
		LDragCancel_ViewPM*	p
		)
{
	m_edit_type	= -1;
	m_edit_pnt = -1;
}
// public functions
public:
//=================================================================================================
//!	construct
//-------------------------------------------------------------------------------------------------
MainView() : 
		m_handle_r( 5 ) , 
		m_edit_type( -1 ) , 
		m_edit_pnt( -1 ) , 
		m_bc( 255 , 255 , 235 ) ,
		m_oc( 60 , 100 , 60 ) , 
		m_hc( 40,121,121 )
{
	m_pnt[0]	= fvector2( -100.0f , 0.0f );
	m_pnt[1]	= fvector2( 0.0f , -100.0f );
	m_pnt[2]	= fvector2( 200.0f , -100.0f );
	m_pnt[3]	= fvector2( 200.0f , 0.0f );
	m_pnt[4]	= fvector2( 200.0f , 100.0f );
	m_pnt[5]	= fvector2( 0.0f , 50.0f );
	m_pnt[6]	= fvector2( 0.0f , 100.0f );
	m_pnt[7]	= fvector2( 0.0f , 0.0f );
}
//=================================================================================================
bool Initialize
		(
		const wstring&	folder
		)
{
	wstring		material;
	if( 0xFFFFFFFF == GetFileAttributesW( ( folder + L"../../../../material" ).c_str() ) )
		material = folder + L"material/";
	else
		material = folder + L"../../../../material/";

	int		off;
	for( off = 0 ; off < 4 ; off++ )
	{
		wchar_t		path[256];
		cb_swprintf( path , L"tex%d.psd" , off );
		if( false == m_sourcegen->m_source->AddTexture( material + path ) )
		{
			MessageBox( ( wstring( L"can't open file: " ) + path ) , L"error" );
			return false;
		}
	}
	return true;
}
};

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

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





