/*
	Ninja Library
	
	COPYRIGHT ( C ) SEGA ENTERPRISES, LTD.
*/

#include "NuMotionMake.h"


NUS_CUR_MOTIONLINK_INFO			_nu_motionlink_info_;




void nuStartMotionLink( const NUS_MOTION_LINK *motion_link, Float rate )
{
	//	なるべくカレントモーション情報がスロット 0 で終わるようにするため 1,0 の順にしている。
	nuSetCurMotionInfoSlot( 1 );
	nuStartMotionObjEx( motion_link->motion[1], motion_link->frame[1] );
	
	nuSetCurMotionInfoSlot( 0 );
	nuStartMotionObjEx( motion_link->motion[0], motion_link->frame[0] );
	
	_nu_motionlink_info_.rate	= rate;
}


void nuSetNextMotionLinkNode( void )
{
	nuSetCurMotionInfoSlot( 1 );
	nuSetNextMotionNodeEx();
	
	nuSetCurMotionInfoSlot( 0 );
	nuSetNextMotionNodeEx();
}

int nuGetMotionLinkNodeData( const NJS_CNK_OBJECT *cnkobj, Float pos[3], Angle ang[3], Float scl[3], NJS_QUATERNION *qua )
{
	Float				pos0[3];
	Float				scl0[3];
	Angle				ang0[3];
	NJS_QUATERNION		qua0;
	int					MotRot0;
	Float				rate0;
	
	Float				pos1[3];
	Float				scl1[3];
	Angle				ang1[3];
	NJS_QUATERNION		qua1;
	int					MotRot1;
	Float				rate1;
	Uint16				event_val;
	
	rate1	= _nu_motionlink_info_.rate;
	rate0	= 1.0f - rate1;
	
	//	なるべくカレントモーション情報がスロット 0 で終わるようにするため 1,0 の順にしている。
	nuSetCurMotionInfoSlot( 1 );
	MotRot1 = nuGetMotionNodeData( cnkobj, pos1, ang1, scl1, &qua1 );
	
	/* EventMotionのバックアップ */
	if(_nu_motion_event_flag_){
		event_val = _nu_motion_event_val_;
	}
	
	nuSetCurMotionInfoSlot( 0 );
	MotRot0 = nuGetMotionNodeData( cnkobj, pos0, ang0, scl0, &qua0 );
	
	/* EventMotionをリンクさせる */
	if(_nu_motion_event_flag_){
		if(rate1 < 1.0f){
			_nu_motion_event_val_ = event_val;
		}
	}
	
	if ( MotRot0 != NUD_MROT_QUATERNION ) {
		//	コータニオンに直してから補完
		if ( MotRot0 == NUD_MROT_ANGLEXYZ ) {
			//	XYZ
			njXYZAngleToQuaternion( ang0, &qua0 );
		}
		else {
			//	ZXY
			njZXYAngleToQuaternion( ang0, &qua0 );
		}
	}
	if ( MotRot1 != NUD_MROT_QUATERNION ) {
		//	コータニオンに直してから補完
		if ( MotRot1 == NUD_MROT_ANGLEXYZ ) {
			//	XYZ
			njXYZAngleToQuaternion( ang1, &qua1 );
		}
		else {
			//	ZXY
			njZXYAngleToQuaternion( ang1, &qua1 );
		}
	}
	
	pos[0]	= pos0[0] * rate0 + pos1[0] * rate1;
	pos[1]	= pos0[1] * rate0 + pos1[1] * rate1;
	pos[2]	= pos0[2] * rate0 + pos1[2] * rate1;
	
	scl[0]	= scl0[0] * rate0 + scl1[0] * rate1;
	scl[1]	= scl0[1] * rate0 + scl1[1] * rate1;
	scl[2]	= scl0[2] * rate0 + scl1[2] * rate1;
	
	njInterpolateQuaternion( &qua0, &qua1, rate1, qua );
	
	
	
	return	NUD_MROT_QUATERNION;
}

/*
	func:	現在のモーションリンクパラメータにおいての、カレントノードのマトリックスを作成し、カレントマトリックスの
			右から乗算する。
			
	in:		cnkobj					= NUS_MDATA(n)への参照ポインタと対応した NJS_CNK_OBJECT 構造体へのポインタ。
									  モーションデータが無い場合にこの構造体のpos,ang,sclメンバが参照される。
	
	out:	cur'		= cur [カレントノードのマトリックス]
	
	expl.:	この関数は、カレントノードのマトリックスを作成する。
			
			引数 cnkobj には、NUS_MDATA(n) への参照ポインタに対応した NJS_CNK_OBJECT 構造体へのポインタを指定する。
			
			指定された cnkobj の evalflags メンバに NJD_EVAL_SKIP が指定されていない場合:
				・NUS_MDATA(n) 配列への参照ポインタが指すキーフレーム配列の補完データが採用される。
				・NUS_MDATA(n) 配列への参照ポインタは１つ進められる。
			
			指定された cnkobj の evalflags メンバに NJD_EVAL_SKIP が指定されている場合:
				・対応するモーションデータが無いとみなされ、モーションデータの、NUS_MDATA(n)配列 は参照されずに
				  cnkobj の中のpos,ang,sclメンバがそのまま採用される。
				・NUS_MDATA(n) 配列への参照ポインタは進められない。
			
*/
void nuMotionLinkTransformEx( const NJS_CNK_OBJECT *cnkobj )
{
	Float				pos[3];
	Float				scl[3];
	Angle				ang[3];
	NJS_QUATERNION		qua;
	int					MotRot;
	
	MotRot	= nuGetMotionLinkNodeData( cnkobj, pos, ang, scl, &qua );
	
	njTranslateEx( (NJS_VECTOR *)pos );
	
	switch( MotRot ) {
	case NUD_MROT_ANGLEXYZ :
		njRotateEx( ang, 0 );
		break;
	case NUD_MROT_ANGLEZXY :
		njRotateEx( ang, 1 );
		break;
	default:
		njQuaternionEx( &qua );
		break;
	}
	
	njScaleEx( ( NJS_VECTOR *)scl );
}
