/*************************************************************************************************/
/*!
   	@file		pp.h
	@author 	Fanzo
 	@date 		2008/4/16
*/
/*************************************************************************************************/
#pragma		once

///////////////////////////////////////////////////////////////////////////////////////////////////
//include files
#include	"../../iCubicCore/iCubicCore.h"

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

namespace icubic
{

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

///////////////////////////////////////////////////////////////////////////////////////////////////
// type define
enum pp_processor
{
	null_pp_processor	= -1 , 
	cpu_pp_processor	= 0 , 
	sse_pp_processor	= 1 , 
	
	num_pp_processor , 
};
enum pp_format
{
	rgb_pp_format		= 0 , 
	rgba_pp_format		= 1 , 
	a_pp_format			= 2 , 
};
enum pp_wraptype
{
	repeat_pp_wraptype	= 0 , 
	clamp_pp_wraptype = 1 , 
};

///////////////////////////////////////////////////////////////////////////////////////////////////
// global variable define
extern const uint16			g_pp_255_to_256_tbl[ 256 ];

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

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

struct pp_rgb
{
	uint8	padding , r , g , b;
};
struct pp_rgba
{
	uint8	a , r , g , b;
};
struct pp_a
{
	uint8	a;
};
struct pp_alpha
{
	uint16	a;					// 0-256
};
struct pp_color
{
	uint16	a , r , g , b;		// 0-256
};
struct pp_pixel
{
	union 
	{
		pp_rgb		rgb;
		pp_rgba		rgba;
		pp_a		a;
	};
};
#pragma pack( pop )			//release align
///////////////////////////////////////////////////////////////////////////////////////////////////
// include
};

#include	"cpp/pp_cpp.h"
#ifdef PP_SSE
#include	"sse/pp_sse.h"
#endif

namespace icubic
{
///////////////////////////////////////////////////////////////////////////////////////////////////
// global functions define

#ifdef PP_SSE
//=================================================================================================
//!	support sse2
//!	@retval			if support sse2 , return 1 else return 0
//-------------------------------------------------------------------------------------------------
cb_inline
int pp_support_sse2()
{
	static
	int		support = -1;
	if( support != -1 )
		return support;
	_asm
	{
		mov		eax , 0
		cpuid
		cmp		eax , 1
		jb		no_support_sse2
		mov		support , 1
		jmp		support_sse2_exit
	no_support_sse2:
		mov		support , 0
	support_sse2_exit:		
	}
	return support;
}
#endif

//=================================================================================================
//!	get function type
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
pp_processor pp_get_default_processor()
{
#ifdef PP_SSE
	if( 1 == pp_support_sse2() )
		return sse_pp_processor;
	return cpu_pp_processor;
#else
	return cpu_pp_processor;
#endif
}
//=================================================================================================
//!	get and set function type
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
pp_processor pp_get_processor
		(
		pp_processor	pt = null_pp_processor
		)
{
	static
	pp_processor		processor = pp_get_default_processor();
	if( pt == null_pp_processor )
		return processor;
#ifdef PP_SSE
	processor	= pt;
#else
#endif
	return processor;
}
//=================================================================================================
//!	blender onezero
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void pp_blender_onezero_m
		(
		pp_format			destformat , 
		void*				dest , 
		pp_format			srcformat ,
		const void*			src , 
		int32				len , 
		const pp_color&		b_color , 
		const pp_alpha&		alpha
		)
{
	typedef	void (*func)( pp_format , void* , pp_format , const void* , int32 , const pp_color& , const pp_alpha& );
	static
	func	funclist[ num_pp_processor ] = 
	{
		pp_cpp_blender_onezero_m , 
#ifdef PP_SSE
		pp_sse_blender_onezero_m , 
#else
		0 , 
#endif	
	};	
	funclist[pp_get_processor()]( destformat , dest , srcformat , src , len , b_color , alpha );
}
//=================================================================================================
//!	blender onezero
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void pp_blender_onezero_c
		(
		pp_format		destformat , 
		void*			dest , 
		int32			len , 
		const pp_color&	color
		)
{
	typedef	void (*func)( pp_format , void* , int32 , const pp_color& );
	static
	func	funclist[ num_pp_processor ] = 
	{
		pp_cpp_blender_onezero_c , 
#ifdef PP_SSE
		pp_sse_blender_onezero_c , 
#else
		0 , 
#endif	
	};	
	funclist[pp_get_processor()]( destformat , dest , len , color );
}
//=================================================================================================
//!	blender overlap
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void pp_blender_overlap_m
		(
		pp_format		destformat , 
		void*			dest , 
		pp_format		srcformat ,
		const void*		src , 
		int32			len , 
		const pp_color&	b_color , 
		const pp_alpha&	alpha
		)
{
	typedef	void (*func)( pp_format , void* , pp_format , const void* , int32 , const pp_color& , const pp_alpha&	alpha );
	static
	func	funclist[ num_pp_processor ] = 
	{
		pp_cpp_blender_overlap_m , 
#ifdef PP_SSE
		pp_sse_blender_overlap_m , 
#else
		0 , 
#endif	
	};	
	funclist[pp_get_processor()]( destformat , dest , srcformat , src , len , b_color , alpha );
}
//=================================================================================================
//!	blender overlap
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void pp_blender_overlap_c
		(
		pp_format		destformat , 
		void*			dest , 
		int32			len , 
		const pp_color&	color
		)
{
	typedef	void (*func)( pp_format , void* , int32 , const pp_color&	color );
	static
	func	funclist[ num_pp_processor ] = 
	{
		pp_cpp_blender_overlap_c , 
#ifdef PP_SSE
		pp_sse_blender_overlap_c , 
#else
		0 , 
#endif	
	};	
	funclist[pp_get_processor()]( destformat , dest , len , color );
}
//=================================================================================================
//!	downsample
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void pp_downsample_m
		(
		pp_format		destformat , 
		void*			dest , 
		int32			len , 
		pp_format		srcformat ,
		const void*		src , 
		int32			pitchbyte , 
		int32			sft_samplenum , 
		const pp_color&	b_color , 
		const pp_alpha&	alpha
		)
{
	typedef	void (*func)( pp_format , void* , int32 , pp_format , const void* , int32 , int32 , const pp_color& , const pp_alpha& );
	static
	func	funclist[ num_pp_processor ] = 
	{
		pp_cpp_downsample_m , 
#ifdef PP_SSE
		pp_sse_downsample_m , 
#else
		0 , 
#endif	
	};	
	funclist[pp_get_processor()]( destformat , dest , len , srcformat ,src , pitchbyte , sft_samplenum , b_color , alpha );
}
//=================================================================================================
//!	oversample
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void pp_oversample_m
		(
		pp_format		destformat , 
		void*			dest , 
		int32			pitchbyte , 
		pp_format		srcformat ,
		const void*		src , 
		int32			len , 
		int32			sft_samplenum , 
		const pp_color&	b_color , 
		const pp_alpha&	alpha
		)
{
	typedef	void (*func)( pp_format , void* , int32 , pp_format , const void* , int32 , int32 , const pp_color& , const pp_alpha&	alpha );
	static
	func	funclist[ num_pp_processor ] = 
	{
		pp_cpp_oversample_m , 
#ifdef PP_SSE
		pp_sse_oversample_m , 
#else
		0 , 
#endif	
	};	
	funclist[pp_get_processor()]( destformat , dest , pitchbyte , srcformat ,src , len , sft_samplenum , b_color , alpha );
}
//=================================================================================================
//!	gradation linear
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void pp_gradation_linear_i16
		(
		pp_format		destformat , 
		void*			dest , 
		int32			len , 
		const pp_color&	ss_color , 
		const pp_color&	st_color , 
		float			st , 
		float			tt , 
		const int16*	blendtbl
		)
{
	typedef	void (*func)( pp_format , void* , int32 , const pp_color& , const pp_color& , float , float , const int16* );
	static
	func	funclist[ num_pp_processor ] = 
	{
		pp_cpp_gradation_linear_i16 , 
#ifdef PP_SSE
		pp_sse_gradation_linear_i16 , 
#else
		0 , 
#endif	
	};	
	funclist[pp_get_processor()]( destformat , dest , len , ss_color , st_color , st , tt , blendtbl );
}
//=================================================================================================
//!	gradation linear
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void pp_gradation_linear_f
		(
		pp_format		destformat , 
		void*			dest , 
		int32			len , 
		const pp_color&	ss_color , 
		const pp_color&	st_color , 
		float			st , 
		float			tt , 
		const float*	blendtbl
		)
{
	typedef	void (*func)( pp_format , void* , int32 , const pp_color& , const pp_color& , float , float , const float* );
	static
	func	funclist[ num_pp_processor ] = 
	{
		pp_cpp_gradation_linear_f , 
#ifdef PP_SSE
		pp_sse_gradation_linear_f , 
#else
		0 , 
#endif	
	};	
	funclist[pp_get_processor()]( destformat , dest , len , ss_color , st_color , st , tt , blendtbl );
}
//=================================================================================================
//!	gradation radial
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void pp_gradation_radial_i16
		(
		pp_format		destformat , 
		void*			dest , 
		int32			len , 
		float			dsx , 
		float			dsy , 
		float			dtx , 
		float			dty , 
		const pp_color&	ss_color , 
		const pp_color&	st_color , 
		float			ls , 
		float			lt , 
		const int16*	blendtbl , 
		bool			inverse
		)
{
	typedef	void (*func)( pp_format , void* , int32 , float , float , float , float , const pp_color& , const pp_color& , float , float , const int16* , bool );
	static
	func	funclist[ num_pp_processor ] = 
	{
		pp_cpp_gradation_radial_i16 , 
#ifdef PP_SSE
		pp_sse_gradation_radial_i16 , 
#else
		0 , 
#endif	
	};	
	funclist[pp_get_processor()]( destformat , dest , len , dsx , dsy , dtx , dty , ss_color , st_color , ls , lt , blendtbl , inverse );
}
//=================================================================================================
//!	gradation radial
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void pp_gradation_radial_f
		(
		pp_format		destformat , 
		void*			dest , 
		int32			len , 
		float			dsx , 
		float			dsy , 
		float			dtx , 
		float			dty , 
		const pp_color&	ss_color , 
		const pp_color&	st_color , 
		float			ls , 
		float			lt , 
		const float*	blendtbl , 
		bool			inverse
		)
{
	typedef	void (*func)( pp_format , void* , int32 , float , float , float , float , const pp_color& , const pp_color& , float , float , const float* , bool );
	static
	func	funclist[ num_pp_processor ] = 
	{
		pp_cpp_gradation_radial_f , 
#ifdef PP_SSE
		pp_sse_gradation_radial_f , 
#else
		0 , 
#endif	
	};	
	funclist[pp_get_processor()]( destformat , dest , len , dsx , dsy , dtx , dty , ss_color , st_color , ls , lt , blendtbl , inverse );
}
//=================================================================================================
//!	texture nearest
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void pp_texture_nearest_m
		(
		pp_format		destformat , 
		void*			dest , 
		int32			len , 
		float			ssu , 
		float			ssv , 
		float			ttu , 
		float			ttv , 
		pp_format		srcformat , 
		const void*		src , 
		int32			src_pitchbyte , 
		int16			src_w , 
		int16			src_h , 
		const pp_color&	b_color , 
		const pp_alpha&	alpha , 
		pp_wraptype		wrap
		)
{
	typedef	void (*func)( pp_format , void* , int32 , float , float , float , float , pp_format , const void* , int32 , int16 , int16 , const pp_color& , const pp_alpha&	alpha , pp_wraptype );
	static
	func	funclist[ num_pp_processor ] = 
	{
		pp_cpp_texture_nearest_m , 
#ifdef PP_SSE
		pp_sse_texture_nearest_m , 
#else
		0 , 
#endif	
	};	
	funclist[pp_get_processor()]( destformat , dest , len , ssu , ssv , ttu , ttv , srcformat , src , src_pitchbyte , src_w , src_h , b_color , alpha , wrap );
}
//=================================================================================================
//!	texture weight4f
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void pp_texture_weight4f_m
		(
		pp_format		destformat , 
		void*			dest , 
		int32			len , 
		float			ssu , 
		float			ssv , 
		float			ttu , 
		float			ttv , 
		pp_format		srcformat , 
		const void*		src , 
		int32			src_pitchbyte , 
		int16			src_w , 
		int16			src_h , 
		const pp_color&	b_color , 
		const pp_alpha&	alpha , 
		pp_wraptype		wrap , 
		const float*	weighttbl
		)
{
	typedef	void (*func)( pp_format , void* , int32 , float , float , float , float , pp_format , const void* , int32 , int16 , int16 , const pp_color& , const pp_alpha& , pp_wraptype , const float* );
	static
	func	funclist[ num_pp_processor ] = 
	{
		pp_cpp_texture_weight4f_m , 
#ifdef PP_SSE
		pp_sse_texture_weight4f_m , 
#else
		0 , 
#endif	
	};	
	funclist[pp_get_processor()]( destformat , dest , len , ssu , ssv , ttu , ttv , srcformat , src , src_pitchbyte , src_w , src_h , b_color , alpha , wrap , weighttbl );
}
//=================================================================================================
//!	texture weight16f
//!	@retval			---
//-------------------------------------------------------------------------------------------------
cb_inline
void pp_texture_weight16f_m
		(
		pp_format		destformat , 
		void*			dest , 
		int32			len , 
		float			ssu , 
		float			ssv , 
		float			ttu , 
		float			ttv , 
		pp_format		srcformat , 
		const void*		src , 
		int32			src_pitchbyte , 
		int16			src_w , 
		int16			src_h , 
		const pp_color&	b_color , 
		const pp_alpha&	alpha , 
		pp_wraptype		wrap , 
		const float*	weighttbl1 , 
		const float*	weighttbl2
		)
{
	typedef	void (*func)( pp_format , void* , int32 , float , float , float , float , pp_format , const void* , int32 , int16 , int16 , const pp_color& , const pp_alpha& , pp_wraptype , const float* , const float* );
	static
	func	funclist[ num_pp_processor ] = 
	{
		pp_cpp_texture_weight16f_m , 
#ifdef PP_SSE
		pp_sse_texture_weight16f_m , 
#else
		0 , 
#endif	
	};	
	funclist[pp_get_processor()]( destformat , dest , len , ssu , ssv , ttu , ttv , srcformat , src , src_pitchbyte , src_w , src_h , b_color , alpha , wrap , weighttbl1 , weighttbl2 );
}

};	//namespace
//using namespace icubic;		

#pragma pack( pop )			//release align
