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

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

float			LightDir[3] = { -1.0f, 0.0f, 0.0f };
unsigned		TotalPolys = 0;
unsigned 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;				/* APの開始時間 */
#endif
extern	int					frame;					/* 画面フレーム */
extern	int					frame_2;				/* 画面フレーム上位 */
extern	int					pcount_f;				/* Hight-resolution counter supported? */
extern	double				nFPS;					/* 現在の性能(Frame/Second) */
extern	double				aFPS;					/* 性能の平均値 */
extern	double				MxFPS;					/* 最高性能 */
extern	double				MnFPS;					/* 最低性能 */
extern	__int64				Time3i;					/* render API 完了時刻 */
extern	double				OldTime3;				/* １フレーム前のrender直後の時間(msec) */
extern	double				Time3;					/* render API 完了時刻 */
extern	double				freq;					/* カウンタの精度 */
extern	double				nowTime;				/* 現在の描画時間(msec) */
extern	double				maxTime;				/* 最高描画時間(msec) */
extern	double				minTime;				/* 最低描画時間(msec) */
extern	double				totalTime;				/* 累積render時間(msec) */
extern	double				aveTime;				/* 平均描画時間(msec) */
#endif

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

/*--------------------------------------------------------------------*/
/*  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,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_)
	/* render終了の時刻 ----------------------------------------------------------------- */
	if(pcount_f) {
		QueryPerformanceCounter((LARGE_INTEGER*)&Time3i);	/* sgltri_render終了の時刻 */
		OldTime3 = Time3; Time3 = (double)Time3i * freq;
	}
	else {
		OldTime3 = Time3; Time3 = (double)timeGetTime();	/* sgltri_render終了の時刻 */
	}

/* 性能計算 ------------------------------------------------------------------ */
	nowTime = Time3 - OldTime3;					/* ただいまのフレームを作成するのにかかった時間 */
	if(nowTime > 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, KMSURFACEDESC Texture, int Effect, int Trans, INFO CInfo)
{
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;

/*	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 & Set Texture */
	status = kmProcessVertexRenderState(&VertexContext);
	Check_Status(status, "kmProcessVertexRenderState");

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

	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.55f;
		BV01[0].fBaseGreen		=   0.87f;
		BV01[0].fBaseBlue		=   0.96f;

		/* 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.15f;
		BV01[1].fBaseBlue		=   0.73f;

		/* 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.55f;
		BV01[2].fBaseGreen		=   0.87f;
		BV01[2].fBaseBlue		=   0.96f;

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

		/* set VERTEX */
		PRINTOUT(("Non-Textured Background\n"));
		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 */
		PRINTOUT(("Textured Background\n"));
		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   : SetContext                                        */
/*  Inputs          : CInfo                                             */
/*  Outputs         :                                                   */
/*  Returns         :                                                   */
/*  Globals Used    :                                                   */
/*  Description     :                                                   */
/*----------------------------------------------------------------------*/

void SetContext (INFO CInfo)
{


/*	SGLContext.bFogOn               = CInfo.TableFog; */
/*	SGLContext.fFogB				= 0.0f; */
/*	SGLContext.fFogG				= 0.0f; */
/*	SGLContext.fFogR				= 0.0f; */

/*	SGLContext.u32FogDensity        = 3; */
/*	SGLContext.bCullBackfacing      = 0; */
/*	SGLContext.bDoClipping          = TRUE; */
/*	SGLContext.cBackgroundColour[0] = 0; */
/*	SGLContext.cBackgroundColour[1] = 0; */
/*	SGLContext.cBackgroundColour[2] = 0; */
/*	SGLContext.eShadowLightVolMode  = NO_SHADOWS_OR_LIGHTVOLS; */
/*	SGLContext.u.fShadowBrightness  = 0.5f; */
/*	SGLContext.u.u32LightVolColour  = RGBAColour (255, 255, 255, 255); */
/*	SGLContext.bFlipU               = TRUE; */
/*	SGLContext.bFlipV               = TRUE; */
/*	SGLContext.bDoUVTimesInvW       = TRUE; */
/*	SGLContext.RenderRegions        = 0; */
/*	SGLContext.n32MipmapOffset      = 0; */
/*	SGLContext.u32GlobalTrans       = 128; */
/*	SGLContext.eFilterType          = sgl_tf_bilinear; */

/*	SGLContext.u32Flags             = 0;//SGLTT_MIPMAP; */

/*	if (CInfo.Bilinear)	     	SGLContext.u32Flags |= SGLTT_BILINEAR; */
/*	if (CInfo.Textured)			SGLContext.u32Flags |= SGLTT_TEXTURE ; */
/*	if (CInfo.Highlight & CInfo.Textured)     	SGLContext.u32Flags |= SGLTT_HIGHLIGHT; */
/*	if (CInfo.Gouraud)      	SGLContext.u32Flags |= SGLTT_GOURAUD; */
/*	if (CInfo.GlobalTrans)		SGLContext.u32Flags |= SGLTT_GLOBALTRANS; */
/*	if (CInfo.VertexAlpha)		SGLContext.u32Flags |= SGLTT_VERTEXTRANS; */
/*	if (CInfo.VertexFog) 		SGLContext.u32Flags |= SGLTT_VERTEXFOG; */

	/*-------------------------------------------------------------------------------- */
	/* Initialize Vertex Context */
	/*-------------------------------------------------------------------------------- */
	memset( &VertexContext, 0, sizeof(VertexContext));	/* Crear Context */
	InitVertexContext(&VertexContext);					/* Initialize context */

	VertexContext.RenderState = 0;
	if (CInfo.Bilinear) {
			VertexContext.RenderState	|= KM_FILTERMODE;
			VertexContext.FilterMode	 = KM_BILINEAR;
	}
	status = kmProcessVertexRenderState(&VertexContext);
	Check_Status(status, "kmProcessVertexRenderState");
}

/*----------------------------------------------------------------------*/
/*  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
}
/*---------------------- End Of File -----------------------------------*/
