/*----------------------------------------------------------------
   Name   : Strips.c  (ARC1 demo) 
   Author : Carlos Sarria            
   Date   : Jan 1998
    
   Copyright : 1998 by VideoLogic Limited. All rights reserved.
   Modified  : 23, June, 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>
--*/

#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	"kmstrips.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;

int			Frame = 0;
int			nCylinders = 10;
int			nStrip = 10;
sgl_vector	X_Axle = { 1, 0, 0 }, Y_Axle = { 0, 1, 0 }, Z_Axle = { 0, 0, 1 };
#if 0
unsigned	TexStrip,TexStrip1, TexBack;
#endif
KMSURFACEDESC	TexStrip,TexStrip1, TexBack;

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

/* Prototypes */

static void SetTextures			(void);
static void NextFrame			(void);
static void DisplayInformation	(void);
void InitContext (PKMVERTEXCONTEXT pVertexContext, INFO CInfo, PKMSURFACEDESC pTexture);
void SetContext (PKMVERTEXCONTEXT pVertexContext, INFO CInfo, PKMSURFACEDESC pTexture);
static void ReadMaple (void);

/* Textures */
extern unsigned char Backgrnd;
extern unsigned char Strip;
extern unsigned char Strip1;

/* Macros for kamui */
#define		GetRED(col)			((KMFLOAT) ( ((col) & 0x00ff0000) >> 16 ) / 256.0f)
#define		GetGREEN(col)		((KMFLOAT) ( ((col) & 0x0000ff00) >>  8 ) / 256.0f)
#define		GetBLUE(col)		((KMFLOAT) ( ((col) & 0x000000ff)       ) / 256.0f)
#define		GetALPHA(col)		((KMFLOAT) ( ((col) & 0xff000000) >> 24 ) / 256.0f)

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

NJS_PERIPHERAL *per;

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

#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(("** Strips **\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

	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 1MB */
									0,						/* Opaque-Modifier */
									262144,					/* Trans-Polygon 1MB */
									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 */
	/* SetContext  (Info); */
	SetTextures ();
	SetBackground (&TexBack);
	InitContext (&VertexContext01, Info, &TexStrip);
	InitContext (&VertexContext02, Info, &TexStrip1);

	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_) */

	InitMeshes ();

   	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.Textured = (Info.Textured) ? FALSE:TRUE;
				 DisplayInformation ();
				 break;
	      
			case K_F3 :
				 Info.Strips = (Info.Strips) ? FALSE:TRUE;
				 DisplayInformation ();
				 break;
	   }
	   Val = 0;
#else	/* not _X86_ */
		ReadMaple ();
		NextFrame ();
#endif
	}

Finish:

    FreeMeshes ();
/*	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
	/*TexStrip  = LoadBMPTexture ("Strip.bmp", FALSE, TRUE, FALSE); */
	/*TexStrip1 = LoadBMPTexture ("Strip1.bmp", FALSE, TRUE, FALSE); */
	TexBack   = LoadBMPTexture ("backgrnd.bmp", FALSE, TRUE, FALSE);
	
	TexStrip  = LoadVQTexture ("Strip.vqf");
	TexStrip1 = LoadVQTexture ("Strip1.vqf");
	/*TexBack   = LoadVQTexture ("backgrnd.vqf"); */
#endif

	PKMDWORD			pTexture01;				/* Pointer to texture */
	KMTEXTURETYPE		nTextureType;			/* texture type definition */

	/*----------------------------------------------------------------------------------- */
	/* Create texture surface */
	nTextureType = KM_TEXTURE_TWIDDLED | KM_TEXTURE_RGB565;	/* Set texture type */
	status = kmCreateTextureSurface(
		&TexBack,				/* OUT	PKMSURFACEDESC	pSurfaceDesc */
		256,					/*	IN	KMINT32			nWidth  */
		256,					/*	IN	KMINT32			nHeight  */
		nTextureType			/*	IN	KMTEXTURETYPE	nTextureType */
	);
	Check_Status(status, "kmCreateTextureSurface #1");
	/*----------------------------------------------------------------------------------- */
	/* Create texture surface */
	nTextureType = KM_TEXTURE_TWIDDLED_MM | KM_TEXTURE_RGB565;	/* Set texture type */
	status = kmCreateTextureSurface(
		&TexStrip,				/* OUT	PKMSURFACEDESC	pSurfaceDesc */
		128,					/*	IN	KMINT32			nWidth  */
		128,					/*	IN	KMINT32			nHeight  */
		nTextureType			/*	IN	KMTEXTURETYPE	nTextureType */
	);
	Check_Status(status, "kmCreateTextureSurface #2");
	/*----------------------------------------------------------------------------------- */
	/* Create texture surface */
	nTextureType = KM_TEXTURE_TWIDDLED_MM | KM_TEXTURE_RGB565;	/* Set texture type */
	status = kmCreateTextureSurface(
		&TexStrip1,				/* OUT	PKMSURFACEDESC	pSurfaceDesc */
		128,					/*	IN	KMINT32			nWidth  */
		128,					/*	IN	KMINT32			nHeight  */
		nTextureType			/*	IN	KMTEXTURETYPE	nTextureType */
	);
	Check_Status(status, "kmCreateTextureSurface #3");
	/*----------------------------------------------------------------------------------- */
	/* Load and set texture */
	pTexture01 = (unsigned long *)&Backgrnd;
	status = kmLoadTexture(&TexBack,			/* PKMSURFACEDESC pSurfaceDesc */
							pTexture01 + (16 / sizeof(KMDWORD)),			/* PKMDWORD pTexture */
							FALSE,				/* KMBOOLEAN bAutoMipMap */
							FALSE				/* KMBOOLEAN bDither */
							);
	Check_Status(status, "kmLoadTexture #1");
	/*----------------------------------------------------------------------------------- */
	/* Load and set texture */
	pTexture01 = (unsigned long *)&Strip;
	status = kmLoadTexture(&TexStrip,			/* PKMSURFACEDESC pSurfaceDesc */
							pTexture01 + (16 / sizeof(KMDWORD)),			/* PKMDWORD pTexture */
							FALSE,				/* KMBOOLEAN bAutoMipMap */
							FALSE				/* KMBOOLEAN bDither */
							);
	Check_Status(status, "kmLoadTexture #2");
	/*----------------------------------------------------------------------------------- */
	/* Load and set texture */
	pTexture01 = (unsigned long *)&Strip1;
	status = kmLoadTexture(&TexStrip1,			/* PKMSURFACEDESC pSurfaceDesc */
							pTexture01 + (16 / sizeof(KMDWORD)),			/* PKMDWORD pTexture */
							FALSE,				/* KMBOOLEAN bAutoMipMap */
							FALSE				/* KMBOOLEAN bDither */
							);
	Check_Status(status, "kmLoadTexture #3");

}
/*-------------------------------------------------------------------------------------*/
void NextFrame (void)
{
register i,j;

    InitScene (); /* Call to sgltri_startofframe */
	
	for (i=0; i<10; i++)  ResetMatrix (i);

	for (j=0; j<nCylinders; j++) /* 10 cylinders */
		{
		for (i=0; i<10; i++) { /* 10 strips (30 faces) in each cylinder  */
			Rotate (i, Y_Axle, (PI/(255+i))*Frame);
			Rotate (i, Z_Axle, (PI/(555+i))*Frame);
		}
/*		SetContext (Info); */
		SetStrips (Info.Strips, nStrip); /* Draw 10 strips in just one call. */
	}

/*	Timer(DISPLAY_TIME); */
/*	SetBackground (TexBack); */
	
	EndScene(); /* Call to sgltri_render */
  
	pdExecPeripheralServer();
  
    Frame+=1;
}
/*-------------------------------------------------------------------------------------*/

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

	txt_SetCursor(0,14);

	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(( "Geometry  %s\n", StrTri[Info.Strips]));
	PRINTOUT(( "Cylinders : %4d\nStrips    : %4d\nFaces     : %4d",nCylinders, nStrip, (nCylinders * nStrip * 30 ) ));

/*	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 */
	static	float	nStrip2 = 10.0f;
	static	float	nCylinders2 = 10.0f;

	per = njGetPeripheral(NJD_PORT_A0);

		/* UP cross key */
		if ( per->on & NJD_DGT_KU ){
			nStrip2 += 0.1f;
			if(nStrip2 > 10.0f) nStrip2 = 10.0f;
			nStrip = (int)nStrip2;
			DisplayInformation ();
		}
		/* DOWN cross key */
		if ( per->on & NJD_DGT_KD ){
			nStrip2 -= 0.1f;
			if(nStrip2 < 1.0f) nStrip2 = 1.0f;
			nStrip = (int)nStrip2;
			DisplayInformation ();
		}
		/* Left cross key */
		if ( per->on & NJD_DGT_KL ){
			nCylinders2 += 0.1f;
			if(nCylinders2 > 10.0f) nCylinders2 = 10.0f;
			nCylinders = (int)nCylinders2;
			DisplayInformation ();
		}
		/* Right cross key */
		if ( per->on & NJD_DGT_KR ){
			nCylinders2 -= 0.1f;
			if(nCylinders2 < 1.0f) nCylinders2 = 1.0f;
			nCylinders = (int)nCylinders2;
			DisplayInformation ();
		}

		/* A button */
		if ( swadelay == 0 ) {
			if ( per->on & NJD_DGT_TA ){
				Info.Bilinear = (Info.Bilinear) ? FALSE:TRUE;
				SetContext (&VertexContext01, Info, &TexStrip);
				SetContext (&VertexContext02, Info, &TexStrip1);
				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, &TexStrip);
				SetContext (&VertexContext02, Info, &TexStrip1);
				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, &TexStrip);
				SetContext (&VertexContext02, Info, &TexStrip1);
				DisplayInformation ();
				swxdelay = 1;
			}
		} else {
			if ( per->off & NJD_DGT_TX ){
				swxdelay = 0;
			}
		}

		/* Y button */
		if ( swydelay == 0 ) {
			if ( per->on & NJD_DGT_TY ){
				swydelay = 1;
			}
		} else {
			if ( per->off & NJD_DGT_TY ){
				swydelay = 0;
			}
		}

}

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

