/*--------------------------------------------------------------------*/
/*   Name   : Tools.c   (Some tools for Arc1a)                        */
/*   Author : Carlos Sarria (Matrix code is Jim's)                    */
/*   Date   : October 1997                                            */
/*                                                                    */
/*   Copyright : 1997 by VideoLogic Limited. All rights reserved.     */
/*--------------------------------------------------------------------*/
/*
#define		_X86_
*/
/* _X86_ flag for win95 : SET2 */

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

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

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

#include "kmtools.h"
/*--
#include "ABCTable.h"
--*/

#define _KM_USE_VERTEX_MACRO_
#define _KM_USE_VERTEX_MACRO_L3_
#include	"kamuix.h"

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

static float	LightDir[3] = { -1.0f, 1.0f, -1.0f };
static unsigned	TotalPolys = 0;
static char		VFog = 0;

/*SGLCONTEXT	SGLContext; */
SGLVERTEX		*SGLVert[256];
CASTMESHES		CMesh[256];
TRANSFORM		T[256];

/***********************************************************************/
/* Kamui Val.s *********************************************************/
/***********************************************************************/
#if defined(_DISP_PERFORMANCE_)
#if defined(_X86_)
extern	time_t				start_time;				
#endif
extern	int					frame;					
extern	int					frame_2;				
extern	int					pcount_f;				
extern	double				nFPS;					
extern	double				aFPS;					
extern	double				MxFPS;					
extern	double				MnFPS;					
extern	__int64				Time3i;					
extern	double				OldTime3;				
extern	double				Time3;					
extern	double				freq;					
extern	double				nowTime;				
extern	double				maxTime;				
extern	double				minTime;				
extern	double				totalTime;				
extern	double				aveTime;				
#endif

extern	KMSTATUS			status;					/* return status of KAMUI API */
extern	KMVERTEXBUFFDESC	VertexBufferDesc;		/* Vertex-buffer */
extern	KMVERTEXCONTEXT		VertexContext;			/* Vertex context */

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

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

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

	for(i = 0; i < nNumFaces; i++)
	{
		kmxxStartVertexStrip(&BufferDesc);
		if(bTexture == TRUE) {
			pVert = &pVertices[pFaces[i][0]];
			kmxxSetVertex_3(KM_VERTEXPARAM_NORMAL,
							pVert->fX,
							pVert->fY,
							pVert->fInvW,
							pVert->fUOverW,
							pVert->fVOverW,
							pVert->u32Colour,
							pVert->u32Specular
							);

			pVert = &pVertices[pFaces[i][1]];
			kmxxSetVertex_3(KM_VERTEXPARAM_NORMAL,
							pVert->fX,
							pVert->fY,
							pVert->fInvW,
							pVert->fUOverW,
							pVert->fVOverW,
							pVert->u32Colour,
							pVert->u32Specular
							);

			pVert = &pVertices[pFaces[i][2]];
			kmxxSetVertex_3(KM_VERTEXPARAM_ENDOFSTRIP,
							pVert->fX,
							pVert->fY,
							pVert->fInvW,
							pVert->fUOverW,
							pVert->fVOverW,
							pVert->u32Colour,
							pVert->u32Specular
							);
		}
		else {	/* if(bTexture == TRUE) : NO-TEXTURE */
			pVert = &pVertices[pFaces[i][0]];
			kmxxSetVertex_0(KM_VERTEXPARAM_NORMAL,
							pVert->fX,
							pVert->fY,
							pVert->fInvW,
							pVert->u32Colour
							);

			pVert = &pVertices[pFaces[i][1]];
			kmxxSetVertex_0(KM_VERTEXPARAM_NORMAL,
							pVert->fX,
							pVert->fY,
							pVert->fInvW,
							pVert->u32Colour
							);

			pVert = &pVertices[pFaces[i][2]];
			kmxxSetVertex_0(KM_VERTEXPARAM_ENDOFSTRIP,
							pVert->fX,
							pVert->fY,
							pVert->fInvW,
							pVert->u32Colour
							);
		} /* end of if(bTexture == TRUE) */
	}
	kmxxReleaseCurrentPtr(&BufferDesc);
}

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

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

	for(i = 0; i < nNumFaces; i++)
	{
		kmxxStartVertexStrip(&BufferDesc);
		if(bTexture == TRUE) {
			pVert = &pVertices[pFaces[i][0]];
			kmxxSetVertex_3(KM_VERTEXPARAM_NORMAL,
							pVert->fX,
							pVert->fY,
							pVert->fInvW,
							pVert->fUOverW,
							pVert->fVOverW,
							pVert->u32Colour,
							pVert->u32Specular
							);

			pVert = &pVertices[pFaces[i][1]];
			kmxxSetVertex_3(KM_VERTEXPARAM_NORMAL,
							pVert->fX,
							pVert->fY,
							pVert->fInvW,
							pVert->fUOverW,
							pVert->fVOverW,
							pVert->u32Colour,
							pVert->u32Specular
							);

			pVert = &pVertices[pFaces[i][3]];
			kmxxSetVertex_3(KM_VERTEXPARAM_NORMAL,
							pVert->fX,
							pVert->fY,
							pVert->fInvW,
							pVert->fUOverW,
							pVert->fVOverW,
							pVert->u32Colour,
							pVert->u32Specular
							);

			pVert = &pVertices[pFaces[i][2]];
			kmxxSetVertex_3(KM_VERTEXPARAM_ENDOFSTRIP,
							pVert->fX,
							pVert->fY,
							pVert->fInvW,
							pVert->fUOverW,
							pVert->fVOverW,
							pVert->u32Colour,
							pVert->u32Specular
							);
		}
		else {	/* if(bTexture == TRUE) : NO-TEXTURE */
			pVert = &pVertices[pFaces[i][0]];
			kmxxSetVertex_0(KM_VERTEXPARAM_NORMAL,
							pVert->fX,
							pVert->fY,
							pVert->fInvW,
							pVert->u32Colour
							);

			pVert = &pVertices[pFaces[i][1]];
			kmxxSetVertex_0(KM_VERTEXPARAM_NORMAL,
							pVert->fX,
							pVert->fY,
							pVert->fInvW,
							pVert->u32Colour
							);

			pVert = &pVertices[pFaces[i][3]];
			kmxxSetVertex_0(KM_VERTEXPARAM_NORMAL,
							pVert->fX,
							pVert->fY,
							pVert->fInvW,
							pVert->u32Colour
							);

			pVert = &pVertices[pFaces[i][2]];
			kmxxSetVertex_0(KM_VERTEXPARAM_ENDOFSTRIP,
							pVert->fX,
							pVert->fY,
							pVert->fInvW,
							pVert->u32Colour
							);
		} /* end of if(bTexture == TRUE) */
	}
	kmxxReleaseCurrentPtr(&BufferDesc);
}

/****************************************************************************/
/**	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_TEXTUREGOURAUD;
	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_POINT_SAMPLE;
/*	pVertexContext->FilterMode			= KM_BILINEAR; */
	pVertexContext->bSuperSample		= FALSE;
	pVertexContext->MipMapAdjust		= 0x00000004;		/* D=1.00 */
	pVertexContext->TextureShadingMode	= KM_MODULATE;
/*	pVertexContext->TextureShadingMode	= KM_MODULATE_ALPHA; */
	
	/* for Texture ControlBit */

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

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

	kmProcessVertexRenderState(pVertexContext);
}

/*--------------------------------------------------------------------*/
/*  Function Name   : ResetMatrix                                     */
/*  Inputs          : Object                                          */
/*  Outputs         :                                                 */
/*  Returns         :                                                 */
/*  Globals Used    :                                                 */
/*  Description     : Builds an identity matrix and stores it in T    */
/*--------------------------------------------------------------------*/
void ResetMatrix (int Object)
{
	static TRANSFORM Id = 
	{ 
		{
			{1.0f, 0.0f, 0.0f, 0.0f},
		  	{0.0f, 1.0f, 0.0f, 0.0f},
		  	{0.0f, 0.0f, 1.0f, 0.0f}
		},
		{
			{1.0f, 0.0f, 0.0f, 0.0f},
		  	{0.0f, 1.0f, 0.0f, 0.0f},
		  	{0.0f, 0.0f, 1.0f, 0.0f}
		}
	};

	memcpy (&T[Object], &Id, sizeof (TRANSFORM));
}
/*----------------------------------------------------------------------*/
/*  Function Name   :  Rotate                                           */
/*  Inputs          :  Object, Axis, Theta                              */
/*  Outputs         :                                                   */
/*  Returns         :                                                   */
/*  Globals Used    :                                                   */
/*  Description     :  Rotate T an angle Theta around Axis              */
/*----------------------------------------------------------------------*/
void Rotate (int Object, sgl_vector Axis, float Theta)
{
	float	halfTheta;
 	float	sinHalfTheta;
 	float	cosHalfTheta;
	float	MRot[3][4], MTemp[3][4]; 
	float	W,X,Y,Z;
	float	Tm1,Tm2,Tm3,Tm4,Tm5,TmNorm;
	int		Row, Col;

	/* convert to quaternian */

	halfTheta = Theta * 0.5f;

	/*	Using double sin and cos  */ 

	cosHalfTheta = (float) cos(halfTheta);
	sinHalfTheta = (float) sin(halfTheta);

	W = cosHalfTheta;
	X = sinHalfTheta * Axis[0];
	Y = sinHalfTheta * Axis[1];
	Z = sinHalfTheta * Axis[2];

	/* convert quaternian into Matrix form */ 

	Tm1 = X * X;
	Tm2 = Y * Y;
	Tm3 = Z * Z;
	Tm4 = Tm2 + Tm3;

	TmNorm= W*W + Tm1 + Tm4;  /* Normalising term */

	if (TmNorm!=0.0f)
	{
		Tm5 = 2.0f / TmNorm; 
	}
	else
	{
		Tm5 = 0.0f;
	}

	MRot[0][0] = 1.0f - Tm5*Tm4;
	MRot[1][1] = 1.0f - Tm5*(Tm1+Tm3);    
	MRot[2][2] = 1.0f - Tm5*(Tm1+Tm2);

	Tm1 = Tm5*X;
	Tm2 = Tm5*Y;
	Tm4 = Tm5*Z*W;
	Tm5 = Tm1*Y; 

	MRot[0][1] = Tm5 - Tm4;
	MRot[1][0] = Tm5 + Tm4;

	Tm4 = Tm2*W;
	Tm5 = Tm1*Z;

	MRot[0][2] = Tm5 + Tm4;
	MRot[2][0] = Tm5 - Tm4;


	Tm4 = Tm1*W; 
	Tm5 = Tm2*Z;

	MRot[1][2] = Tm5 - Tm4;
	MRot[2][1] = Tm5 + Tm4;

	memcpy (MTemp, &T[Object].Matrix, sizeof (T[Object].Matrix));

	for(Row = 0; Row < 3; Row ++)
	{
		for(Col = 0; Col < 3; Col ++)
		{
			/*
				unroll the innermost loop to do sr bit
			*/

			T[Object].Matrix[Row][Col] = MTemp[Row][0] * MRot[0][Col] +
								  MTemp[Row][1] * MRot[1][Col] +
								  MTemp[Row][2] * MRot[2][Col];
		}
	}

	memcpy (MTemp, &T[Object].Inverse, sizeof (T[Object].Matrix));

	for(Row = 0; Row < 3; Row ++)
	{
		for(Col = 0; Col < 3; Col ++)
		{
			/*
				unroll the innermost loop to do sr bit
				inverse of a rotation is its transpose!
			*/

			T[Object].Inverse[Row][Col] = MRot[0][Row] * MTemp[0][Col] +
								   MRot[1][Row] * MTemp[1][Col] +
								   MRot[2][Row] * MTemp[2][Col];
		}
	}
}
/*----------------------------------------------------------------------*/
/*  Function Name   :  Scale                                            */
/*  Inputs          :  Object, S                                        */
/*  Outputs         :                                                   */
/*  Returns         :                                                   */
/*  Globals Used    :                                                   */
/*  Description     :  Escale T using S values (x, y, z)                */
/*----------------------------------------------------------------------*/
void Scale (int Object, float SX, float SY, float SZ)
{
	int i;

	float invX = 1.0f / SX;
	float invY = 1.0f / SY;
	float invZ = 1.0f / SZ;

	for(i = 0; i < 3; i ++)
	{
	 	T[Object].Matrix[i][0] *= SX;
	 	T[Object].Matrix[i][1] *= SY;
	 	T[Object].Matrix[i][2] *= SZ;

	 	T[Object].Inverse[0][i] *= invX;
	 	T[Object].Inverse[1][i] *= invY;
	 	T[Object].Inverse[2][i] *= invZ;
	}

 	T[Object].Inverse[0][3] *= invX;
 	T[Object].Inverse[1][3] *= invY;
 	T[Object].Inverse[2][3] *= invZ;
}
/*----------------------------------------------------------------------*/
/*  Function Name   : Translate                                         */
/*  Inputs          : Object, Tr                                        */
/*  Outputs         :                                                   */
/*  Returns         :                                                   */
/*  Globals Used    :                                                   */
/*  Description     : Translate T using Tr(x,y,z) displacement.         */
/*----------------------------------------------------------------------*/
void Translate (int Object, float TrX, float TrY, float TrZ)
{
	T[Object].Matrix[0][3] += T[Object].Matrix[0][0] * TrX + T[Object].Matrix[0][1] * TrY + T[Object].Matrix[0][2] * TrZ;	
	T[Object].Matrix[1][3] += T[Object].Matrix[1][0] * TrX + T[Object].Matrix[1][1] * TrY + T[Object].Matrix[1][2] * TrZ;	
	T[Object].Matrix[2][3] += T[Object].Matrix[2][0] * TrX + T[Object].Matrix[2][1] * TrY + T[Object].Matrix[2][2] * TrZ;	

	T[Object].Inverse[0][3] -= TrX;	
	T[Object].Inverse[1][3] -= TrY;	
	T[Object].Inverse[2][3] -= TrZ;	
}
/*----------------------------------------------------------------------*/
/*  Function Name   : InitScene                                         */
/*  Inputs          :                                                   */
/*  Outputs         :                                                   */
/*  Returns         :                                                   */
/*  Globals Used    :                                                   */
/*  Description     : Draw a object in SGL                              */
/*----------------------------------------------------------------------*/
void InitScene (void)
{
/*	sgltri_startofframe  (&SGLContext); */
}
/*----------------------------------------------------------------------*/
/*  Function Name   : EndScene                                          */
/*  Inputs          :                                                   */
/*  Outputs         :                                                   */
/*  Returns         :                                                   */
/*  Globals Used    :                                                   */
/*  Description     : Draw a object in SGL                              */
/*----------------------------------------------------------------------*/
void EndScene (void)
{
#if defined(_X86_)
	time_t		ltime;
#endif

/*	sgltri_render        (&SGLContext); */

	txt_SetCursor(0,1);
#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 > 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   : InitMeshes                                        */
/*  Inputs          :                                                   */
/*  Outputs         :                                                   */
/*  Returns         :                                                   */
/*  Globals Used    :                                                   */
/*  Description     : Draw a object in SGL                              */
/*----------------------------------------------------------------------*/
void InitMeshes (int nMeshes, CASTMESHES *pMeshes)
{
register i;
#if defined(_X86_)
#else
/* SET4 / SET5 */
int mptr = 0x0c400000;
#endif

	/*(CASTMESHES *) CMesh = pMeshes; */

	/* Memory allocation for SGLVert, UV values and SmoothShading*/
    for (i=0; i<nMeshes; i++) 
	{
		memcpy ( &CMesh[i], &pMeshes[i], sizeof (CASTMESHES) );
#if defined(_X86_)
		SGLVert[i] = (SGLVERTEX *) malloc (CMesh[i].NumVertex*sizeof(SGLVERTEX));
#else
		SGLVert[i] = (SGLVERTEX *)mptr; mptr += CMesh[i].NumVertex*sizeof(SGLVERTEX);
#endif
		ResetMatrix (i); 
		SetUV (i);
		SetSmoothShading (i, (i==0)?C_NONE:C_PLAIN);
		TotalPolys += CMesh[i].NumFaces;
	}
}
/*----------------------------------------------------------------------*/
/*  Function Name   : FreeMeshes                                        */
/*  Inputs          :                                                   */
/*  Outputs         :                                                   */
/*  Returns         :                                                   */
/*  Globals Used    :                                                   */
/*  Description     : Draw a object in SGL                              */
/*----------------------------------------------------------------------*/
void FreeMeshes (int nMeshes)
{
register i;

	for (i=0; i<nMeshes; i++) free(SGLVert[i]);

}
/*----------------------------------------------------------------------*/
/*  Function Name   : SetVertices                                       */
/*  Inputs          : nFaces, Faces, nVertex, pVertex                   */
/*  Outputs         :                                                   */
/*  Returns         :                                                   */
/*  Globals Used    :                                                   */
/*  Description     : Draw a object in SGL                              */
/*----------------------------------------------------------------------*/
/*void SetVertices (int Object, int Texture, int Effect) */
void SetVertices (int Object, KMVERTEXCONTEXT VertexContext, int Effect )
{
register		i, nVertex = 0;
float			fX, fY, fZ, pV[3], f1OverZ;
float			CamFocus = 600.0f;

    for (i=0; i<CMesh[Object].NumVertex; i++)
	{
	
	pV[0] = *(CMesh[Object].Vertex+nVertex++);
	pV[1] = *(CMesh[Object].Vertex+nVertex++);
	pV[2] = *(CMesh[Object].Vertex+nVertex++);

	fX = (pV[0] * T[Object].Matrix[0][0] + pV[1] * T[Object].Matrix[0][1] + pV[2] * T[Object].Matrix[0][2] + T[Object].Matrix[0][3]);
	fY = (pV[0] * T[Object].Matrix[1][0] + pV[1] * T[Object].Matrix[1][1] + pV[2] * T[Object].Matrix[1][2] + T[Object].Matrix[1][3]);
	fZ = (pV[0] * T[Object].Matrix[2][0] + pV[1] * T[Object].Matrix[2][1] + pV[2] * T[Object].Matrix[2][2] + T[Object].Matrix[2][3]);

	fZ += 800;

	if (fZ<0.00001f) fZ = 0.00001f;

	f1OverZ = 1.0f / fZ;

	(SGLVert[Object]+i)->fX = f1OverZ * fX * 600 + 320;
	(SGLVert[Object]+i)->fY = -f1OverZ * fY * 600 + 240;
    (SGLVert[Object]+i)->fInvW = f1OverZ;

	if (Effect == FX_OPTIC)
	{
		(SGLVert[Object]+i)->fUOverW = 0.5f + (fX + pV[2])/200.0f;
		(SGLVert[Object]+i)->fVOverW = 0.5f + (fY + pV[2])/200.0f;
	}

    if (Effect == FX_PLANAR)
	{
		(SGLVert[Object]+i)->fUOverW = 0.5f + fX/640.0f;
		(SGLVert[Object]+i)->fVOverW = 0.5f + fY/480.0f;
	}
	}
   
    VFog = (unsigned char) ((fZ*150.0f)/2000.0f) - 30;

#if 0
/*	SGLContext.nTextureName = Texture; */
	/* Clear render state */
	VertexContext.RenderState	= 0;

	if(Trans == TRUE) {
		/* */
		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;
		/* */
		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_TEXTURESHADINGMODE;
		VertexContext.TextureShadingMode	= KM_MODULATE;
		/* */
		VertexContext.RenderState	|= KM_USEALPHA;
		VertexContext.bUseAlpha = FALSE;
	}

	if (CInfo.Textured) {
		/* Set shading mode */
		VertexContext.RenderState	|= KM_SHADINGMODE;
		VertexContext.ShadingMode	= KM_TEXTUREGOURAUD;
		/* Set texture surface */
		VertexContext.pTextureSurfaceDesc	= &Texture;
	}
	else {
		/* Set shading mode */
		VertexContext.RenderState	|= KM_SHADINGMODE;
		VertexContext.ShadingMode	= KM_NOTEXTUREGOURAUD;
	}

	/* Process VertexContext */
	status = kmProcessVertexRenderState(&VertexContext);
	Check_Status(status, "kmProcessVertexRenderState");
#endif

/*	sgltri_triangles (&SGLContext, NumFac, (int(*)[3])CMesh[Object].Faces, SGLVert[Object]); */
	kmtri_triangles (	VertexBufferDesc,				/* KMVERTEXBUFFDESC	BufferDesc, */
						VertexContext,					/* KMVERTEXCONTEXT		VertexContext, */
						CMesh[Object].NumFaces,			/* int  nNumFaces, */
						(int(*)[3])CMesh[Object].Faces,	/* int  pFaces[][3], */
						SGLVert[Object],				/* PSGLVERTEX  pVertices */
						TRUE							/* int	bTexture */
						);

}
/*----------------------------------------------------------------------*/
/*  Function Name   : SetUV                                             */
/*  Inputs          : nFaces, Faces, pUV                                */
/*  Outputs         :                                                   */
/*  Returns         :                                                   */
/*  Globals Used    :                                                   */
/*  Description     :                                                   */
/*----------------------------------------------------------------------*/
void SetUV (int Object)
{
register i;

    for (i=0; i<CMesh[Object].NumVertex; i++)
	{
	(SGLVert[Object]+i)->fUOverW = *(CMesh[Object].UV++);
	(SGLVert[Object]+i)->fVOverW = *(CMesh[Object].UV++);
	}

}
/*----------------------------------------------------------------------*/
/*  Function Name   : SetSmoothShading                                  */
/*  Inputs          : nFaces, Faces, nVertex, pNormals                  */
/*  Outputs         :                                                   */
/*  Returns         :                                                   */
/*  Globals Used    :                                                   */
/*  Description     :                                                   */
/*----------------------------------------------------------------------*/
void SetSmoothShading (int Object, int Color)
{
register				i, nNormal = 0;
unsigned char			Col, Spec;
/*unsigned char			Spec; */
static unsigned char	SpecVal[256] = { 0 };
float					LightLocal[3], f1OverLength, fN[3];

    	LightLocal[0] = LightDir[0]*T[Object].Inverse[0][0] + LightDir[1]*T[Object].Inverse[0][1] + LightDir[2]*T[Object].Inverse[0][2];
		LightLocal[1] = LightDir[0]*T[Object].Inverse[1][0] + LightDir[1]*T[Object].Inverse[1][1] + LightDir[2]*T[Object].Inverse[1][2];
		LightLocal[2] = LightDir[0]*T[Object].Inverse[2][0] + LightDir[1]*T[Object].Inverse[2][1] + LightDir[2]*T[Object].Inverse[2][2];

		f1OverLength =  1.0f / (float) sqrt (LightLocal[0]*LightLocal[0] + 
											 LightLocal[1]*LightLocal[1] + 
											 LightLocal[2]*LightLocal[2]);

		LightLocal[0] *= f1OverLength;
		LightLocal[1] *= f1OverLength;
		LightLocal[2] *= f1OverLength;

		for (i=0; i<CMesh[Object].NumVertex; i++)
		{
		fN[0] = *(CMesh[Object].Normals+nNormal++);
		fN[1] = *(CMesh[Object].Normals+nNormal++);
		fN[2] = *(CMesh[Object].Normals+nNormal++);

		Col = (unsigned char) (127.0f * (fN[0]*LightLocal[0] + fN[1]*LightLocal[1] + fN[2]*LightLocal[2]+ 1.0f) );
		Spec =(((Col>240) ? (Col-240)*16 : 0));
	   
		/* Setting vertex colour */
		/* Specular RGB is Highlight Color, Specular A is Vertexfog */
		(SGLVert[Object]+i)->u32Specular  = RGBAColour(Spec, Spec, Spec,  0xFF);
     
		switch (Color)
		{
		case C_WHITE :  (SGLVert[Object]+i)->u32Colour = RGBAColour(Col,Col,Col, 150); break;
        case C_BLACK :  (SGLVert[Object]+i)->u32Colour = RGBAColour(Col>>3,Col>>3,Col>>3, 128); break;
	    case C_GREY  :  (SGLVert[Object]+i)->u32Colour = RGBAColour(Col>>1,Col>>1,Col>>1, 128); break;
		case C_RED   :  (SGLVert[Object]+i)->u32Colour = RGBAColour(Col, 0, 0, 128); break;
		case C_GREEN :  (SGLVert[Object]+i)->u32Colour = RGBAColour(0, Col, 0, 128); break;
		case C_BLUE  :  (SGLVert[Object]+i)->u32Colour = RGBAColour(0, 0, Col, 128); break;
		case C_YELLOW:  (SGLVert[Object]+i)->u32Colour = RGBAColour(Col, Col, 0, 128); break;
		case C_BROWN :  (SGLVert[Object]+i)->u32Colour = RGBAColour(Col,Col>>1,Col>>2, 128); break;
		case C_PLAIN :  (SGLVert[Object]+i)->u32Specular  = RGBAColour(0,0,0, 0);
		                (SGLVert[Object]+i)->u32Colour = RGBAColour(255,255,255, 150);
						break;
      }
		}
		

}
/*----------------------------------------------------------------------*/
/*  Function Name   : SetBackground                                     */
/*  Inputs          :                                                   */
/*  Outputs         :                                                   */
/*  Returns         :                                                   */
/*  Globals Used    :                                                   */
/*  Description     :                                                   */
/*----------------------------------------------------------------------*/
void SetBackground (PKMSURFACEDESC TextureID)
{
#if 0
	SGLVERTEX Plane[3];
	int Tri[3] = { 2, 1, 0 };

     Plane[0].fX		= 0.0f;
	 Plane[0].fY		= 0.0f;
	 Plane[0].fInvW		= 0.000001f;
	 Plane[0].u32Colour = RGBAColour (255, 255, 255, 255);
	 Plane[0].fUOverW   = 0.0f + BILINEAR_CORRECTION;
     Plane[0].fVOverW   = 1.0f - BILINEAR_CORRECTION; 
            

	 Plane[1].fX		= 640.0f;
	 Plane[1].fY		= 0.0f;
	 Plane[1].fInvW		= 0.000001f;
	 Plane[1].u32Colour = RGBAColour (255, 255, 255, 255);
	 Plane[1].fUOverW   = 1.0f - BILINEAR_CORRECTION;
     Plane[1].fVOverW   = 1.0f - BILINEAR_CORRECTION; 

	 Plane[2].fX		= 640.0f;
	 Plane[2].fY		= 480.0f;
	 Plane[2].fInvW		= 0.000001f;
	 Plane[2].u32Colour = RGBAColour (255, 255, 255, 255);
	 Plane[2].fUOverW   = 1.0f - BILINEAR_CORRECTION;
     Plane[2].fVOverW   = 0.0f + BILINEAR_CORRECTION; 

/*	SGLContext.nTextureName =  TextureID; */
/*	SGLContext.eFilterType  =  sgl_tf_bilinear; */
/*	SGLContext.u32Flags     =  SGLTT_TEXTURE | SGLTT_BILINEAR ; */
	 
	/* sgltri_set_background (&SGLContext,  Plane, 1.0f/10000.0f); */

	InitBackGround();
#endif

	KMSTATUS			status;
	KMVERTEXCONTEXT		BackVertexContext;		/* Vertex context */
	KMVERTEX_01			BV01[3];				/* for NO-TEXTURE-GOURAUD */
	KMVERTEX_03			BV03[3];				/* for TEXTURE-GOURAUD */
	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.bUseSpecular			= FALSE;
	BackVertexContext.UVFormat				= KM_32BITUV;

	/* for ISP/TSP InstructionWord  */
	BackVertexContext.DepthMode				= KM_GREATER;
	BackVertexContext.CullingMode			= KM_NOCULLING;
	BackVertexContext.ScreenCoordination	= KM_SCREEN;
	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;
#if 1
	BackVertexContext.FogMode				= KM_NOFOG;
#endif

	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		= 0.0f;		/* Specular Color Alpha */
	BackVertexContext.fOffsetColorRed		= 0.0f;		/* Specular Color Red */
	BackVertexContext.fOffsetColorGreen		= 0.0f;		/* Specular Color Green */
	BackVertexContext.fOffsetColorBlue		= 0.0f;		/* Specular Color Blue */

	if(TextureID == (PKMSURFACEDESC)NULL) {	/* No texture */
		BackVertexContext.ColorType				= KM_FLOATINGCOLOR;
		BackVertexContext.ShadingMode			= KM_NOTEXTUREGOURAUD;
	}
	else {					/* Use texture */
		BackVertexContext.ColorType				= KM_PACKEDCOLOR;
		BackVertexContext.ShadingMode			= KM_TEXTUREGOURAUD;
		BackVertexContext.pTextureSurfaceDesc	= TextureID;
	}

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

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

	if(TextureID == (PKMSURFACEDESC)NULL) {	/* No texture */
		/* Vertex #1 */
		BV01[0].ParamControlWord	= KM_VERTEXPARAM_NORMAL;
		BV01[0].fX				=   0.0f;
		BV01[0].fY				= 479.0f;
#if defined(_STRICT_UNION_)
		BV01[0].u.fZ			=  0.0001f;
#else
		BV01[0].fZ				=  0.0001f;
#endif
		BV01[0].fBaseAlpha		=   0.0f;
		BV01[0].fBaseRed		=   0.0f;
		BV01[0].fBaseGreen		=   0.0f;
		BV01[0].fBaseBlue		=   0.0f;

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

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

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

		/* set VERTEX */
		status = kmSetBackGroundPlane(	pBV,					/* pVertex */
										KM_VERTEXTYPE_01,		/* VertexType */
										sizeof(KMVERTEX_01)		/* StructSize */
										);
		Check_Status(status, "kmSetBackGroundPlane");
	}
	else {		/* Use texture */
		/* Vertex #1 */
		BV03[0].ParamControlWord	= KM_VERTEXPARAM_NORMAL;
		BV03[0].fX					=  0.0f;
		BV03[0].fY					=  0.0f;
#if defined(_STRICT_UNION_)
		BV03[0].u.fZ				=  0.0001f;
#else
		BV03[0].fZ					=  0.0001f;
#endif
		BV03[0].fU					=  0.0f;
		BV03[0].fV					=  1.0f;
		BV03[0].uBaseRGB.dwPacked	=  RGBAColour (255, 255, 255, 255);
		BV03[0].uOffsetRGB.dwPacked	=  RGBAColour (255, 255, 255, 255);

		/* Vertex #2 */
		BV03[1].ParamControlWord	= KM_VERTEXPARAM_NORMAL;
		BV03[1].fX					= 640.0f;
		BV03[1].fY					=   0.0f;
#if defined(_STRICT_UNION_)
		BV03[1].u.fZ				=  0.0001f;
#else
		BV03[1].fZ					=  0.0001f;
#endif
		BV03[1].fU					= 1.0f;
		BV03[1].fV					= 1.0f;
		BV03[1].uBaseRGB.dwPacked	= RGBAColour (255, 255, 255, 255);
		BV03[1].uOffsetRGB.dwPacked	= RGBAColour (255, 255, 255, 255);

		/* Vertex #3 */
		BV03[2].ParamControlWord	= KM_VERTEXPARAM_ENDOFSTRIP;
		BV03[2].fX					= 640.0f;
		BV03[2].fY					= 480.0f;
#if defined(_STRICT_UNION_)
		BV03[2].u.fZ				=  0.0001f;
#else
		BV03[2].fZ					=  0.0001f;
#endif
		BV03[2].fU					= 1.0f;
		BV03[2].fV					= 0.0f;
		BV03[2].uBaseRGB.dwPacked	= RGBAColour (255, 255, 255, 255);
		BV03[2].uOffsetRGB.dwPacked	= RGBAColour (255, 255, 255, 255);

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

		/* set VERTEX */
		status = kmSetBackGroundPlane(	pBV,					/* pVertex */
										KM_VERTEXTYPE_03,		/* VertexType */
										sizeof(KMVERTEX_03)		/* StructSize */
										);
		Check_Status(status, "kmSetBackGroundPlane");
	}

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

}
/*----------------------------------------------------------------------*/
/*  Function Name   : Timer                                             */
/*  Inputs          :                                                   */
/*  Outputs         :                                                   */
/*  Returns         :                                                   */
/*  Globals Used    :                                                   */
/*  Description     :                                                   */
/*----------------------------------------------------------------------*/
void Timer (int Action)
{
char Text[500];
static double TotalTime= 0.0f, CurrentTime = 0.0f, AverageTime = 0.0f;
static unsigned TimeFrame = 0;
static LARGE_INTEGER LapTime1, LapTime2, Freq;
extern int nTrees, Type;
int NT[] = { 3, 6, 12};
	
    if (Action == RESET_TIME || TimeFrame == 0)
	{
		TotalTime = 0.0f;
		TimeFrame = 1;
        QueryPerformanceCounter(&LapTime1);
		return;
	}

	QueryPerformanceFrequency(&Freq);
	QueryPerformanceCounter(&LapTime2);
  
	if (LapTime2.LowPart < LapTime1.LowPart){
       QueryPerformanceCounter(&LapTime1);
	   return;
	   }		
	 
	CurrentTime = (double)LapTime2.LowPart - (double)LapTime1.LowPart;

	QueryPerformanceCounter(&LapTime1);

	CurrentTime  = (CurrentTime)/((double)Freq.LowPart);

	TotalTime += CurrentTime;

	AverageTime = (TotalTime*1000.0f)/TimeFrame;

	if (Action == DISPLAY_TIME)
	{
	sprintf (Text,"Transformed Polys per sec : %d",TotalPolys+nTrees*NT[Type]); 
	Print3D  (2, 5, 0.6f, Text);
    
	sprintf (Text,"Software FPS : %d",(int)(1.0f/CurrentTime)); 
	Print3D  (2, 25, 0.6f	,Text);
	Print3D  (2, 45, 0.6f	,"Hardware FPS on consol screen (F9)");
	}

	else if (Action==HARD_TIME)
	{
	/* printf ("\r Hardware  FPS: %.2f     ",(1.0f/CurrentTime));  */
	}

   TimeFrame++;

}
/*----------------------------------------------------------------------*/
/*  Function Name   : EnviroMap                                         */
/*  Inputs          : nFaces, Faces, pUV                                */
/*  Outputs         :                                                   */
/*  Returns         :                                                   */
/*  Globals Used    :                                                   */
/*  Description     :                                                   */
/*----------------------------------------------------------------------*/
void EnviroMap (int nVertex, float *pVertex, SGLVERTEX *SglVertex)
{
register i;

    for (i=0; i<nVertex; i++)
	{
	(SglVertex+i)->fUOverW = (SglVertex+i)->fUOverW;/*(((float) atan2 (Vertices[k][2] - Centre[2], fX) + PI) * ONEOVERTWOPI) * fU; */
	(SglVertex+i)->fVOverW = (SglVertex+i)->fUOverW;/*(((float) atan2 (Vertices[k][1] - Centre[1], fX) + PI) * ONEOVERTWOPI) * fV; */
	}

}

/*----------------------------------------------------------------------*/
/*  Function Name   : 3DPrint                                           */
/*  Inputs          : nFaces, Faces, pUV                                */
/*  Outputs         :                                                   */
/*  Returns         :                                                   */
/*  Globals Used    :                                                   */
/*  Description     :                                                   */
/*----------------------------------------------------------------------*/
void Print3D (float PosX, float PosY, float Size, char *Text)
{
#if 0
unsigned				i = 0;
sgl_intermediate_map	TempMap;
SGLVERTEX				LettVert[4];
int						Val, Tri[] = {0,1,2,3}; 
float					CurPos = 0, VPos, HPos, UVHPos, UVVPos, TSize = 160.0f;
static					TexID = 666, Depht = 1;
    
    if (Size<=0) return;

    if (TexID == 666) {
		TempMap.id[0]='I'; TempMap.id[1]='M'; TempMap.id[2]='A'; TempMap.id[3]='P';
		TempMap.x_dim = 256;
		TempMap.y_dim = 256;
		TempMap.pixels = (sgl_map_pixel *) malloc (4*256*256);

		for (i=0; i<256*256; i++)
		{
			(TempMap.pixels+i)->red   = 255;
			(TempMap.pixels+i)->green = 0;
			(TempMap.pixels+i)->blue  = 0;
			(TempMap.pixels+i)->alpha = ABCTexture[i];
		}

		TexID = sgl_create_texture (sgl_map_trans16, sgl_map_256x256, FALSE, FALSE, &TempMap, NULL);
	}

      i=0;
	  PosY -= 0.01f; PosX += 0.01f; /* To avoid integer rounding */
	  TSize *= Size;

      while (TRUE)
	  {
       Val = (int)*(Text+i++);
	   if (Val==0 || i>100) return;

	   if (Val==' ')  {CurPos += TextSize['1']*TSize; continue;}
  
	   VPos   = TSize*(30.0f/255.0f);
	   HPos   = TSize*TextSize[Val];
	   UVHPos = TextSize[Val];
	   UVVPos = (28.0f/255.0f);

	   LettVert[0].fX = (PosX+CurPos);
	   LettVert[0].fY =  PosY;
	   LettVert[0].fInvW = 10000.0f;
	   LettVert[0].u32Colour = RGBAColour (255,255,255,255);
	   LettVert[0].fUOverW = TextU[Val];
	   LettVert[0].fVOverW = 1.0f-TextV[Val];

	   LettVert[1].fX = (PosX+CurPos+HPos) ;
	   LettVert[1].fY = PosY;
	   LettVert[1].fInvW = 10000.0f;
	   LettVert[1].u32Colour = RGBAColour (255,255,255,255);
	   LettVert[1].fUOverW = TextU[Val]+UVHPos;
	   LettVert[1].fVOverW = 1.0f-TextV[Val];

	   LettVert[2].fX = (PosX+CurPos+HPos);
	   LettVert[2].fY = (PosY+VPos);
	   LettVert[2].fInvW = 10000.0f;
	   LettVert[2].u32Colour = RGBAColour (255,255,255,255);
	   LettVert[2].fUOverW = TextU[Val]+UVHPos;
	   LettVert[2].fVOverW = 1.0f-TextV[Val]-UVVPos;

	   LettVert[3].fX = (PosX+CurPos);
	   LettVert[3].fY = (PosY+VPos) ;
	   LettVert[3].fInvW = 10000.0f;
	   LettVert[3].u32Colour = RGBAColour (255,255,255,255);
	   LettVert[3].fUOverW = TextU[Val];
	   LettVert[3].fVOverW = 1.0f-TextV[Val]-UVVPos;

       CurPos += TextSize[Val]*TSize;

	   SGLContext.nTextureName =  TexID;
	   SGLContext.u32Flags     =  SGLTT_TEXTURE | SGLTT_BILINEAR ;

	  sgltri_quads (&SGLContext, 1, (int (*)[4])Tri, LettVert);
	  }
#endif
}

/*----------------------------------------------------------------------*/
/*  Function Name   : SetGround                                         */
/*  Inputs          :                                                   */
/*  Outputs         :                                                   */
/*  Returns         :                                                   */
/*  Globals Used    : SGLContext                                        */
/*  Description     : Draws the floor and moves it (just UV values).    */
/*----------------------------------------------------------------------*/
void SetGround(KMVERTEXCONTEXT VertexContext)
{
extern float Ang, PosX, PosY;

/* extern int	TexGround; */
KMSURFACEDESC	TexGround;

SGLVERTEX  Vert[4];
int   Face[1][4] = {0,1,2,3}, i;
float CosA, SinA, x;
static float Movement=0;
float Pnt[4][3] =  {{-5000.0f,  -140.0f, -100.0f},           
                    {-5000.0f,  40.0f, 8000.0f},
                    { 6000.0f,  40.0f, 8000.0f},
                    { 6000.0f,  -140.0f, -100.0f}};	


	CosA = (float)cos(Ang);
	SinA = (float)sin(Ang);

    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   = RGBAColour (255,255,255, 255);    
        Vert[i].u32Specular = RGBAColour (255,255,255, 255);
		if (i==1||i==2)  Vert[i].u32Colour = RGBAColour (0,0,0,0);
   }

    /* Here the continous fluency of the ground.  */
    /* Note that I just move texture's UV values. */
    /* I don't move the camera.                   */
 
    /* Set UV values for each textured vertex. */
    Vert[0].fUOverW = -15.0f;  Vert[0].fVOverW = 0.0f;          
    Vert[1].fUOverW = -15.0f;  Vert[1].fVOverW =  10.0f;
    Vert[2].fUOverW =  15.0f;  Vert[2].fVOverW  = 10.0f;
    Vert[3].fUOverW =  15.0f;  Vert[3].fVOverW =  0.0f;

	PosX += (float)sin(Ang)/50.0f;
	for (i=0; i<4; i++)
	{
		x = Vert[i].fUOverW;
		Vert[i].fUOverW += PosX;
		Vert[i].fVOverW += PosY;
	}

    /* Set a sigle textured quad to create the ground. */
#if 0
    SGLContext.nTextureName   = TexGround;    
	SGLContext2.u32Flags      = 0;
    SGLContext.u32Flags       = SGLTT_TEXTURE | SGLTT_CHANGEFILTER | SGLTT_MIPMAPOFFSET | SGLTT_GOURAUD;
#endif

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

/*----------------------------------------------------------------------*/
/*  Function Name   : Perspect                                          */
/*  Inputs          :                                                   */
/*  Outputs         :                                                   */
/*  Returns         :                                                   */
/*  Globals Used    :                                                   */
/*  Description     :                                                   */
/*----------------------------------------------------------------------*/
void Perspect (const sgl_vector Point3D, SGLVERTEX *Vert)
{
const sgl_vector CamPos = { 0.0, 40.0, 150.0};
float x, y, z;

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

    Vert->fX    =  (800 * x) / z + 320;
    Vert->fY    =  (800 * 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;                   
}

/*----------------------------------------------------------------------*/
/*  Function Name   : Lightning                                         */
/*  Inputs          : TextureID                                         */
/*  Outputs         :                                                   */
/*  Returns         :                                                   */
/*  Globals Used    : SGLContext                                        */
/*  Description     : Especial Effect.                                  */
/*----------------------------------------------------------------------*/
void Lightning (KMVERTEXCONTEXT VertexContext)
{
extern float PosX;
extern unsigned char BColor[3];
SGLVERTEX Plane[4];
int Quad[] = {0,1,2,3};
extern Frame;
static float Cont=20, PX, Size;

#if 0
     if ((unsigned)(sgl_rand()%1000)<10) {
		 PX = (float)(sgl_rand()%200)+200.0f; 
	     Cont=0.0f;
		 Size=(sgl_rand()%200>100)?1.0f:-1.0f; 
	 }
#endif
	if ((unsigned)(rand()%1000)<10) {
		PX = (float)(rand()%200)+200.0f;
		Cont=0.0f;
		Size=(rand()%200>100)?1.0f:-1.0f;
	 }
	 if (Cont++>10)return;


     Plane[0].fX = 0.0f +PX;
	 Plane[0].fY = 0.0f;
	 Plane[0].fInvW = 1.0f/1000.0f;
	 Plane[0].u32Colour =  RGBAColour(255, 255, 255, 255);
	 Plane[0].fUOverW    =  0;
     Plane[0].fVOverW    =  1.0f; 
           

	 Plane[1].fX = 150+PX;
	 Plane[1].fY = 0.0f;
	 Plane[1].fInvW = 1.0f/1000.0f;
	 Plane[1].u32Colour =  RGBAColour(255, 255, 255,255);
	 Plane[1].fUOverW    =  Size;
     Plane[1].fVOverW    =  1.0f; 

	 Plane[2].fX = 380;
	 Plane[2].fY = 340.0f;
	 Plane[2].fInvW = 1.0f/1000.0f;
	 Plane[2].u32Colour =  RGBAColour(255, 255, 255,255);
	 Plane[2].fUOverW    =  Size;
     Plane[2].fVOverW    =  0; 

	 Plane[3].fX = 250;
	 Plane[3].fY = 340 ;
	 Plane[3].fInvW = 1.0f/1000.0f;
	 Plane[3].u32Colour = RGBAColour(255, 255, 255, 255);
	 Plane[3].fUOverW    =  0;
     Plane[3].fVOverW    =  0; 

#if 0
     SGLContext.nTextureName  =  TextureID;
	 /*
	  * Blend mode:  Source : SOURCEALPHA (from a BMP map)   Destination: ONE
	  */
	 SGLContext2.u32BlendCntl = sgl_blend_cntl( sgl_blend_srca, sgl_blend_one, sgl_accum2_notused );
	 SGLContext.u32Flags |= SGLTT_DIRECT_EXTENSIONS;
     SGLContext2.u32Flags     =  SGLTT2_BLENDCNTL | SGLTT2_TEXTUREBLEND;
#endif

/*	 sgltri_quads (&SGLContext, 1, (int(*)[4])Quad, Plane); */
	kmtri_quads (	VertexBufferDesc,	/* KMVERTEXBUFFDESC	BufferDesc, */
					VertexContext,		/* KMVERTEXCONTEXT		VertexContext, */
					1,					/* int  nNumFaces, */
					(int(*)[4])Quad,	/* int  pFaces[][3], */
					Plane,				/* PSGLVERTEX  pVertices */
					TRUE				/* int	bTexture */
					);

}

/*----------------------------------------------------------------------*/
/*  Function Name   : SetFogTable                                       */
/*  Inputs          :                                                   */
/*  Outputs         :                                                   */
/*  Returns         :                                                   */
/*  Globals Used    :                                                   */
/*  Description     :                                                   */
/*----------------------------------------------------------------------*/
void SetFogTable (KMDWORD FogDensity)
{
	int				i;
	KMPACKEDARGB	fogcol;
	KMFLOAT			FogTable[128];

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

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

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

}

/*----------------------------------------------------------------------*/
/*  Function Name   : SetContext                                        */
/*  Inputs          : CInfo                                             */
/*  Outputs         :                                                   */
/*  Returns         :                                                   */
/*  Globals Used    :                                                   */
/*  Description     :                                                   */
/*----------------------------------------------------------------------*/

void SetContext (PKMVERTEXCONTEXT pVertexContext, INFO CInfo, PKMSURFACEDESC pTexture)
{

	pVertexContext->RenderState = 0;
	if (CInfo.Bilinear) {
			pVertexContext->RenderState	|= KM_FILTERMODE;
			pVertexContext->FilterMode	 = KM_BILINEAR;
	}
	else {
			pVertexContext->RenderState	|= KM_FILTERMODE;
			pVertexContext->FilterMode	 = KM_POINT_SAMPLE;
	}

	if (CInfo.Textured) {
		if(CInfo.Gouraud) {
			/* Set shading mode */
			pVertexContext->RenderState	|= KM_SHADINGMODE;
			pVertexContext->ShadingMode	= KM_TEXTUREGOURAUD;
			/* Set texture surface */
			pVertexContext->pTextureSurfaceDesc	= pTexture;
		}
		else {
			/* Set shading mode */
			pVertexContext->RenderState	|= KM_SHADINGMODE;
			pVertexContext->ShadingMode	= KM_TEXTUREFLAT;
			/* Set texture surface */
			pVertexContext->pTextureSurfaceDesc	= pTexture;
		}
	}
	else {
		if(CInfo.Gouraud) {
			/* Set shading mode */
			pVertexContext->RenderState	|= KM_SHADINGMODE;
			pVertexContext->ShadingMode	= KM_NOTEXTUREGOURAUD;
		}
		else {
			/* Set shading mode */
			pVertexContext->RenderState	|= KM_SHADINGMODE;
			pVertexContext->ShadingMode	= KM_NOTEXTUREFLAT;
		}
	}

	pVertexContext->RenderState	|= KM_FLIPUV;
	pVertexContext->FlipUV		= KM_FLIP_UV;


	status = kmProcessVertexRenderState(pVertexContext);
	Check_Status(status, "kmProcessVertexRenderState");
}

/*---------------------- End Of File -----------------------------------*/
