/*----------------------------------------------------------------
   Name   : Imagine.c  (ARC1 demo) 
   Author : Carlos Sarria            
   Date   : September 1997
    
   Copyright : 1997 by VideoLogic Limited. All rights reserved.
   Modified  : 01, July, 1998 by Takeshi Muto / NEC Software,Ltd. for KAMUI
 -----------------------------------------------------------------*/

/*
#define		_X86_
*/
/* _X86_ flag for win95 : SET2 */

#define		_DISPLAY_STRING_
/* if defined then display strings on screen */

#define		_DISP_PERFORMANCE_
/* Display performance : for windows */

/* Set Display Mode */
#define NTSC 1

#include	<math.h>
#include	<stdio.h>
#include	<stdlib.h>
#include	<float.h>

#include	<shinobi.h>

/*--
#include	<conio.h>
#include	<malloc.h>
#include	<memory.h>
--*/

#if defined(_X86_)
	#include	<time.h>
	#include	<windows.h>
#endif

#pragma warning (disable : 4244) /* Disables float to double conversion warning */

#include	"kamui.h"				/* for Kamui Call */
#include	"dispstr.h"				/* for DisplayString */
/* #include	"sgl2.h" */
#include	"kmtools.h"
#include	"kmSpace.h"  /* This is the file with 3D data */


#if defined(_DISP_PERFORMANCE_)
#if defined(_X86_)
#else
	#include    "QPF.H"                 /* for QueryPerformance */
#endif
#endif

/****************************************************************************/
/**	Valuables for KAMUI *****************************************************/
/****************************************************************************/
	KMSTATUS			status;					/* return status of KAMUI API */
	KMVERSIONINFO		VersionInfo;			/* KAMUI Version information */
	KMSURFACEDESC		PrimarySurfaceDesc;		/* Primary frame buffer */
	KMSURFACEDESC		BackSurfaceDesc;		/* Back-buffer frame buffer */
	KMVERTEXBUFFDESC	VertexBufferDesc;		/* Vertex-buffer */
	KMVERTEXCONTEXT		VertexContext01;		/* Vertex context */
	KMVERTEXCONTEXT		VertexContext02;		/* Vertex context */
	KMDWORD				FogDensity;				/* Fog density */
	KMDWORD				FogD = 1;

/* 性能測定用変数 */
	int			frame;				/* 画面フレーム */
	int			frame_2 = 0;		/* 画面フレーム上位 */
#if defined(_DISP_PERFORMANCE_)
	int			pcount_f;			/* Hight-resolution counter supported? */
	double		nFPS;				/* 現在の性能(Frame/Second) */
	double		aFPS;				/* 性能の平均値 */
	double		MxFPS;				/* 最高性能 */
	double		MnFPS;				/* 最低性能 */
	__int64 	Time3i;				/* render API 完了時刻 */
	__int64		freqi;				/* カウンタの精度 */
	double		freq;				/* カウンタの精度 */
	double		Time3;				/* render API 完了時刻 */
	double		maxTime = 0.00001;	/* 最高描画時間(msec) */
	double		minTime = 99999;	/* 最低描画時間(msec) */
	double		OldTime3;			/* １フレーム前のrender直後の時間(msec) */
	double		nowTime;			/* 現在の描画時間(msec) */
	double		totalTime	= 0;	/* 累積render時間(msec) */
	double		aveTime;			/* 平均描画時間(msec) */
#if defined(_X86_)
	time_t		start_time;			/* APの開始時間 */
#endif
#endif

/*------------------------------- Global Variables -----------------------------------*/
/* Globals */

/* Not counted. */
unsigned int nTrees = 0;
unsigned int Type = 0;

float	drx = 0.0f;	/* object rotation step by X axis */
float	dry = 0.002f;	/* object rotation step by Y axis */
float	drz = 0.05f;	/* object rotation step by Z axis */
float	rx = 0.0f;		/* object rotation angle by X axis */
float	ry = 0.0f;		/* object rotation angle by Y axis */
float	rz = 0.0f;		/* object rotation angle by Z axis */
float	PosZ = 0.0f;	/* object position Z */

float   Frame = 0;
#if 0
unsigned   TexOpaq;
#endif
KMSURFACEDESC	TexOpaq;
extern TRANSFORM  T[NUM_MESHES];
static sgl_vector X_Axe = { 1, 0, 0 }, Y_Axe = { 0, 1, 0 }, Z_Axe = { 0, 0, 1 };

/* Info Structure */
INFO Info = 
{
	FALSE,		/* OpaqMap       */
	TRUE,       /* Textured      */
	TRUE,		/* Gouraud       */
	FALSE,      /* GlobalTrans   */
	FALSE,      /* VertexAlpha   */
	FALSE,		/* TableFog      */
	FALSE,      /* VertexFog     */
	TRUE,       /* Bilinear      */
	TRUE,       /* Highlight     */
};

/* Prototypes */

static void SetTextures			(void);
static void NextFrame			(void);
static void DisplayInformation	(void);
static void ReadMaple (void);

extern sgl_vector LightDir;
/*
extern SGLCONTEXT SGLContext;
*/
/* Textures */
extern unsigned char Space;

/*-------------------------------------------------------------------------------------*/
/*                                       MAIN                                          */
/*-------------------------------------------------------------------------------------*/

NJS_PERIPHERAL *per;

int main (void)
{
KMPACKEDARGB   cBorder;
int Control = 0, Device, Val = 0;

#ifdef __GNUC__
	shinobi_workaround();
#endif


#if 0
    Device = sgl_create_screen_device (0, 640, 480, sgl_device_16bit, FALSE);
	if (Device<0) return -1;
#endif

	txt_ClearScreen();	/* Clear text screen */
	PRINTOUT(("** Space : Refrection mapping **\n"));

	/*----------------------------------------------------------------------------------- */
	/* Initialize Hardware */

#if NTSC
	sbInitSystem( NJD_RESOLUTION_640x480_NTSCNI, NJD_FRAMEBUFFER_MODE_RGB565, 1 );
#else
	sbInitSystem( NJD_RESOLUTION_VGA, NJD_FRAMEBUFFER_MODE_RGB565, 1 );
#endif

	/* Black Border */
	cBorder.dwPacked	=	0x00000000;
	kmSetBorderColor(cBorder);

	kmGetVersionInfo(&VersionInfo);
#if 0
	PRINTOUT(("MajorVersion      0x0%08x\n",VersionInfo.kmMajorVersion));
	PRINTOUT(("LocalVersion      0x0%08x\n",VersionInfo.kmLocalVersion));
	PRINTOUT(("kmFrameBufferSize 0x0%08x\n",VersionInfo.kmFrameBufferSize));
#endif

	/*----------------------------------------------------------------------------------- */
	/* Create vertex buffer */
	status = kmCreateVertexBuffer(&VertexBufferDesc,		/* pBufferDesc */
									262144,					/* Opaque-Polygon */
									0,						/* Opaque-Modifier */
									32768,					/* Trans-Polygon */
									0						/* Trans-Modifier */
									);
	Check_Status(status, "kmCreateVertexBuffer");

	/*----------------------------------------------------------------------------------- */
	/* Create primary frame buffer surface */
	status = kmCreateFrameBufferSurface(&PrimarySurfaceDesc,	/* pSurfaceDesc */
								640,	/* nWidth */
								480,	/* nHeight */
								FALSE,	/* bStripBuffer */
								FALSE	/* bBufferClear */
								);
	Check_Status(status, "kmCreateFrameBufferSurface(Primary)");

	/*----------------------------------------------------------------------------------- */
	/* Create backbuffer frame buffer surface */
	status = kmCreateFrameBufferSurface(&BackSurfaceDesc,	/* pSurfaceDesc */
								640,	/* nWidth */
								480,	/* nHeight */
								FALSE,	/* bStripBuffer */
								FALSE	/* bBufferClear */
								);
	Check_Status(status, "kmCreateFrameBufferSurface(Back-buffer)");

	kmSetWaitVsyncCount( 0 );	/* No wait V-Sync */

	/*----------------------------------------------------------------------------------- */
	/* set display surface */
	status = kmActivateFrameBuffer(	&PrimarySurfaceDesc,	/* pSurfaceDesc */
									&BackSurfaceDesc,		/* pSurfaceDesc */
									FALSE,					/* bStripBuffer */
									TRUE					/* bWaitVSync */
									);
	Check_Status(status, "kmActivateFrameBuffer");

	/*-----------------------------------------------------------------------------------*/
	/* Initialize DisplayString routine */
	txt_InitDisplayString();

	/*----------------------------------------------------------------------------------- */
	/* some initializes */
	SetTextures   ();
/*	SetContext    (Info); */

	InitContext (&VertexContext01, Info, &TexOpaq);
	InitContext (&VertexContext02, Info, &TexOpaq);
	/* Clear render state */
	VertexContext02.RenderState	= 0;
	/* */
	VertexContext02.RenderState	|= KM_SRCBLENDINGMODE;
	VertexContext02.SRCBlendingMode	= KM_SRCALPHA;
	/* */
	VertexContext02.RenderState	|= KM_DSTBLENDINGMODE;
	VertexContext02.DSTBlendingMode	= KM_INVSRCALPHA;
	/* */
	VertexContext02.RenderState	|= KM_LISTTYPE;
	VertexContext02.ListType	= KM_TRANS_POLYGON;
	/* */
	VertexContext02.RenderState	|= KM_TEXTURESHADINGMODE;
	VertexContext02.TextureShadingMode	= KM_MODULATE_ALPHA;
	/* */
	VertexContext02.RenderState	|= KM_USEALPHA;
	VertexContext02.bUseAlpha = TRUE;
	/* Process & Set Texture */
	status = kmProcessVertexRenderState(&VertexContext02);

	Check_Status(status, "kmProcessVertexRenderState");
	SetBackground (&TexOpaq);
	DisplayInformation ();

	/*-------------------------------------------------------------------------------- */
	/* 性能測定用各種変数の初期化 */
	frame		= 0;
#if defined(_DISP_PERFORMANCE_)
	totalTime	= 0;

	pcount_f = QueryPerformanceFrequency((LARGE_INTEGER*)&freqi);	/* カウンタの単位の読み出し */
	if(pcount_f) {	/*	QueryPerformanceCounterがサポートされている */
		QueryPerformanceCounter((LARGE_INTEGER*)&Time3i);	/* ダミー値による初期化 */
		freq = 1000.0f / (double)freqi;						/* msec変換用係数の生成 */
		OldTime3 = Time3 = (double)Time3i * freq;			/* countからmsecへ変換 */
	}
	else {	/* QueryPerformanceCounterがサポートされていない */
		Time3 = (double)timeGetTime();						/* ダミー値による初期化 */
	}

	/* Get AP start time ---------------------------------------------*/
#if defined(_X86_)
	 time( &start_time );
#endif
#endif	/* defined(_DISP_PERFORMANCE_) */

	/* This function creates an array of structures with 3D data */
	CreateMeshesArray ();
	InitMeshes (NUM_MESHES, (CASTMESHES *) Mesh);

   	while (TRUE)
	{
	
#if defined(_X86_)
	   while(!kbhit())  NextFrame ();
	   Val = _getch ();
      
	   switch (Val)
	   {
			case K_ESC:
			case K_F12:
				 goto Finish;    

	      	case K_F1 :
			     Info.Bilinear = (Info.Bilinear) ? FALSE:TRUE;
				 DisplayInformation ();
				 break;
	
			case K_F2 :
				 Info.Gouraud = (Info.Gouraud) ? FALSE:TRUE;
				 DisplayInformation ();
				 break;
			case K_F3 :
				 Info.Textured = (Info.Textured) ? FALSE:TRUE;
				 DisplayInformation ();
				 break;

	      
			case K_F4:
				 Info.Highlight = (Info.Highlight) ? FALSE:TRUE;
				 DisplayInformation ();
				 break;
	   }
	   Val = 0;
#else	/* not _X86_ */
		ReadMaple ();
		NextFrame ();
#endif
	}

Finish:
    FreeMeshes (NUM_MESHES);
/*	FreeAllBMPTextures (); */
/*	sgl_delete_device(Device); */

	/*----------------------------------------------------------------------------------- */
	/* Free vertex buffer */
	status = kmDiscardVertexBuffer(&VertexBufferDesc);
	Check_Status(status, "kmDiscardVertexBuffer");

	/*----------------------------------------------------------------------------------- */
	/* End display */
	status = kmStopDisplayFrameBuffer();
	Check_Status(status, "kmStopDisplayFrameBuffer");

    return 0;
}
/*-------------------------------------------------------------------------------------*/
void SetTextures (void)
{
#if 0
	TexOpaq = LoadBMPTexture ("Space.bmp", FALSE, TRUE, FALSE);
	/*TexOpaq = LoadVQTexture ("Space.vqf"); */
#endif
	PKMDWORD			pTexture01;				/* Pointer to texture */
	KMTEXTURETYPE		nTextureType;			/* texture type definition */

	/*----------------------------------------------------------------------------------- */
	/* Create texture surface */
	nTextureType = KM_TEXTURE_TWIDDLED_MM | KM_TEXTURE_RGB565;	/* Set texture type */
	status = kmCreateTextureSurface(
		&TexOpaq,				/* OUT	PKMSURFACEDESC	pSurfaceDesc */
		256,					/*	IN	KMINT32			nWidth  */
		256,					/*	IN	KMINT32			nHeight  */
		nTextureType			/*	IN	KMTEXTURETYPE	nTextureType */
	);
	Check_Status(status, "kmCreateTextureSurface #1");
	/*----------------------------------------------------------------------------------- */
	/* Load and set texture */
	pTexture01 = (unsigned long *)&Space;
	status = kmLoadTexture(&TexOpaq,			/* PKMSURFACEDESC pSurfaceDesc */
							pTexture01 + (16 / sizeof(KMDWORD)),			/* PKMDWORD pTexture */
							FALSE,				/* KMBOOLEAN bAutoMipMap */
							FALSE				/* KMBOOLEAN bDither */
							);
	Check_Status(status, "kmLoadTexture #1");
}
/*-------------------------------------------------------------------------------------*/
void NextFrame (void)
{
register i;

 InitScene ();
 

  for (i=0;i<NUM_MESHES; i++)  ResetMatrix (i);


  for (i=0;i<NUM_MESHES; i++) {

		rx += drx;
		ry += dry;
		rz += drz;
		Translate (i, 0.0f, 0.0f, PosZ);
		Rotate   (i, Y_Axe, ry);
		Rotate   (i, X_Axe, rx);
		Rotate   (i, Z_Axe, rz);

		SetSmoothShading (i, (i==1)?C_GREEN: C_RED);
	   if (i==1) {
			/*	Info.VertexAlpha = FALSE; */
			/*	SetContext (Info); */
			/*	SetVertices (i,  TexOpaq, FX_OPTIC);	*/
			SetVertices (i, VertexContext01, FX_OPTIC, Info.Textured);
		}
		else {
			/* Info.VertexAlpha = TRUE; */
			/*	SetContext (Info); */
			/*	SetVertices (i,  TexOpaq, FX_OPTIC);	*/
		SetVertices (i, VertexContext02, FX_OPTIC, Info.Textured);
		}

  }

/*
  Timer (DISPLAY_TIME);
  SetBackground   (TexOpaq);
*/

  EndScene();
  
	pdExecPeripheralServer();
  
     Frame++;
}
/*-------------------------------------------------------------------------------------*/

void DisplayInformation (void)
{
char *Flag[2]   = { "FALSE", "TRUE" };

	txt_SetCursor(0,16);

	PRINTOUT(( "Pad Control\n"));
	PRINTOUT(( " A : Bilinear    %s\n",   Flag[Info.Bilinear]));
	PRINTOUT(( " B : Gouraud     %s\n",   Flag[Info.Gouraud]));
	PRINTOUT(( " X : Textured    %s\n",   Flag[Info.Textured]));
	PRINTOUT(( " Y : HighLight   %s\n",   Flag[Info.Highlight]));

	Timer (RESET_TIME);
}

/*----------------------------------------------------------------------*/
/*  Function Name   : ReadMaple                                         */
/*  Inputs          :                                                   */
/*  Outputs         :                                                   */
/*  Returns         :                                                   */
/*  Globals Used    : PosZ, BlendSrc, BlendDst, AlphaSource,            */
/*                    BlendModulate                                     */
/*  Description     : Read MAPLE status                                 */
/*----------------------------------------------------------------------*/
void ReadMaple (void)
{
	static	int	swadelay = 0;	/* flag for cancel chattering of A button */
	static	int	swbdelay = 0;	/* flag for cancel chattering of B button */
	static	int	swxdelay = 0;	/* flag for cancel chattering of X button */
	static	int	swydelay = 0;	/* flag for cancel chattering of Y button */

	per = njGetPeripheral(NJD_PORT_A0);

		/* START button */
		if ( per->on & NJD_DGT_ST ){
			drx = 0.0f;
			dry = 0.0f;
			drz = 0.0f;
/*			PosZ = 0.0f; */
		}

		/* UP cross key */
		if ( per->on & NJD_DGT_KU ){
				 if(drz > -0.1f) drz -= 0.0002f;
		}
		/* DOWN cross key */
		if ( per->on & NJD_DGT_KD ){
				 if(drz <  0.1f) drz += 0.0002f;
		}
		/* Left cross key */
		if ( per->on & NJD_DGT_KL ){
				 if(dry <  0.1f) dry += 0.0002f;
		}
		/* Right cross key */
		if ( per->on & NJD_DGT_KR ){
				 if(dry > -0.1f) dry -= 0.0002f;
		}

		/* Medama X */
		ry += ((float)per->x1) / 2000.0f;

		/* Medama Y */
		rx += ((float)per->y1) / 2000.0f;

		/* Slider Right */
		PosZ += ((float)per->r) / 100.0f;

		/* Slider Left */
		PosZ -= ((float)per->l) / 100.0f;

		/* A button */
		if ( swadelay == 0 ) {
			if ( per->on & NJD_DGT_TA ){
				Info.Bilinear = (Info.Bilinear) ? FALSE:TRUE;
				SetContext (&VertexContext01, Info, &TexOpaq);
				SetContext (&VertexContext02, Info, &TexOpaq);
				DisplayInformation ();
				swadelay = 1;
			}
		} else {
			if ( per->off & NJD_DGT_TA ){
				swadelay = 0;
			}
		}

		/* B button */
		if ( swbdelay == 0 ) {
			if ( per->on & NJD_DGT_TB ){
				Info.Gouraud = (Info.Gouraud) ? FALSE:TRUE;
				SetContext (&VertexContext01, Info, &TexOpaq);
				SetContext (&VertexContext02, Info, &TexOpaq);
				DisplayInformation ();
				swbdelay = 1;
			}
		} else {
			if ( per->off & NJD_DGT_TB ){
				swbdelay = 0;
			}
		}

		/* X button */
		if ( swxdelay == 0 ) {
			if ( per->on & NJD_DGT_TX ){
				Info.Textured = (Info.Textured) ? FALSE:TRUE;
				SetContext (&VertexContext01, Info, &TexOpaq);
				SetContext (&VertexContext02, Info, &TexOpaq);
				DisplayInformation ();
				swxdelay = 1;
			}
		} else {
			if ( per->off & NJD_DGT_TX ){
				swxdelay = 0;
			}
		}

		/* Y button */
		if ( swydelay == 0 ) {
			if ( per->on & NJD_DGT_TY ){
				Info.Highlight = (Info.Highlight) ? FALSE:TRUE;
				SetContext (&VertexContext01, Info, &TexOpaq);
				SetContext (&VertexContext02, Info, &TexOpaq);
				DisplayInformation ();
				swydelay = 1;
			}
		} else {
			if ( per->off & NJD_DGT_TY ){
				swydelay = 0;
			}
		}

}

/*--------------------------- End of File --------------------------------*/

