/*----------------------------------------------------------------
   Name   : ToyPlane.c  (ARC1 demo - SGL2) 
   Author : Carlos Sarria            
   Date   : September 1997 (updated Jan98)
    
   Copyright : 1998 by VideoLogic Limited. All rights reserved.
   Modified  : 08, 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	"Plane.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		VertexContext;			/* 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;

static float		Frame = 0;
#if 0
static unsigned		TexOpaq, TexBack;
#endif
KMSURFACEDESC		TexOpaq, TexBack;

static sgl_vector	Axis = { 0,1,0},Axis1 = { 0,0,1},Axis2 = { 1,0,0};

/* 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 BuildFogTable       (void);

/* Textures */
extern unsigned char Back;
extern unsigned char Opaq;

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

/****************************************************************************/
/**	Check KAMUI function status *********************************************/
/****************************************************************************/
void	Check_Status(KMSTATUS status, char *func)
{
	switch(status) {
	case KMSTATUS_SUCCESS:
		/* No message is displayed when SUCCESS */
		break;
	case KMSTATUS_INVALID_DISPLAY_MODE:
		PRINTOUT(("%s:KMSTATUS_INVALID_DISPLAY_MODE\n",func)); break;
	case KMSTATUS_INVALID_VIDEO_MODE:
		PRINTOUT(("%s:KMSTATUS_INVALID_VIDEO_MODE\n",func)); break;
	case KMSTATUS_NOT_ENOUGH_MEMORY:
		PRINTOUT(("%s:KMSTATUS_NOT_ENOUGH_MEMORY\n",func)); break;
	case KMSTATUS_INVALID_TEXTURE_TYPE:
		PRINTOUT(("%s:KMSTATUS_INVALID_TEXTURE_TYPE\n",func)); break;
	case KMSTATUS_INVALID_MIPMAPED_TEXTURE:
		PRINTOUT(("%s:KMSTATUS_INVALID_MIPMAPED_TEXTURE\n",func)); break;
	case KMSTATUS_CANT_FLIP_SURFACE:
		PRINTOUT(("%s:KMSTATUS_CANT_FLIP_SURFACE\n",func)); break;
	case KMSTATUS_INVALID_ADDRESS:
		PRINTOUT(("%s:KMSTATUS_INVALID_ADDRESS\n",func)); break;
	case KMSTATUS_HARDWARE_NOT_PRESENTED:
		PRINTOUT(("%s:KMSTATUS_HARDWARE_NOT_PRESENTED\n",func)); break;
	case KMSTATUS_INVALID_SETTING:
		PRINTOUT(("%s:KMSTATUS_INVALID_SETTING\n",func)); break;
	case KMSTATUS_INVALID_VERTEX_TYPE:
		PRINTOUT(("%s:KMSTATUS_INVALID_VERTEX_TYPE\n",func)); break;
	case KMSTATUS_NOT_IMPLEMENTED:
		PRINTOUT(("%s:KMSTATUS_NOT_IMPREMENTED\n",func)); break;
	case KMSTATUS_INVALID_PARAMETER:
		PRINTOUT(("%s:KMSTATUS_INVALID_PARAMETER\n",func)); break;
	default:
		PRINTOUT(("%s:???Undefined status : %d\n", func, status));
		break;
	}
}

/****************************************************************************/
/**	kmtri_triangles  by T.Hirata ********************************************/
/****************************************************************************/
void 
kmtri_triangles ( KMVERTEXBUFFDESC		BufferDesc,
				  KMVERTEXCONTEXT		VertexContext,
				  int  					nNumFaces,
				  int  					pFaces[][3],
				  PSGLVERTEX  			pVertices,
				  int					bTexture)
{
	KMSTATUS	status;
	int			i;
	KMVERTEX_01	Ver01;				/* for NO-TEXTURE-GOURAUD */
	KMVERTEX_03	Ver03;				/* for TEXTURE-GOURAUD */

	status = kmSetVertexRenderState(&VertexContext);
	Check_Status(status, "kmSetVertexRenderState");

	for(i = 0; i < nNumFaces; i++)
	{
		status = kmStartVertexStrip(&BufferDesc);
		Check_Status(status, "kmStartVertexStrip");

		if(bTexture == TRUE) {
			Ver03.ParamControlWord		= KM_VERTEXPARAM_NORMAL;
			Ver03.fX					= pVertices[pFaces[i][0]].fX;
			Ver03.fY					= pVertices[pFaces[i][0]].fY;
#if defined(_STRICT_UNION_)
			Ver03.u.fZ					= pVertices[pFaces[i][0]].fInvW;
#else
			Ver03.fZ					= pVertices[pFaces[i][0]].fInvW;
#endif
			Ver03.fU					= pVertices[pFaces[i][0]].fUOverW;
			Ver03.fV					= pVertices[pFaces[i][0]].fVOverW;
			Ver03.uBaseRGB.dwPacked		= pVertices[pFaces[i][0]].u32Colour;
			Ver03.uOffsetRGB.dwPacked	= pVertices[pFaces[i][0]].u32Specular;
			status = kmSetVertex(&BufferDesc,&Ver03,KM_VERTEXTYPE_03,sizeof(KMVERTEX_03) );
			Check_Status(status, "kmSetVertex");

			Ver03.ParamControlWord		= KM_VERTEXPARAM_NORMAL;
			Ver03.fX					= pVertices[pFaces[i][1]].fX;
			Ver03.fY					= pVertices[pFaces[i][1]].fY;
#if defined(_STRICT_UNION_)
			Ver03.u.fZ					= pVertices[pFaces[i][1]].fInvW;
#else
			Ver03.fZ					= pVertices[pFaces[i][1]].fInvW;
#endif
			Ver03.fU					= pVertices[pFaces[i][1]].fUOverW;
			Ver03.fV					= pVertices[pFaces[i][1]].fVOverW;
			Ver03.uBaseRGB.dwPacked		= pVertices[pFaces[i][1]].u32Colour;
			Ver03.uOffsetRGB.dwPacked	= pVertices[pFaces[i][1]].u32Specular;
			status = kmSetVertex(&BufferDesc,&Ver03,KM_VERTEXTYPE_03,sizeof(KMVERTEX_03) );
			Check_Status(status, "kmSetVertex");

			Ver03.ParamControlWord		= KM_VERTEXPARAM_ENDOFSTRIP;
			Ver03.fX					= pVertices[pFaces[i][2]].fX;
			Ver03.fY					= pVertices[pFaces[i][2]].fY;
#if defined(_STRICT_UNION_)
			Ver03.u.fZ					= pVertices[pFaces[i][2]].fInvW;
#else
			Ver03.fZ					= pVertices[pFaces[i][2]].fInvW;
#endif
			Ver03.fU					= pVertices[pFaces[i][2]].fUOverW;
			Ver03.fV					= pVertices[pFaces[i][2]].fVOverW;
			Ver03.uBaseRGB.dwPacked		= pVertices[pFaces[i][2]].u32Colour;
			Ver03.uOffsetRGB.dwPacked	= pVertices[pFaces[i][2]].u32Specular;
			status = kmSetVertex(&BufferDesc,&Ver03,KM_VERTEXTYPE_03,sizeof(KMVERTEX_03) );
			Check_Status(status, "kmSetVertex");
		}
		else {	/* if(bTexture == TRUE) : NO-TEXTURE */
			Ver01.ParamControlWord	= KM_VERTEXPARAM_NORMAL;
			Ver01.fX				= pVertices[pFaces[i][0]].fX;
			Ver01.fY				= pVertices[pFaces[i][0]].fY;
#if defined(_STRICT_UNION_)
			Ver01.u.fZ				= pVertices[pFaces[i][0]].fInvW;
#else
			Ver01.fZ				= pVertices[pFaces[i][0]].fInvW;
#endif
			Ver01.fBaseAlpha		= GetALPHA(pVertices[pFaces[i][0]].u32Colour);
			Ver01.fBaseRed			= GetRED  (pVertices[pFaces[i][0]].u32Colour);
			Ver01.fBaseGreen		= GetGREEN(pVertices[pFaces[i][0]].u32Colour);
			Ver01.fBaseBlue			= GetBLUE (pVertices[pFaces[i][0]].u32Colour);
			status = kmSetVertex(&BufferDesc,&Ver01,KM_VERTEXTYPE_01,sizeof(KMVERTEX_01) );
			Check_Status(status, "kmSetVertex");

			Ver01.ParamControlWord	= KM_VERTEXPARAM_NORMAL;
			Ver01.fX				= pVertices[pFaces[i][1]].fX;
			Ver01.fY				= pVertices[pFaces[i][1]].fY;
#if defined(_STRICT_UNION_)
			Ver01.u.fZ				= pVertices[pFaces[i][1]].fInvW;
#else
			Ver01.fZ				= pVertices[pFaces[i][1]].fInvW;
#endif
			Ver01.fBaseAlpha		= GetALPHA(pVertices[pFaces[i][1]].u32Colour);
			Ver01.fBaseRed			= GetRED  (pVertices[pFaces[i][1]].u32Colour);
			Ver01.fBaseGreen		= GetGREEN(pVertices[pFaces[i][1]].u32Colour);
			Ver01.fBaseBlue			= GetBLUE (pVertices[pFaces[i][1]].u32Colour);
			status = kmSetVertex(&BufferDesc,&Ver01,KM_VERTEXTYPE_01,sizeof(KMVERTEX_01) );
			Check_Status(status, "kmSetVertex");

			Ver01.ParamControlWord	= KM_VERTEXPARAM_ENDOFSTRIP;
			Ver01.fX				= pVertices[pFaces[i][2]].fX;
			Ver01.fY				= pVertices[pFaces[i][2]].fY;
#if defined(_STRICT_UNION_)
			Ver01.u.fZ				= pVertices[pFaces[i][2]].fInvW;
#else
			Ver01.fZ				= pVertices[pFaces[i][2]].fInvW;
#endif
			Ver01.fBaseAlpha		= GetALPHA(pVertices[pFaces[i][2]].u32Colour);
			Ver01.fBaseRed			= GetRED  (pVertices[pFaces[i][2]].u32Colour);
			Ver01.fBaseGreen		= GetGREEN(pVertices[pFaces[i][2]].u32Colour);
			Ver01.fBaseBlue			= GetBLUE (pVertices[pFaces[i][2]].u32Colour);
			status = kmSetVertex(&BufferDesc,&Ver01,KM_VERTEXTYPE_01,sizeof(KMVERTEX_01) );
			Check_Status(status, "kmSetVertex");
		} /* end of if(bTexture == TRUE) */
	}
}

/****************************************************************************/
/**	Initialize Vertex Context ***********************************************/
/****************************************************************************/
void	InitVertexContext(PKMVERTEXCONTEXT pVertexContext)
{
	/* 頂点CONTEXTの生成 */
	pVertexContext->RenderState	= KM_DEPTHMODE  		| KM_CULLINGMODE
								| KM_SCREENCOORDINATION	| KM_SHADINGMODE
								| KM_MODIFIER 			| KM_ZWRITEDISABLE
								| KM_SRCBLENDINGMODE	| KM_DSTBLENDINGMODE
								| KM_SRCSELECT			| KM_DSTSELECT
								| KM_FOGMODE			| KM_USESPECULAR
								| KM_USEALPHA			| KM_IGNORETEXTUREALPHA
								| KM_FLIPUV 			| KM_CLAMPUV 
								| KM_FILTERMODE			| KM_SUPERSAMPLE
								| KM_MIPMAPDADJUST 		| KM_TEXTURESHADINGMODE
								| KM_PARAMTYPE 			| KM_LISTTYPE
								| KM_COLORTYPE			| KM_USESPECULAR
								| KM_UVFORMAT;

	/* for ParameterControlWord  */
	pVertexContext->ParamType			= KM_POLYGON;
	pVertexContext->ListType			= KM_OPAQUE_POLYGON;
	pVertexContext->ColorType			= KM_PACKEDCOLOR;
	pVertexContext->bUseSpecular		= TRUE;
	pVertexContext->UVFormat			= KM_32BITUV;

	/* for ISP/TSP InstructionWord  */
	pVertexContext->DepthMode			= KM_GREATER;
	pVertexContext->CullingMode			= KM_NOCULLING;
/*	pVertexContext->CullingMode			= KM_CULLSMALL; */
	pVertexContext->ScreenCoordination	= KM_SCREEN;
	pVertexContext->ShadingMode			= KM_NOTEXTUREGOURAUD;
	pVertexContext->SelectModifier		= KM_NOMODIFIER;
	pVertexContext->bZWriteDisable		= FALSE;			/* ARC1にはない */

	/* for TSP ControlWord  */
	pVertexContext->SRCBlendingMode		= KM_ONE;
	pVertexContext->DSTBlendingMode		= KM_ZERO;
	pVertexContext->bSRCSel				= FALSE;			/* ARC1にはない */
	pVertexContext->bDSTSel				= FALSE;			/* ARC1にはない */
	pVertexContext->FogMode				= KM_FOGTABLE;		/* 11はリザーブ */
	pVertexContext->bUseSpecular		= TRUE;
	pVertexContext->bUseAlpha			= FALSE;
	pVertexContext->FlipUV				= KM_NOFLIP;
	pVertexContext->ClampUV				= KM_NOCLAMP;
	pVertexContext->FilterMode			= KM_POINT_SAMPLE;
/*	pVertexContext->FilterMode			= KM_BILINEAR; */
	pVertexContext->bSuperSample		= FALSE;
	pVertexContext->MipMapAdjust		= 0x00000004;		/* D=1.00 */
	pVertexContext->TextureShadingMode	= KM_MODULATE;
/*	pVertexContext->TextureShadingMode	= KM_MODULATE_ALPHA; */
	
	/* for Texture ControlBit */

	/* No effect on ARC1 */
	pVertexContext->bColorClamp		= FALSE;
	pVertexContext->PaletteBank		= 0;

	/* for GlobalColorData */
	pVertexContext->fFaceColorAlpha		= 1.0f;		/* Face Color Alpha */
	pVertexContext->fFaceColorRed		= 1.0f;		/* Face Color Red */
	pVertexContext->fFaceColorGreen		= 1.0f;		/* Face Color Green */
	pVertexContext->fFaceColorBlue		= 1.0f;		/* Face Color Blue */
	pVertexContext->fOffsetColorAlpha	= 1.0f;		/* Specular Color Alpha */
	pVertexContext->fOffsetColorRed		= 1.0f;		/* Specular Color Red */
	pVertexContext->fOffsetColorGreen	= 1.0f;		/* Specular Color Green */
	pVertexContext->fOffsetColorBlue	= 1.0f;		/* Specular Color Blue */

	kmProcessVertexRenderState(pVertexContext);
}

/*-------------------------------------------------------------------------------------*/
/*                                       MAIN                                          */
/*-------------------------------------------------------------------------------------*/
int main (void)
{
KMPACKEDARGB   cBorder;
int Control = 0, Device, Val = 0;

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

	txt_ClearScreen();	/* Clear text screen */
	PRINTOUT(("** Toy Plane : Fog test 2V Latency Opq Direct **\n\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);
	PRINTOUT(("MajorVersion      0x0%08x\n",VersionInfo.kmMajorVersion));
	PRINTOUT(("LocalVersion      0x0%08x\n",VersionInfo.kmLocalVersion));
	PRINTOUT(("kmFrameBufferSize 0x0%08x\n",VersionInfo.kmFrameBufferSize));

	/*----------------------------------------------------------------------------------- */
	/* Set Latency Model */
	kmChangeLatencyModel(KM_LATENCYMODEL_2V, KM_VERTEXBUFMODEL_NOBUF_OPAQUE); 

	/*----------------------------------------------------------------------------------- */
	/* 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);
/*	SetBackground ((PKMSURFACEDESC)NULL); */
	BuildFogTable ();
	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 (it is in Plane.h)*/
	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_F8:
				 Info.Stop = (Info.Stop) ? FALSE:TRUE;
				 DisplayInformation ();
				 break;
		   		
            case K_F5 :
				 Info.TableFog = (Info.TableFog) ? FALSE:TRUE;
				 DisplayInformation ();
				 break;
			case K_F4 :
				 Info.Highlight = (Info.Highlight) ? FALSE:TRUE;
				 DisplayInformation ();
				 break;
	   }
	   Val = 0;
#else	/* not _X86_ */
		NextFrame ();
		/* Change fog density */
		if((frame % 400) == 0) {
			FogDensity += FogD;	/* FF09 - FF0D */
			if(FogDensity > 0xFF0E) { FogDensity = 0xFF0D; FogD = -FogD; }
			if(FogDensity < 0xFF09) { FogDensity = 0xFF0A; FogD = -FogD; }
			status = kmSetFogDensity(FogDensity);
			Check_Status(status, "kmSetFogDensity");
			DisplayInformation ();
		}
#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 ("Wood.bmp", FALSE, TRUE, FALSE); */
	TexBack  = LoadBMPTexture ("Backgrnd.bmp", FALSE, TRUE, FALSE);

	TexOpaq  = LoadVQTexture ("Wood.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(
		&TexOpaq,				/* OUT	PKMSURFACEDESC	pSurfaceDesc */
		256,					/*	IN	KMINT32			nWidth  */
		256,					/*	IN	KMINT32			nHeight  */
		nTextureType			/*	IN	KMTEXTURETYPE	nTextureType */
	);
	Check_Status(status, "kmCreateTextureSurface #2");
	/*----------------------------------------------------------------------------------- */
	/* Load and set texture */
	pTexture01 = (unsigned long *)&Back;
	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 *)&Opaq;
	status = kmLoadTexture(&TexOpaq,			/* PKMSURFACEDESC pSurfaceDesc */
							pTexture01 + (16 / sizeof(KMDWORD)),			/* PKMDWORD pTexture */
							FALSE,				/* KMBOOLEAN bAutoMipMap */
							FALSE				/* KMBOOLEAN bDither */
							);
	Check_Status(status, "kmLoadTexture #2");

}
/*-------------------------------------------------------------------------------------*/
void NextFrame (void)
{
register i;
float Speed = 15.0f;

  InitScene (); 

  SetContext (Info);

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

  Speed = Frame/20.0f; 

   /*  The plane   */
   for (i=0;i<NUM_MESHES; i++) 
   {
       Translate (i, cos(Speed)*500, 0, -sin(Speed)*700+800);
       Rotate   (i, Axis, Speed);
	   Rotate   (i, Axis1, PI/8.0f);

	   if (i==HELIX) Rotate   (i, Axis1, Frame);

	   SetSmoothShading (i, C_NONE);
/*		SetVertices (i,  TexOpaq, FX_NONE); */
		SetVertices (i, TexOpaq, FX_NONE, FALSE, Info);
   }

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



   EndScene();


/*   if (Info.Stop==0) Frame++; */
	Frame++;

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

	txt_SetCursor(0,21);

	PRINTOUT(( " Fog Density : %08Xh\n",  FogDensity ));

	PRINTOUT(( " F1 : Bilinear    %s\n",   Flag[Info.Bilinear]));
	PRINTOUT(( " F2 : Gouraud     %s\n",   Flag[Info.Gouraud]));
	PRINTOUT(( " F3 : Textured    %s\n",   Flag[Info.Textured]));
	PRINTOUT(( " F4 : HighLight   %s\n",   Flag[Info.Highlight]));
	PRINTOUT(( " F5 : Table Fog   %s\n\n", Flag[Info.VertexFog]));

/*	Timer (RESET_TIME); */
}
/*------------------------------------------------------------------------------------*/
void BuildFogTable (void)
{
#if 0
SGL_FOG SGLfog;
PSGL_FOGTABLE FogTable;
int NumEntries = 0, i;

	  /* 
	     This piece of code shows how to use high-level fog tables. 
	     You can select one of the three pre-defined modes:
		 sgl_linear_fog, sgl_exp_fog and sgl_exp2_fog

	       SGLfog.fog_density = 0.7f;
           SGLfog.w_start = 1.0f / 10.0f;
	       sgl_exp_fog (&SGLfog);

           return;
      */
	 
	  /*  
	   * This is low-level fog  (all densities must be defined here) 
	   */

      /* sgl_prepare_fog_table returns the number of available entries,
	     so it must be called once with NULL in the second parameter to know 
		 that figure.
	  */
	  NumEntries = sgl_prepare_fog_table (0.1f, NULL);

	  FogTable = (SGL_FOGTABLE *) malloc (sizeof(SGL_FOGTABLE)*NumEntries);

	  sgl_prepare_fog_table (1.0f/10.0f, FogTable);

	  for (i=0; i<NumEntries; i++)
	  {
		   /* The fog value must be any value between 1.0f(soap) and 0.0f(no fog). 
		      In this case the intensity change from 0 to 1 linearly.             
		   */
		    (FogTable+i)->fog_density = (float)i/(float)NumEntries;
	  }

	  sgl_load_fog_table (FogTable);
#endif

	int				i;
	KMPACKEDARGB	fogcol;
	KMFLOAT			FogTable[128];

	/* Fog Color */
	fogcol.byte.bBlue	= 0.5 * 255;
	fogcol.byte.bGreen	= 0.5 * 255;
	fogcol.byte.bRed	= 0.5 * 255;
	status = kmSetFogTableColor(fogcol);
	Check_Status(status, "kmSetFogTableColor");

	/* Fog Density */
	FogDensity = 0xFF0B;		/* FF09 - FF0D */
/*	status = kmSetFogDensity(0xFF09); */
	status = kmSetFogDensity(FogDensity);
	Check_Status(status, "kmSetFogDensity");

	/* Fog Table */
	for(i = 0; i < 128; i++) {
/*		// Linear Fog table ---------------------------------------------*/
/*		FogTable[i] = 1.0f - ((float)i / 128.0f); */
/*		// PCX Fog table ------------------------------------------------*/
/*		FogTable[i] = (float)PCXFogTable[i] / 256.0f; */
/*		// Slope Fog table ----------------------------------------------*/
#define	FOG_MIN		(-0.8f)
		FogTable[i] = 1.0f - (float)i * ((1.0f - FOG_MIN) / 128.0f);
		if(FogTable[i] < 0.0f) FogTable[i] = 0.0f;
	}
	status = kmSetFogTable(&FogTable[0]);
	Check_Status(status, "kmSetFogTable");

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

