/*--
******************************************************************************
 Name     : LOGO
 Title    : KAMUI test program "LOGO" from VL
 Author   : VideoLogic Carlos Sarria / NEC Software Takeshi Muto
 Created  : July 1997 by VideoLogic
 Modified : Octover 30. 1997 by Takeshi Muto for KAMUI

 Description : 
 Copyright : 1997 by VideoLogic Limited. All rights reserved.
******************************************************************************
--*/
/*
#define		_X86_
*/
/* _X86_ flag for win95 : SET2 */

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

#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 title[];			/* texture data */
extern const unsigned char reflect[];
extern const unsigned char pvr[];

/*--
#include <malloc.h>
#include <ddraw.h>
#include "sgl.h"
#include "frontend.h"
--*/

#include "kmlogo.h"   /* This is the file with 3D data */
              
#pragma warning (disable : 4244)  /* Disables float to double conversion warning */

#define PI	(3.1416f)
#define RESOLUTION 0

#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)

typedef	KMUINT32	sgl_uint32;		/* type of sgl_uint32 */
typedef float		sgl_vector[3];	/* type of sgl_vector */
typedef float		sgl_2d_vec[2];	/* type of sgl_2d_vec */
typedef float		sgl_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		Texture[10];			/* texture surface */
	KMVERTEXBUFFDESC	VertexBufferDesc;		/* Vertex-buffer */
	KMVERTEXCONTEXT		VertexContext;			/* Vertex context */


	int			frame;				
	int			frame_2 = 0;		
#if defined(_DISP_PERFORMANCE_)
	int			pcount_f;			/* High-resolution counter supported? */
	double		nFPS;				
	double		aFPS;				
	double		MxFPS;				
	double		MnFPS;				
	__int64 	Time3i;				
	__int64		freqi;				
	double		freq;				
	double		Time3;				
	double		maxTime = 0.00001;	
	double		minTime = 99999;	
	double		OldTime3;			
	double		nowTime;			
	double		totalTime	= 0;	
	double		aveTime;			
#if defined(_X86_)
	time_t		start_time;			
#endif
#endif

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

float XAng = -PI/2, YAng = 0.0f, ZAng = 0.0f, XAng1 = -0.01f, YAng1 = -0.02f, ZAng1=0.005f;

static int   Device, Init = TRUE;
/*, Texture[10];  */
static float *TempNormals[NUM_MESHES];
static float Light1[3] = { -1, 1.5, -1.5};
static float Shad[255];
static float CamFocus = 600.0;

SGLVERTEX  *TempVert[NUM_MESHES];
/*SGLCONTEXT SGLContext; */

static void SetupContext (void);
static void SetupTextures (void);
static void InitMeshes    (void);
static void DrawAll       (void);
static void UpdateVertex  (int Num);
static void Shading       (int Num);
static void UpdateReflection (int Num);

/****************************************************************************/
/**	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_01			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_FLOATINGCOLOR;
	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_NOFOG;			/* 11 is reserved */
	BackVertexContext.bUseSpecular			= FALSE;
	BackVertexContext.bUseAlpha				= FALSE;
	BackVertexContext.ClampUV				= KM_NOCLAMP;
	BackVertexContext.FilterMode			= KM_POINT_SAMPLE;
	BackVertexContext.bSuperSample			= FALSE;
	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				=   0.0f;	
	BV[0].fY				= 479.0f;
#if defined(_STRICT_UNION_)
	BV[0].u.fZ				=  0.0001f;
#else
	BV[0].fZ				=  0.0001f;
#endif
	BV[0].fBaseAlpha		=   1.0f;	
	BV[0].fBaseRed			=   1.0f;
	BV[0].fBaseGreen		=   1.0f;
	BV[0].fBaseBlue			=   0.0f;

	/* Vertex #2 */
	BV[1].ParamControlWord	= KM_VERTEXPARAM_NORMAL;
	BV[1].fX				= 320.0f;	
	BV[1].fY				=   0.0f;
#if defined(_STRICT_UNION_)
	BV[1].u.fZ				=  0.0001f;
#else
	BV[1].fZ				=  0.0001f;
#endif
	BV[1].fBaseAlpha		=   1.0f;	
	BV[1].fBaseRed			=   0.5f;
	BV[1].fBaseGreen		=   0.1f;
	BV[1].fBaseBlue			=   0.0f;

	/* Vertex #3 */
	BV[2].ParamControlWord	= KM_VERTEXPARAM_ENDOFSTRIP;
	BV[2].fX				= 639.0f;	
	BV[2].fY				= 479.0f;
#if defined(_STRICT_UNION_)
	BV[2].u.fZ				=  0.0001f;
#else
	BV[2].fZ				=  0.0001f;
#endif
	BV[2].fBaseAlpha		=   1.0f;	
	BV[2].fBaseRed			=   1.0f;
	BV[2].fBaseGreen		=   1.0f;
	BV[2].fBaseBlue			=   0.0f;

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

	/*-----------------------------------------------------------------------------------*/
	/* set VERTEX */
	status = kmSetBackGroundPlane(	pBV,					/* pVertex */
									KM_VERTEXTYPE_01,		/* VertexType */
									sizeof(KMVERTEX_01)		/* 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;
	KMVERTEX_03	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,
				  int					bTexture)
{
	KMSTATUS	status;
	int			i;
	KMVERTEX_00	Ver00;				/* 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 */
			Ver00.ParamControlWord	= KM_VERTEXPARAM_NORMAL;
			Ver00.fX				= pVertices[pFaces[i][0]].fX;
			Ver00.fY				= pVertices[pFaces[i][0]].fY;
#if defined(_STRICT_UNION_)
			Ver00.u.fZ				= pVertices[pFaces[i][0]].fInvW;
#else
			Ver00.fZ				= pVertices[pFaces[i][0]].fInvW;
#endif
			Ver00.uBaseRGB.dwPacked	= pVertices[pFaces[i][0]].u32Colour;
			status = kmSetVertex(&BufferDesc,&Ver00,KM_VERTEXTYPE_00,sizeof(KMVERTEX_00) );
			Check_Status(status, "kmSetVertex");

			Ver00.ParamControlWord	= KM_VERTEXPARAM_NORMAL;
			Ver00.fX				= pVertices[pFaces[i][1]].fX;
			Ver00.fY				= pVertices[pFaces[i][1]].fY;
#if defined(_STRICT_UNION_)
			Ver00.u.fZ				= pVertices[pFaces[i][1]].fInvW;
#else
			Ver00.fZ				= pVertices[pFaces[i][1]].fInvW;
#endif
			Ver00.uBaseRGB.dwPacked	= pVertices[pFaces[i][1]].u32Colour;
			status = kmSetVertex(&BufferDesc,&Ver00,KM_VERTEXTYPE_00,sizeof(KMVERTEX_00) );
			Check_Status(status, "kmSetVertex");

			Ver00.ParamControlWord	= KM_VERTEXPARAM_ENDOFSTRIP;
			Ver00.fX				= pVertices[pFaces[i][2]].fX;
			Ver00.fY				= pVertices[pFaces[i][2]].fY;
#if defined(_STRICT_UNION_)
			Ver00.u.fZ				= pVertices[pFaces[i][2]].fInvW;
#else
			Ver00.fZ				= pVertices[pFaces[i][2]].fInvW;
#endif
			Ver00.uBaseRGB.dwPacked	= pVertices[pFaces[i][2]].u32Colour;
			status = kmSetVertex(&BufferDesc,&Ver00,KM_VERTEXTYPE_00,sizeof(KMVERTEX_00) );
			Check_Status(status, "kmSetVertex");
		} /* end of if(bTexture == TRUE) */
	}
}

/****************************************************************************/
/**	Initialize Vertex Context ***********************************************/
/****************************************************************************/
void	InitVertexContext(PKMVERTEXCONTEXT pVertexContext)
{
	
	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->CullingMode			= KM_CULLSMALL;
	pVertexContext->ScreenCoordination	= KM_SCREEN;
	pVertexContext->ShadingMode			= KM_NOTEXTUREGOURAUD;
	pVertexContext->SelectModifier		= KM_NOMODIFIER;
	pVertexContext->bZWriteDisable		= FALSE;			

	/* for TSP ControlWord  */
	pVertexContext->SRCBlendingMode		= KM_ONE;
	pVertexContext->DSTBlendingMode		= KM_ZERO;
	pVertexContext->bSRCSel				= FALSE;			
	pVertexContext->bDSTSel				= FALSE;			
	pVertexContext->FogMode				= KM_NOFOG;			
	pVertexContext->bUseSpecular		= FALSE;
	pVertexContext->bUseAlpha			= FALSE;
	pVertexContext->FlipUV				= KM_NOFLIP;
	pVertexContext->ClampUV				= KM_NOCLAMP;
	pVertexContext->FilterMode			= KM_BILINEAR;
	pVertexContext->bSuperSample		= FALSE;
	pVertexContext->MipMapAdjust		= 0x00000004;		/* D=1.00 */
	pVertexContext->TextureShadingMode	= KM_MODULATE;

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

/*	switch (RESOLUTION) */
/*	{ */
/*	       case 0: */
/*			   Device = sgl_create_screen_device (0, 640, 480, sgl_device_16bit, TRUE);  */
/*			   break; */
/*	       case 1: */
/*			   Device = sgl_create_screen_device (0, 800, 600, sgl_device_16bit, TRUE);  */
/*			   break; */
/*		   case 2: */
/*	           Device = sgl_create_screen_device (0, 1024, 768, sgl_device_16bit, TRUE);  */
/*			   break; */
/*	}	 */
/*	if (Device<0) return ERR_CREATE_SCREEN_DEVICE; */

	/*-----------------------------------------------------------------------------------*/
	/* Initialize Random number */
#if	defined(_X86_)
	srand ((unsigned)time(NULL));
#else
	srand ((unsigned)10);
#endif
	#define	RMIN	  0.0f		/* minimum number of random-number */
	#define	RMAX	200.0f		/* maximum number of random-number */
	XAng1 = ((int)(rand() * ((RMAX - RMIN) / RAND_MAX) + RMIN) - 100.0f) / 10000.0f; /* Dummy */
	YAng1 = ((int)(rand() * ((RMAX - RMIN) / RAND_MAX) + RMIN) - 100.0f) / 10000.0f;
	ZAng1 = ((int)(rand() * ((RMAX - RMIN) / RAND_MAX) + RMIN) - 100.0f) / 10000.0f;
	XAng1 = ((int)(rand() * ((RMAX - RMIN) / RAND_MAX) + RMIN) - 100.0f) / 10000.0f;

	/*-----------------------------------------------------------------------------------*/
	/* 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);
	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 */
									262144,					/* Opaque-Polygon 1MB */
									0,						/* Opaque-Modifier */
									262144,					/* Trans-Polygon 1MB */
									0						/* Trans-Modifier */
									);
	Check_Status(status, "kmCreateVertexBuffer");

	/*-----------------------------------------------------------------------------------*/
	/* Set Culling Register */
	status = kmSetCullingRegister(1.0f);
	Check_Status(status, "kmSetCullingRegister");

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

	/*-----------------------------------------------------------------------------------*/
	/* Initialize DisplayString routine */
	txt_InitDisplayString();
    SetupTextures (); 
	SetupContext  ();
    InitMeshes ();

	InitBackGround();		/* Setup background plane */


	/*-----------------------------------------------------------------------------------*/
	

	frame		= 0;

#if defined(_DISP_PERFORMANCE_)
	totalTime	= 0;

	pcount_f = QueryPerformanceFrequency((LARGE_INTEGER*)&freqi);	
	if(pcount_f) {	
		QueryPerformanceCounter((LARGE_INTEGER*)&Time3i);	
		freq = 1000.0f / (double)freqi;						
		OldTime3 = Time3 = (double)Time3i * freq;			
	}
	else {	
		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(void)
{
#if defined(_X86_)
	time_t		ltime;
#endif
/*	sgltri_startofframe (&SGLContext); */
	   DrawAll ();
/*	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_) */

	/*-----------------------------------------------------------------------------------*/
	/* 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_)
	
	if(pcount_f) {
		QueryPerformanceCounter((LARGE_INTEGER*)&Time3i);	
		OldTime3 = Time3; Time3 = (double)Time3i * freq;
	}
	else {
		OldTime3 = Time3; Time3 = (double)timeGetTime();	
	}


	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(void)
{
/*	FreeAllBMPTextures (); */
/*	sgl_delete_device(Device);	 */
	Init = FALSE;

	/*-----------------------------------------------------------------------------------*/
	/* Free Texture Surface */

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

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

/*-------------------------------------------------------------------------------------*/
/*  Function Name   :  DrawAll                                                         */
/*  Inputs          :  None                                                            */
/*  Outputs         :  None                                                            */
/*  Returns         :  None                                                            */
/*  Globals Used    :  XAng, YAng, XAng1, YAng1, SGLContext                            */
/*  Description     :  Updates and draws all the meshes in the model.                  */
/*  Note            :  The definition of Mesh[i] struct is in logo.h                   */
/*-------------------------------------------------------------------------------------*/
void DrawAll(void)
{
register	i;
int			bTexture;

    XAng += (XAng1 / SPEED);   /* Scene angles are changed every frame */
    YAng += (YAng1 / SPEED);   /* XAng1 and YAng1 are the speed */
  
    for (i=0; i<NUM_MESHES; i++)
	{
        UpdateVertex  (i); /* Recalculate SGL vertices for the new position */
                           
        if (i==REFLECT || i==REFLECT01 || i==REFLECT02) UpdateReflection (i); 
        else  Shading (i);  /* We do not want to shade a reflection mesh */

		/* Updating texture parameters for each mesh of the model */
/*		SGLContext.nTextureName = Texture[Mesh[i].Material]; */
/*		SGLContext.u32Flags = SGLTT_TEXTURE | SGLTT_GOURAUD | SGLTT_BILINEAR; */
		/* No Texture */
/*		if (Mesh[i].TexMap == FALSE)  SGLContext.u32Flags = SGLTT_GOURAUD | SGLTT_BILINEAR;  */
		/* Global Translucent */
/*		if (i==REFLECT || i==REFLECT01 || i==REFLECT02)  */
/*		{  */
/*			SGLContext.u32Flags       =  SGLTT_TEXTURE | SGLTT_GOURAUD | SGLTT_GLOBALTRANS | SGLTT_BILINEAR; */
/*			SGLContext.u32GlobalTrans =  32L; */
/*		} */

	/* Clear render state */
	VertexContext.RenderState	= 0;
	if (Mesh[i].TexMap == FALSE) {
		/* Set shading mode */
		VertexContext.RenderState	|= KM_SHADINGMODE;
		VertexContext.ShadingMode	= KM_NOTEXTUREGOURAUD;
		bTexture = FALSE;
	}
	else {
		/* Set shading mode */
		VertexContext.RenderState	|= KM_SHADINGMODE;
		VertexContext.ShadingMode	= KM_TEXTUREGOURAUD;
		/* Set texture surface */
		VertexContext.pTextureSurfaceDesc	= &Texture[Mesh[i].Material];
		bTexture = TRUE;
	}

	if (i==REFLECT || i==REFLECT01 || i==REFLECT02)  {

		VertexContext.RenderState	|= KM_SRCBLENDINGMODE;
		VertexContext.SRCBlendingMode	= KM_SRCALPHA;

		VertexContext.RenderState	|= KM_DSTBLENDINGMODE;
		VertexContext.DSTBlendingMode	= KM_INVSRCALPHA;

		VertexContext.RenderState	|= KM_LISTTYPE;
		VertexContext.ListType  = KM_TRANS_POLYGON;

		VertexContext.RenderState	|= KM_TEXTURESHADINGMODE;
		VertexContext.TextureShadingMode	= KM_MODULATE_ALPHA;

		VertexContext.RenderState	|= KM_USEALPHA;
		VertexContext.bUseAlpha = TRUE;
	}
	else {

		VertexContext.RenderState	|= KM_SRCBLENDINGMODE;
		VertexContext.SRCBlendingMode	= KM_ONE;

		VertexContext.RenderState	|= KM_DSTBLENDINGMODE;
		VertexContext.DSTBlendingMode	= KM_ZERO;

		VertexContext.RenderState	|= KM_LISTTYPE;
		VertexContext.ListType  = KM_OPAQUE_POLYGON;

		VertexContext.RenderState	|= KM_USEALPHA;
		VertexContext.bUseAlpha = FALSE;
	}
	kmProcessVertexRenderState(&VertexContext);

		/* And now... triangles  */
/*		sgltri_triangles (&SGLContext, Mesh[i].NumFaces, (int(*)[3])Mesh[i].Faces, TempVert[i]); */
kmtri_triangles (	VertexBufferDesc,			/* KMVERTEXBUFFDESC	BufferDesc, */
					VertexContext,				/* KMVERTEXCONTEXT		VertexContext, */
					Mesh[i].NumFaces,			/* int  nNumFaces, */
					(int(*)[3])Mesh[i].Faces,	/* int  pFaces[][3], */
					TempVert[i],				/* PSGLVERTEX  pVertices */
					bTexture					/* int	bTexture */
					);

   } 
}

/*-------------------------------------------------------------------------------------*/
/*  Function Name   : SetupTextures                                                    */
/*  Inputs          : None                                                             */
/*  Outputs         : None                                                             */
/*  Returns         : None                                                             */
/*  Globals Used    : NumMaterials, Texture, MatInfo                                   */
/*  Description     : Loads BMP files getting the information from MatInfo struct      */
/*-------------------------------------------------------------------------------------*/
void SetupTextures (void)
{
/*sgl_intermediate_map BuffTex[NUM_MESHES]; */
register i;
	PKMDWORD			pTexture01;				/* Pointer to texture */
	KMTEXTURETYPE		nTextureType;			/* texture type definition */

   for (i=0;i<NumMaterials; i++)
   {
      if (*MatInfo[i].MatFile == 0) continue;
		if (i==1) /* The material for the "PowerVR" word use alpha chanel */
	{
/*			BuffTex[i] = ConvertBMPtoSGL   (MatInfo[i].MatFile, TRUE); */
/*			Texture[i] = sgl_create_texture( sgl_map_trans16, sgl_map_256x256, */
/*											FALSE, FALSE, &BuffTex[i],  NULL); */
	/*-----------------------------------------------------------------------------------*/
	/* Create texture surface */
	nTextureType = KM_TEXTURE_TWIDDLED | KM_TEXTURE_ARGB4444;	/* Set texture type */
	status = kmCreateTextureSurface(
		&Texture[i],			/* OUT	PKMSURFACEDESC	pSurfaceDesc */
		256,					/*	IN	KMINT32			nWidth */
		256,					/*	IN	KMINT32			nHeight */
		nTextureType			/*	IN	KMTEXTURETYPE	nTextureType */
	);
	Check_Status(status, "kmCreateTextureSurface(ARGB)");
	/*-----------------------------------------------------------------------------------*/
	/* Load and set texture */
/*--
	pTexture01 =  LoadTextureFile(MatInfo[i].MatFile);
--*/
	switch(i){
	case 0:	break;
	case 1:	pTexture01 = (unsigned long *)&title; break;
	case 2:	pTexture01 = (unsigned long *)&reflect; break;
	case 3:	break;
	case 4:	pTexture01 = (unsigned long *)&pvr; break;
	}
	status = kmLoadTexture(&Texture[i],			/* PKMSURFACEDESC pSurfaceDesc */
							pTexture01 + (16 / sizeof(KMDWORD)),			/* PKMDWORD pTexture */
							FALSE,				/* KMBOOLEAN bAutoMipMap */
							FALSE				/* KMBOOLEAN bDither */
							);
	Check_Status(status, "kmLoadTexture(ARGB)");
/*--
	free(pTexture01);
--*/

	}
	else 
	{
/*			BuffTex[i] = ConvertBMPtoSGL   (MatInfo[i].MatFile, FALSE); */
/*			Texture[i] = sgl_create_texture( sgl_map_16bit, sgl_map_256x256, */
/*											FALSE, FALSE, &BuffTex[i],  NULL); */
	/*-----------------------------------------------------------------------------------*/
	/* Create texture surface */
	nTextureType = KM_TEXTURE_TWIDDLED | KM_TEXTURE_RGB565;	/* Set texture type */
	status = kmCreateTextureSurface(
		&Texture[i],			/* OUT	PKMSURFACEDESC	pSurfaceDesc */
		256,					/*	IN	KMINT32			nWidth */
		256,					/*	IN	KMINT32			nHeight */
		nTextureType			/*	IN	KMTEXTURETYPE	nTextureType */
	);
	Check_Status(status, "kmCreateTextureSurface(RGB)");
	/*-----------------------------------------------------------------------------------*/
	/* Load and set texture */
/*--
	pTexture01 =  LoadTextureFile(MatInfo[i].MatFile);
--*/
	switch(i){
	case 0:	break;
	case 1:	pTexture01 = (unsigned long *)&title; break;
	case 2:	pTexture01 = (unsigned long *)&reflect; break;
	case 3:	break;
	case 4:	pTexture01 = (unsigned long *)&pvr; break;
	}
	status = kmLoadTexture(&Texture[i],			/* PKMSURFACEDESC pSurfaceDesc */
							pTexture01 + (16 / sizeof(KMDWORD)),			/* PKMDWORD pTexture */
							FALSE,				/* KMBOOLEAN bAutoMipMap */
							FALSE				/* KMBOOLEAN bDither */
							);
	Check_Status(status, "kmLoadTexture(ARGB)");
/*--
	free(pTexture01);
--*/

	}
   }
}
/*-------------------------------------------------------------------------------------*/
/*  Function Name   : SetupContext                                                     */
/*  Inputs          : None                                                             */
/*  Outputs         : None                                                             */
/*  Returns         : None                                                             */
/*  Globals Used    : SGLContext                                                       */
/*  Description     : Sets default values for the render context.                      */
/*-------------------------------------------------------------------------------------*/
void SetupContext (void)
{
/*	SGLContext.bFogOn               = FALSE; */
/*	SGLContext.fFogR                = 0.3f; */
/*	SGLContext.fFogG                = 0.7f; */
/*	SGLContext.fFogB                = 0.7f; */
/*	SGLContext.u32FogDensity        = 5; */
/*	SGLContext.bCullBackfacing      = FALSE; */
/*	SGLContext.u32Flags             = SGLTT_TEXTURE | SGLTT_GOURAUD | SGLTT_BILINEAR; */
/*	SGLContext.nTextureName         = 0; */
/*	SGLContext.bDoClipping          = TRUE; */
/*	SGLContext.cBackgroundColour[0] = 0.0f; */
/*	SGLContext.cBackgroundColour[1] = 0.0f; */
/*	SGLContext.cBackgroundColour[2] = 0.0f; */
/*	SGLContext.eShadowLightVolMode  = 0; */
/*	SGLContext.bFlipU               = FALSE; */
/*	SGLContext.bFlipV               = FALSE; */
/*	SGLContext.bDoUVTimesInvW       = TRUE; */
/*	SGLContext.RenderRegions        = 0; */
/*	SGLContext.n32MipmapOffset      = 0; */
/*	SGLContext.u32GlobalTrans       = 255; */
/*	SGLContext.eFilterType          = sgl_tf_bilinear; */
	/*--------------------------------------------------------------------------------*/
	/* Initialize Vertex Context */
	/*--------------------------------------------------------------------------------*/
	memset( &VertexContext, 0, sizeof(VertexContext));	/* Crear Context */
	InitVertexContext(&VertexContext);					/* Initialize context */

}

/*-------------------------------------------------------------------------------------*/
/*  Function Name   : InitMeshes                                                       */
/*  Inputs          : None                                                             */
/*  Outputs         : None                                                             */
/*  Returns         : None                                                             */
/*  Globals Used    : Shad, Mesh, TempVert, TempNormals                                */
/*  Description     : Sets initials values for meshes managing                         */
/*-------------------------------------------------------------------------------------*/
void InitMeshes (void)
{
float x, z, y, Dx;
register i, j, k=0;
#if defined(_X86_)
#else
/* SET4 */
/*int mptr = 0x0c400000;*/
/* SET5 */
int mptr = 0x0c700000;
#endif

    /* This function is in kmlogo.h and creates an array of structures with 3D data */
    CreateMeshesArray (); 
   
	/* Shad is a 255 values array whith information for smooth shading */
    for (i=0; i<120; i++) Shad[k++] = (float)(120-i)/960.0;
    for (i=0; i<100; i++) Shad[k++] = (float) i/100.0;
    for (i=0; i<35;  i++) Shad[k++] = 1.0f;

#if defined(_X86_)
	/* Memory allocation for TempVert and TempNormals */ 
    for (i=0; i<NUM_MESHES; i++)
	{
         TempVert[i] = (SGLVERTEX *) malloc (Mesh[i].NumVertex*sizeof(SGLVERTEX));
         TempNormals[i]  = (float *) malloc (Mesh[i].NumVertex*sizeof(float)*3);
	}
#else
	for (i=0; i<NUM_MESHES; i++)
	{
		TempVert[i] = (SGLVERTEX *)mptr; mptr += Mesh[i].NumVertex*sizeof(SGLVERTEX);
		TempNormals[i] = (float *)mptr; mptr += Mesh[i].NumVertex*sizeof(float)*3 ;
	}
#endif

	/* Setting UV values for all the meshes and calculating TempNormals for reflections */
    for (j=0; j<NUM_MESHES; j++)
	{
        for (i=0; i<Mesh[j].NumVertex; i++)
		{
            (TempVert[j]+i)->fUOverW    =  (Mesh[j].TexMap) ? *(Mesh[j].UV + i * 2 + 0) : 0;
            (TempVert[j]+i)->fVOverW    =  (Mesh[j].TexMap) ? *(Mesh[j].UV + i * 2 + 1) : 0;

			/* TempNormals are calculated with the normal and the position of each vertex */
            x =  (*(Mesh[j].Vertex+i*3+0) - Mesh[j].Center[0]);
            y =  (*(Mesh[j].Vertex+i*3+1) - Mesh[j].Center[1]);
            z =  (*(Mesh[j].Vertex+i*3+2) - Mesh[j].Center[2]);

            if (j==REFLECT)   y += 50;
            if (j==REFLECT01) y += 50;
            if (j==REFLECT02) y -= 10;

            Dx = sqrt (x*x+y*y+z*z);
                      
            *(TempNormals[j]+i*3+0) = ((*(Mesh[j].Normals+i*3+0) + x/Dx)/2.0);
            *(TempNormals[j]+i*3+1) = ((*(Mesh[j].Normals+i*3+1) + y/Dx)/2.0);
            *(TempNormals[j]+i*3+2) = ((*(Mesh[j].Normals+i*3+2) + z/Dx)/2.0);
		}
    }
}

/*-------------------------------------------------------------------------------------*/
/*  Function Name   : UpdateVertex                                                     */
/*  Inputs          : Num (the mesh in the model)                                      */
/*  Outputs         : None                                                             */
/*  Returns         : None                                                             */
/*  Globals Used    : XAng, YAng                                                       */
/*  Description     : Turns vertices around two axes.                                  */
/*-------------------------------------------------------------------------------------*/
void UpdateVertex (int Num)
{
float  ResX[3] = { 320, 400, 516 }, ResY[3] = { 240, 300, 384};
float  CosX, SinX, CosY, SinY, CosZ, SinZ, x, z, y , CamZ;
int    i, j=0, k=0, l=0;
sgl_vector Temp;

    CosX = cos(XAng); SinX = sin(XAng);
    CosY = cos(YAng); SinY = sin(YAng);
    CosZ = cos(ZAng); SinZ = sin(ZAng);

    for (i=0; i<Mesh[Num].NumVertex; i++)
	{
         x = *(Mesh[Num].Vertex+k++) - GroupCenter[0];
         y = *(Mesh[Num].Vertex+k++) - GroupCenter[1];
         z = *(Mesh[Num].Vertex+k++) - GroupCenter[2];

         /* Temp is the outcome vertex after the rotation */
         Temp[0]  = x * CosY - z * SinY;
         Temp[2]  = z * CosY + x * SinY;

         z        = Temp[2];
         Temp[1]  = y * CosX - z * SinX;
         Temp[2]  = z * CosX + y * SinX + 500;

         if (Temp[2] <=0.0f) Temp[2] = 0.001f;
         
		 /* We store the SGL vertex in TempVert */
         CamZ = 1.0/(Temp[2]);
    	 (TempVert[Num]+i)->fX    =  CamFocus *  Temp[0] * CamZ + ResX[RESOLUTION];
         (TempVert[Num]+i)->fY    = -CamFocus *  Temp[1] * CamZ + ResY[RESOLUTION];
	     (TempVert[Num]+i)->fInvW =  CamZ;
   }
}

/*-------------------------------------------------------------------------------------*/
/*  Function Name   : Shading                                                          */
/*  Inputs          : Num                                                              */
/*  Outputs         : None                                                             */
/*  Returns         : None                                                             */
/*  Globals Used    : Light1, MatInfo, Mesh, TempVert                                  */
/*  Description     : Shades a mesh.                                                   */
/*-------------------------------------------------------------------------------------*/
void Shading (int Num)
{
register   l=0, i, Val;
unsigned   k=0;
float      CosX, SinX, CosY, SinY, x, z, y ;
float      TempCo[3], TCo, Dir, LTemp[3];
sgl_uint32 Col[3];

    /* We just rotate the light vector in the opposite direction instead of rotating all the normals */
    Dir = sqrt (Light1[0]*Light1[0]+Light1[1]*Light1[1]+Light1[2]*Light1[2]);
    x = Light1[0]/Dir;
	y = Light1[1]/Dir;
	z = Light1[2]/Dir;

    CosX = cos(-XAng); SinX = sin(-XAng);
    CosY = cos(-YAng); SinY = sin(-YAng);
     
    LTemp[1]  = y * CosX - z * SinX;
    LTemp[2]  = z * CosX + y * SinX; 
     
    z = LTemp[2];
    LTemp[0]  = x * CosY - z * SinY;
    LTemp[2]  = z * CosY + x * SinY;

    k = Mesh[Num].Material;

	/* This is the mesh colour */
    TempCo[0] = 255.0 * MatInfo[k].MatDiffuse[0];
    TempCo[1] = 255.0 * MatInfo[k].MatDiffuse[1];
    TempCo[2] = 255.0 * MatInfo[k].MatDiffuse[2];

    if (Mesh[Num].Material == NumMaterials) TempCo[0]=TempCo[1]=TempCo[2]=255; /* No material */

    for (i=0; i<Mesh[Num].NumVertex; i++)
	{
    	x = *(Mesh[Num].Normals+l++);
        y = *(Mesh[Num].Normals+l++);
        z = *(Mesh[Num].Normals+l++);

		/* Val is a value from 0 to 255 depending on the angle between a normal */
		/* and the light direction.                                             */
		Val = (int) (127.0 * fabs( LTemp[0] * x + LTemp[1] * y + LTemp[2] * z + 1.0) );
   
        TCo = Shad[Val];

        Col[0] = (int)(TempCo[0]*TCo); 
        Col[1] = (int)(TempCo[1]*TCo);
        Col[2] = (int)(TempCo[2]*TCo);

		/* Setting vertex colour */
        (TempVert[Num]+i)->u32Colour  = RGBColour (Col[0],Col[1],Col[2]);
    }

}
/*-------------------------------------------------------------------------------------*/
/*  Function Name   :  UpdateReflection                                                */
/*  Inputs          :  Num                                                             */
/*  Outputs         :  None                                                            */
/*  Returns         :  None                                                            */
/*  Globals Used    :  XAng, YAng, Mesh, TemVert                                       */
/*  Description     :  Changes UV values fixing their position when the mesh rotates.  */
/*                     So, it has to move all values in the opposite direction.        */
/*-------------------------------------------------------------------------------------*/
void UpdateReflection (int Num)
{
int   i, j=0, k=0, k1=0, l=0;
float CosX, SinX, CosY, SinY, x, z, y;
float Temp[3];

CosX = cos(XAng); SinX = sin(XAng);
CosY = cos(YAng); SinY = sin(YAng);

    for (i=0; i<Mesh[Num].NumVertex; i++)
	{
         x = *(TempNormals[Num]+k++);
         y = *(TempNormals[Num]+k++);
         z = *(TempNormals[Num]+k++);

         Temp[0]  = x * CosY - z * SinY;
         Temp[2]  = z * CosY + x * SinY;

         z        = Temp[2];
         Temp[1]  = y * CosX - z * SinX;
         Temp[2]  = z * CosX + y * SinX ;

         Temp[2] = fabs(Temp[2])+0.01;

		 /* Now we proyect the espherical coordinates to rectangular ones... */
         x = (PI + atan(Temp[0]/Temp[2]))/PI;
         y = (PI + atan(Temp[1]/Temp[2]))/PI;
 
		 /* ...and we have now our new UV values */
        (TempVert[Num]+i)->fUOverW =  x+0.5;
        (TempVert[Num]+i)->fVOverW =  y+0.5; 
		/* Setting vertex colour */
        (TempVert[Num]+i)->u32Colour  = RGBA(255, 255, 255, 64);
   }
}
/*--------------------------- END OF FILE --------------------------------*/
/****************************************************************************/
/**	main ********************************************************************/
/****************************************************************************/
int	main(void)
{
	int	count = 0;

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

	do {
		NextFrame();	/* Rendering */
		if((count % 300) == 0) {
			XAng1 = ((int)(rand() * ((RMAX - RMIN) / RAND_MAX) + RMIN) - 100.0f) / 5000.0f;
			YAng1 = ((int)(rand() * ((RMAX - RMIN) / RAND_MAX) + RMIN) - 100.0f) / 5000.0f;
			ZAng1 = ((int)(rand() * ((RMAX - RMIN) / RAND_MAX) + RMIN) - 100.0f) / 5000.0f;
		}
		count++;
		if(count > 100000) count = 0;
	} while(1);

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

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