//---------------------------------------------------------------------------
//	Ninja Sample
//	COPYRIGHT (C) SEGA ENTERPRISES, LTD.
//	
//	CameraEx Demonstration
//---------------------------------------------------------------------------
#include	<shinobi.h>
#include	"Nj.h"
#include	"Common.h"
#include	<nuMotion.h>


#define MAX_SHAPE_NUM		(10)
#define MAX_TMP_MATRIX		10

static Float			*pShapeBuf;
NJS_MATRIX				*pTmpMat;

enum {
	DEMO_MANUAL		= 0,
	DEMO_WALK,
	DEMO_UFOMAN,
	DEMO_UFOMAN2,
	DEMO_MAX
};
static int			DemoType;

typedef struct {
	void		(*pFunc)( int State );
	char		*pDemoName;
} TDemoInfo;

TDemoInfo		DemoInfo[DEMO_MAX] = {
	{ ManualDemo,	"Manual camera" },
	{ WalkDemo,		"Look at walker" },
	{ UFOManDemo,	"UFOMan ObjectCamera Test" },
	{ UFOManDemo2,	"UFOMan CameraMotion Test" },
};

enum {
	LINEAR = 0 ,
	SPLINE
};


static void		CallCurrentDemo( int State );
static int		MakeMotionCameraMatrixSub( const NJS_CNK_OBJECT *obj, int *pCurObjID, int StopObjID, NJS_MATRIX *pMat );


//---------------------------------------------------------------------------
//		初期化
//---------------------------------------------------------------------------
Sint32 UserInit(void)
{
	pTmpMat		= NULL;
	pShapeBuf	= NULL;
	
	if ( ( pTmpMat = syMalloc( sizeof(NJS_MATRIX) * MAX_TMP_MATRIX ) ) == NULL ) {
		return	USER_EXIT;
	}
	if ( ( pShapeBuf = syMalloc( 16 * MAX_SHAPE_NUM )) == NULL ) {
		return	USER_EXIT;
	}
	
	//	シェープバッファの確保
	njInitShape( pShapeBuf, MAX_SHAPE_NUM);
	njSetShapeList( UFOMAN_SHAPELIST);
	
	//	シェーディングモードの設定
	njTextureShadingMode( NJD_TEX_SHADING_MODE_MODULATEALPHA );
	
    //	背景色の設定
	njSetBackColor( 0x00000000, 0x00000000, 0x000000C0 );
	
	
	//	画角を初期設定する
	njSetPerspective( NJM_DEG_ANG( 60.0f ) );
	
	
	
	DemoType		= DEMO_MANUAL;
	
	CallCurrentDemo( STATE_ATTACH );
	
	return	USER_CONTINUE;
}

//---------------------------------------------------------------------------
//		メイン
//---------------------------------------------------------------------------
Sint32 UserMain(void)
{
	CallCurrentDemo( STATE_RUN );
	
	{
		const PDS_PERIPHERAL		*per;
		per		= pdGetPeripheral(PDD_PORT_A0);
		
		if ( per->press & PDD_DGT_TB ) {
#if DEBUG
			njPrint( NJM_LOCATION(10,12), "BUTTON B:CHANGE MODE" );
#endif			
			CallCurrentDemo( STATE_DETACH );
			
			DemoType++;
			if ( DemoType >= DEMO_MAX ) {
				DemoType	= 0;
			}
			
			CallCurrentDemo( STATE_ATTACH );
		}
	}
	
	return	USER_CONTINUE;
}

//---------------------------------------------------------------------------
//		終了処理
//---------------------------------------------------------------------------
Sint32 UserExit(void)
{
	if ( pTmpMat != NULL ) {
		syFree( pTmpMat );
	}
	if ( pShapeBuf != NULL ) {
		syFree( pShapeBuf );
	}
	
	return USER_CONTINUE;
}

int MakeMotionCameraMatrix( const NJS_CNK_OBJECT *obj, const NJS_MOTION *motion, Float frame, int ObjID )
{
	int					CurObjID;
	ALLOC_LOCAL_MATRIX_SPACE( 1 );
	NJS_MATRIX_PTR		pTmpMat		= GET_LOCAL_MATRIX_PTR( 0 );
	
	njStartMotionObj( motion, frame );
	
	CurObjID		= 0;
	if ( MakeMotionCameraMatrixSub( obj, &CurObjID, ObjID, (NJS_MATRIX *)pTmpMat ) ) {
		njPopMatrix( 1 );
		njPushMatrix( (NJS_MATRIX *)pTmpMat );
		
		return	TRUE;
	}
	else {
		return	FALSE;
	}
}

static void CallCurrentDemo( int State )
{
#if DEBUG
	njPrint( NJM_LOCATION(1,3), "%d:%s", DemoType, DemoInfo[DemoType].pDemoName );
#endif	
	(*DemoInfo[DemoType].pFunc)( State );
}

static int MakeMotionCameraMatrixSub( const NJS_CNK_OBJECT *obj, int *pCurObjID, int StopObjID, NJS_MATRIX *pMat )
{
	do {
		njPushMatrix( NULL );
		
		//njCnkMotionTransformEx( obj );
		
		{
			Float				pos[3];
			Float				scl[3];
			Angle				ang[3];
			NJS_QUATERNION		qua;
			int					MotRot;
			
			MotRot	= njGetMotionNodeData( obj, pos, ang, scl, &qua );
			
			
			njTranslateCameraEx( pos[0], pos[1], pos[2] );
			
			switch( MotRot ) {
			case NJD_MROT_ANGLEXYZ :
				njRotateCameraEx( ang, 0 );
				break;
			case NJD_MROT_ANGLEZXY :
				njRotateCameraEx( ang, 1 );
				break;
			default:
				//njQuaternionEx( &qua );
				break;
			}
			
			//njScaleEx( ( NJS_VECTOR *)scl );
		}
		
		
		if ( *pCurObjID == StopObjID ) {
			njGetMatrix( pMat );
			njPopMatrix( 1 );
			return	TRUE;
		}
		
		(*pCurObjID)++;
		if ( obj->child != NULL /* && !( obj->evalflags & NJD_EVAL_BREAK ) */ ) {
			if ( MakeMotionCameraMatrixSub( obj->child, pCurObjID, StopObjID, pMat ) ) {
				njPopMatrix( 1 );
				return	TRUE;
			}
		}
		
		njPopMatrix( 1 );
		
		obj = obj->sibling;
	} while ( obj != NULL );
	
	return	FALSE;
}

/*
	in:		StartPos	= 平面を描く場所の中心点をカレントマトリックスでの
						  座標表現で表わしたもの。
*/
void DrawPlane( NJS_POINT3 *pStartPos, Uint32 color1, Uint32 color2 )
{
	float				f;
	float				g;
	float				h;
	Uint32				color;
	
	g	= (float)(int)( pStartPos->x * 0.1f + 0.5f ) * 10.0f;
	h	= (float)(int)( pStartPos->z * 0.1f + 0.5f ) * 10.0f;
	for ( f = h - 100.0f; f <= h + 100.0f; f+= 10.0f ) {
		//	Ｘ軸に平行なグリッドを描く
		if ( f != 0 ) {
			color	= color1;
		}
		else {
			color	= color2;
		}
		
		DrawLine( g - 100.0f, pStartPos->y, f,
				  g + 100.0f, pStartPos->y, f,
				  color );
	}
	
	for ( f = g - 100.0f; f <= g + 100.0f; f+= 10.0f ) {
		//	Ｚ軸に平行なグリッドを描く
		if ( f != 0 ) {
			color	= color1;
		}
		else {
			color	= color2;
		}
		
		DrawLine( f, pStartPos->y, h - 100.0f,
				  f, pStartPos->y, h + 100.0f,
				  color );
	}
	
	//	Ｙ軸を描く
	DrawLine( 0.0f, pStartPos->y - 100.0f, 0.0f,
			  0.0f, pStartPos->y + 100.0f, 0.0f,
			  color2 );
}

void DrawLine( float x1, float y1, float z1, float x2, float y2, float z2, Uint32 color )
{
	NJS_POINT3			points[2];
	
	points[0].x		= x1;
	points[0].y		= y1;
	points[0].z		= z1;
	points[1].x		= x2;
	points[1].y		= y2;
	points[1].z		= z2;
	
	//njDrawLine3D( &c, 1, NJD_DRAW_NORMAL );
	
	
	njDrawLineExStart( 0.5f, color, 0 );
	njDrawLine3DExSetList( points, 2 );
	njDrawLineExEnd();
}

void DrawWorldAxis( void )
{
	static NJS_POINT3			Pos0		= { 0.0f, 0.0f, 0.0f };
	static Uint32				ColorWhite	= RGBA2COL( 255, 255, 255, 255 );
	static Uint32				ColorYellow	= RGBA2COL( 255, 255, 0, 255 );
	static Uint32				ColorGreen	= RGBA2COL( 0, 255, 0, 255 );
	
	njPushMatrix( NULL );
	njTranslate( NULL, 0.0f, -30.0f, 0.0f );
	DrawPlane( &Pos0, ColorWhite, ColorWhite );
	njPopMatrix( 1 );
	
	njPushMatrix( NULL );
	njTranslate( NULL, 30.0f, 100.0f-30.0f, 0.0f );
	njRotateZ( NULL, 0x4000 );
	DrawPlane( &Pos0, ColorYellow, ColorYellow );
	njPopMatrix( 1 );
	
	njPushMatrix( NULL );
	njTranslate( NULL, -30.0f, 100.0f-30.0f, 0.0f );
	njRotateZ( NULL, 0x4000 );
	DrawPlane( &Pos0, ColorGreen, ColorGreen );
	njPopMatrix( 1 );
}
