/********************************************************************************/
/* Name     : kmDirectSeal */
/* Title    : KAMUI test program "DirectSeal" from VL */
/* Author   : VideoLogic Carlos Sarria / NEC Software Takeshi Muto */
/* Created  : March 1997 by VideoLogic */
/* Modified : Octover 18. 1997 by Takeshi Muto for KAMUI */
/*            April   16. 1998 by Takeshi Muto for KAMUI SET5 */
/* Description :  */
/********************************************************************************/
/*
#define		_X86_
*/
/* _X86_ flag for win95 : SET2 */

#define		FRAMES			(1000000)				/* rendering frame number */
#define		SPEED			(1.5f)					/* pet move speed ( 1 to n ) */

#define		SUPERSAMPLE		TRUE
/*#define		SUPERSAMPLE		FALSE*/
/* Super sample filter mode */

#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	<io.h>
#include	<FCNTL.H>
--*/

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

#include	"kamui.h"				/* for Kamui Call */
#include	"dispstr.h"				/* for DisplayString */

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

extern const unsigned char ground[];
extern const unsigned char sea[];
extern const unsigned char seal[];
extern const unsigned char sky[];

/*#include	"frontend.h" */

/*******************************************************************************/

#pragma warning (disable : 4244)  /* Float to Double Conversion Warning */
#pragma warning (disable : 4056)

/*#define NAMED_ITEM  TRUE */
/*#define UNAMED_ITEM FALSE */

#define PI (3.142f)

/*#define RGBColour(r, g, b) ((sgl_uint32) (((r) << 16) | ((g) << 8) | (b))) */
#define	RGBColour(r, g, b)	((KMUINT32) (((r) << 16) | ((g) << 8) | (b)))
#define	RGBA(r, g, b, a)	((KMUINT32) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)))

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

/* SGL互換TYPE */
typedef float	km_vector[3];	/* type of sgl_vector */
typedef float	km_2d_vec[2];	/* type of sgl_2d_vec */
typedef float	km_colour[3];	/* type of sgl_colour */
/* --------- */
/* SGLVERTEX */
/* --------- */
/* This structure is currently physically equivalent to Direct3D's D3DTLVERTEX */
/* (so one can be cast to the other), with the exception that Direct3D's u and */
/* v values must be multiplied by the 1/w value.  RAVE vertices already contain */
/* u/w and v/w. */
typedef struct tagSGLVERTEX
{
	/* Projected screen coordinates: */
	float		fX;		/* 0 <= fX < screen width (up to 1024) */
	float		fY;		/* 0 <= fY < screen height (up to 1024) */
	float		fZ;		/* 0.01 <= fZ <= 1, where 1 is infinite distance away */
	/* 1/w for the perspective projection (should be set to 1.0/fZ; fZ is */
	/* actually ignored): */
	float		fInvW;
	KMUINT32	u32Colour;			/* Material colour (D3DCOLOR format): */
	KMUINT32	u32Specular;		/* Specular colour (D3DCOLOR format): */
	float		fUOverW, fVOverW;	/* Texture coordinates: */
} SGLVERTEX, *PSGLVERTEX;

/****************************************************************************/
/**	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 */
	KMSURFACEDESC		SeaTex;					/* texture surface */
	KMSURFACEDESC		SealTex;				/* texture surface */
	KMSURFACEDESC		GroundTex;				/* texture surface */
	KMSURFACEDESC		SkyTex;					/* texture surface */
	KMVERTEXBUFFDESC	VertexBufferDesc;		/* Vertex-buffer */
	KMVERTEXCONTEXT		VertexContextGround;	/* Vertex context */
	KMVERTEXCONTEXT		VertexContextSky;		/* Vertex context */
	KMVERTEXCONTEXT		VertexContextSea;		/* Vertex context */
	KMVERTEXCONTEXT		VertexContextSeal;		/* Vertex context */

/* 性能測定用変数 */
	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 -----------------------------------*/
int Spd, Poll;

km_vector PetPath [20];
float	PetTime		=  0.0f, VelH = 0.3f;
float	PetPosY		= 10.0f, dY   = 0.3f,   Radius = 50.0f,   TPet = 3.0f;
float	SeaFrame	= 10.0f, SF   = 1.0f;
float	SkyFrame	= 10.0f;

km_colour	PollCol[3] = {{0.1f,0.5f,0.7f},{0.1f,0.3f,0.5f},{0.1f,0.1f,0.1f}};
int			PollFog[3] = { 9, 10, 12}; 

float CamFocus = 1500.0;

/*SGLCONTEXT SGLContext; */
SGLVERTEX  SealVert  [20*10],   ShadowVert  [2*11];
int        SealFaces [20*9][4], ShadowFaces [11][4];


/* PCX : SGL-Direct fog table */
static KMUINT32 PCXFogTable[]={
	0x000000ff,	0x000000fe,	0x000000fd,	0x000000fb,	0x000000fa,	0x000000f9,	0x000000f7,	0x000000f6,
	0x000000f5,	0x000000f3,	0x000000f2,	0x000000f1,	0x000000ef,	0x000000ee,	0x000000ed,	0x000000ec,
	0x000000ea,	0x000000e9,	0x000000e8,	0x000000e6,	0x000000e5,	0x000000e4,	0x000000e3,	0x000000e2,
	0x000000e0,	0x000000df,	0x000000de,	0x000000dd,	0x000000db,	0x000000da,	0x000000d9,	0x000000d8,
	0x000000d7,	0x000000d6,	0x000000d4,	0x000000d3,	0x000000d2,	0x000000d1,	0x000000d0,	0x000000cf,
	0x000000ce,	0x000000cd,	0x000000cb,	0x000000ca,	0x000000c9,	0x000000c8,	0x000000c7,	0x000000c6,
	0x000000c5,	0x000000c4,	0x000000c3,	0x000000c2,	0x000000c1,	0x000000c0,	0x000000bf,	0x000000be,
	0x000000bd,	0x000000bc,	0x000000ba,	0x000000b9,	0x000000b8,	0x000000b7,	0x000000b6,	0x000000b6,
	0x000000b5,	0x000000b4,	0x000000b3,	0x000000b2,	0x000000b1,	0x000000b0,	0x000000af,	0x000000ae,
	0x000000ad,	0x000000ac,	0x000000ab,	0x000000aa,	0x000000a9,	0x000000a8,	0x000000a7,	0x000000a6,
	0x000000a5,	0x000000a5,	0x000000a4,	0x000000a3,	0x000000a2,	0x000000a1,	0x000000a0,	0x0000009f,
	0x0000009e,	0x0000009e,	0x0000009d,	0x0000009c,	0x0000009b,	0x0000009a,	0x00000099,	0x00000099,
	0x00000098,	0x00000097,	0x00000096,	0x00000095,	0x00000094,	0x00000094,	0x00000093,	0x00000092,
	0x00000091,	0x00000090,	0x00000090,	0x0000008f,	0x0000008e,	0x0000008d,	0x0000008d,	0x0000008c,
	0x0000008b,	0x0000008a,	0x0000008a,	0x00000089,	0x00000088,	0x00000087,	0x00000087,	0x00000086,
	0x00000085,	0x00000084,	0x00000084,	0x00000083,	0x00000082,	0x00000082,	0x00000081,	0x00000080
};

/*----------------------------  Routines Prototypes ---------------------------------*/

void SetupContext  (void),
     SetupPet      (void),
     SetupTextures (void);

void DrawGround    (void),
     DrawSky       (void),
     DrawSea       (void),
     MovePet       (void),
     DrawPet       (void);

void Perspect      (const km_vector Point3D, SGLVERTEX *Vert);

/****************************************************************************/
/**	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;
	}
}

/****************************************************************************/
/**	Background surface setting **********************************************/
/****************************************************************************/
void	InitBackGround(void)
{
	KMSTATUS			status;
	KMVERTEXCONTEXT		BackVertexContext;		/* Vertex context */
	KMVERTEX_00			BV[3];					/* pointer to Vertex */
	PVOID				pBV[3];					/* pointer to Vertex */

	/* Clear VertexContext */
	memset(&BackVertexContext,0,sizeof(KMVERTEXCONTEXT));

	/* Setup VertexContext */
	BackVertexContext.RenderState	= KM_DEPTHMODE  		| KM_CULLINGMODE				/* ISP/TSP IW */
									| KM_SCREENCOORDINATION	| KM_SHADINGMODE
									| KM_MODIFIER 			| KM_ZWRITEDISABLE				/* TSP CW */
									| KM_SRCBLENDINGMODE
									| 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 					/* Param CW */
									| KM_COLORTYPE			| KM_USESPECULAR
									| KM_UVFORMAT;

	/* for ParameterControlWord  */
	BackVertexContext.ParamType				= KM_POLYGON;
	BackVertexContext.ListType				= KM_OPAQUE_POLYGON;
	BackVertexContext.ColorType				= KM_PACKEDCOLOR;
	BackVertexContext.bUseSpecular			= FALSE;
	BackVertexContext.UVFormat				= KM_32BITUV;

	/* for ISP/TSP InstructionWord  */
	BackVertexContext.DepthMode				= KM_GREATER;
	BackVertexContext.CullingMode			= KM_NOCULLING;
	BackVertexContext.ScreenCoordination	= KM_SCREEN;
	BackVertexContext.ShadingMode			= KM_NOTEXTUREGOURAUD;
	BackVertexContext.SelectModifier		= KM_NOMODIFIER;
	BackVertexContext.bZWriteDisable		= FALSE;			/* not effective on ARC1 */

	/* for TSP ControlWord  */
	BackVertexContext.SRCBlendingMode		= KM_ONE;
/*	BackVertexContext.DSTBlendingMode		= KM_ZERO;	// must not set this parameter on background plane */
	BackVertexContext.bSRCSel				= FALSE;			/* not effective on ARC1 */
	BackVertexContext.bDSTSel				= FALSE;			/* not effective on ARC1 */
	BackVertexContext.FogMode				= KM_FOGTABLE;		/* 11 is reserved */
	BackVertexContext.bUseSpecular			= FALSE;
	BackVertexContext.bUseAlpha				= FALSE;
	BackVertexContext.ClampUV				= KM_NOCLAMP;
	BackVertexContext.FilterMode			= KM_POINT_SAMPLE;
	BackVertexContext.bSuperSample			= FALSE;/*SUPERSAMPLE;*/
	BackVertexContext.MipMapAdjust			= 0x00000004;		/* D=1.00 */
	BackVertexContext.TextureShadingMode	= KM_MODULATE;
	
	/* for Texture ControlBit */

	/* No effect on ARC1 */
	BackVertexContext.bColorClamp			= FALSE;
	BackVertexContext.PaletteBank			= 0;

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

	status = kmProcessVertexRenderState(&BackVertexContext);
	Check_Status(status, "kmProcessVertexRenderState");
	status = kmSetBackGroundRenderState(&BackVertexContext);
	Check_Status(status, "kmSetBackGroundRenderState");

	/*----------------------------------------------------------------------------------- */
	/* set VERTEX DATA */

	/* Vertex #1 */
	BV[0].ParamControlWord	= KM_VERTEXPARAM_NORMAL;
	BV[0].fX				=  2.0f;	
	BV[0].fY				= 260.0f;
#if defined(_STRICT_UNION_)
	BV[0].u.fZ				=  0.0001f;
#else
	BV[0].fZ				=  0.0001f;
#endif
	BV[0].uBaseRGB.dwPacked	= RGBA(0, 0, 0, 255);

	/* Vertex #2 */
	BV[1].ParamControlWord	= KM_VERTEXPARAM_NORMAL;
	BV[1].fX				= 150.0f;	
	BV[1].fY				=  2.0f;
#if defined(_STRICT_UNION_)
	BV[1].u.fZ				=  0.0001f;
#else
	BV[1].fZ				=  0.0001f;
#endif
	BV[1].uBaseRGB.dwPacked	= RGBA(0, 0, 0, 255);

	/* Vertex #3 */
	BV[2].ParamControlWord	= KM_VERTEXPARAM_ENDOFSTRIP;
	BV[2].fX				= 560.0f;	
	BV[2].fY				= 260.0f;
#if defined(_STRICT_UNION_)
	BV[2].u.fZ				=  0.0001f;
#else
	BV[2].fZ				=  0.0001f;
#endif
	BV[2].uBaseRGB.dwPacked	= RGBA(0, 0, 0, 255);

	pBV[0] = &BV[0];
	pBV[1] = &BV[1];
	pBV[2] = &BV[2];

	/*----------------------------------------------------------------------------------- */
	/* set VERTEX */
	status = kmSetBackGroundPlane(	pBV,					/* pVertex */
									KM_VERTEXTYPE_00,		/* VertexType */
									sizeof(KMVERTEX_00)		/* StructSize */
									);
	Check_Status(status, "kmSetBackGroundPlane");
}

/****************************************************************************/
/**	kmtri_quads  by T.Hirata ************************************************/
/****************************************************************************/
void 
kmtri_quads (	KMVERTEXBUFFDESC	BufferDesc,
				KMVERTEXCONTEXT		VertexContext,
				int  nNumFaces,
				int  pFaces[][4],
				PSGLVERTEX  pVertices )
{
	KMSTATUS	status;
	int			i;
	KMVERTEX3	Ver;

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

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

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

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

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

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

/****************************************************************************/
/**	kmtri_triangles  by T.Hirata ********************************************/
/****************************************************************************/
void 
kmtri_triangles ( KMVERTEXBUFFDESC		BufferDesc,
				  KMVERTEXCONTEXT		VertexContext,
				  int  					nNumFaces,
				  int  					pFaces[][3],
				  PSGLVERTEX  			pVertices )
{
	KMSTATUS	status;
	int			i;
	KMVERTEX3	Ver03;

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

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

		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");
	}
}

/****************************************************************************/
/**	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		= FALSE;
	pVertexContext->UVFormat			= KM_32BITUV;

	/* for ISP/TSP InstructionWord  */
	pVertexContext->DepthMode			= KM_GREATER;
	pVertexContext->CullingMode			= KM_NOCULLING;
	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->FogMode				= KM_NOFOG;*/
	pVertexContext->bUseSpecular		= FALSE;
	pVertexContext->bUseAlpha			= FALSE;
	pVertexContext->FlipUV				= KM_NOFLIP;
	pVertexContext->ClampUV				= KM_NOCLAMP;
/*	pVertexContext->FilterMode			= KM_POINT_SAMPLE; */
	pVertexContext->FilterMode			= KM_BILINEAR;
	pVertexContext->bSuperSample		= FALSE;/*SUPERSAMPLE;*/
	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);
}

#if 0
/****************************************************************************/
/**	Load texture ************************************************************/
/****************************************************************************/
PKMDWORD LoadTextureFile(char *filename)
{
	int			hFile;
	long		filelen;
	PKMDWORD	pTexture;

	/* Open input file */
	hFile = _open(filename, _O_RDONLY | _O_BINARY);
	if(hFile != -1) {
		filelen = _filelength(hFile);			/* length of texture file */
		pTexture = (PKMDWORD)malloc(filelen);	/* allocate mainmemory */
		_read(hFile, pTexture, filelen);		/* read in texture file */
		_close(hFile);							/* file close */
		printf("LoadTextureFile: Texture file %s load OK.\n",filename);
	}
	else {
		printf("LoadTextureFile: ??ERROR Can not read texture file %s .\n",filename);
	}
	return pTexture;
}
#endif

/*-------------------------------------------------------------------------------------*/
/*  Function Name   :   SetupScene                                                     */ 
/*  Inputs          :   None                                                           */  
/*  Outputs         :   None                                                           */
/*  Returns         :   Error message or 0                                             */
/*  Globals Used    :   Device                                                         */
/*  Description     :   This routine is used to set SGL device and setup some values.  */
/*                      This routine is called from FRONTEND.C                           */
/*-------------------------------------------------------------------------------------*/
int SetupScene (void)
{
KMPACKEDARGB   cBorder;

   
 /*  Device = sgl_create_screen_device (0, 640, 480, sgl_device_16bit, FALSE); */
 /*  if (Device<0) return ERR_CREATE_SCREEN_DEVICE; */

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

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

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

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

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

	/*----------------------------------------------------------------------------------- */
	/* Fog Setting */

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

	/* Fog Density */
	status = kmSetFogDensity(0xFF09);
	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");


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

	/*-------------------------------------------------------------------------------- */
	/* 性能測定用各種変数の初期化 */

	/*----------------------------------------------------------------------------------- */
	/* some initializes */

	SetupTextures ();			/* Create texture surface & Load texture file */
	SetupContext  ();			/* Initialize Vertex Context */
	SetupPet      ();			/* Initialize object vertex data */

	txt_InitDisplayString();	/* Initialize DisplayString routine */
	InitBackGround();			/* Setup background plane */

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

	return 0;
}
/*-------------------------------------------------------------------------------------*/
/*  Function Name   :   NextFrame                                                      */ 
/*  Inputs          :   None                                                           */  
/*  Outputs         :   None                                                           */
/*  Returns         :   None                                                           */
/*  Globals Used    :   SGLContext                                                     */
/*  Description     :   Drawing everything and rendering.                              */
/*                      This routine is called from FRONTEND.C                         */
/*-------------------------------------------------------------------------------------*/
void NextFrame()
{
#if defined(_X86_)
	time_t		ltime;
#endif

/* sgltri_startofframe (&SGLContext); */
    MovePet   ();
    DrawPet   ();
    DrawGround();
    DrawSky   ();
    DrawSea   ();
 /* sgltri_render (&SGLContext); */

	txt_SetCursor(0,4);
#if defined(_DISP_PERFORMANCE_)
	/* Write Date & Time on screen --------------------------------------------- */
#if defined(_X86_)
	 time( &ltime );
    PRINTOUT(("START : %s", ctime( &start_time )));
    PRINTOUT(("NOW   : %s", ctime( &ltime )));
#endif
	/* Write FPS on screen -----------------------------------------------------*/
	PRINTOUT(("FRAME : %06d%06d  Now:%07.3fFPS, Ave:%07.3fFPS\n",frame_2, frame,nFPS,aFPS));
#else
	PRINTOUT(("FRAME : %06d%06d\n",frame_2, frame));
#endif	/* defined(_DISP_PERFORMANCE_) */

/* レンダリングの終了を待つ -------------------------------------------------- */
/*	if(wait_render_f) sgltri_isrendercomplete (&SGLContext,(sgl_uint32)1000); */

	/*----------------------------------------------------------------------------------- */
	/* Rendering start */
#if defined(_DISPLAY_STRING_)
	txt_DispScreen(VertexBufferDesc);		/* Display screen */
#endif
	status = kmRender();
	Check_Status(status, "kmRender");

	/*----------------------------------------------------------------------------------- */
	/* Flip screen */
	status = kmFlipFrameBuffer();
	Check_Status(status, "kmFlipFrameBuffer");

#if defined(_DISP_PERFORMANCE_)
	/* render終了の時刻 ----------------------------------------------------------------- */
	if(pcount_f) {
		QueryPerformanceCounter((LARGE_INTEGER*)&Time3i);	/* sgltri_render終了の時刻 */
		OldTime3 = Time3; Time3 = (double)Time3i * freq;
	}
	else {
		OldTime3 = Time3; Time3 = (double)timeGetTime();	/* sgltri_render終了の時刻 */
	}

/* 性能計算 ------------------------------------------------------------------ */
	nowTime = Time3 - OldTime3;						/* ただいまのフレームを作成するのにかかった時間 */
	if((nowTime > 1000.0f)||(nowTime < 1.0f)) nowTime = 20.0f;		/* 得られた値が異常であった場合は無視 */
	if(nowTime > maxTime) maxTime = nowTime;	/* もっとも時間がかかった？ */
	if(nowTime < minTime) minTime = nowTime;	/* もっとも早かった？ */

	totalTime += nowTime;										/* 累積時間 */
	aveTime = totalTime / ((double)frame + 1.0f);		/* 今までの平均時間 */

	nFPS  = 1000.0f / (double)nowTime;
	aFPS  = 1000.0f / (double)aveTime;
	MxFPS = 1000.0f / (double)minTime;
	MnFPS = 1000.0f / (double)maxTime;
#endif	/* defined(_DISP_PERFORMANCE_) */

	frame++;
	if(frame > 1000000) {	/* フレームのリセット */
		frame = 0;
#if defined(_DISP_PERFORMANCE_)
		totalTime = 0;
#endif	/* defined(_DISP_PERFORMANCE_) */
		frame_2++;
	}
}
/*-------------------------------------------------------------------------------------*/
/*  Function Name   :   Finish                                                         */ 
/*  Inputs          :   None                                                           */  
/*  Outputs         :   None                                                           */
/*  Returns         :   None                                                           */
/*  Globals Used    :   Device                                                         */
/*  Description     :   Free textures and close device.                                */
/*                      This routine is called from FRONTEND.C                         */
/*-------------------------------------------------------------------------------------*/
void Finish()
{
 /*  FreeAllBMPTextures (); */
 /* sgl_delete_device  (Device);	 */

	/*----------------------------------------------------------------------------------- */
	/* Free Texture Surface */
	status = kmFreeTexture(&SeaTex);
	Check_Status(status, "kmFreeTexture");
	status = kmFreeTexture(&SealTex);
	Check_Status(status, "kmFreeTexture");
	status = kmFreeTexture(&GroundTex);
	Check_Status(status, "kmFreeTexture");
	status = kmFreeTexture(&SkyTex);
	Check_Status(status, "kmFreeTexture");

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

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

/*-------------------------------------------------------------------------------------*/
/*  Function Name   :   DrawGround                                                     */ 
/*  Inputs          :   None                                                           */  
/*  Outputs         :   None                                                           */
/*  Returns         :   None                                                           */
/*  Globals Used    :   SGLContex                                                      */
/*  Description     :   Draws ground.                                                  */
/*-------------------------------------------------------------------------------------*/
void DrawGround()
{
SGLVERTEX  Vert[4];
int Face[1][4] = {0,1,2,3}, i;
/* Four points to set a big quad. */
km_vector Pnt[4]	=  {{-5000.0f,  -5.0f, -100.0f},           
                       {-5000.0f,  -5.0f, 5000.0f},
                       { 5000.0f,  -5.0f, 5000.0f},
                       { 5000.0f,  -5.0f, -100.0f}};	


    for (i=0; i<4; i++)
    {
		/* Translate from 3D to SGL-Direct coord. */
		Perspect (Pnt[i], &Vert[i]);                     
		/* Set the colour for each vertex. */
		Vert[i].u32Colour   = RGBColour (255,255,255);
		Vert[i].u32Specular = RGBColour (255,255,255);
    }
   /* Set UV values for each textured vertex. */
   Vert[0].fUOverW = 0.0f;      Vert[0].fVOverW = 0.0f;          
   Vert[1].fUOverW = 0.0f;      Vert[1].fVOverW = 80.0f;
   Vert[2].fUOverW = 400.0f;    Vert[2].fVOverW = 80.0f;
   Vert[3].fUOverW = 400.0f;    Vert[3].fVOverW = 0.0f;
   /* Set a sigle textured quad to create the ground. */
/*   SGLContext.nTextureName = GroundTex; */
/*   sgltri_quads (&SGLContext, 1, Face, Vert);            */
kmtri_quads (	VertexBufferDesc,		/* KMVERTEXBUFFDESC	BufferDesc, */
				VertexContextGround,	/* KMVERTEXCONTEXT		VertexContext, */
				1,						/* int  nNumFaces, */
				Face,					/* int  pFaces[][4], */
				Vert					/* PSGLVERTEX  pVertices */
				);
}
/*-------------------------------------------------------------------------------------*/
/*  Function Name   :   DrawSky                                                        */ 
/*  Inputs          :   None                                                           */  
/*  Outputs         :   None                                                           */
/*  Returns         :   None                                                           */
/*  Globals Used    :   SGLContex                                                      */
/*  Description     :   Draws Sky. (The same as DrawGround)                            */
/*-------------------------------------------------------------------------------------*/
void DrawSky()
{
float Pos=0;
SGLVERTEX  Vert[4];
int Face[1][4] = {0,1,2,3}, i;
km_vector Pnt[4]	=   {{-5000.0f,100.0f, -100.0f}, 
                         {-5000.0f,100.0f, 5000.0f},
                         { 5000.0f,100.0f, 5000.0f},
                         { 5000.0f,100.0f, -100.0f}};	


    for (i=0; i<4; i++)
    { 
     Perspect (Pnt[i], &Vert[i]);
		Vert[i].u32Colour   = RGBColour (255,255,255);
		Vert[i].u32Specular = RGBColour (255,255,255);
    }

   /* Here the continous fluency of the sky.     */
   /* Note that I just move texture's UV values. */
   Pos =(float)SkyFrame / 100.0f;                            
   Vert[0].fUOverW =  0.0;  Vert[0].fVOverW = Pos+00.0;  
   Vert[1].fUOverW =  0.0;  Vert[1].fVOverW = Pos+20.0;
   Vert[2].fUOverW = 90.0;  Vert[2].fVOverW = Pos+20.0;
   Vert[3].fUOverW = 90.0;  Vert[3].fVOverW = Pos+00.0;


/*	SGLContext.nTextureName = SkyTex; */
/*	sgltri_quads (&SGLContext, 1, Face, Vert); */
	kmtri_quads (	VertexBufferDesc,	/* KMVERTEXBUFFDESC	BufferDesc, */
					VertexContextSky,	/* KMVERTEXCONTEXT		VertexContext, */
					1,					/* int  nNumFaces, */
					Face,				/* int  pFaces[][4], */
					Vert				/* PSGLVERTEX  pVertices */
					);

	SkyFrame += ( 1.0f / SPEED );
	if(SkyFrame > 10000.0f) SkyFrame = 10.0f;
}
/*-------------------------------------------------------------------------------------*/
/*  Function Name   :   DrawSea                                                        */ 
/*  Inputs          :   None                                                           */  
/*  Outputs         :   None                                                           */
/*  Returns         :   None                                                           */
/*  Globals Used    :   SGLContex                                                      */
/*  Description     :   Draws Sea surface and its shadow.                              */
/*-------------------------------------------------------------------------------------*/
void DrawSea()
{
km_vector	Move, Scale;
SGLVERTEX	Vert[4];
int			Face[1][4] = {0,1,2,3}, i;
km_vector	Pnt[4]	=   {{-100.0f, 50.0f, -100.0f}, 
                         {-5000.0f,50.0f, 5000.0f},
                         { 5000.0f,50.0f, 5000.0f},
                         { 100.0f, 50.0f, -100.0f}};	

/*	if (SeaFrame > 20000 || SeaFrame < 1) SF = -SF;     */
	if (SeaFrame > 1809.5573 || SeaFrame < 1) SF = -SF;    
    /* SF is just a up-down step for SeaFrame          */
    /* to avoid a large integer part of this variable  */

   Move[0] = SeaFrame / 20.0;
   Move[2] = 0.0;

   Scale[0] = 0.9 + sin(SeaFrame/32.0)/15.0;
   Scale[2] = 0.9 + sin(SeaFrame/64.0)/15.0;

   /* Here the sea stream.                    */
   /* Note that I just move the quad's vertex */
   for (i=0; i<4; i++)
   { 
   Pnt[i][0] *= Scale[0];                      
   Pnt[i][0] += Move[0];                     
   Pnt[i][2] *= Scale[2]; 
   Pnt[i][2] += Move[2];
	
   Perspect (Pnt[i], &Vert[i]);
	Vert[i].u32Colour   = RGBA(255,255,255,170);
	Vert[i].u32Specular = RGBColour (255,255,255);
   }


   Vert[0].fUOverW =  -1.0;  Vert[0].fVOverW = -1.0;
   Vert[1].fUOverW = -40.0;  Vert[1].fVOverW = 40.0;
   Vert[2].fUOverW =  80.0;  Vert[2].fVOverW = 40.0;
   Vert[3].fUOverW =   1.0;  Vert[3].fVOverW = -1.0;

  /* Sea surface (transparent quad). */
/*	SGLContext.nTextureName = SeaTex; */
/*	SGLContext.u32Flags = SGLTT_TEXTURE | SGLTT_GLOBALTRANS; */
/*	SGLContext.u32GlobalTrans = 170; */
/*	sgltri_quads (&SGLContext, 1, Face, Vert);   */
	kmtri_quads (	VertexBufferDesc,	/* KMVERTEXBUFFDESC	BufferDesc, */
					VertexContextSea,	/* KMVERTEXCONTEXT		VertexContext, */
					1,					/* int  nNumFaces, */
					Face,				/* int  pFaces[][4], */
					Vert				/* PSGLVERTEX  pVertices */
					);
	
   /* Sea shadow (transparent quad). */
/*   for (i=0; i<4; i++){ Pnt[i][1] = -4.99f; Perspect (Pnt[i], &Vert[i]);} */
   for (i=0; i<4; i++)
   { 
   Pnt[i][1] = -4.99f;
   Perspect (Pnt[i], &Vert[i]);
	Vert[i].u32Colour   = RGBA(255,255,255,90);
	Vert[i].u32Specular = RGBColour (255,255,255);
   }
/*   SGLContext.u32GlobalTrans = 90; */

/*   sgltri_quads (&SGLContext, 1, Face, Vert);  */
	kmtri_quads (	VertexBufferDesc,	/* KMVERTEXBUFFDESC	BufferDesc, */
					VertexContextSea,	/* KMVERTEXCONTEXT		VertexContext, */
					1,					/* int  nNumFaces, */
					Face,				/* int  pFaces[][4], */
					Vert				/* PSGLVERTEX  pVertices */
					);

/* Restore SGLContex */
/*	SetupContext (); */

   SeaFrame += ( SF / SPEED );
}
/*-------------------------------------------------------------------------------------*/
/*  Function Name   :   MovePet                                                        */ 
/*  Inputs          :   None                                                           */  
/*  Outputs         :   None                                                           */
/*  Returns         :   None                                                           */
/*  Globals Used    :   PetPath, PetTime, PetPosY, VelH, Radius and TPet               */
/*  Description     :   Set a 10 points path for the seal's spine.                     */
/*-------------------------------------------------------------------------------------*/
void MovePet (void)
{
register i;

    for (i=0; i<11; i++)
    {
      PetPath[10-i][1] = PetPosY + sin((PetTime+i)/3.0)*3.0;
      PetPath[10-i][0] = cos ((PetTime+i)*(TPet/(Radius))) * Radius;
      PetPath[10-i][2] = sin ((PetTime+i)*(TPet/(Radius))) * Radius + 150;
    }
 	PetTime += (1.0f / SPEED);
	PetPosY += (VelH / SPEED); 
    if (PetPosY < -0.0 || PetPosY > 50.0) VelH = -VelH;
}   
/*-------------------------------------------------------------------------------------*/
/*  Function Name   :   DrawPet                                                        */ 
/*  Inputs          :   None                                                           */  
/*  Outputs         :   None                                                           */
/*  Returns         :   None                                                           */
/*  Globals Used    :   SealVerts, ShadowVerts, Sealfaces, ShadowFaces                 */
/*  Description     :   This routine draws our seal.                                   */
/*-------------------------------------------------------------------------------------*/
void DrawPet (void)
{
 km_vector	pp, n, TempP, Shadow[10*2];
 register   i, j, pos;
 int        PperC = 10, NumL = 10;                     
 double     CosA, SinA, CosB, SinB, CosC, SenC;      
 double     LenXYZ, LenXY, p0, p1;


 for(j = 0; j < NumL; j++ )
    {
 
       n[0]=PetPath[j][0] - PetPath[j+1][0];
       n[2]=PetPath[j][2] - PetPath[j+1][2];
       n[1]=PetPath[j][1] - PetPath[j+1][1];
	    
       LenXY = sqrt(n[0]*n[0] + n[2]*n[2]);

       if (LenXY > 0.0) {CosA = n[0] / LenXY; SinA = n[2] / LenXY;}
       else             {CosA = 1.0;          SinA = 0.0;         }

       LenXYZ  = sqrt (n[0]*n[0] + n[2]*n[2] + n[1]*n[1]);

       CosB = n[1]  / LenXYZ;           SinB = LenXY / LenXYZ;
       CosC = cos ((2.0*PI)/(PperC-1)); SenC = sin ((2.0*PI)/(PperC-1));

       /* This sets a point pp(0, r, 0) */
       pp[0] =  pp[2]= 0.0;  pp[1] =  sin((float)j*(PI/8.0))*3.0 + 0.2;  
		
      /* This's the tail size */
      if (j==9) {pp[1] = 3.0;}                                          

     for (i=0; i<PperC; i++)
     {
	  /* Rotating pp around n (two consecutive spine points) */
        p0    =  CosA * pp[0] + SinA * pp[2];
        pp[2] = -SinA * pp[0] + CosA * pp[2];
        pp[0] =  p0;

        p1    =  CosB * pp[1] + SinB * pp[0];
        pp[0] = -SinB * pp[1] + CosB * pp[0];
        pp[1] =  p1;

        p0    =  CosC * pp[0] - SenC * pp[2];
        pp[2] =  SenC * pp[0] + CosC * pp[2];
        pp[0] =  p0;

        p1    =  CosB * pp[1] - SinB * pp[0];
        pp[0] =  SinB * pp[1] + CosB * pp[0];
        pp[1] =  p1;

        p0    =  CosA * pp[0] - SinA * pp[2];
        pp[2] =  SinA * pp[0] + CosA * pp[2];
        pp[0] =  p0;
        pos   = i+(j)*PperC;

        /* Seal vertex */
        TempP[0] = PetPath[j][0]-pp[0];
        TempP[1] = PetPath[j][1]-pp[1];
        TempP[2] = PetPath[j][2]-pp[2];

       /* Flatting the tail */
       if (j==9){ TempP[1] = PetPath[j][1]; }            

      /* Shadow vertex */
      if (i==2) {Shadow[j*2+0][0]=TempP[0];  Shadow[j*2+0][1]=-4.8f;  Shadow[j*2+0][2]=TempP[2];}
      if (i==7) {Shadow[j*2+1][0]=TempP[0];  Shadow[j*2+1][1]=-4.8f;  Shadow[j*2+1][2]=TempP[2];}

     Perspect (TempP, &SealVert[pos]);
     }
  }
    for (j=0;j<10;j++)
    {
    Perspect (Shadow[j*2+0], &ShadowVert[j*2+0]);
    Perspect (Shadow[j*2+1], &ShadowVert[j*2+1]);
    }

/*  SGLContext.nTextureName  = SealTex; */
    /* Drawing seal mesh */
/*	sgltri_quads        (&SGLContext, 10*8, SealFaces,   SealVert);   */
	 kmtri_quads (	VertexBufferDesc,	/* KMVERTEXBUFFDESC	BufferDesc, */
					VertexContextSeal,	/* KMVERTEXCONTEXT		VertexContext, */
					10*8,				/* int  nNumFaces, */
					SealFaces,			/* int  pFaces[][4], */
					SealVert			/* PSGLVERTEX  pVertices */
					);
   /* Drawing seal's shadow mesh */
/*	sgltri_quads        (&SGLContext,    9, ShadowFaces, ShadowVert);    */
	 kmtri_quads (	VertexBufferDesc,	/* KMVERTEXBUFFDESC	BufferDesc, */
					VertexContextSeal,	/* KMVERTEXCONTEXT		VertexContext, */
					9,					/* int  nNumFaces, */
					ShadowFaces,		/* int  pFaces[][4], */
					ShadowVert			/* PSGLVERTEX  pVertices */
					);
}
/*-------------------------------------------------------------------------------------*/
/*  Function Name   :   SetupPet                                                       */ 
/*  Inputs          :   None                                                           */  
/*  Outputs         :   None                                                           */
/*  Returns         :   None                                                           */
/*  Globals Used    :   SealVerts, ShadowVerts, Sealfaces, ShadowFaces                 */
/*  Description     :   Set a 10 points path for the seal's spine.                     */
/*-------------------------------------------------------------------------------------*/
void SetupPet (void)
{
unsigned char	SealSh[] = { 0, 56, 150, 255, 255, 152, 56, 0, 0, 0 }; 
register		i, j;
int				cont = 0;

	/* Seal vertex */
	for ( j = 0; j < 10; j++)
	{
		for ( i = 0; i < 10; i++)
		{
		/* Setting seal's smooth shadow colouring faces. */
		if ( j == 8 ) SealSh[i] = 0; if ( j == 9 ) SealSh[i] = 0;	/* tail */
		SealVert[cont].u32Colour	= RGBColour (SealSh[i], SealSh[i], SealSh[i]);
		SealVert[cont].u32Specular	= RGBColour (0, 0, 0);
		/* U & V values for texture. */
		SealVert[cont].fUOverW     = (float)( i + 1 ) / 9.0;        
		SealVert[cont].fVOverW     = (float)( j ) / 11.0;          
		cont++;
		}
	}
 
    cont = 0;
   
	/* Seal faces */
	for (j = 0; j < 10; j++)
	{
	for (i = 0; i < 9; i++)
	{
    /* In a Quad the 3 first points must be not too much close. */
    /* I have separated the mesh in two parts to avoid the pointed nose effect. */ 
    if (j < 5 || j==8){	/* front harf of object & tail    */
       SealFaces[cont][2] = i+(j)*10;      SealFaces[cont][3] = i+1+j*10; 
       SealFaces[cont][0] = i+1+(j+1)*10;  SealFaces[cont][1] = i+(j+1)*10;
    }
    else {				/* rear harf of object */
       SealFaces[cont][0] = i+(j)*10;      SealFaces[cont][1] = i+1+j*10; 
       SealFaces[cont][2] = i+1+(j+1)*10;  SealFaces[cont][3] = i+(j+1)*10;
    }
    cont++;
   }
  }

  cont = 0;

  /* Shadow vertex */
  for (j=0; j<10; j++)
  {
    for (i=0; i<2; i++)
    {
	ShadowVert[cont].u32Colour   = RGBColour (0,0,0);
	ShadowVert[cont].u32Specular = RGBColour (0,0,0);
	ShadowVert[cont].fUOverW     = 0.1f;
	ShadowVert[cont].fVOverW     = 0.1f;
	cont++;
	}
  }

 /* Shadow faces */
 for (j=0;j<9;j++)
 {
      ShadowFaces[j][0] = 1+j*2; ShadowFaces[j][1] = 0+j*2; 
      ShadowFaces[j][2] = 2+j*2; ShadowFaces[j][3] = 3+j*2;
 }
}
/*-------------------------------------------------------------------------------------*/
/*  Function Name   :   SetupTextures                                                  */ 
/*  Inputs          :   None                                                           */  
/*  Outputs         :   None                                                           */
/*  Returns         :   None                                                           */
/*  Globals Used    :   SeaTex, SealTex, GroundTex, SkyTex                             */
/*  Description     :   Loads all texture bitmaps.                                     */
/*-------------------------------------------------------------------------------------*/
void SetupTextures (void)
{
/*		SeaTex     = LoadBMPTexture ("Sea.bmp",    FALSE,  FALSE, TRUE); */
/*		SealTex    = LoadBMPTexture ("Seal.bmp",   FALSE,  TRUE,  FALSE); */
/*		GroundTex  = LoadBMPTexture ("Ground.bmp", FALSE,  TRUE,  FALSE); */
/*		SkyTex     = LoadBMPTexture ("Sky.bmp",    FALSE,  TRUE,  FALSE); */

	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(
		&SeaTex,				/* OUT	PKMSURFACEDESC	pSurfaceDesc */
		128,					/*	IN	KMINT32			nWidth  */
		128,					/*	IN	KMINT32			nHeight  */
		nTextureType			/*	IN	KMTEXTURETYPE	nTextureType */
	);
	Check_Status(status, "kmCreateTextureSurface(SeaTex)");

	nTextureType = KM_TEXTURE_TWIDDLED | KM_TEXTURE_RGB565;	/* Set texture type */
	status = kmCreateTextureSurface(
		&SealTex,				/* OUT	PKMSURFACEDESC	pSurfaceDesc */
		128,					/*	IN	KMINT32			nWidth  */
		128,					/*	IN	KMINT32			nHeight  */
		nTextureType			/*	IN	KMTEXTURETYPE	nTextureType */
	);
	Check_Status(status, "kmCreateTextureSurface(SealTex)");

	nTextureType = KM_TEXTURE_TWIDDLED | KM_TEXTURE_RGB565;	/* Set texture type */
	status = kmCreateTextureSurface(
		&GroundTex,				/* OUT	PKMSURFACEDESC	pSurfaceDesc */
		128,					/*	IN	KMINT32			nWidth  */
		128,					/*	IN	KMINT32			nHeight  */
		nTextureType			/*	IN	KMTEXTURETYPE	nTextureType */
	);
	Check_Status(status, "kmCreateTextureSurface(GroundTex)");

	nTextureType = KM_TEXTURE_TWIDDLED | KM_TEXTURE_RGB565;	/* Set texture type */
	status = kmCreateTextureSurface(
		&SkyTex,				/* OUT	PKMSURFACEDESC	pSurfaceDesc */
		128,					/*	IN	KMINT32			nWidth  */
		128,					/*	IN	KMINT32			nHeight  */
		nTextureType			/*	IN	KMTEXTURETYPE	nTextureType */
	);
	Check_Status(status, "kmCreateTextureSurface(SkyTex)");

	/*----------------------------------------------------------------------------------- */
	/* Load and set texture */
/*--
	pTexture01 =  LoadTextureFile("Sea.pvr");
--*/
	pTexture01 = (unsigned long *)&sea;
	status = kmLoadTexture(&SeaTex,				/* PKMSURFACEDESC pSurfaceDesc */
							pTexture01 + (16 / sizeof(KMDWORD)),			/* PKMDWORD pTexture */
							FALSE,				/* KMBOOLEAN bAutoMipMap */
							FALSE				/* KMBOOLEAN bDither */
							);
	Check_Status(status, "kmLoadTexture(Sea.pvr)");
/*--
	free(pTexture01);
--*/

/*--
	pTexture01 =  LoadTextureFile("Seal.pvr");
--*/
	pTexture01 = (unsigned long *)&seal;
	status = kmLoadTexture(&SealTex,			/* PKMSURFACEDESC pSurfaceDesc */
							pTexture01 + (16 / sizeof(KMDWORD)),			/* PKMDWORD pTexture */
							FALSE,				/* KMBOOLEAN bAutoMipMap */
							FALSE				/* KMBOOLEAN bDither */
							);
	Check_Status(status, "kmLoadTexture(Seal.pvr)");
/*--
	free(pTexture01);
--*/

/*--
	pTexture01 =  LoadTextureFile("Ground.pvr");
--*/
	pTexture01 = (unsigned long *)&ground;
	status = kmLoadTexture(&GroundTex,				/* PKMSURFACEDESC pSurfaceDesc */
							pTexture01 + (16 / sizeof(KMDWORD)),			/* PKMDWORD pTexture */
							FALSE,				/* KMBOOLEAN bAutoMipMap */
							FALSE				/* KMBOOLEAN bDither */
							);
	Check_Status(status, "kmLoadTexture(Ground.pvr)");
/*--
	free(pTexture01);
--*/

/*--
	pTexture01 =  LoadTextureFile("Sky.pvr");
--*/
	pTexture01 = (unsigned long *)&sky;
	status = kmLoadTexture(&SkyTex,				/* PKMSURFACEDESC pSurfaceDesc */
							pTexture01 + (16 / sizeof(KMDWORD)),			/* PKMDWORD pTexture */
							FALSE,				/* KMBOOLEAN bAutoMipMap */
							FALSE				/* KMBOOLEAN bDither */
							);
	Check_Status(status, "kmLoadTexture(Sky.pvr)");
/*--
	free(pTexture01);
--*/
}
/*-------------------------------------------------------------------------------------*/
/*  Function Name   :   SetupContex                                                    */ 
/*  Inputs          :   None                                                           */  
/*  Outputs         :   None                                                           */
/*  Returns         :   None                                                           */
/*  Globals Used    :   SGLContex                                                      */
/*  Description     :   Setup SGLContex values.                                        */
/*-------------------------------------------------------------------------------------*/
void SetupContext (void)
{
/*	SGLContext.bFogOn               = TRUE; */
/*	SGLContext.fFogR                = 0.1f; */
/*	SGLContext.fFogG                = 0.3f; */
/*	SGLContext.fFogB                = 0.5f; */
/*	SGLContext.u32FogDensity        = 10; */
/*	SGLContext.bCullBackfacing      = FALSE; */
/*	SGLContext.u32Flags             = SGLTT_TEXTURE | SGLTT_GOURAUD; */
/*	SGLContext.nTextureName         = 0; */
/*	SGLContext.bDoClipping          = TRUE; */
/*	SGLContext.cBackgroundColour[0] = 0.1f; */
/*	SGLContext.cBackgroundColour[1] = 0.3f; */
/*	SGLContext.cBackgroundColour[2] = 0.5f; */
/*	SGLContext.eShadowLightVolMode  = NO_SHADOWS_OR_LIGHTVOLS; */
/*	SGLContext.bFlipU               = FALSE; */
/*	SGLContext.bFlipV               = FALSE; */
/*	SGLContext.bDoUVTimesInvW       = TRUE; */

	/*-------------------------------------------------------------------------------- */
	/* Initialize Vertex Context */
	/*-------------------------------------------------------------------------------- */
	/* Context for Ground */
	memset( &VertexContextGround, 0, sizeof(VertexContextGround));	/* Crear Context */
	InitVertexContext(&VertexContextGround);					/* Initialize context */
	/* Clear render state */
	VertexContextGround.RenderState	= 0;
	/* Set shading mode */
	VertexContextGround.RenderState	|= KM_SHADINGMODE;
	VertexContextGround.ShadingMode	= KM_TEXTUREGOURAUD;
   	/* Set texture surface */
	VertexContextGround.pTextureSurfaceDesc	= &GroundTex;
	/* Process & Set Texture */
	status = kmProcessVertexRenderState(&VertexContextGround);
	Check_Status(status, "kmProcessVertexRenderState");
	/*-------------------------------------------------------------------------------- */
	/* Context for Sky */
	memset( &VertexContextSky, 0, sizeof(VertexContextSky));	/* Crear Context */
	InitVertexContext(&VertexContextSky);					/* Initialize context */
	/* Clear render state */
	VertexContextSky.RenderState	= 0;
	/* Set shading mode */
	VertexContextSky.RenderState	|= KM_SHADINGMODE;
	VertexContextSky.ShadingMode	= KM_TEXTUREGOURAUD;
	/* Set texture surface */
	VertexContextSky.pTextureSurfaceDesc	= &SkyTex;
	/* Process & Set Texture */
	status = kmProcessVertexRenderState(&VertexContextSky);
	Check_Status(status, "kmProcessVertexRenderState");
	/*-------------------------------------------------------------------------------- */
	/* Context for Sea */
	memset( &VertexContextSea, 0, sizeof(VertexContextSea));	/* Crear Context */
	InitVertexContext(&VertexContextSea);					/* Initialize context */
	/* Clear render state */
	VertexContextSea.RenderState	= 0;
	/* */
	VertexContextSea.RenderState	|= KM_SRCBLENDINGMODE;
	VertexContextSea.SRCBlendingMode	= KM_SRCALPHA;
	/* */
	VertexContextSea.RenderState	|= KM_DSTBLENDINGMODE;
	VertexContextSea.DSTBlendingMode	= KM_INVSRCALPHA;
	/* */
	VertexContextSea.RenderState	|= KM_LISTTYPE;
	VertexContextSea.ListType	= KM_TRANS_POLYGON;
	/* */
	VertexContextSea.RenderState	|= KM_TEXTURESHADINGMODE;
	VertexContextSea.TextureShadingMode	= KM_MODULATE_ALPHA;
	/* */
	VertexContextSea.RenderState	|= KM_USEALPHA;
	VertexContextSea.bUseAlpha = TRUE;
	/* Set shading mode */
	VertexContextSea.RenderState	|= KM_SHADINGMODE;
	VertexContextSea.ShadingMode	= KM_TEXTUREGOURAUD;
	/* Set texture surface */
	VertexContextSea.pTextureSurfaceDesc	= &SeaTex;
	/* Process & Set Texture */
	status = kmProcessVertexRenderState(&VertexContextSea);
	Check_Status(status, "kmProcessVertexRenderState");
	/*-------------------------------------------------------------------------------- */
	/* Context for Seal */
	memset( &VertexContextSeal, 0, sizeof(VertexContextSeal));	/* Crear Context */
	InitVertexContext(&VertexContextSeal);					/* Initialize context */
	/* Clear render state */
	VertexContextSeal.RenderState	= 0;
	/* Set shading mode */
	VertexContextSeal.RenderState	|= KM_SHADINGMODE;
	VertexContextSeal.ShadingMode	= KM_TEXTUREGOURAUD;
/*	VertexContextSeal.ShadingMode	= KM_NOTEXTUREGOURAUD; */
	/* Set texture surface */
	VertexContextSeal.pTextureSurfaceDesc	= &SealTex;
	/* Process & Set Texture */
	status = kmProcessVertexRenderState(&VertexContextSeal);
	Check_Status(status, "kmProcessVertexRenderState");

}
/*-------------------------------------------------------------------------------------*/
/*  Function Name   :   Perspect                                                       */ 
/*  Inputs          :   Point3D                                                        */  
/*  Outputs         :   Vert                                                           */
/*  Returns         :   None                                                           */
/*  Globals Used    :   None                                                           */
/*  Description     :   Calculates SGL-Direct coordinates from 3D coordenates.         */
/*-------------------------------------------------------------------------------------*/
void Perspect (const km_vector Point3D, SGLVERTEX *Vert)
{
const km_vector CamPos = { 0.0f, 10.0f, 150.0f};
float x, y, z;

    x    =  Point3D[0] + CamPos[0];
    y    = -Point3D[1] + CamPos[1];
    z    = (Point3D[2] + CamPos[2]);

   Vert->fX    =  (CamFocus * x) / z + 320;
   Vert->fY    =  (CamFocus * y) / z + 240;

   /* The render uses fInvW (1/z) to set the Z-buffer */
   /* In this case I use it to set the fog effect as well */
   Vert->fInvW =  1.8f / z;                   
}
/*------------------------------------------------------------------------------------*/
/*--------------------------- End of File --------------------------------------------*/
/****************************************************************************/
/**	main ********************************************************************/
/****************************************************************************/ 
int	main(void)
{
/*	int	count; */

	txt_ClearScreen();	/* Clear text screen */
	PRINTOUT(("** Sea lion 2V Latency Opaque Direct**\n"));
    SetupScene ();	/* Initialize */

/*	for(count =0; count < FRAMES; count++) { */
	while(1) {
		NextFrame();	/* Rendering */
/*		if((count % 50) == 0) { */
/*			printf(" FRAME : %04d  Now:%07.3fFPS, Ave:%07.3fFPS, Max:%07.3fFPS, Min:%07.3fFPS\n",frame,nFPS,aFPS,MxFPS,MnFPS); */
/*		} */
	}

	Finish();		/* End of render */
	PRINTOUT(("** END DirectSeal **\n"));
	return 0;
}

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

 