#include <GameOS\GameOS.hpp>
#include <GameOS\ToolOs.hpp>
#pragma warning( disable: 4514 )
#include <stdlib.h>
#include <memory.h>
#include <math.h>
#include <stdio.h>
#include "Data3D.hpp"


#define INITIAL_TEST 2
//
//
//
// Testing shell for 3D routines
//
//
//
//
//#define FLIP_VIEWPORT			// 0,0 in bottom left when enabled, normally top right is 0,0
//
//#define TEST_DIRTYRECT
//
//
//#define TEST_GDI_EMULATION		// Test the GDI Font Emulation
//

#define NumLines 300			// Number of points and lines

static Spin1, Spin2, Spin3;
int NumPot=5;
int MoveX=0,MoveY=0;
float Angle;
float SlowAngle;
float Gamma=1.0;
int Lines[NumLines][6];
HGOSFONT3D Font_Arial8;
HGOSFONT3D Font_GDIArial8;
int Test;
DWORD Frame;
int Polys;
int Seed;
double lastframe;
bool LoadTest=0;
DWORD Average;
DWORD frame;
DWORD TotalPolys;
double TotalFrameRate;
DWORD tex1=0,tex2,tex3,tex4,tex5,tex6,tex7,tex8,tex9,tex10,tex11,tex12,tex13,tex14,tex15,tex16,tex17;
DWORD rtex1=0,rtex2,rtex3,rtex4,rtex5,rtex6,rtex7,rtex8,rtex9,rtex10,rtex11,rtex12,rtex13,rtex14,rtex15,rtex16,rtex17;


DWORD ColorTable[8]={ 0xff000000, 0xffff0000, 0xff00ff00, 0xff0000ff, 0xffffff00, 0xff00ffff, 0xffff00ff, 0xffffffff };
DWORD RenderTexture;
volatile float TestData;
gosD3DVERTEX* pTeapot=0;
bool InitTeapot=1;
DWORD hTeapot=0;
BYTE *pROMImage = NULL;
DWORD ROMImageSize;

gos_CycleData CycleData;
__int64 CycleData1;
//
//
DWORD AlphaTexture;
DWORD TestTexture;
DWORD TestMipMap;
DWORD WhichTexture=1;
DWORD EnableFog=1;
DWORD BackGroundColor;
DWORD HandleRC;
float Size;
float Step;
float SafeSize;
float ViewportMulX,ViewportAddX,ViewportMulY,ViewportAddY;
DWORD UseTexture;
const float Xpixels=(1.0f/640.0f);
const float Ypixels=(1.0f/480.0f);


DWORD LightmapTexture;
DWORD WallTexture;

DWORD LoadPNG;
DWORD LoadJPG;
DWORD LoadTGA;
DWORD LoadBMP;



#define PI                  3.14159265358979323846f
#define ELLIPSE_NUMRINGS    20
#define ELLIPSE_NUMSECTIONS 20
#define ELLIPSE_X_LENGTH    1.5f
#define ELLIPSE_Y_LENGTH    1.5f
#define ELLIPSE_Z_LENGTH    4.5f
DWORD hBanana=0;
DWORD BananaTexture=0;
WORD* pBananaIndices=0;
bool InitBanana=1;



#define SUB_VECTOR( result,u,v ) ( result.x=u.x-v.x, result.y=u.y-v.y, result.z=u.z-v.z )
#define CROSS_PRODUCT( result,u,v ) ( result.x=u.y*v.z-u.z*v.y, result.y=u.z*v.x-u.x*v.z, result.z=u.x*v.y-u.y*v.x )
#define NORMALIZE( n ) {float l=1.0f/sqrtf(n.x*n.x + n.y*n.y + n.z*n.z); n.x*=l; n.y*=l; n.z*=l;}


// Variables used for bump map
const numBumpTri = 128;
const numBumpVert = numBumpTri+2; // 66;
float seaX[numBumpVert];
float seaY[numBumpVert];
float seaXBump[numBumpVert];
float seaYBump[numBumpVert];
gos_VERTEX_3UV bumpVert[numBumpVert];
DWORD bumptex=0;
DWORD normtex = 0;
DWORD watertex = 0;
DWORD bumpenvtex = 0;
const numBumpIndices = numBumpTri*3;
unsigned short bumpIndices[numBumpIndices];
float bumpRadius = 100.f;



int MaxSwap = 4;
const int MaxSwapWidth = 512;
const int MaxSwapHeight = 1024;
DWORD SwapBuffer[MaxSwapWidth];
int TexView = 10;

struct SwapInfo
{
	DWORD Width;
	DWORD Height;
	DWORD Handle;
	DWORD Color;
} SwapTexData[80];
int texturesCreated = 0;



void __stdcall SwapPopulateFunction( DWORD handle, void *pInstance )
{
	DWORD *ptr;
	DWORD x;
	SwapInfo *pInfo = (SwapInfo *)pInstance;

	for( ptr = (DWORD *)SwapBuffer, x=0; x<pInfo->Width; x++ )
		*ptr++ = pInfo->Color;
	
	// transfer buffer to texture

	gos_ConvertTextureRect(handle,0,0,SwapBuffer,0,pInfo->Width,pInfo->Height);

}



gosMATRIX SetRotateXMatrix( float fRads )
{
	gosMATRIX mat={         1.0f,         0.0f,         0.0f,         0.0f,
				            0.0f,  cosf(fRads), -sinf(fRads),         0.0f,
							0.0f,  sinf(fRads),  cosf(fRads),         0.0f,
							0.0f,         0.0f,         0.0f,         1.0f,
				  };
	return mat;
}


gosMATRIX ProjectionMatrix( float near_plane,    // distance to near clipping plane
							float far_plane,     // distance to far clipping plane
							float fov_horiz,     // horizontal field of view angle, in radians
							float fov_vert )     // vertical field of view angle, in radians
{
    float    h, w, Q;
 
    w = (float)(cosf(fov_horiz/2)/sinf(fov_horiz/2));
    h = (float)(cosf(fov_vert/2)/sinf(fov_vert/2));
    Q = far_plane/(far_plane - near_plane);
 
    gosMATRIX ret;
	memset( &ret, 0, sizeof(ret) );
    ret._11 = w;
    ret._22 = h;
    ret._33 = Q;
    ret._43 = -Q*near_plane;
    ret._34 = 1.0f;
    return ret;
}   

static int RebuildCount = 0;


void __stdcall MyRebuildFunction( DWORD handle, void *pInstance )
{
	DWORD *pBuffer = (DWORD *)gos_Malloc( 32*32*4 );
	DWORD *ptr;
	int x,y;

	RebuildCount = (RebuildCount+1)%8;
	DWORD color = ColorTable[RebuildCount];

	pInstance = pInstance;	// avoid unused warning

	// Fill buffer with magenta

	ptr = pBuffer;
	for( y=0; y<32; y++ )
		for( x=0; x<32; x++ )
			*ptr++ = color;
	
	// transfer buffer to texture

	gos_ConvertTextureRect(handle,0,0,pBuffer,32*4,32,32);

	gos_Free( pBuffer );
}


void TestStackWalk()
{
	*(char*)0=0;
}

void FilledQuad( DWORD x, DWORD y, DWORD Width, DWORD Height, DWORD Color )
{
	gos_VERTEX pVertices[4];

	memset( pVertices, 0, sizeof(pVertices) );
	
	pVertices[0].x		= (float)x;
	pVertices[0].y		= (float)y;
	pVertices[0].z		= 0.0;
	pVertices[0].rhw	= 1.0;
	pVertices[0].argb	= Color;

	pVertices[1].x		= (float)x;
	pVertices[1].y		= (float)(y+Height);
	pVertices[1].z		= 0.0;
	pVertices[1].rhw	= 1.0;
	pVertices[1].argb	= Color;

	pVertices[2].x		= (float)(x+Width);
	pVertices[2].y		= (float)(y+Height);
	pVertices[2].z		= 0.0;
	pVertices[2].rhw	= 1.0;
	pVertices[2].argb	= Color;

	pVertices[3].x		= (float)(x+Width);
	pVertices[3].y		= (float)(y);
	pVertices[3].z		= 0.0;
	pVertices[3].rhw	= 1.0;
	pVertices[3].argb	= Color;

	gos_DrawQuads( pVertices, 4 );
}




void DoQuad( DWORD l, DWORD t, DWORD r, DWORD b, float w, bool TestAddress=false )
{
	gos_VERTEX pVertices[10];

	r=(DWORD)(l+(r-l)*w);
	b=(DWORD)(t+(b-t)*w);

	gos_GetViewport( &ViewportMulX, &ViewportMulY, &ViewportAddX, &ViewportAddY );

	pVertices[0].x		= (l*Xpixels)*ViewportMulX + ViewportAddX-0.5f;
	pVertices[0].y		= (t*Ypixels)*ViewportMulY + ViewportAddY-0.5f;
	pVertices[0].z		= 0.5f;
	pVertices[0].rhw	= w;
	pVertices[0].argb	= TestAddress ? 0xffffffff : 0x000000ff;
	pVertices[0].frgb	= 0;

	pVertices[1].x		= (l*Xpixels)*ViewportMulX + ViewportAddX-0.5f;
	pVertices[1].y		= (b*Ypixels)*ViewportMulY + ViewportAddY-0.5f;
	pVertices[1].z		= 0.5f;
	pVertices[1].rhw	= w;
	pVertices[1].argb	= TestAddress ? 0xffffffff : 0x0000ff00;
	pVertices[1].frgb	= 0;

	pVertices[2].x		= (r*Xpixels)*ViewportMulX + ViewportAddX-0.5f;
	pVertices[2].y		= (b*Ypixels)*ViewportMulY + ViewportAddY-0.5f;
	pVertices[2].z		= 0.5f;
	pVertices[2].rhw	= w;
	pVertices[2].argb	= TestAddress ? 0xffffffff : 0xffff0000;
	pVertices[2].frgb	= 0;

	pVertices[3].x		= (r*Xpixels)*ViewportMulX + ViewportAddX-0.5f;
	pVertices[3].y		= (t*Ypixels)*ViewportMulY + ViewportAddY-0.5f;
	pVertices[3].z		= 0.5f;
	pVertices[3].rhw	= w;
	pVertices[3].argb	= TestAddress ? 0xffffffff : 0xffffffff;
	pVertices[3].frgb	= 0;

	if( TestAddress )
	{
		pVertices[0].u		= -2.0f;
		pVertices[0].v		= -2.0f;
		pVertices[1].u		= -2.0f;
		pVertices[1].v		= 2.0f;
		pVertices[2].u		= 2.0f;
		pVertices[2].v		= 2.0f;
		pVertices[3].u		= 2.0f;
		pVertices[3].v		= -2.0f;
	}
	else
	{
		pVertices[0].u		= 0.0f;
		pVertices[0].v		= 0.0f;
		pVertices[1].u		= 0.0f;
		pVertices[1].v		= 1.0f;
		pVertices[2].u		= 1.0f;
		pVertices[2].v		= 1.0f;
		pVertices[3].u		= 1.0f;
		pVertices[3].v		= 0.0f;
	}

	gos_DrawQuads( pVertices, 4 );
}

void tDrawLine( int X0, int Y0, int X1, int Y1, DWORD Color )
{
	gos_VERTEX v[2];

	memset( v,0,sizeof(v) );
	v[0].rhw		= 1.0f;
	v[1].rhw		= 1.0f;

	v[0].x		= (float)X0;
	v[0].y		= (float)Y0;
	v[0].argb	= Color;

	v[1].x		= (float)X1;
	v[1].y		= (float)Y1;
	v[1].argb	= Color;

	gos_DrawLines( v, 2 );
}				

void tDrawPoint( int X0, int Y0, DWORD Color )
{
	gos_VERTEX v[1];

	memset( v,0,sizeof(v) );
	v[0].rhw		= 1.0f;

	v[0].x		= (float)X0;
	v[0].y		= (float)Y0;
	v[0].argb	= Color;

	gos_DrawPoints( v, 1 );
}				


void DofQuad( DWORD l, DWORD t, DWORD r, DWORD b, float w, DWORD Fog=0xff000000, bool DirtyUpdate=0 )
{
	DirtyUpdate=DirtyUpdate;
	gos_VERTEX pVertices[10];

	r=(DWORD)(l+(r-l)*w);
	b=(DWORD)(t+(b-t)*w);

	gos_GetViewport( &ViewportMulX, &ViewportMulY, &ViewportAddX, &ViewportAddY );

	pVertices[0].x		= (l*Xpixels)*ViewportMulX + ViewportAddX-0.5f;
	pVertices[0].y		= (t*Ypixels)*ViewportMulY + ViewportAddY-0.5f;
	pVertices[0].z		= 1.0f-w;
	pVertices[0].rhw	= w;
	pVertices[0].u		= 0.0;
	pVertices[0].v		= 0.0;
	pVertices[0].argb	= 0xffffffff;
	pVertices[0].frgb	= Fog;

	pVertices[1].x		= (l*Xpixels)*ViewportMulX + ViewportAddX-0.5f;
	pVertices[1].y		= (b*Ypixels)*ViewportMulY + ViewportAddY-0.5f;
	pVertices[1].z		= 1.0f-w;
	pVertices[1].rhw	= w;
	pVertices[1].u		= 0.0;
	pVertices[1].v		= 1.0;
	pVertices[1].argb	= 0xffffffff;
	pVertices[1].frgb	= Fog;

	pVertices[2].x		= (r*Xpixels)*ViewportMulX + ViewportAddX-0.5f;
	pVertices[2].y		= (b*Ypixels)*ViewportMulY + ViewportAddY-0.5f;
	pVertices[2].z		= 1.0f-w;
	pVertices[2].rhw	= w;
	pVertices[2].u		= 1.0;
	pVertices[2].v		= 1.0;
	pVertices[2].argb	= 0xffffffff;
	pVertices[2].frgb	= Fog;

	pVertices[3].x		= (r*Xpixels)*ViewportMulX + ViewportAddX-0.5f;
	pVertices[3].y		= (t*Ypixels)*ViewportMulY + ViewportAddY-0.5f;
	pVertices[3].z		= 1.0f-w;
	pVertices[3].rhw	= w;
	pVertices[3].u		= 1.0;
	pVertices[3].v		= 0.0;
	pVertices[3].argb	= 0xffffffff;
	pVertices[3].frgb	= Fog;

	#ifdef TEST_DIRTYRECT
	if( DirtyUpdate )
	{
		gosDirtyRectangeRestoreArea( (DWORD)pVertices[0].x-1, (DWORD)pVertices[0].y-1, (DWORD)pVertices[2].x+1, (DWORD)pVertices[2].y+1 );
	}
	#endif

	gos_DrawQuads( pVertices, 4 );
}




void DrawSpinningTriangle( float X, float Y, DWORD Angle, float Size )
{
	gos_VERTEX pVertices[4];

	pVertices[0].x		= X+Size*(float)sin((2.0f*3.1415926/256.0f)*(Angle&255));
	pVertices[0].y		= Y+Size*(float)cos((2.0f*3.1415926/256.0f)*(Angle&255));
	pVertices[0].z		= 0.5f;
	pVertices[0].rhw	= 1.0;
	pVertices[0].argb	= 0xff800000;
	pVertices[0].frgb	= 0;
	pVertices[0].u		= 0.0f;
	pVertices[0].v		= 0.0f;

	pVertices[1].x		= X+Size*(float)sin((2.0f*3.1415926/256.0f)*((Angle+85)&255));
	pVertices[1].y		= Y+Size*(float)cos((2.0f*3.1415926/256.0f)*((Angle+85)&255));
	pVertices[1].z		= 0.5f;
	pVertices[1].rhw	= 1.0;
	pVertices[1].argb	= 0xff800000;
	pVertices[1].frgb	= 0;
	pVertices[1].u		= 0.0f;
	pVertices[1].v		= 1.0f;

	pVertices[2].x		= X+Size*(float)sin((2.0f*3.1415926/256.0f)*((Angle-85)&255));
	pVertices[2].y		= Y+Size*(float)cos((2.0f*3.1415926/256.0f)*((Angle-85)&255));
	pVertices[2].z		= 0.5f;
	pVertices[2].rhw	= 1.0;
	pVertices[2].argb	= 0xff800000;
	pVertices[2].frgb	= 0;
	pVertices[2].u		= 1.0f;
	pVertices[2].v		= 1.0f;

	gos_DrawTriangles( pVertices, 3 );
}





















//
//
//
void __stdcall UpdateRenderers()
{
//
//
//
	#ifdef TEST_DIRTYRECT
	bool WholeRedraw=(Frame==1) || gosDirtyRectangeLostTarget();
	#endif
//
// Always use the same random numbers
//
	gos_srand( Seed );
//
// Make viewport the whole screen
//
	#ifdef FLIP_VIEWPORT
	gos_SetupViewport( 1,1.0,1,BackGroundColor, 1.0, 0.0, 0.0, 1.0, 1, 0 );
	#else
		#ifdef TEST_DIRTYRECT
		gos_SetupViewport( WholeRedraw, 1.0, WholeRedraw, 0x208020, 0.0, 0.0, 1.0, 1.0, 1, 0 );
		#else
		gos_SetupViewport( 1,1.0,1,BackGroundColor, 0.0, 0.0, 1.0, 1.0, 1, 0 );
		#endif
	#endif
//
//
//
/*		gos_TextSetAttributes( Font_Arial8, 0xffffffff, 10, 0, 1, 0, 0 );
		gos_TextSetPosition( 50,50 );
		gos_TextDraw( "%f",gos_GetElapsedTime() );

		gos_TextSetAttributes( Font_Arial8, 0xffffffff, 10, 0, 1, 0, 0 );
		gos_TextSetPosition( 50,150 );
		gos_TextDraw( "%f",gos_GetElapsedTime(1) );
*/
	gos_TextSetRegion( 0, 0, Environment.screenWidth, Environment.screenHeight );

//	gos_TextSetAttributes( Font_Arial8, 0xffffffff, 2.0, 0, 1, 0, 0 );
//	gos_TextSetPosition( 50,50 );
//	gos_TextDraw( "Frame=%d, Time=%f",Frame, gos_GetElapsedTime() );

//
// 128 Pixel triangles
//
	if( Test==0 )
	{
		gos_GetViewport( &ViewportMulX, &ViewportMulY, &ViewportAddX, &ViewportAddY );
		gos_VERTEX v[16*3];

		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 0, 1, 0, 0 );

		double framerate=gos_GetElapsedTime()-lastframe;
		lastframe=gos_GetElapsedTime();
		TotalPolys+=Polys;
		TotalFrameRate+=framerate;
		if( TotalFrameRate && framerate && 0==(frame&31) )
		{
			Average=(DWORD)(TotalPolys/TotalFrameRate);
			TotalPolys=0;
			TotalFrameRate=0.0;
		}
		frame++;
		gos_TextSetPosition( 50,Environment.screenHeight-35 );
		gos_TextDraw( "%d triangles/second",Average );
		gos_TextSetPosition( 50,Environment.screenHeight-20 );
		gos_TextDraw( "%d - 128 Pixel %s Triangles",Polys,UseTexture ? "Textured" : "" );
		gos_TextSetPosition( 350,Environment.screenHeight-20 );
		gos_TextDraw( "1 - Advance test, 2 - More Tris, 3-Less, T-Texture" );

		gos_SetRenderState( gos_State_Clipping, 0 );
		gos_SetRenderState( gos_State_Fog, 0 );
		gos_SetRenderState( gos_State_MonoEnable, 0 );
		gos_SetRenderState( gos_State_ShadeMode, gos_ShadeGouraud );
		gos_SetRenderState( gos_State_Filter, gos_FilterNone );
		gos_SetRenderState( gos_State_Texture, UseTexture ? TestTexture : 0 );
		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneZero );
		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulate );

		memset( v, 0, 48*sizeof(gos_VERTEX) );

		for( int t0=0; t0<Polys; t0+=16 )
		{
			for( int t1=0; t1<48; t1+=3 )
			{
				float xo=0.2f+gos_rand()*(0.6f/32768.0f);
				float yo=0.2f+gos_rand()*(0.6f/32768.0f);
			
				v[t1].argb		= 0xffff0000;
				v[t1+1].argb	= 0xff00ff00;
				v[t1+2].argb	= 0xff0000ff;
				v[t1].rhw		= 1.0;
				v[t1+1].rhw		= 1.0;
				v[t1+2].rhw		= 1.0;

				v[t1+1].u		= 1.0;
				v[t1+1].v		= 1.0;
				v[t1+2].u		= 1.0;
				v[t1+2].v		= 1.0;

				v[t1].x		= (xo)*ViewportMulX + ViewportAddX;
				v[t1].y		= (yo)*ViewportMulY + ViewportAddY;

				v[t1+1].x	= (xo+Xpixels*16)*ViewportMulX + ViewportAddX;
				v[t1+1].y	= (yo)*ViewportMulY + ViewportAddY;

				v[t1+2].x	= (xo+Xpixels*16)*ViewportMulX + ViewportAddX;
				v[t1+2].y	= (yo+Ypixels*16)*ViewportMulY + ViewportAddY;
			}
			gos_DrawTriangles( v, 48 );
		}
	}
//
// Testing alpha modes
//
	if( Test==1 )
	{
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 0, 1, 0, 0 );
		gos_TextSetPosition( 50,Environment.screenHeight-20 );
		gos_TextDraw( "Alpha modes" );
		gos_TextSetPosition( 380,Environment.screenHeight-20 );
		gos_TextDraw( "1 - Advance test" );

		extern DWORD ValidatePasses;
		extern DWORD ValidateResult;
		char Tex10,Tex11,Tex1I,TexAI;

		gos_SetRenderState( gos_State_Filter, gos_FilterNone );
		gos_SetRenderState( gos_State_Texture, TestTexture );
		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulateAlpha );

		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneZero );
		Tex10=ValidateResult ? '0' : '1';
		DoQuad( 64+128*0,20, 64+128*0+256,256, 0.5 );

		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneOne );
		Tex11=ValidateResult ? '0' : '1';
		DoQuad( 64+128*1,20, 64+128*1+256,256, 0.5 );

		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneInvAlpha );
		Tex1I=ValidateResult ? '0' : '1';
		DoQuad( 64+128*2,20, 64+128*2+256,256, 0.5 );

		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_AlphaInvAlpha );
		TexAI=ValidateResult ? '0' : '1';
		DoQuad( 64+128*3,20, 64+128*3+256,256, 0.5 );

		gos_SetRenderState( gos_State_Texture, 0 );

		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneZero );
		Tex10=ValidateResult ? '0' : '1';
		DoQuad( 64+128*0,256, 64+128*0+256,512, 0.5 );

		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneOne );
		Tex11=ValidateResult ? '0' : '1';
		DoQuad( 64+128*1,256, 64+128*1+256,512, 0.5 );

		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneInvAlpha );
		Tex1I=ValidateResult ? '0' : '1';
		DoQuad( 64+128*2,256, 64+128*2+256,512, 0.5 );

		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_AlphaInvAlpha );
		TexAI=ValidateResult ? '0' : '1';
		DoQuad( 64+128*3,256, 64+128*3+256,512, 0.5 );

		gos_TextSetPosition( 64+128*0+10,150 );
		gos_TextDraw("OneZero %c",Tex10 );

		gos_TextSetPosition( 64+128*1+10,150 );
		gos_TextDraw("OneOne %c",Tex11 );

		gos_TextSetPosition( 64+128*2+10,150 );
		gos_TextDraw("OneInvAlpha %c",Tex1I );

		gos_TextSetPosition( 64+128*3+10,150 );
		gos_TextDraw("AlphaInvAlpha %c",TexAI );

		gos_TextSetPosition( 64+128*0+10,406 );
		gos_TextDraw("OneZero %c",Tex10 );

		gos_TextSetPosition( 64+128*1+10,406 );
		gos_TextDraw("OneOne %c",Tex11 );

		gos_TextSetPosition( 64+128*2+10,406 );
		gos_TextDraw("OneInvAlpha %c",Tex1I );

		gos_TextSetPosition( 64+128*3+10,406 );
		gos_TextDraw("AlphaInvAlpha %c",TexAI );
	}

//
// Testing filtering modes
//
	if( Test==2 )
	{
		#ifdef TEST_DIRTYRECT
		if( WholeRedraw )
		#endif
		{
			gos_SetRenderState( gos_State_Filter, gos_FilterNone );
			gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 0, 1, 0, 0 );
			gos_TextSetPosition( 50,Environment.screenHeight-20 );
			gos_TextDraw( "Point, BiLinear and Trilinear filtering" );
			gos_TextSetPosition( 380,440 );
			gos_TextDraw( "F - Fog on/off" );
			gos_TextSetPosition( 380,450 );
			gos_TextDraw( "M - Different Texture" );
			gos_TextSetPosition( 380,Environment.screenHeight-20 );
			gos_TextDraw( "1 - Advance test" );
		}

		DWORD FogColor=0xffffff;
		gos_SetRenderState( gos_State_Fog, EnableFog ? (DWORD)&FogColor : 0);

		gos_SetRenderState( gos_State_AlphaTest, 0 );
		gos_SetRenderState( gos_State_Perspective, 0 );
		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneZero );
		gos_SetRenderState( gos_State_Texture, WhichTexture ? TestMipMap : TestTexture );
		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulateAlpha );
		gos_SetRenderState( gos_State_Filter, gos_FilterBiLinear );

		#ifdef TEST_DIRTYRECT
		if( WholeRedraw )
		#endif
		{
			DofQuad( 12,40, 268,296, 1.0 );
			DofQuad( 278,40, 534,296, 0.5 );
			DofQuad( 416,40, 672,296, 0.25, 0x80000000 );			// Half fog
			DofQuad( 490,40, 746,296, 0.125, 0 );					// No fog
		}

		SafeSize=Size;

		#ifdef TEST_DIRTYRECT
		if( WholeRedraw )
			gosDirtyRectangleSaveTarget();
		#endif

		gos_SetRenderState( gos_State_AlphaTest, 0 );
		gos_SetRenderState( gos_State_Perspective, 0 );
		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneZero );
		gos_SetRenderState( gos_State_Texture, WhichTexture ? TestMipMap : TestTexture );
		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendDecal );
		gos_SetRenderState( gos_State_ZCompare, 0 );

		gos_SetRenderState( gos_State_Filter, gos_FilterNone );
		DofQuad( (DWORD)(10+128*(1.0-SafeSize)), (DWORD)(214+128*(1.0-SafeSize)), (DWORD)(266+128*(1.0-SafeSize)), (DWORD)(470+128*(1.0-SafeSize)), SafeSize, 0xff000000, 1 );

		gos_SetRenderState( gos_State_Filter, gos_FilterBiLinear );
		DofQuad( (DWORD)(192+128*(1.0-SafeSize)), (DWORD)(214+128*(1.0-SafeSize)), (DWORD)(448+128*(1.0-SafeSize)), (DWORD)(470+128*(1.0-SafeSize)), SafeSize, 0xff000000, 1 );

		gos_SetRenderState( gos_State_Filter, gos_FilterTriLinear );
		DofQuad( (DWORD)(374+128*(1.0-SafeSize)), (DWORD)(214+128*(1.0-SafeSize)), (DWORD)(630+128*(1.0-SafeSize)), (DWORD)(470+128*(1.0-SafeSize)), SafeSize, 0xff000000, 1 );
	}

//
// Test Bitmap TEXT
//
	if( Test == 3 )
	{
//		char TestString[]="This is a test string of TEXT, 0123456789 !@#$%%^&*()_+-= ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
	

		char* TestString;
		
		TestString=gos_GetResourceString( HandleRC, 1 );

		gos_TextSetAttributes( Font_Arial8, 0xffffffff, 1, 0, 1, 0, 0, 0 );
		gos_TextSetPosition( 50,Environment.screenHeight-20 );
		gos_TextDraw( "Text Test" );
		gos_TextSetPosition( 380,Environment.screenHeight-20 );
		gos_TextDraw( "1 - Advance test" );
//
		gos_TextSetRegion( 0, 0, 640, 480 );
//
		gos_SetRenderState( gos_State_Fog, 0 );
		gos_SetRenderState( gos_State_Filter, gos_FilterNone );
//
// Proportional
//
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, 1, 0, 1, 0, 0, 0 );
		gos_TextSetPosition( 20,40 );
		gos_TextDraw( TestString );
//
// Non-Proportional
//
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, 1, 0, 0, 0, 0, 0 );
		gos_TextSetPosition( 20,60 );
		gos_TextDraw( TestString );
//
// Bold
//
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, 1, 0, 1, 1, 0, 0 );
		gos_TextSetPosition( 20,80 );
		gos_TextDraw( TestString );
//
// Italic
//
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, 1, 0, 1, 0, 1, 0 );
		gos_TextSetPosition( 20,100 );
		gos_TextDraw( TestString );
//
// Bold+Italic
//
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, 1, 0, 1, 1, 1, 0 );
		gos_TextSetPosition( 20,120 );
		gos_TextDraw( TestString );
//
// 0.9* size
//
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, 0.9f, 0, 1, 0, 0, 0 );
		gos_TextSetPosition( 20,140 );
		gos_TextDraw( TestString );
//
// 2.0* size
//
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -16, 0, 1, 0, 0, 0 );
		gos_TextSetPosition( 20,160 );
		gos_TextDraw( TestString );
//
// 3.0* size
//
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -24, 0, 1, 0, 0, 0 );
		gos_TextSetPosition( 20,190 );
		gos_TextDraw( TestString );
//
// 3.0* size
//
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -24, 0, 1, 1, 1, 0 );
		gos_TextSetPosition( 20,230 );
		gos_TextDraw( TestString );
//
// Regions
//
		gos_TextSetRegion( 48, 270, 398, 290 );
		gos_TextDrawBackground( 48, 270, 398, 290, 0x8000c000 );
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 0, 1, 0, 0, 0 );
		gos_TextSetPosition( 20, 275 );
		gos_TextDraw( TestString );
//
// Text Size (unlimited single line text box)
//
		char TestLenString[]="This is a test of lengths OK?";
		DWORD Width,Height;
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 0, 1, 0, 0, 0 );
		gos_TextSetRegion( 0, 0, 640, 480 );
		gos_TextStringLength( &Width, &Height, TestLenString );
		gos_TextSetRegion( 20, 295, 20+Width, 295+Height );
		gos_TextDrawBackground( 20, 295, 20+Width, 295+Height, 0x40c00000 );
		gos_TextSetPosition( 20, 295 );
		gos_TextDraw( TestLenString );
//
// Text Size (limit width to 100, height depends on text and wrapping) - Right Align
//
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -16, 1, 1, 1, 1, 1 );
		gos_TextSetRegion( 0, 0, 100, 480 );
		gos_TextStringLength( &Width, &Height, TestLenString );
		gos_TextSetRegion( 20, 315, 20+100, 315+Height );
		gos_TextDrawBackground( 20, 315, 20+100, 315+Height, 0x40c00000 );
		gos_TextSetPosition( 20, 315 );
		gos_TextDraw( "Here is another length test." );
//
// Text Size with line breaks (and centering)
//
		char TestLenString1[]="Center this\n with\n line breaks";
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 1, 1, 0, 0, 3 );
		gos_TextSetRegion( 0, 0, 640, 480 );
		gos_TextStringLength( &Width, &Height, TestLenString1 );
		gos_TextSetRegion( 125, 345, 125+Width, 345+Height );
		gos_TextDrawBackground( 125, 345, 125+Width, 345+Height, 0xff0000c0 );
		gos_TextSetPosition( 125, 345 );
		gos_TextDraw( TestLenString1 );
//
// Text word wrap (centered)
//
		char TestLenString2[]="Davion Weapons Reasearch Station";
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 1, 1, 0, 0, 3 );
		Width=64;
		Height=64;
		gos_TextSetRegion( 420, 295, 420+Width, 295+Height );
		gos_TextDrawBackground( 420, 295, 420+Width, 295+Height, 0xff0000c0 );
		gos_TextSetPosition( 420, 295 );
		gos_TextDraw( TestLenString2 );
//
// Text Size with control codes
//
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 0, 1, 0, 0, 0 );
		gos_TextSetRegion( 0, 0, Environment.screenWidth, Environment.screenHeight );
		gos_TextSetPosition( 20, 440 );
		gos_TextDraw( "Testing  //color /test / ok /color=ffff0000RED/color=ff00ff00GREEN/color=ff0000ffBLUE/color=80ffffff ALPHA /color=ffffffff/bold=1BOLD/bold=0 /proportional=0Fixed Space/proportional=1 /italic=1Italic/italic=0  Normal text" );
//
// Big @ sign for accuracy
//
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -64, 0, 1, 0, 0, 0 );
		gos_TextSetPosition( 500, Environment.screenHeight-100 );
		gos_TextDraw( "@A" );
	}

//
// Test GDI TEXT 
//
	if( Test==4 )
	{
//		char TestString[]="This is a test string of TEXT, 0123456789 !@#$%%^&*()_+-= ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
	

		char* TestString;
		
		TestString=gos_GetResourceString( HandleRC, 1 );

		gos_TextSetAttributes( Font_GDIArial8, 0xffffffff, 1, 0, 1, 0, 0, 0 );
		gos_TextSetPosition( 50,Environment.screenHeight-20 );
		gos_TextDraw( "Text Test" );
		gos_TextSetPosition( 380,Environment.screenHeight-20 );
		gos_TextDraw( "1 - Advance test" );
//
		gos_TextSetRegion( 0, 0, 640, 480 );
//
		gos_SetRenderState( gos_State_Fog, 0 );
		gos_SetRenderState( gos_State_Filter, gos_FilterNone );
//
// Proportional
//
		gos_TextSetAttributes( Font_GDIArial8, 0xffffffff, 1, 0, 1, 0, 0, 0 );
		gos_TextSetPosition( 20,40 );
		gos_TextDraw( TestString );
//
// Non-Proportional
//
		gos_TextSetAttributes( Font_GDIArial8, 0xffffffff, 1, 0, 0, 0, 0, 0 );
		gos_TextSetPosition( 20,60 );
		gos_TextDraw( TestString );
//
// Bold
//
		gos_TextSetAttributes( Font_GDIArial8, 0xffffffff, 1, 0, 1, 1, 0, 0 );
		gos_TextSetPosition( 20,80 );
		gos_TextDraw( TestString );
//
// Italic
//
		gos_TextSetAttributes( Font_GDIArial8, 0xffffffff, 1, 0, 1, 0, 1, 0 );
		gos_TextSetPosition( 20,100 );
		gos_TextDraw( TestString );
//
// Bold+Italic
//
		gos_TextSetAttributes( Font_GDIArial8, 0xffffffff, 1, 0, 1, 1, 1, 0 );
		gos_TextSetPosition( 20,120 );
		gos_TextDraw( TestString );
//
// 0.9* size
//
		gos_TextSetAttributes( Font_GDIArial8, 0xffffffff, 0.9f, 0, 1, 0, 0, 0 );
		gos_TextSetPosition( 20,140 );
		gos_TextDraw( TestString );
//
// 2.0* size
//
		gos_TextSetAttributes( Font_GDIArial8, 0xffffffff, -16, 0, 1, 0, 0, 0 );
		gos_TextSetPosition( 20,160 );
		gos_TextDraw( TestString );
//
// 3.0* size
//
		gos_TextSetAttributes( Font_GDIArial8, 0xffffffff, -24, 0, 1, 0, 0, 0 );
		gos_TextSetPosition( 20,190 );
		gos_TextDraw( TestString );
//
// 3.0* size
//
		gos_TextSetAttributes( Font_GDIArial8, 0xffffffff, -24, 0, 1, 1, 1, 0 );
		gos_TextSetPosition( 20,230 );
		gos_TextDraw( TestString );
//
// Regions
//
		gos_TextSetRegion( 48, 270, 398, 290 );
		gos_TextDrawBackground( 48, 270, 398, 290, 0x8000c000 );
		gos_TextSetAttributes( Font_GDIArial8, 0xffffffff, -8, 0, 1, 0, 0, 0 );
		gos_TextSetPosition( 20, 275 );
		gos_TextDraw( TestString );
//
// Text Size (unlimited single line text box)
//
		char TestLenString[]="This is a test of lengths OK?";
		DWORD Width,Height;
		gos_TextSetAttributes( Font_GDIArial8, 0xffffffff, -8, 0, 1, 0, 0, 0 );
		gos_TextSetRegion( 0, 0, 640, 480 );
		gos_TextStringLength( &Width, &Height, TestLenString );
		gos_TextSetRegion( 20, 295, 20+Width, 295+Height );
		gos_TextDrawBackground( 20, 295, 20+Width, 295+Height, 0x40c00000 );
		gos_TextSetPosition( 20, 295 );
		gos_TextDraw( TestLenString );
//
// Text Size (limit width to 100, height depends on text and wrapping) - Right Align
//
		gos_TextSetAttributes( Font_GDIArial8, 0xffffffff, -16, 1, 1, 1, 1, 1 );
		gos_TextSetRegion( 0, 0, 100, 480 );
		gos_TextStringLength( &Width, &Height, TestLenString );
		gos_TextSetRegion( 20, 315, 20+100, 315+Height );
		gos_TextDrawBackground( 20, 315, 20+100, 315+Height, 0x40c00000 );
		gos_TextSetPosition( 20, 315 );
		gos_TextDraw( "Here is another lengths test." );
//
// Text Size with line breaks (and centering)
//
		char TestLenString1[]="Center this\n with\n line breaks";
		gos_TextSetAttributes( Font_GDIArial8, 0xffffffff, -8, 1, 1, 0, 0, 3 );
		gos_TextSetRegion( 0, 0, 640, 480 );
		gos_TextStringLength( &Width, &Height, TestLenString1 );
		gos_TextSetRegion( 125, 345, 125+Width, 345+Height );
		gos_TextDrawBackground( 125, 345, 125+Width, 345+Height, 0xff0000c0 );
		gos_TextSetPosition( 125, 345 );
		gos_TextDraw( TestLenString1 );
//
// Text word wrap (centered)
//
		char TestLenString2[]="Davion Weapons Reasearch Station";
		gos_TextSetAttributes( Font_GDIArial8, 0xffffffff, -8, 1, 1, 0, 0, 3 );
		Width=64;
		Height=64;
		gos_TextSetRegion( 420, 295, 420+Width, 295+Height );
		gos_TextDrawBackground( 420, 295, 420+Width, 295+Height, 0xff0000c0 );
		gos_TextSetPosition( 420, 295 );
		gos_TextDraw( TestLenString2 );
//
// Text Size with control codes
//
		gos_TextSetAttributes( Font_GDIArial8, 0xffffffff, -8, 0, 1, 0, 0, 0 );
		gos_TextSetRegion( 0, 0, Environment.screenWidth, Environment.screenHeight );
		gos_TextSetPosition( 20, 440 );
		gos_TextDraw( "Testing  //color /test / ok /color=ffff0000RED/color=ff00ff00GREEN/color=ff0000ffBLUE/color=80ffffff ALPHA /color=ffffffff/bold=1BOLD/bold=0 /proportional=0Fixed Space/proportional=1 /italic=1Italic/italic=0  Normal text" );
//
// Big @ sign for accuracy
//
		gos_TextSetAttributes( Font_GDIArial8, 0xffffffff, -64, 0, 1, 0, 0, 0 );
		gos_TextSetPosition( 500, Environment.screenHeight-100 );
		gos_TextDraw( "@A" );
	}
//
// 1 Pixel triangles
//
	if( Test==5 )
	{
		gos_GetViewport( &ViewportMulX, &ViewportMulY, &ViewportAddX, &ViewportAddY );
		gos_VERTEX v[16*3];

		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 0, 1, 0, 0 );

		double framerate=gos_GetElapsedTime()-lastframe;
		lastframe=gos_GetElapsedTime();
		TotalPolys+=Polys*2;
		TotalFrameRate+=framerate;
		if( TotalFrameRate && framerate && 0==(frame&31) )
		{
			Average=(DWORD)(TotalPolys/TotalFrameRate);
			TotalPolys=0;
			TotalFrameRate=0.0;
		}
		frame++;
		gos_TextSetPosition( 50,Environment.screenHeight-35 );
		gos_TextDraw( "%d triangles/second",Average );

		gos_TextSetPosition( 50,Environment.screenHeight-20 );
		gos_TextDraw( "%d - 1 Pixel %s Triangles",Polys*2 ,UseTexture ? "Textured" : "" );
		gos_TextSetPosition( 350,Environment.screenHeight-20 );
		gos_TextDraw( "1 - Advance test, 2 - More Tris, 3-Less, T-Texture" );

		gos_SetRenderState( gos_State_Clipping, 0 );
		gos_SetRenderState( gos_State_Fog, 0 );
		gos_SetRenderState( gos_State_MonoEnable, 0 );
		gos_SetRenderState( gos_State_ShadeMode, gos_ShadeGouraud );
		gos_SetRenderState( gos_State_Filter, gos_FilterNone );
		gos_SetRenderState( gos_State_Texture, UseTexture ? TestTexture : 0 );
		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneZero );
		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulate );

		memset( v, 0, 48*sizeof(gos_VERTEX) );

		for( int t0=0; t0<Polys*2; t0+=16 )
		{
			for( int t1=0; t1<48; t1+=3 )
			{
				float xo=0.2f+gos_rand()*(0.6f/32768.0f);
				float yo=0.2f+gos_rand()*(0.6f/32768.0f);
			
				v[t1].argb		= 0xffff0000;
				v[t1+1].argb	= 0xff00ff00;
				v[t1+2].argb	= 0xff0000ff;
				v[t1].rhw		= 1.0;
				v[t1+1].rhw		= 1.0;
				v[t1+2].rhw		= 1.0;

				v[t1+1].u		= 1.0;
				v[t1+1].v		= 1.0;
				v[t1+2].u		= 1.0;
				v[t1+2].v		= 1.0;

				v[t1].x		= (xo)*ViewportMulX + ViewportAddX;
				v[t1].y		= (yo)*ViewportMulY + ViewportAddY;

				v[t1+1].x	= (xo+Xpixels*1)*ViewportMulX + ViewportAddX;
				v[t1+1].y	= (yo)*ViewportMulY + ViewportAddY;

				v[t1+2].x	= (xo+Xpixels*1)*ViewportMulX + ViewportAddX;
				v[t1+2].y	= (yo+Ypixels*1)*ViewportMulY + ViewportAddY;

			}
			gos_DrawTriangles( v, 48 );
		}
	}

//
// Test lines and points
//
	if( Test==6 )
	{
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 0, 1, 0, 0 );
		gos_TextSetPosition( 50,Environment.screenHeight-20 );
		gos_TextDraw( "Lines and Points" );
		gos_TextSetPosition( 380,Environment.screenHeight-20 );
		gos_TextDraw( "1 - Advance test" );

		gos_SetRenderState( gos_State_Filter, gos_FilterNone );
		gos_SetRenderState( gos_State_Texture, 0 );
		gos_SetRenderState( gos_State_MonoEnable, 0 );
		gos_SetRenderState( gos_State_ShadeMode, gos_ShadeGouraud );
		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_AlphaInvAlpha );
		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulate );

		if( Environment.screenWidth<640 )
			gos_SetRenderState( gos_State_Clipping, 1 );

		tDrawLine( 10,440, 630,440, 0x80ff0000 );
		tDrawLine( 10,442, 630,442, 0x8000ff00 );
		tDrawLine( 10,444, 630,444, 0x800000ff );
		tDrawLine( 10,446, 630,446, 0x80ffffff );
		tDrawLine( 10,448, 630,448, 0x80000000 );

		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneZero );

		tDrawLine( 10,430, 630,430, 0xffff0000 );
		tDrawLine( 10,432, 630,432, 0xff00ff00 );
		tDrawLine( 10,434, 630,434, 0xff0000ff );
		tDrawLine( 10,436, 630,436, 0xffffffff );
		tDrawLine( 10,438, 630,438, 0xff000000 );

		for( int t0=0; t0<NumLines; t0+=2 )
		{
			if( Lines[t0][4]!=Lines[t0][5] )
			{
				DWORD X1=Lines[t0][0]+   ( (Lines[t0][1]-Lines[t0][0]) * Lines[t0][5] ) / Lines[t0][4];
				DWORD Y1=Lines[t0][2]+   ( (Lines[t0][3]-Lines[t0][2]) * Lines[t0][5] ) / Lines[t0][4];
				DWORD X2=Lines[t0+1][0]+ ( (Lines[t0+1][1]-Lines[t0+1][0]) * Lines[t0][5] ) / Lines[t0][4];
				DWORD Y2=Lines[t0+1][2]+ ( (Lines[t0+1][3]-Lines[t0+1][2]) * Lines[t0][5] ) / Lines[t0][4];
				
				tDrawLine( X1,Y1, X2,Y2, ColorTable[(t0>>1)&7] );

				tDrawPoint( X1,(Y1-(480-256)/2)/3+20, ColorTable[(t0>>1)&7] );
			}
		}

		gos_SetRenderState( gos_State_Clipping, 0 );
	}

//
// Test texture swapping
//
	if( Test==7 )
	{
		gos_SetRenderState( gos_State_Filter, gos_FilterNone );
		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneZero );
		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendDecal );

		gos_SetRenderState( gos_State_Texture, tex1 );
		DofQuad( 20+0*64,20, 20+0*64+256,256, 0.25 );

		gos_SetRenderState( gos_State_Texture, tex2 );
		DofQuad( 20+1*64,20, 20+1*64+256,256, 0.25 );

		gos_SetRenderState( gos_State_Texture, tex3 );
		DofQuad( 20+2*64,20, 20+2*64+256,256, 0.25 );

		gos_SetRenderState( gos_State_Texture, tex4 );
		DofQuad( 20+3*64,20, 20+3*64+256,256, 0.25 );

		gos_SetRenderState( gos_State_Texture, tex5 );
		DofQuad( 20+4*64,20, 20+4*64+256,256, 0.25 );

		gos_SetRenderState( gos_State_Texture, tex6 );
		DofQuad( 20+5*64,20, 20+5*64+256,256, 0.25 );

		gos_SetRenderState( gos_State_Texture, tex7 );
		DofQuad( 20+6*64,20, 20+6*64+256,256, 0.25 );

		gos_SetRenderState( gos_State_Texture, tex8 );
		DofQuad( 20+7*64,20, 20+7*64+256,256, 0.25 );

		gos_SetRenderState( gos_State_Texture, tex9 );
		DofQuad( 20+8*64,20, 20+8*64+256,256, 0.25 );


		gos_SetRenderState( gos_State_Texture, tex10 );
		DofQuad( 20+0*64,256, 20+0*64+256,512, 0.25 );

		gos_SetRenderState( gos_State_Texture, tex11 );
		DofQuad( 20+1*64,256, 20+1*64+256,512, 0.25 );

		gos_SetRenderState( gos_State_Texture, tex12 );
		DofQuad( 20+2*64,256, 20+2*64+256,512, 0.25 );

		gos_SetRenderState( gos_State_Texture, tex13 );
		DofQuad( 20+3*64,256, 20+3*64+256,512, 0.25 );

		gos_SetRenderState( gos_State_Texture, tex14 );
		DofQuad( 20+4*64,256, 20+4*64+256,512, 0.25 );

		gos_SetRenderState( gos_State_Texture, tex15 );
		DofQuad( 20+5*64,256, 20+5*64+256,512, 0.25 );

		gos_SetRenderState( gos_State_Texture, tex16 );
		DofQuad( 20+6*64,256, 20+6*64+256,512, 0.25 );

		gos_SetRenderState( gos_State_Texture, tex17 );
		DofQuad( 20+7*64,256, 20+7*64+256,512, 0.25 );

		gos_SetRenderState( gos_State_Clipping, 0 );
		
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 0, 1, 0, 0 );

		gos_TextSetPosition( 50,Environment.screenHeight-20 );	 //RLC
		gos_TextDraw( "Texture Swapping Test");					 //RLC

		gos_TextSetPosition( 350,Environment.screenHeight-20 );  //RLC
		gos_TextDraw( "1 - Advance test" );						 //RLC
	}

//
// 32768 Pixel triangles
//
	if( Test==8 )
	{
		gos_GetViewport( &ViewportMulX, &ViewportMulY, &ViewportAddX, &ViewportAddY );
		gos_VERTEX v[16*3];

		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 0, 1, 0, 0 );

		double framerate=gos_GetElapsedTime()-lastframe;
		lastframe=gos_GetElapsedTime();
		TotalPolys+=Polys/20;
		TotalFrameRate+=framerate;
		if( TotalFrameRate && framerate && 0==(frame&31) )
		{
			Average=(DWORD)(TotalPolys/TotalFrameRate);
			TotalPolys=0;
			TotalFrameRate=0.0;
		}
		frame++;
		gos_TextSetPosition( 50,Environment.screenHeight-35 );
		gos_TextDraw( "%d triangles/second",Average );

		gos_TextSetPosition( 50,Environment.screenHeight-20 );
		gos_TextDraw( "%d - 32768 Pixel %s Triangles",Polys/20,UseTexture ? "Textured" : "" );
		gos_TextSetPosition( 350,Environment.screenHeight-20 );
		gos_TextDraw( "1 - Advance test, 2 - More Tris, 3-Less, T-Texture" );

		gos_SetRenderState( gos_State_Clipping, 0 );
		gos_SetRenderState( gos_State_Fog, 0 );
		gos_SetRenderState( gos_State_MonoEnable, 0 );
		gos_SetRenderState( gos_State_ShadeMode, gos_ShadeGouraud );
		gos_SetRenderState( gos_State_Filter, gos_FilterNone );
		gos_SetRenderState( gos_State_Texture, UseTexture ? TestTexture : 0 );
		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneZero );
		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulate );

		memset( v, 0, 48*sizeof(gos_VERTEX) );

		for( int t0=0; t0<Polys/20; t0+=16 )
		{
			for( int t1=0; t1<48; t1+=3 )
			{
				float xo=0.1f+gos_rand()*(0.4f/32768.0f);
				float yo=0.1f+gos_rand()*(0.25f/32768.0f);
			
				v[t1].argb		= 0xffff0000;
				v[t1+1].argb	= 0xff00ff00;
				v[t1+2].argb	= 0xff0000ff;
				v[t1].rhw		= 1.0;
				v[t1+1].rhw		= 1.0;
				v[t1+2].rhw		= 1.0;

				v[t1+1].u		= 1.0;
				v[t1+1].v		= 1.0;
				v[t1+2].u		= 1.0;
				v[t1+2].v		= 1.0;

				v[t1].x		= (xo)*ViewportMulX + ViewportAddX;
				v[t1].y		= (yo)*ViewportMulY + ViewportAddY;

				v[t1+1].x	= (xo+Xpixels*256)*ViewportMulX + ViewportAddX;
				v[t1+1].y	= (yo)*ViewportMulY + ViewportAddY;

				v[t1+2].x	= (xo+Xpixels*256)*ViewportMulX + ViewportAddX;
				v[t1+2].y	= (yo+Ypixels*256)*ViewportMulY + ViewportAddY;
			}
			gos_DrawTriangles( v, 48 );
		}
	}
//
// 1 Pixel triangles in 30 vertex indexed array
//
	if( Test==9 )
	{
		gos_GetViewport( &ViewportMulX, &ViewportMulY, &ViewportAddX, &ViewportAddY );
		gos_VERTEX v[32];
		WORD Indices[30*3];

		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 0, 1, 0, 0 );
		gos_TextSetPosition( 50,Environment.screenHeight-20 );
		gos_TextDraw( "%d - 1 Pixel %s Tris as 30 triangles in 32 vertex array",Polys*4 ,UseTexture ? "Textured" : "" );

		WORD vertex=0;
		for( int t1=0;t1<30;t1++ )
		{
			Indices[t1*3]=vertex;
			Indices[t1*3+1]=(WORD)(vertex+1);
			Indices[t1*3+2]=(WORD)(vertex+2);
			vertex++;
		}

		double framerate=gos_GetElapsedTime()-lastframe;
		lastframe=gos_GetElapsedTime();
		TotalPolys+=Polys*4;
		TotalFrameRate+=framerate;
		if( TotalFrameRate && framerate && 0==(frame&31) )
		{
			Average=(DWORD)(TotalPolys/TotalFrameRate);
			TotalPolys=0;
			TotalFrameRate=0.0;
		}
		frame++;
		gos_TextSetPosition( 50,Environment.screenHeight-35 );
		gos_TextDraw( "%d triangles/second",Average );

		gos_TextSetPosition( 350,Environment.screenHeight-20 );
		gos_TextDraw( "1 - Advance test, 2 - More Tris, 3-Less, T-Texture" );

		gos_SetRenderState( gos_State_Clipping, 0 );
		gos_SetRenderState( gos_State_Fog, 0 );
		gos_SetRenderState( gos_State_MonoEnable, 0 );
		gos_SetRenderState( gos_State_ShadeMode, gos_ShadeGouraud );
		gos_SetRenderState( gos_State_Filter, gos_FilterNone );
		gos_SetRenderState( gos_State_Texture, UseTexture ? TestTexture : 0 );
		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneZero );
		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulate );

		memset( v, 0, sizeof(v) );

		for( int t0=0; t0<Polys*4; t0+=30 )
		{
			float xo=0.2f+gos_rand()*(0.6f/32768.0f);
			float yo=0.2f+gos_rand()*(0.6f/32768.0f);
			float skipx=0.0f;
			float skipy=0.0f;
			DWORD Color=0xffff0000;

			float uv=1.0;			

			for( int t1=0; t1<32; t1++ )
			{
				v[t1].argb		= Color;
				v[t1].rhw		= 1.0f;
				v[t1].u			= 1.0f-uv;
				v[t1].v			= uv;
				uv=1.0f-uv;
				Color^=0x00ffffff;

				v[t1].x		= (xo+skipx*Xpixels)*ViewportMulX + ViewportAddX;
				v[t1].y		= (yo+skipy*Ypixels)*ViewportMulY + ViewportAddY;

				skipx+=1.0f;
				skipy=1.0f-skipy;
			}
			gos_RenderIndexedArray( v, 32, Indices, 30*3 );
		}
	}

//
// Testing modulate modes
//
	if( Test==10 )
	{
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 0, 1, 0, 0 );
		gos_TextSetPosition( 50,Environment.screenHeight-20 );
		gos_TextDraw( "Modulate / Addressing modes" );
		gos_TextSetPosition( 380,Environment.screenHeight-20 );
		gos_TextDraw( "1 - Advance test" );
//
// Test modulate modes
//
		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_AlphaInvAlpha );
		gos_SetRenderState( gos_State_Filter, gos_FilterNone );
		gos_SetRenderState( gos_State_Texture, TestTexture );
		gos_SetRenderState( gos_State_MonoEnable, 0 );
		gos_SetRenderState( gos_State_ShadeMode, gos_ShadeGouraud );
		gos_SetRenderState( gos_State_Perspective, 0 );

		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendDecal );
		DoQuad( 64+128*0,20, 64+128*0+256,256, 0.5 );

		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulate );
		DoQuad( 64+128*1,20, 64+128*1+256,256, 0.5 );

		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulateAlpha );
		DoQuad( 64+128*2,20, 64+128*2+256,256, 0.5 );

		gos_SetRenderState( gos_State_Texture, AlphaTexture );

		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendDecal );
		DoQuad( 64+128*0,256, 64+128*0+256,512, 0.5 );

		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulate );
		DoQuad( 64+128*1,256, 64+128*1+256,512, 0.5 );

		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulateAlpha );
		DoQuad( 64+128*2,256, 64+128*2+256,512, 0.5 );
//
// Test wrap and clamp
//
		gos_SetRenderState( gos_State_Texture, TestTexture );
		gos_SetRenderState( gos_State_TextureAddress, gos_TextureWrap );
		DoQuad( 64+128*3,20, 64+128*3+256,256, 0.5, true );
		gos_SetRenderState( gos_State_TextureAddress, gos_TextureClamp );
		DoQuad( 64+128*3,256, 64+128*3+256,512, 0.5, true );
		gos_SetRenderState( gos_State_TextureAddress, gos_TextureWrap );

		gos_TextSetPosition( 64+128*0+10,150 );
		gos_TextDraw( "Decal" );

		gos_TextSetPosition( 64+128*1+10,150 );
		gos_TextDraw( "Modulate" );

		gos_TextSetPosition( 64+128*2+10,150 );
		gos_TextDraw( "ModulateAlpha" );

		gos_TextSetPosition( 64+128*3+10,150 );
		gos_TextDraw( "Wrap" );

		gos_TextSetPosition( 64+128*0+10,406 );
		gos_TextDraw( "Decal" );

		gos_TextSetPosition( 64+128*1+10,406 );
		gos_TextDraw( "Modulate" );

		gos_TextSetPosition( 64+128*2+10,406 );
		gos_TextDraw( "ModulateAlpha" );

		gos_TextSetPosition( 64+128*3+10,406 );
		gos_TextDraw( "Clamp" );
		gos_SetRenderState( gos_State_Perspective, 1 );
	}

//
// Stencil test
//
	if( Test==11 )
	{
		gos_SetRenderState( gos_State_AlphaTest, 0 );
		gos_SetRenderState( gos_State_Perspective, 0 );
		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneZero );
		gos_SetRenderState( gos_State_Texture, TestTexture );
		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulateAlpha );
		gos_SetRenderState( gos_State_Filter, gos_FilterBiLinear );
//
// Setup stencil to increment each pixel written
//
		gos_SetRenderState( gos_State_StencilEnable, 1 );
		gos_SetRenderState( gos_State_StencilFunc, gos_Cmp_Always );
		gos_SetRenderState( gos_State_StencilPass, gos_Stencil_Incr );
		gos_SetRenderState( gos_State_StencilZFail, gos_Stencil_Incr );
		gos_SetRenderState( gos_State_StencilMask, 0xffffffff );
//
// Draw scene
//
		DofQuad( 12,40, 268,296, 1.0 );
		DofQuad( 278,40, 534,296, 0.5 );
		DofQuad( 416,40, 672,296, 0.25, 0x80000000 );			// Half fog
		DofQuad( 490,40, 746,296, 0.125, 0 );					// No fog

		SafeSize=Size;

		gos_SetRenderState( gos_State_AlphaTest, 0 );
		gos_SetRenderState( gos_State_Perspective, 0 );
		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneZero );
		gos_SetRenderState( gos_State_Texture, TestTexture );
		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendDecal );
		gos_SetRenderState( gos_State_ZCompare, 0 );

		gos_SetRenderState( gos_State_Filter, gos_FilterNone );
		DofQuad( (DWORD)(10+128*(1.0-SafeSize)), (DWORD)(214+128*(1.0-SafeSize)), (DWORD)(266+128*(1.0-SafeSize)), (DWORD)(470+128*(1.0-SafeSize)), SafeSize, 0xff000000, 1 );

		gos_SetRenderState( gos_State_Filter, gos_FilterBiLinear );
		DofQuad( (DWORD)(192+128*(1.0-SafeSize)), (DWORD)(214+128*(1.0-SafeSize)), (DWORD)(448+128*(1.0-SafeSize)), (DWORD)(470+128*(1.0-SafeSize)), SafeSize, 0xff000000, 1 );

		gos_SetRenderState( gos_State_Filter, gos_FilterTriLinear );
		DofQuad( (DWORD)(374+128*(1.0-SafeSize)), (DWORD)(214+128*(1.0-SafeSize)), (DWORD)(630+128*(1.0-SafeSize)), (DWORD)(470+128*(1.0-SafeSize)), SafeSize, 0xff000000, 1 );
//
// Now show depth complexity
//
		if( Environment.Stencil )
		{

			gos_SetRenderState( gos_State_Texture, 0 );
			gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulate );
			gos_SetRenderState( gos_State_Filter, gos_FilterNone );

			gos_SetRenderState( gos_State_StencilFunc, gos_Cmp_Equal );
			gos_SetRenderState( gos_State_StencilPass, gos_Stencil_Keep );
			gos_SetRenderState( gos_State_StencilZFail, gos_Stencil_Keep );
			gos_SetRenderState( gos_State_StencilFail, gos_Stencil_Keep );

			for( int t0=0; t0<4; t0++ )
			{
				gos_SetRenderState( gos_State_StencilRef, t0 );

				DWORD Color;
				if( t0==0 )
					Color=0;
				else if( t0==1 )
					Color=0xff00ff;
				else if( t0==2 )
					Color=0x00ffff;
				else if( t0==3 )
					Color=0x0000ff;
				else if( t0==4 )
					Color=0x00ff00;
				else
					Color=0xff0000;

				FilledQuad( 70, 150, Environment.screenWidth-140, Environment.screenHeight-300, Color );
			}
		}

		gos_SetRenderState( gos_State_StencilEnable, 0 );
		gos_SetRenderState( gos_State_Filter, gos_FilterNone );
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 0, 1, 0, 0 );
		gos_TextSetPosition( 50,Environment.screenHeight-20 );
		gos_TextDraw( "Test Stencil" );
		gos_TextSetPosition( 380,Environment.screenHeight-20 );
		gos_TextDraw( "1 - Advance test" );
		gos_TextSetPosition( 380,Environment.screenHeight-40 );
		if( Environment.Stencil )
			gos_TextDraw( "S - Disable stencil mode" );
		else
		{
			if( Environment.Renderer==3 )
			{
					gos_TextDraw( "Stencil buffer not supported" );
			}
			else
			{
				if( 0==gos_GetMachineInformation(gos_Info_NumberDevices) || 0==gos_GetMachineInformation( gos_Info_CanDeviceRenderStencil, Environment.fullScreen ? Environment.FullScreenDevice : 0) )
					gos_TextDraw( "Stencil buffer not supported" );
				else if( Environment.Renderer==0 && Environment.bitDepth!=32 && 2==gos_GetMachineInformation( gos_Info_CanDeviceRenderStencil, Environment.fullScreen ? Environment.FullScreenDevice : 0) )
					gos_TextDraw( "S - Enable stencil - Requires 32 bit mode" );
				else
					gos_TextDraw( "S - Enable stencil mode" );
			}
		}
	}



//
// Testing multitexture modes - Specular map
//
	if( Test==12 )
	{
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 0, 1, 0, 0 );
		gos_TextSetPosition( 50,Environment.screenHeight-20 );
		gos_TextDraw( "Multitexture modes - Specular map" );
		if( !gos_GetMachineInformation(gos_Info_CanMultitextureSpecularMap) )
			gos_TextDraw( " - NOT SUPPORTED" );
		gos_TextSetPosition( 380,Environment.screenHeight-20 );
		gos_TextDraw( "1 - Advance test" );

		gos_SetRenderState( gos_State_TextureAddress, gos_TextureClamp );
		gos_SetRenderState( gos_State_Filter, gos_FilterNone );
		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneZero );
		gos_SetRenderState( gos_State_MonoEnable, 0 );
		gos_SetRenderState( gos_State_ShadeMode, gos_ShadeFlat );
		gos_SetRenderState( gos_State_Perspective, 0 );
//
// Draw wall
//
		gos_SetRenderState( gos_State_Texture, WallTexture );
		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulate );

		{
			gos_VERTEX pVertices[4];

			pVertices[0].x		= 48;
			pVertices[0].y		= 80;
			pVertices[0].z		= 0.5f;
			pVertices[0].rhw	= 1.0;
			pVertices[0].argb	= 0xffffffff;
			pVertices[0].frgb	= 0;
			pVertices[0].u		= 0.0f;
			pVertices[0].v		= 0.0f;

			pVertices[1].x		= 48;
			pVertices[1].y		= 336;
			pVertices[1].z		= 0.5f;
			pVertices[1].rhw	= 1.0;
			pVertices[1].argb	= 0xffffffff;
			pVertices[1].frgb	= 0;
			pVertices[1].u		= 0.0f;
			pVertices[1].v		= 1.0f;

			pVertices[2].x		= 304;
			pVertices[2].y		= 336;
			pVertices[2].z		= 0.5f;
			pVertices[2].rhw	= 1.0;
			pVertices[2].argb	= 0xffffffff;
			pVertices[2].frgb	= 0;
			pVertices[2].u		= 1.0f;
			pVertices[2].v		= 1.0f;

			pVertices[3].x		= 304;
			pVertices[3].y		= 80;
			pVertices[3].z		= 0.5f;
			pVertices[3].rhw	= 1.0;
			pVertices[3].argb	= 0xffffffff;
			pVertices[3].frgb	= 0;
			pVertices[3].u		= 1.0f;
			pVertices[3].v		= 0.0f;

			WORD Index[]={0,2,1,0,3,2};
			
			gos_RenderIndexedArray( pVertices, 4, Index, 6 );
		}
//
// Draw lightmap
//
		if( gos_GetMachineInformation(gos_Info_CanAlphaOneOne) )
		{
			gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulateAlpha );
			gos_SetRenderState( gos_State_Texture, LightmapTexture );
			gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneOne );
			{
				gos_VERTEX pVertices[4];

				pVertices[0].x		= 48;
				pVertices[0].y		= 80;
				pVertices[0].z		= 0.5f;
				pVertices[0].rhw	= 1.0;
				pVertices[0].argb	= 0xffffffff;
				pVertices[0].frgb	= 0;
				pVertices[0].u		= 0.0f-MoveX/128.0f;
				pVertices[0].v		= 0.0f-MoveY/128.0f;

				pVertices[1].x		= 48;
				pVertices[1].y		= 336;
				pVertices[1].z		= 0.5f;
				pVertices[1].rhw	= 1.0;
				pVertices[1].argb	= 0xffffffff;
				pVertices[1].frgb	= 0;
				pVertices[1].u		= 0.0f-MoveX/128.0f;
				pVertices[1].v		= 1.0f-MoveY/128.0f;

				pVertices[2].x		= 304;
				pVertices[2].y		= 336;
				pVertices[2].z		= 0.5f;
				pVertices[2].rhw	= 1.0;
				pVertices[2].argb	= 0xffffffff;
				pVertices[2].frgb	= 0;
				pVertices[2].u		= 1.0f-MoveX/128.0f;
				pVertices[2].v		= 1.0f-MoveY/128.0f;

				pVertices[3].x		= 304;
				pVertices[3].y		= 80;
				pVertices[3].z		= 0.5f;
				pVertices[3].rhw	= 1.0;
				pVertices[3].argb	= 0xffffffff;
				pVertices[3].frgb	= 0;
				pVertices[3].u		= 1.0f-MoveX/128.0f;
				pVertices[3].v		= 0.0f-MoveY/128.0f;

				WORD Index[]={0,2,1,0,3,2};
				
				gos_RenderIndexedArray( pVertices, 4, Index, 6 );
			}
		}

		gos_TextSetPosition( 128,90+256 );
		gos_TextDraw( "Using AlphaOneOne" );
//
// Draw wall and lightmap with multitexture
//
		if( gos_GetMachineInformation(gos_Info_CanMultitextureSpecularMap) )
		{
			gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneZero );
			gos_SetRenderState( gos_State_Texture2, LightmapTexture );
			gos_SetRenderState( gos_State_Texture, WallTexture );
			gos_SetRenderState( gos_State_Multitexture, gos_Multitexture_SpecularMap );

			gos_VERTEX_2UV pVertices[4];

			pVertices[0].x		= 336;
			pVertices[0].y		= 80;
			pVertices[0].z		= 0.5f;
			pVertices[0].rhw	= 1.0;
			pVertices[0].argb	= 0xffffffff;
			pVertices[0].frgb	= 0;
			pVertices[0].u1		= 0.0f;
			pVertices[0].v1		= 0.0f;
			pVertices[0].u2		= 0.0f-MoveX/128.0f;
			pVertices[0].v2		= 0.0f-MoveY/128.0f;

			pVertices[1].x		= 336;
			pVertices[1].y		= 336;
			pVertices[1].z		= 0.5f;
			pVertices[1].rhw	= 1.0;
			pVertices[1].argb	= 0xffffffff;
			pVertices[1].frgb	= 0;
			pVertices[1].u1		= 0.0f;
			pVertices[1].v1		= 1.0f;
			pVertices[1].u2		= 0.0f-MoveX/128.0f;
			pVertices[1].v2		= 1.0f-MoveY/128.0f;

			pVertices[2].x		= 592;
			pVertices[2].y		= 336;
			pVertices[2].z		= 0.5f;
			pVertices[2].rhw	= 1.0;
			pVertices[2].argb	= 0xffffffff;
			pVertices[2].frgb	= 0;
			pVertices[2].u1		= 1.0f;
			pVertices[2].v1		= 1.0f;
			pVertices[2].u2		= 1.0f-MoveX/128.0f;
			pVertices[2].v2		= 1.0f-MoveY/128.0f;

			pVertices[3].x		= 592;
			pVertices[3].y		= 80;
			pVertices[3].z		= 0.5f;
			pVertices[3].rhw	= 1.0;
			pVertices[3].argb	= 0xffffffff;
			pVertices[3].frgb	= 0;
			pVertices[3].u1		= 1.0f;
			pVertices[3].v1		= 0.0f;
			pVertices[3].u2		= 1.0f-MoveX/128.0f;
			pVertices[3].v2		= 0.0f-MoveY/128.0f;

			WORD Index[]={0,2,1,0,3,2};
			
			gos_RenderIndexedArray( pVertices, 4, Index, 6 );

			gos_SetRenderState( gos_State_Multitexture, gos_Multitexture_None );

			gos_TextSetPosition( 432,90+256 );
			gos_TextDraw( "Using SpecularMap" );
		}
	}



//
// Testing multitexture modes - Light map
//
	if( Test==13 )
	{
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 0, 1, 0, 0 );
		gos_TextSetPosition( 50,Environment.screenHeight-20 );
		gos_TextDraw( "Multitexture modes - Light map" );
		if( !gos_GetMachineInformation(gos_Info_CanMultitextureLightMap) )
			gos_TextDraw( " - NOT SUPPORTED" );
		gos_TextSetPosition( 380,Environment.screenHeight-20 );
		gos_TextDraw( "1 - Advance test" );

		gos_SetRenderState( gos_State_TextureAddress, gos_TextureClamp );
		gos_SetRenderState( gos_State_Filter, gos_FilterNone );
		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneZero );
		gos_SetRenderState( gos_State_MonoEnable, 0 );
		gos_SetRenderState( gos_State_ShadeMode, gos_ShadeFlat );
		gos_SetRenderState( gos_State_Perspective, 0 );
//
// Draw wall
//
		gos_SetRenderState( gos_State_Texture, WallTexture );
		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulate );
		{
			gos_VERTEX pVertices[4];

			pVertices[0].x		= 48;
			pVertices[0].y		= 80;
			pVertices[0].z		= 0.5f;
			pVertices[0].rhw	= 1.0;
			pVertices[0].argb	= 0xffffffff;
			pVertices[0].frgb	= 0;
			pVertices[0].u		= 0.0f;
			pVertices[0].v		= 0.0f;

			pVertices[1].x		= 48;
			pVertices[1].y		= 336;
			pVertices[1].z		= 0.5f;
			pVertices[1].rhw	= 1.0;
			pVertices[1].argb	= 0xffffffff;
			pVertices[1].frgb	= 0;
			pVertices[1].u		= 0.0f;
			pVertices[1].v		= 1.0f;

			pVertices[2].x		= 304;
			pVertices[2].y		= 336;
			pVertices[2].z		= 0.5f;
			pVertices[2].rhw	= 1.0;
			pVertices[2].argb	= 0xffffffff;
			pVertices[2].frgb	= 0;
			pVertices[2].u		= 1.0f;
			pVertices[2].v		= 1.0f;

			pVertices[3].x		= 304;
			pVertices[3].y		= 80;
			pVertices[3].z		= 0.5f;
			pVertices[3].rhw	= 1.0;
			pVertices[3].argb	= 0xffffffff;
			pVertices[3].frgb	= 0;
			pVertices[3].u		= 1.0f;
			pVertices[3].v		= 0.0f;

			WORD Index[]={0,2,1,0,3,2};
			
			gos_RenderIndexedArray( pVertices, 4, Index, 6 );
		}

		if( gos_GetMachineInformation(gos_Info_CanAlphaOneOne) )
		{
			gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulateAlpha );
			gos_SetRenderState( gos_State_Texture, LightmapTexture );
			gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneOne );
//
// Draw lightmap
//
			{
				gos_VERTEX pVertices[4];

				pVertices[0].x		= 48;
				pVertices[0].y		= 80;
				pVertices[0].z		= 0.5f;
				pVertices[0].rhw	= 1.0;
				pVertices[0].argb	= 0xffffffff;
				pVertices[0].frgb	= 0;
				pVertices[0].u		= 0.0f-MoveX/128.0f;
				pVertices[0].v		= 0.0f-MoveY/128.0f;

				pVertices[1].x		= 48;
				pVertices[1].y		= 336;
				pVertices[1].z		= 0.5f;
				pVertices[1].rhw	= 1.0;
				pVertices[1].argb	= 0xffffffff;
				pVertices[1].frgb	= 0;
				pVertices[1].u		= 0.0f-MoveX/128.0f;
				pVertices[1].v		= 1.0f-MoveY/128.0f;

				pVertices[2].x		= 304;
				pVertices[2].y		= 336;
				pVertices[2].z		= 0.5f;
				pVertices[2].rhw	= 1.0;
				pVertices[2].argb	= 0xffffffff;
				pVertices[2].frgb	= 0;
				pVertices[2].u		= 1.0f-MoveX/128.0f;
				pVertices[2].v		= 1.0f-MoveY/128.0f;

				pVertices[3].x		= 304;
				pVertices[3].y		= 80;
				pVertices[3].z		= 0.5f;
				pVertices[3].rhw	= 1.0;
				pVertices[3].argb	= 0xffffffff;
				pVertices[3].frgb	= 0;
				pVertices[3].u		= 1.0f-MoveX/128.0f;
				pVertices[3].v		= 0.0f-MoveY/128.0f;

				WORD Index[]={0,2,1,0,3,2};
				
				gos_RenderIndexedArray( pVertices, 4, Index, 6 );
			}
		}

		gos_TextSetPosition( 128,90+256 );
		gos_TextDraw( "Using AlphaOneOne" );
//
// Draw wall and lightmap with multitexture
//
		if( gos_GetMachineInformation(gos_Info_CanMultitextureLightMap) )
		{
			gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneZero );
			gos_SetRenderState( gos_State_Texture2, LightmapTexture );
			gos_SetRenderState( gos_State_Texture, WallTexture );
			gos_SetRenderState( gos_State_Multitexture, gos_Multitexture_LightMap );

			gos_VERTEX_2UV pVertices[4];

			pVertices[0].x		= 336;
			pVertices[0].y		= 80;
			pVertices[0].z		= 0.5f;
			pVertices[0].rhw	= 1.0;
			pVertices[0].argb	= 0xffffffff;
			pVertices[0].frgb	= 0;
			pVertices[0].u1		= 0.0f;
			pVertices[0].v1		= 0.0f;
			pVertices[0].u2		= 0.0f-MoveX/128.0f;
			pVertices[0].v2		= 0.0f-MoveY/128.0f;

			pVertices[1].x		= 336;
			pVertices[1].y		= 336;
			pVertices[1].z		= 0.5f;
			pVertices[1].rhw	= 1.0;
			pVertices[1].argb	= 0xffffffff;
			pVertices[1].frgb	= 0;
			pVertices[1].u1		= 0.0f;
			pVertices[1].v1		= 1.0f;
			pVertices[1].u2		= 0.0f-MoveX/128.0f;
			pVertices[1].v2		= 1.0f-MoveY/128.0f;

			pVertices[2].x		= 592;
			pVertices[2].y		= 336;
			pVertices[2].z		= 0.5f;
			pVertices[2].rhw	= 1.0;
			pVertices[2].argb	= 0xffffffff;
			pVertices[2].frgb	= 0;
			pVertices[2].u1		= 1.0f;
			pVertices[2].v1		= 1.0f;
			pVertices[2].u2		= 1.0f-MoveX/128.0f;
			pVertices[2].v2		= 1.0f-MoveY/128.0f;

			pVertices[3].x		= 592;
			pVertices[3].y		= 80;
			pVertices[3].z		= 0.5f;
			pVertices[3].rhw	= 1.0;
			pVertices[3].argb	= 0xffffffff;
			pVertices[3].frgb	= 0;
			pVertices[3].u1		= 1.0f;
			pVertices[3].v1		= 0.0f;
			pVertices[3].u2		= 1.0f-MoveX/128.0f;
			pVertices[3].v2		= 0.0f-MoveY/128.0f;

			WORD Index[]={0,2,1,0,3,2};
			
			gos_RenderIndexedArray( pVertices, 4, Index, 6 );

			gos_SetRenderState( gos_State_Multitexture, gos_Multitexture_None );

			gos_TextSetPosition( 432,90+256 );
			gos_TextDraw( "Using LightMap" );
		}
	}


//
// Testing strips and fans
//
	if( Test==14 )
	{
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 0, 1, 0, 0 );
		gos_TextSetPosition( 50,Environment.screenHeight-20 );
		gos_TextDraw( "Strips and Fans" );
		gos_TextSetPosition( 380,Environment.screenHeight-20 );
		gos_TextDraw( "1 - Advance test" );

		gos_SetRenderState( gos_State_Filter, gos_FilterNone );
		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneZero );
		gos_SetRenderState( gos_State_MonoEnable, 0 );
		gos_SetRenderState( gos_State_ShadeMode, gos_ShadeFlat );
		gos_SetRenderState( gos_State_Perspective, 0 );
		gos_SetRenderState( gos_State_Texture, 0 );
		gos_SetRenderState( gos_State_Clipping, 1 );
//
// Draw a pie chart (FAN)
//
		gos_VERTEX PieData[103];	
		#define SizeOfPie 96.0f

		memset( &PieData[0], 0, sizeof(PieData) );
		PieData[0].x=SizeOfPie/2+90.0f;
		PieData[0].y=SizeOfPie/2+180.0f;
		PieData[0].rhw=1.0f;

		for( int t1=1; t1<102; t1++ )
		{
			PieData[t1].x=(float)(PieData[0].x+SizeOfPie/2*sin( (2.0f*3.1415926f*(t1-1))/100.0f ));
			PieData[t1].y=(float)(PieData[0].y-SizeOfPie/2*cos( (2.0f*3.1415926f*(t1-1))/100.0f ));
			PieData[t1].rhw=1.0f;
			PieData[t1].argb=0xff000000+t1*2+50;
		}
		PieData[t1].x=(float)(PieData[0].x+SizeOfPie/2*sin( 0 ));
		PieData[t1].y=(float)(PieData[0].y-SizeOfPie/2*cos( 0 ));
		PieData[t1].rhw=1.0f;
//
// Make first slices red, green, blue
//
		PieData[1].argb=0xffff0000;
		PieData[2].argb=0xff00ff00;
		PieData[3].argb=0xff0000ff;

		gos_DrawFans( PieData, 102 );

		gos_TextSetPosition( 50,295 );
		gos_TextDraw( "FAN - Red, Green, Blue as first slices" );
//
// Draw a strip of triangles
//
		memset( &PieData[0], 0, sizeof(PieData) );
		for( int t0=0; t0<16; t0++ )
		{
			PieData[t0].rhw=1.0f;
			PieData[t0].x=320.0f+t0*20.0f;
			PieData[t0].y=t0&1 ? 220.0f : 260.0f;
		}

		PieData[0].argb	 = 0xffff0000;
		PieData[1].argb	 = 0xff00ff00;
		PieData[2].argb	 = 0xff0000ff;
		PieData[3].argb	 = 0xff000000;
		PieData[4].argb	 = 0xffff00ff;
		PieData[5].argb	 = 0xffffff00;
		PieData[6].argb	 = 0xff00ffff;
		PieData[7].argb	 = 0xff808080;
		PieData[8].argb	 = 0xff800000;
		PieData[9].argb  = 0xff008000;
		PieData[10].argb = 0xff000080;
		PieData[11].argb = 0xff000000;
		PieData[12].argb = 0xff800080;
		PieData[13].argb = 0xff808000;
		PieData[14].argb = 0xff008080;
		PieData[15].argb = 0xffffffff;

		gos_DrawStrips( PieData, 16 );

		gos_TextSetPosition( 370,295 );
		gos_TextDraw( "STRIP - Red, Green, Blue as first triangles" );
		gos_SetRenderState( gos_State_Clipping, 0 );
	}




//
// Testing rendering to a texture using blade
//
	if( Test==15 )
	{
		gos_VERTEX pVertices[4];

		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 0, 1, 0, 0 );
		gos_TextSetPosition( 50,Environment.screenHeight-20 );
		gos_TextDraw( "Rendering to a texture" );
		gos_TextSetPosition( 380,Environment.screenHeight-20 );
		gos_TextDraw( "1 - Advance test" );
//
// Render a spinning triangle to the test texture
//
		gos_StartRenderToTexture( RenderTexture );

		DrawSpinningTriangle( 128,100, Spin1, 64.0f );
		DrawSpinningTriangle( 160,140, Spin2, 100.0f );
		DrawSpinningTriangle( 100,180, Spin3, 50.0f );
		DrawSpinningTriangle( 190,200, Spin1, 120.0f );
		DrawSpinningTriangle( 100,120, Spin3, 80.0f );

		gos_EndRenderToTexture( 1 );
//
// Draw a test pattern and render the test texture as a 50% shadow
//
		gos_SetRenderState( gos_State_TextureAddress, gos_TextureWrap );
		gos_SetRenderState( gos_State_Filter, gos_FilterNone );
		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneZero );
		gos_SetRenderState( gos_State_MonoEnable, 0 );
		gos_SetRenderState( gos_State_ShadeMode, gos_ShadeGouraud );
		gos_SetRenderState( gos_State_Perspective, 0 );
//
// Draw wall
//
		gos_SetRenderState( gos_State_Texture, WallTexture );
		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendDecal );

		pVertices[0].x		= 192;
		pVertices[0].y		= 80;
		pVertices[0].z		= 0.5f;
		pVertices[0].rhw	= 1.0;
		pVertices[0].argb	= 0xffffffff;
		pVertices[0].frgb	= 0;
		pVertices[0].u		= 0.0f;
		pVertices[0].v		= 0.0f;

		pVertices[1].x		= 192;
		pVertices[1].y		= 336;
		pVertices[1].z		= 0.5f;
		pVertices[1].rhw	= 1.0;
		pVertices[1].argb	= 0xffffffff;
		pVertices[1].frgb	= 0;
		pVertices[1].u		= 0.0f;
		pVertices[1].v		= 1.0f;

		pVertices[2].x		= 448;
		pVertices[2].y		= 336;
		pVertices[2].z		= 0.5f;
		pVertices[2].rhw	= 1.0;
		pVertices[2].argb	= 0xffffffff;
		pVertices[2].frgb	= 0;
		pVertices[2].u		= 1.0f;
		pVertices[2].v		= 1.0f;

		pVertices[3].x		= 448;
		pVertices[3].y		= 80;
		pVertices[3].z		= 0.5f;
		pVertices[3].rhw	= 1.0;
		pVertices[3].argb	= 0xffffffff;
		pVertices[3].frgb	= 0;
		pVertices[3].u		= 1.0f;
		pVertices[3].v		= 0.0f;

		WORD Index[]={0,1,2,0,2,3};
		
		gos_RenderIndexedArray( pVertices, 4, Index, 6 );							// Draw base pattern

		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulateAlpha );
		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_AlphaInvAlpha );
		gos_SetRenderState( gos_State_Texture, RenderTexture );

		pVertices[0].argb	= 0x80ffffff;
		pVertices[1].argb	= 0x80ffffff;
		pVertices[2].argb	= 0x80ffffff;
		pVertices[3].argb	= 0x80ffffff;

		gos_RenderIndexedArray( pVertices, 4, Index, 6 );							// Draw shadow

	}



//
// Testing hardware transform and lighting using an indexed vertex array and spinning a single triangle
//
	if( Test==16 )
	{
		static gosD3DVERTEX Vertex[6];
		static WORD Index[6]={0,1,2,3,5,4};											// Note indices reversed for front/back visible

		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 0, 1, 0, 0 );
		gos_TextSetPosition( 50,Environment.screenHeight-20 );
		gos_TextDraw( "%s T&L - Single spinning yellow triangle", (gos_GetMachineInformation( gos_Info_CanHardwareTandL ) ? "Hardware" : "Software") );
		gos_TextSetPosition( 380,Environment.screenHeight-20 );
		gos_TextDraw( "1 - Advance test  2=More teapots, 3=Less" );
		gos_SetRenderState( gos_State_Texture, 0 );
		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulate );
		gos_SetRenderState( gos_State_Fog, 0 );
		gos_SetRenderState( gos_State_MonoEnable, 0 );
		gos_SetRenderState( gos_State_ShadeMode, gos_ShadeGouraud );
		gos_SetRenderState( gos_State_Filter, gos_FilterNone );
		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneZero );
		gos_SetRenderState( gos_State_Culling, gos_Cull_CCW );
		gos_SetRenderState( gos_State_Lighting, 1 );
		gos_SetRenderState( gos_State_NormalizeNormals, 0 );
		gos_SetRenderState( gos_State_Clipping, 1 );
//
// Triangle vertices
//
		Vertex[0].x= 0.0f; Vertex[0].y= 3.0f; Vertex[0].z= 0.0f; Vertex[0].nx= 0.0f; Vertex[0].ny= 0.0f; Vertex[0].nz= 1.0f; Vertex[0].u= 0.0f;	Vertex[0].v= 0.0f;
		Vertex[1].x= 3.0f; Vertex[1].y=-3.0f; Vertex[1].z= 0.0f; Vertex[1].nx= 0.0f; Vertex[1].ny= 0.0f; Vertex[1].nz= 1.0f; Vertex[1].u= 0.0f;	Vertex[1].v= 0.0f;
		Vertex[2].x=-3.0f; Vertex[2].y=-3.0f; Vertex[2].z= 0.0f; Vertex[2].nx= 0.0f; Vertex[2].ny= 0.0f; Vertex[2].nz= 1.0f; Vertex[2].u= 0.0f;	Vertex[2].v= 0.0f;
		Vertex[3].x= 0.0f; Vertex[3].y= 3.0f; Vertex[3].z= 0.0f; Vertex[3].nx= 0.0f; Vertex[3].ny= 0.0f; Vertex[3].nz=-1.0f; Vertex[3].u= 0.0f;	Vertex[3].v= 0.0f;
		Vertex[4].x= 3.0f; Vertex[4].y=-3.0f; Vertex[4].z= 0.0f; Vertex[4].nx= 0.0f; Vertex[4].ny= 0.0f; Vertex[4].nz=-1.0f; Vertex[4].u= 0.0f;	Vertex[4].v= 0.0f;
		Vertex[5].x=-3.0f; Vertex[5].y=-3.0f; Vertex[5].z= 0.0f; Vertex[5].nx= 0.0f; Vertex[5].ny= 0.0f; Vertex[5].nz=-1.0f; Vertex[5].u= 0.0f;	Vertex[5].v= 0.0f;
//
// Yellow material
//
		gosMATERIAL Material;
		memset( &Material, 0, sizeof(Material) );
		Material.ambient.r=1.0f;
		Material.ambient.g=1.0f;
		Material.ambient.b=0.0f;
		gos_SetMaterial( &Material ); 
//
// Some default lighting
//
		gos_SetRenderState( gos_State_Ambient, 0xffffff );
//
// Get Identity matrix
//
		gosMATRIX Identity={ 1.0f, 0.0f, 0.0f, 0.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 };
//
// View matrix, move back along z by 10 units
//
		gosMATRIX View=Identity;
		View._43 = 10.0f;
		gos_SetTransform( MATRIX_VIEW, &View );
//
// Projection matrix
//
		gosMATRIX Projection=ProjectionMatrix( 1.0f, 20.0f, 3.1415926f/3.0f, 3.1415926f/3.0f );
		gos_SetTransform( MATRIX_PROJECTION, &Projection );
//
// Make world matrix spin based on time
//
		float fCos = (float)cos( Angle );
		float fSin = (float)sin( Angle );
		gosMATRIX World;
		World._11 = fCos;  World._12 = 0.0f;  World._13 =-fSin;  World._14 = 0.0f;
		World._21 = 0.0f;  World._22 = 1.0f;  World._23 = 0.0f;  World._24 = 0.0f;
		World._31 = fSin;  World._32 = 0.0f;  World._33 = fCos;  World._34 = 0.0f;
		World._41 = 0.0f;  World._42 = 0.0f;  World._43 = 0.0f;  World._44 = 1.0f;
		gos_SetTransform( MATRIX_WORLD, &World );

		gos_RenderIndexedArray( Vertex, 6, Index, 6, VERTEX_gosD3DVERTEX );
	}


//
// Testing hardware transform and lighting teapots using indexed arrays
//
	if( Test==17 )
	{
		char Buffer[256];
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 0, 1, 0, 0 );
		gos_TextSetPosition( 50,Environment.screenHeight-20 );
		sprintf( Buffer, "%s T&L - Spinning teapots using /bold=1INDEXED ARRAYS/bold=0", (gos_GetMachineInformation( gos_Info_CanHardwareTandL ) ? "Hardware" : "Software") );		
		gos_TextDraw( Buffer );
		gos_TextSetPosition( 380,Environment.screenHeight-20 );
		gos_TextDraw( "1 - Advance test  2=More teapots, 3=Less" );
		gos_TextSetPosition( 50,Environment.screenHeight-40 );
		static double LastTime=0.1f;
		sprintf( Buffer, "Triangles=%d, Vertices=%d, /proportional=0% 6.2f/proportional=1 Million Triangles/s, /proportional=0% 6.2f/proportional=1 Million Vertices/s", NumPot*sizeof(Model1_i)/6, NumPot*sizeof(Model1_v)/12, (double)(NumPot*sizeof(Model1_i)/6) / (gos_GetHiResTime()-LastTime) / 1000000.0f, (double)(NumPot*sizeof(Model1_v)/12) / (gos_GetHiResTime()-LastTime) / 1000000.0f );
		LastTime=gos_GetHiResTime();
		gos_TextDraw( Buffer );
		gos_SetRenderState( gos_State_Texture, 0 );
		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulate );
		gos_SetRenderState( gos_State_Fog, 0 );
		gos_SetRenderState( gos_State_MonoEnable, 0 );
		gos_SetRenderState( gos_State_ShadeMode, gos_ShadeGouraud );
		gos_SetRenderState( gos_State_Filter, gos_FilterNone );
		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneZero );
		gos_SetRenderState( gos_State_Culling, gos_Cull_CCW );
		gos_SetRenderState( gos_State_Lighting, 1 );
		gos_SetRenderState( gos_State_NormalizeNormals, 0 );
		gos_SetRenderState( gos_State_Clipping, 1 );
//
// Setup Model only once
//
		if( 0==pTeapot )
		{
			pTeapot=(gosD3DVERTEX*)gos_Malloc(sizeof(gosD3DVERTEX)*sizeof(Model1_v)/12);
			memset( pTeapot, 0, sizeof(gosD3DVERTEX)*sizeof(Model1_v)/12 );

			for( int t0=0; t0<sizeof(Model1_v)/4; t0+=3 )
			{
				pTeapot[t0/3].x=Model1_v[t0+0];
				pTeapot[t0/3].y=Model1_v[t0+1];				// Load vertex data
				pTeapot[t0/3].z=Model1_v[t0+2];
			}
			
			for( WORD t1=0; t1<sizeof(Model1_i)/2; t1+=3 )
			{
				WORD a=Model1_i[t1+0];
				WORD b=Model1_i[t1+1];
				WORD c=Model1_i[t1+2];						// Generate normals
				
				gosVECTOR v1={ pTeapot[a].x, pTeapot[a].y, pTeapot[a].z };
				gosVECTOR v2={ pTeapot[b].x, pTeapot[b].y, pTeapot[b].z };
				gosVECTOR v3={ pTeapot[c].x, pTeapot[c].y, pTeapot[c].z };

				gosVECTOR n;								// UxV = u2v3-u3v2  u3v1-u1v3  u1v2-u2v1
				gosVECTOR delta1;
				gosVECTOR delta2;

				SUB_VECTOR( delta1, v2, v1 );
				SUB_VECTOR( delta2, v3, v2 );

				CROSS_PRODUCT( n, delta1, delta2 );

				NORMALIZE( n );

				pTeapot[a].nx+=n.x;
				pTeapot[a].ny+=n.y;
				pTeapot[a].nz+=n.z;

				pTeapot[b].nx+=n.x;
				pTeapot[b].ny+=n.y;
				pTeapot[b].nz+=n.z;

				pTeapot[c].nx+=n.x;
				pTeapot[c].ny+=n.y;
				pTeapot[c].nz+=n.z;
			}

			for( t0=1; t0<sizeof(Model1_v)/12; t0++ )
			{
				gosVECTOR n;
				
				n.x=pTeapot[t0].nx;
				n.y=pTeapot[t0].ny;
				n.z=pTeapot[t0].nz;

				NORMALIZE( n );

				pTeapot[t0].nx=n.x;
				pTeapot[t0].ny=n.y;
				pTeapot[t0].nz=n.z;
			}
		}
//
// Yellow material
//
		gosMATERIAL Material;
		memset( &Material, 0, sizeof(Material) );
		Material.diffuse.r=1.0f;
		Material.diffuse.g=1.0f;
		Material.diffuse.b=1.0f;

		gos_SetMaterial( &Material ); 
//
// Get Identity matrix
//
		gosMATRIX Identity={ 1.0f, 0.0f, 0.0f, 0.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 };
//
// View matrix, move back along z by 10 units
//
		gosMATRIX View=Identity;
		View._43 = 10.0f;
		gos_SetTransform( MATRIX_VIEW, &View );
//
// Projection matrix, scale x and y by 2 and translate z by -1.0f
//
		gosMATRIX Projection=ProjectionMatrix( 1.0f, 20.0f, 3.1415926f/3.0f, 3.1415926f/3.0f );
		gos_SetTransform( MATRIX_PROJECTION, &Projection );
//
// A red light on the left and a green light on the right
//
		gos_SetRenderState( gos_State_Ambient, 0x404040 );

		gosLIGHT Light;
		memset( &Light, 0, sizeof(Light) );
		Light.dltType=LIGHT_DIRECTIONAL;
		Light.dvDirection.x=-10.0f;
		Light.dvDirection.y=  0.0f;
		Light.dvDirection.z=  0.0f;
		Light.dcvDiffuse.a=1.0f;
		Light.dcvDiffuse.r=1.0f;
		Light.dcvDiffuse.g=0.0f;
		Light.dcvDiffuse.b=0.0f;
		gos_SetLight( 0, &Light );
		gos_LightEnable( 0, true );

		gosLIGHT Light1;
		memset( &Light1, 0, sizeof(Light1) );
		Light1.dltType=LIGHT_DIRECTIONAL;
		Light1.dvDirection.x= 1.0f;
		Light1.dvDirection.y= 1.0f;
		Light1.dvDirection.z= 1.0f;
		Light1.dcvDiffuse.a=1.0f;
		Light1.dcvDiffuse.r=0.0f;
		Light1.dcvDiffuse.g=1.0f;
		Light1.dcvDiffuse.b=0.0f;
		gos_SetLight( 1, &Light1 );
		gos_LightEnable( 1, true );
//
// Make world matrix spin based on time
//
		float fCos = (float)cos( Angle );
		float fSin = (float)sin( Angle );
		gosMATRIX World=Identity;
		World._11 = fCos;  World._12 = 0.0f;  World._13 =-fSin;  World._14 = 0.0f;
		World._21 = 0.0f;  World._22 = 1.0f;  World._23 = 0.0f;  World._24 = 0.0f;
		World._31 = fSin;  World._32 = 0.0f;  World._33 = fCos;  World._34 = 0.0f;
		World._41 = 0.0f;  World._42 = 0.0f;  World._43 = 0.0f;  World._44 = 1.0f;
		gos_SetTransform( MATRIX_WORLD, &World );
		gosMATRIX WorldY;
		WorldY._11 = fCos;  WorldY._12 = fSin;  WorldY._13 = 0.0f;  WorldY._14 = 0.0f;
		WorldY._21 =-fSin;  WorldY._22 = fCos;  WorldY._23 = 0.0f;  WorldY._24 = 0.0f;
		WorldY._31 = 0.0f;  WorldY._32 = 0.0f;  WorldY._33 = 1.0f;  WorldY._34 = 0.0f;
		WorldY._41 = 0.0f;  WorldY._42 = 0.0f;  WorldY._43 = 0.0f;  WorldY._44 = 1.0f;
		gos_MultiplyTransform( MATRIX_WORLD, &WorldY );
//
// Render middle teapot
//
		gos_RenderIndexedArray( pTeapot, sizeof(Model1_v)/12, Model1_i, sizeof(Model1_i)/2, VERTEX_gosD3DVERTEX );
//
// Render bottom right teapot
//
		World._41 = 3.0f;
		World._42 = -3.5f;
		gos_SetTransform( MATRIX_WORLD, &World );
		if( NumPot>1 )
			gos_RenderIndexedArray( pTeapot, sizeof(Model1_v)/12, Model1_i, sizeof(Model1_i)/2, VERTEX_gosD3DVERTEX );
//
// Render bottom left teapot
//
		World._41 = -3.0f;
		gos_SetTransform( MATRIX_WORLD, &World );
		if( NumPot>2 )
			gos_RenderIndexedArray( pTeapot, sizeof(Model1_v)/12, Model1_i, sizeof(Model1_i)/2, VERTEX_gosD3DVERTEX );
//
// Render top left teapot
//
		World._42 = 2.0f;
		gos_SetTransform( MATRIX_WORLD, &World );
		if( NumPot>3 )
			gos_RenderIndexedArray( pTeapot, sizeof(Model1_v)/12, Model1_i, sizeof(Model1_i)/2, VERTEX_gosD3DVERTEX );
//
// Render top right teapot
//
		World._41 = 3.0f;
		gos_SetTransform( MATRIX_WORLD, &World );
		if( NumPot>4 )
			gos_RenderIndexedArray( pTeapot, sizeof(Model1_v)/12, Model1_i, sizeof(Model1_i)/2, VERTEX_gosD3DVERTEX );
//
// Disable lights (clean up!)
//
		gos_LightEnable( 0, false);
		gos_LightEnable( 1, false);
	}




//
// Test hardware transform and lighting using a static vertex buffer of a teappot
//
	if( Test==18 )
	{
		char Buffer[256];
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 0, 1, 0, 0 );
		gos_TextSetPosition( 50,Environment.screenHeight-20 );
		sprintf( Buffer, "%s T&L - Spinning teapots using /bold=1VERTEX BUFFERS/bold=0", (gos_GetMachineInformation( gos_Info_CanHardwareTandL ) ? "Hardware" : "Software") );		
		gos_TextDraw( Buffer );
		gos_TextSetPosition( 380,Environment.screenHeight-20 );
		gos_TextDraw( "1 - Advance test  2=More teapots, 3=Less" );
		gos_TextSetPosition( 50,Environment.screenHeight-40 );
		static double LastTime=0.1f;
		sprintf( Buffer, "Triangles=%d, Vertices=%d, /proportional=0% 6.2f/proportional=1 Million Triangles/s, /proportional=0% 6.2f/proportional=1 Million Vertices/s", NumPot*sizeof(Model1_i)/6, NumPot*sizeof(Model1_v)/12, (double)(NumPot*sizeof(Model1_i)/6) / (gos_GetHiResTime()-LastTime) / 1000000.0f, (double)(NumPot*sizeof(Model1_v)/12) / (gos_GetHiResTime()-LastTime) / 1000000.0f );
		LastTime=gos_GetHiResTime();
		gos_TextDraw( Buffer );
		gos_SetRenderState( gos_State_Texture, 0 );
		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulate );
		gos_SetRenderState( gos_State_Fog, 0 );
		gos_SetRenderState( gos_State_MonoEnable, 0 );
		gos_SetRenderState( gos_State_ShadeMode, gos_ShadeGouraud );
		gos_SetRenderState( gos_State_Filter, gos_FilterNone );
		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneZero );
		gos_SetRenderState( gos_State_Culling, gos_Cull_CCW );
		gos_SetRenderState( gos_State_Lighting, 1 );
		gos_SetRenderState( gos_State_NormalizeNormals, 0 );
		gos_SetRenderState( gos_State_Clipping, 1 );
//
// Setup Model only once or when vertex buffer is lost
//
		if( InitTeapot || gos_VertexBuffersLost(hTeapot) )
		{
			gosD3DVERTEX* pData=(gosD3DVERTEX*)gos_LockVertexBuffer( hTeapot, 1, 0 );

			memset( pData, 0, sizeof(gosD3DVERTEX)*sizeof(Model1_v)/12 );

			for( int t0=0; t0<sizeof(Model1_v)/4; t0+=3 )
			{
				pData[t0/3].x=Model1_v[t0+0];
				pData[t0/3].y=Model1_v[t0+1];				// Load vertex data
				pData[t0/3].z=Model1_v[t0+2];
			}
			
			for( WORD t1=0; t1<sizeof(Model1_i)/2; t1+=3 )
			{
				WORD a=Model1_i[t1+0];
				WORD b=Model1_i[t1+1];
				WORD c=Model1_i[t1+2];						// Generate normals
				
				gosVECTOR v1={ pData[a].x, pData[a].y, pData[a].z };
				gosVECTOR v2={ pData[b].x, pData[b].y, pData[b].z };
				gosVECTOR v3={ pData[c].x, pData[c].y, pData[c].z };

				gosVECTOR n;								// UxV = u2v3-u3v2  u3v1-u1v3  u1v2-u2v1
				gosVECTOR delta1;
				gosVECTOR delta2;

				SUB_VECTOR( delta1, v2, v1 );
				SUB_VECTOR( delta2, v3, v2 );

				CROSS_PRODUCT( n, delta1, delta2 );

				NORMALIZE( n );

				pData[a].nx+=n.x;
				pData[a].ny+=n.y;
				pData[a].nz+=n.z;

				pData[b].nx+=n.x;
				pData[b].ny+=n.y;
				pData[b].nz+=n.z;

				pData[c].nx+=n.x;
				pData[c].ny+=n.y;
				pData[c].nz+=n.z;
			}

			for( t0=1; t0<sizeof(Model1_v)/12; t0++ )
			{
				gosVECTOR n;
				
				n.x=pData[t0].nx;
				n.y=pData[t0].ny;
				n.z=pData[t0].nz;

				NORMALIZE( n );

				pData[t0].nx=n.x;
				pData[t0].ny=n.y;
				pData[t0].nz=n.z;
			}

			gos_UnLockVertexBuffer( hTeapot );
			InitTeapot=0;
		}
//
// Yellow material
//
		gosMATERIAL Material;
		memset( &Material, 0, sizeof(Material) );
		Material.diffuse.r=1.0f;
		Material.diffuse.g=1.0f;
		Material.diffuse.b=1.0f;

		gos_SetMaterial( &Material ); 
//
// Get Identity matrix
//
		gosMATRIX Identity={ 1.0f, 0.0f, 0.0f, 0.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 };
//
// View matrix, move back along z by 10 units
//
		gosMATRIX View=Identity;
		View._43 = 10.0f;
		gos_SetTransform( MATRIX_VIEW, &View );
//
// Projection matrix, scale x and y by 2 and translate z by -1.0f
//
		gosMATRIX Projection=ProjectionMatrix( 1.0f, 20.0f, 3.1415926f/3.0f, 3.1415926f/3.0f );
		gos_SetTransform( MATRIX_PROJECTION, &Projection );
//
// A red light on the left and a green light on the right
//
		gos_SetRenderState( gos_State_Ambient, 0x404040 );

		gosLIGHT Light;
		memset( &Light, 0, sizeof(Light) );
		Light.dltType=LIGHT_DIRECTIONAL;
		Light.dvDirection.x=-10.0f;
		Light.dvDirection.y=  0.0f;
		Light.dvDirection.z=  0.0f;
		Light.dcvDiffuse.a=1.0f;
		Light.dcvDiffuse.r=1.0f;
		Light.dcvDiffuse.g=0.0f;
		Light.dcvDiffuse.b=0.0f;
		gos_SetLight( 0, &Light );
		gos_LightEnable( 0, true );

		gosLIGHT Light1;
		memset( &Light1, 0, sizeof(Light1) );
		Light1.dltType=LIGHT_DIRECTIONAL;
		Light1.dvDirection.x= 1.0f;
		Light1.dvDirection.y= 1.0f;
		Light1.dvDirection.z= 1.0f;
		Light1.dcvDiffuse.a=1.0f;
		Light1.dcvDiffuse.r=0.0f;
		Light1.dcvDiffuse.g=1.0f;
		Light1.dcvDiffuse.b=0.0f;
		gos_SetLight( 1, &Light1 );
		gos_LightEnable( 1, true );
//
// Make world matrix spin based on time
//
		float fCos = (float)cos( Angle );
		float fSin = (float)sin( Angle );
		gosMATRIX World=Identity;
		World._11 = fCos;  World._12 = 0.0f;  World._13 =-fSin;  World._14 = 0.0f;
		World._21 = 0.0f;  World._22 = 1.0f;  World._23 = 0.0f;  World._24 = 0.0f;
		World._31 = fSin;  World._32 = 0.0f;  World._33 = fCos;  World._34 = 0.0f;
		World._41 = 0.0f;  World._42 = 0.0f;  World._43 = 0.0f;  World._44 = 1.0f;
		gos_SetTransform( MATRIX_WORLD, &World );
		gosMATRIX WorldY;
		WorldY._11 = fCos;  WorldY._12 = fSin;  WorldY._13 = 0.0f;  WorldY._14 = 0.0f;
		WorldY._21 =-fSin;  WorldY._22 = fCos;  WorldY._23 = 0.0f;  WorldY._24 = 0.0f;
		WorldY._31 = 0.0f;  WorldY._32 = 0.0f;  WorldY._33 = 1.0f;  WorldY._34 = 0.0f;
		WorldY._41 = 0.0f;  WorldY._42 = 0.0f;  WorldY._43 = 0.0f;  WorldY._44 = 1.0f;
		gos_MultiplyTransform( MATRIX_WORLD, &WorldY );
//
// Render middle teapot
//
		gos_RenderVertexBuffer( hTeapot, 0, sizeof(Model1_v)/12, Model1_i, sizeof(Model1_i)/2 );
//
// Render bottom right teapot
//
		World._41 = 3.0f;
		World._42 = -3.5f;
		gos_SetTransform( MATRIX_WORLD, &World );
		if( NumPot>1 )
			gos_RenderVertexBuffer( hTeapot, 0, sizeof(Model1_v)/12, Model1_i, sizeof(Model1_i)/2 );
//
// Render bottom left teapot
//
		World._41 = -3.0f;
		gos_SetTransform( MATRIX_WORLD, &World );
		if( NumPot>2 )
			gos_RenderVertexBuffer( hTeapot, 0, sizeof(Model1_v)/12, Model1_i, sizeof(Model1_i)/2 );
//
// Render top left teapot
//
		World._42 = 2.0f;
		gos_SetTransform( MATRIX_WORLD, &World );
		if( NumPot>3 )
			gos_RenderVertexBuffer( hTeapot, 0, sizeof(Model1_v)/12, Model1_i, sizeof(Model1_i)/2 );
//
// Render top right teapot
//
		World._41 = 3.0f;
		gos_SetTransform( MATRIX_WORLD, &World );
		if( NumPot>4 )
			gos_RenderVertexBuffer( hTeapot, 0, sizeof(Model1_v)/12, Model1_i, sizeof(Model1_i)/2 );
//
// Disable lights (clean up!)
//
		gos_LightEnable( 0, false);
		gos_LightEnable( 1, false);
	}




//
// Test blending using the D3D Blend sample source
//
	if( Test==19 )
	{
		char Buffer[256];
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 0, 1, 0, 0 );
		gos_TextSetPosition( 10,Environment.screenHeight-20 );
		sprintf( Buffer, "%s T&L - Vertex Blending (Solid model with 2 blended matrices)", (gos_GetMachineInformation( gos_Info_CanHardwareTandL ) ? "Hardware" : "Software") );		
		gos_TextDraw( Buffer );
		gos_TextSetPosition( 380,Environment.screenHeight-20 );
		gos_TextDraw( "1 - Advance test" );
		gos_TextSetPosition( 50,Environment.screenHeight-40 );
		gos_SetRenderState( gos_State_Texture, BananaTexture );
		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulate );
		gos_SetRenderState( gos_State_Fog, 0 );
		gos_SetRenderState( gos_State_MonoEnable, 0 );
		gos_SetRenderState( gos_State_ShadeMode, gos_ShadeGouraud );
		gos_SetRenderState( gos_State_Filter, gos_FilterNone );
		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneZero );
		gos_SetRenderState( gos_State_Culling, gos_Cull_CCW );
		gos_SetRenderState( gos_State_Lighting, 1 );
		gos_SetRenderState( gos_State_NormalizeNormals, 1 );
		gos_SetRenderState( gos_State_Clipping, 1 );
		gos_SetRenderState( gos_State_VertexBlend, 1 );
		gos_SetRenderState( gos_State_Ambient, 0x404040 );
//
// Only if not in Blade
//
		if( Environment.Renderer!=3 )
		{	
//
// Setup Model only once or when vertex buffer is lost
//
			if( InitBanana || gos_VertexBuffersLost(hBanana) )
			{
				gosD3DBLENDVERTEX* pVertices=(gosD3DBLENDVERTEX*)gos_LockVertexBuffer( hBanana, 1, 0 );

				DWORD dwNumRings=ELLIPSE_NUMRINGS;
				DWORD dwNumSections=ELLIPSE_NUMSECTIONS;
				float sx=1.5f;
				float sy=1.5f;
				float sz=4.5f;

				DWORD dwNumTriangles = (dwNumRings+1) * dwNumSections * 2;
				DWORD dwNumVertices  = (dwNumRings+1) * dwNumSections + 2;

				// Generate vertices at the end points.
				pVertices[0].x=0.0f;
				pVertices[0].y=0.0f;
				pVertices[0].z=sz;
				pVertices[0].blend=1.0f;
				pVertices[0].nx=0.0f;
				pVertices[0].ny=0.0f;
				pVertices[0].nz=1.0f;
				pVertices[0].u=0.0f;
				pVertices[0].v=0.0f;
				pVertices[dwNumVertices-1].x=0.0f;
				pVertices[dwNumVertices-1].y=0.0f;
				pVertices[dwNumVertices-1].z=-sz;
				pVertices[dwNumVertices-1].blend=1.0f;
				pVertices[dwNumVertices-1].nx=0.0f;
				pVertices[dwNumVertices-1].ny=0.0f;
				pVertices[dwNumVertices-1].nz=-1.0f;
				pVertices[dwNumVertices-1].u=0.0f;
				pVertices[dwNumVertices-1].v=0.0f;

				// Generate vertex points for rings
				float dtheta = (float)(PI / (dwNumRings + 2));     //Angle between each ring
				float dphi   = (float)(2*PI / dwNumSections); //Angle between each section
				float theta  = dtheta;
				DWORD n = 1; //vertex being generated, begins at 1 to skip top point

				for( DWORD i = 0; i < (dwNumRings+1); i++ )
				{
					float z   = cosf(theta);				 // z is the same for each ring
					float tv  = theta / PI;                  // v is the same for each ring
					float phi = 0.0f;
					float rsintheta = sinf(theta);

					for( DWORD j = 0; j < dwNumSections; j++ )
					{
						float x  =  rsintheta * sinf(phi);
						float y  = -rsintheta * cosf(phi);
						float tu = (float)(1.0 - phi / (2*PI) );

						pVertices[n].x=sx*x;
						pVertices[n].y=sy*y;
						pVertices[n].z=sz*z;
						pVertices[n].blend=1.0f;
						pVertices[n].nx=x;
						pVertices[n].ny=y;
						pVertices[n].nz=z;
						pVertices[n].u=tu;
						pVertices[n].v=tv;

						phi += dphi;
						++n;
					}
					theta += dtheta;
				}

				// Generate triangles for top and bottom caps.
				for( i = 0; i < dwNumSections; i++ )
				{
					DWORD t1 = 3*i;
					DWORD t2 = 3*(dwNumTriangles - dwNumSections + i);

					pBananaIndices[t1+0] = (WORD)(0);
					pBananaIndices[t1+1] = (WORD)(i + 1);
					pBananaIndices[t1+2] = (WORD)(1 + ((i + 1) % dwNumSections));

					pBananaIndices[t2+0] = (WORD)( dwNumVertices - 1 );
					pBananaIndices[t2+1] = (WORD)( dwNumVertices - 2 - i );
					pBananaIndices[t2+2] = (WORD)( dwNumVertices - 2 - ((1 + i) % dwNumSections) );
				}

				// Generate triangles for the rings
				DWORD m = 1;            // 1st vertex begins at 1 to skip top point
				n = dwNumSections; // triangle being generated, skip the top cap

				for( i = 0; i < dwNumRings; i++ )
				{
					for( DWORD j = 0; j < dwNumSections; j++ )
					{
						pBananaIndices[3*n+0] = (WORD)(m + j);
						pBananaIndices[3*n+1] = (WORD)(m + dwNumSections + j);
						pBananaIndices[3*n+2] = (WORD)(m + dwNumSections + ((j + 1) % dwNumSections));
						n++;

						pBananaIndices[3*n+0] = (WORD)(m + j);
						pBananaIndices[3*n+1] = (WORD)(m + dwNumSections + ((j + 1) % dwNumSections));
						pBananaIndices[3*n+2] = (WORD)(m + ((j + 1) % dwNumSections));
						n++;
					}
					m += dwNumSections;
				}

				float fMinZ = -ELLIPSE_Z_LENGTH;
				float fMaxZ = +ELLIPSE_Z_LENGTH;

				for( i=0; i<dwNumVertices; i++ )
				{
					float a = ( pVertices[i].z - fMinZ ) / ( fMaxZ - fMinZ );

					if( a >= 0.75f )
						pVertices[i].blend = 0.0f;
					else if( a >= 0.5f )
						pVertices[i].blend = 12.0f*((0.75f-a)*(0.75f-a));
					else if( a >= 0.25f )
						pVertices[i].blend = 1.0f-12.0f*((a-0.25f)*(a-0.25f));
					else
						pVertices[i].blend = 1.0f;
				}

				gos_UnLockVertexBuffer( hBanana );
				InitBanana=0;
			}
//
// Setup a material
//
			gosMATERIAL Material;
			memset( &Material, 0, sizeof(Material) );
			Material.diffuse.r=1.0f;
			Material.diffuse.g=1.0f;
			Material.diffuse.b=1.0f;
			gos_SetMaterial( &Material ); 
//
// Setup a light
//
			gosLIGHT Light;
			memset( &Light, 0, sizeof(Light) );
			Light.dltType=LIGHT_DIRECTIONAL;
			Light.dvDirection.x= 0.0f;
			Light.dvDirection.y=-1.0f;
			Light.dvDirection.z= 0.0f;
			Light.dcvDiffuse.a=1.0f;
			Light.dcvDiffuse.r=1.0f;
			Light.dcvDiffuse.g=1.0f;
			Light.dcvDiffuse.b=1.0f;
			gos_SetLight( 0, &Light );
			gos_LightEnable( 0, true );
//
// Setup the projection matrix
//
			gosMATRIX Projection=ProjectionMatrix( 1.0f, 100.0f, 1.57f, 1.0f );
			gos_SetTransform( MATRIX_PROJECTION, &Projection );
//
// Get Identity matrix
//
			gosMATRIX Identity={ 1.0f, 0.0f, 0.0f, 0.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 };
//
// Set the vertex blending bend angle for this frame
//
			float fBendAngle = ( sinf(Angle) + 1.0f ) * 0.6f;

			gosMATRIX matUpperArm=Identity;
			gosMATRIX matLowerArm=SetRotateXMatrix( -fBendAngle );

			gos_SetTransform( MATRIX_WORLD,  &matUpperArm );
			gos_SetTransform( MATRIX_WORLD1, &matLowerArm );
//
// View matrix
//
			gosMATRIX matView= { cosf(SlowAngle), 0.0f,-sinf(SlowAngle), 0.0f,
											0.0f, 1.0f,            0.0f, 0.0f,
								 sinf(SlowAngle), 0.0f, cosf(SlowAngle), 0.0f,
											0.0f, 0.0f,            12.0f, 1.0f,
							   };

			gos_SetTransform( MATRIX_VIEW, &matView );
//
// Render banana
//
			gos_RenderVertexBuffer( hBanana, 0, (ELLIPSE_NUMRINGS+1) * ELLIPSE_NUMSECTIONS + 2, pBananaIndices, (ELLIPSE_NUMRINGS+1) * ELLIPSE_NUMSECTIONS * 2 * 3 );
//
// Disable light (clean up!)
//
			gos_LightEnable( 0, false);
		}
	}

//
// Test texture rebuilding
//
	if( Test==20 )
	{
		gos_SetRenderState( gos_State_Filter, gos_FilterNone );
		gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneZero );
		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendDecal );

		gos_SetRenderState( gos_State_Texture, rtex1 );
		DofQuad( 20+0*64,20, 20+0*64+256,256, 0.25 );

		gos_SetRenderState( gos_State_Texture, rtex2 );
		DofQuad( 20+1*64,20, 20+1*64+256,256, 0.25 );

		gos_SetRenderState( gos_State_Texture, rtex3 );
		DofQuad( 20+2*64,20, 20+2*64+256,256, 0.25 );

		gos_SetRenderState( gos_State_Texture, rtex4 );
		DofQuad( 20+3*64,20, 20+3*64+256,256, 0.25 );

		gos_SetRenderState( gos_State_Texture, rtex5 );
		DofQuad( 20+4*64,20, 20+4*64+256,256, 0.25 );

		gos_SetRenderState( gos_State_Texture, rtex6 );
		DofQuad( 20+5*64,20, 20+5*64+256,256, 0.25 );

		gos_SetRenderState( gos_State_Texture, rtex7 );
		DofQuad( 20+6*64,20, 20+6*64+256,256, 0.25 );

		gos_SetRenderState( gos_State_Texture, rtex8 );
		DofQuad( 20+7*64,20, 20+7*64+256,256, 0.25 );

		gos_SetRenderState( gos_State_Texture, rtex9 );
		DofQuad( 20+8*64,20, 20+8*64+256,256, 0.25 );


		gos_SetRenderState( gos_State_Texture, rtex10 );
		DofQuad( 20+0*64,256, 20+0*64+256,512, 0.25 );

		gos_SetRenderState( gos_State_Texture, rtex11 );
		DofQuad( 20+1*64,256, 20+1*64+256,512, 0.25 );

		gos_SetRenderState( gos_State_Texture, rtex12 );
		DofQuad( 20+2*64,256, 20+2*64+256,512, 0.25 );

		gos_SetRenderState( gos_State_Texture, rtex13 );
		DofQuad( 20+3*64,256, 20+3*64+256,512, 0.25 );

		gos_SetRenderState( gos_State_Texture, rtex14 );
		DofQuad( 20+4*64,256, 20+4*64+256,512, 0.25 );

		gos_SetRenderState( gos_State_Texture, rtex15 );
		DofQuad( 20+5*64,256, 20+5*64+256,512, 0.25 );

		gos_SetRenderState( gos_State_Texture, rtex16 );
		DofQuad( 20+6*64,256, 20+6*64+256,512, 0.25 );

		gos_SetRenderState( gos_State_Texture, rtex17 );
		DofQuad( 20+7*64,256, 20+7*64+256,512, 0.25 );

		gos_SetRenderState( gos_State_Clipping, 0 );
		
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 0, 1, 0, 0 );

		gos_TextSetPosition( 50,Environment.screenHeight-20 );	 //RLC
		gos_TextDraw( "Texture Swapping Test");					 //RLC

		gos_TextSetPosition( 350,Environment.screenHeight-20 );  //RLC
		gos_TextDraw( "1 - Advance test" );						 //RLC
	}

//
// Test texture swapping
//
	if( Test==21 )
	{
		int texno;
		char texName[256];
		static int frameno = 0;

		gos_TextSetAttributes( Font_Arial8, 0xffffffff, 1, 0, 1, 0, 0, 0 );
		gos_TextSetPosition( 50,Environment.screenHeight-35 );
		gos_TextDraw( "%d Megabytes of %d*%d textures swapping",MaxSwap,MaxSwapWidth,MaxSwapHeight );
		gos_TextSetPosition( 380,Environment.screenHeight-20 );
		gos_TextDraw( "1 - Advance test, 2 - More textures, 3-Less" );
		gos_TextSetPosition( 50,Environment.screenHeight-20 );
		gos_TextDraw( "Texture eviction/swapping test" );


		frameno++;
		int starttex = frameno % MaxSwap;
		//starttex = 0;
		int endtex = (starttex + TexView) % MaxSwap;

		if( texturesCreated < MaxSwap )
		{
			for( texno=texturesCreated; texno < MaxSwap; texno++ )
			{
				SwapTexData[texno].Width = MaxSwapWidth;
				SwapTexData[texno].Height = MaxSwapHeight;
				DWORD color = 0;
				int bitpos = 0;
				for( bitpos=0; bitpos<10; bitpos++ )
				{
					if( texno & ( 1 << bitpos ) )
					{
						color |= ((1<<((bitpos%3)+4))<<(8*(bitpos/3)));
					}
				}

				sprintf( texName, "SwapTst0x%03x", texno );

				SwapTexData[texno].Color = color;
				SwapTexData[texno].Handle = gos_NewEmptyTexture(gos_Texture_Solid, texName, ((SwapTexData[texno].Height<<16)|SwapTexData[texno].Width), gosHint_DisableMipmap | gosHint_DisableMipmap, SwapPopulateFunction, (void *)&SwapTexData[texno] );
				SwapPopulateFunction( SwapTexData[texno].Handle , (void *)(&SwapTexData[texno]) );
			}

			texturesCreated=MaxSwap;
		}

		for( texno=starttex; texno != endtex; texno = (texno+1)%MaxSwap )
		{
			gos_SetRenderState( gos_State_Texture, SwapTexData[texno].Handle );
			int x = 14 + (texno & 0x1f) * 16;
			int y = 14 + (texno >> 5 ) * 16;

			DofQuad( x, y, x+14, y+14, 1.f );
		}
	}


//
// Test bump mapping
//
	if( Test==22 )
	{
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, 1, 0, 1, 0, 0, 0 );
		gos_TextSetPosition( 380,Environment.screenHeight-20 );
		gos_TextDraw( "1 - Advance test" );
		gos_TextSetPosition( 50,Environment.screenHeight-20 );

		if( gos_GetMachineInformation( gos_Info_CanBumpEnvMap ) )
		{
			gos_TextDraw( "Test bump mapping: Bump Environment Mapping" );
			gos_SetRenderState( gos_State_Texture, watertex );
			gos_SetRenderState( gos_State_Texture2, bumptex );
			gos_SetRenderState( gos_State_Texture3, bumpenvtex );
			gos_SetRenderState( gos_State_Multitexture, gos_Multitexture_BumpEnvMap );
			gos_RenderIndexedArray( bumpVert, numBumpVert, bumpIndices, numBumpIndices );
			gos_SetRenderState( gos_State_Multitexture, gos_Multitexture_None );
			gos_SetRenderState( gos_State_Texture, 0 );
			gos_SetRenderState( gos_State_Texture2, 0 );
			gos_SetRenderState( gos_State_Texture3, 0 );
		}
		else if( gos_GetMachineInformation( gos_Info_CanBumpDotMap ) )
		{
			gos_TextDraw( "Test bump mapping: Dot Product technique" );
			gos_SetRenderState( gos_State_Texture, normtex );
			gos_SetRenderState( gos_State_Texture2, watertex );
			gos_SetRenderState( gos_State_Multitexture, gos_Multitexture_BumpDotMap );
			gos_RenderIndexedArray( bumpVert, numBumpVert, bumpIndices, numBumpIndices );
			gos_SetRenderState( gos_State_Multitexture, gos_Multitexture_None );
			gos_SetRenderState( gos_State_Texture, 0 );
			gos_SetRenderState( gos_State_Texture2, 0 );
		}
		else
		{
			gos_TextDraw( "Test bump mapping: Bump Mapping not available on this renderer" );
		}
	}


//
// Test texture loading speed
//
	if( Test==23 )
	{
		gos_TextSetAttributes( Font_Arial8, 0xffffffff, 1, 0, 1, 0, 0, 0 );
		gos_TextSetPosition( 380,Environment.screenHeight-20 );
		gos_TextDraw( "1 - Advance test, 2 - %s test", LoadTest ? "Stop" : "Start" );
		gos_TextSetPosition( 50,Environment.screenHeight-20 );
		gos_TextDraw( "Texture Loading speed" );

		if( LoadTest )
		{
			gos_TextSetAttributes( Font_Arial8, 0xffffffff, 2, 0, 1, 1, 0, 0 );
			gos_TextSetPosition( 50,100 );
			gos_TextDraw( "PNG: %dms",LoadPNG );
			gos_TextSetPosition( 50,150 );
			gos_TextDraw( "JPG: %dms",LoadJPG );
			gos_TextSetPosition( 50,200 );
			gos_TextDraw( "TGA: %dms",LoadTGA );
			gos_TextSetPosition( 50,250 );
			gos_TextDraw( "BMP: %dms",LoadBMP );
			gos_TextSetPosition( 50,350 );
			gos_TextDraw( "Loading 'Assets\\Graphics\\SpeedTest.xxx' texture" );
		}
	}
}


































int TestMenu=0;

bool __stdcall CheckMenu()
{
	return 0!=TestMenu;
}

void __stdcall DoMenu()
{
	TestMenu=!TestMenu;
}


int TestMenu1=0;

bool __stdcall CheckMenu1()
{
	return 0!=TestMenu1;
}

void __stdcall DoMenu1()
{
	TestMenu1=!TestMenu1;
}




DWORD TestF1;
BYTE* MemoryF1=0;
DWORD SizeF1=0;
DWORD TestF2;
BYTE* MemoryF2=0;
DWORD SizeF2=0;
DWORD TestF3;
BYTE* MemoryF3=0;
DWORD SizeF3=0;



DWORD TestActive=0;

DWORD TestMenuFunction( char* Name, DWORD Function )
{
	Name=Name;
	SPEW(( 0, "Got '%s'",Name ));
	switch( Function )
	{
		case gosMenu_Name:
//			return 0;										// Return default name
			return (DWORD)"Override Menu Name Test";		// Override name
		case gosMenu_CheckMark:
			return TestActive;				// Return test flag
		case gosMenu_Greyed:
			return 0;						// Always active
		case gosMenu_Activated:
			TestActive=!TestActive;
			return 1;						// Keep menu open
		default:
			return 0;
	}
}


void __stdcall InitializeGameEngine()
{
//
// Test Debugger menus
//
	AddDebuggerMenuItem( "Testing0", 0, DoMenu );
	AddDebuggerMenuItem( "Testing SubMenu\\Menu1", 0, DoMenu );
	AddDebuggerMenuItem( "Testing1", 0, DoMenu );
	AddDebuggerMenuItem( " ", 0, DoMenu );
	AddDebuggerMenuItem( " ", 0, DoMenu );
	AddDebuggerMenuItem( " ", 0, DoMenu );
	AddDebuggerMenuItem( "Testing2", 0, DoMenu );
	AddDebuggerMenuItem( "Testing SubMenu\\Menu2", 0, 0, 0, TestMenuFunction );
	AddDebuggerMenuItem( "Testing SubMenu\\Menu3", 0, DoMenu );

//
// Setup statistics
//
	AddStatistic( "Unlock texture", "", gos_cycledata, &CycleData, Stat_Graph );
//
// Load up a single 256*256 24 bit test TGA
//
	TestTexture = gos_NewTextureFromFile( gos_Texture_Alpha, "Assets\\Graphics\\texture.tga",gosHint_AGPMemory|gosHint_ReloadFromDisk );
	AlphaTexture = gos_NewTextureFromFile( gos_Texture_Detect, "Assets\\Graphics\\font.tga", gosHint_ReloadFromDisk );
	TestMipMap = gos_NewTextureFromFile( gos_Texture_Alpha, "Assets\\Graphics\\MipMap0.tga",gosHint_UserMipMaps );

	WallTexture = gos_NewTextureFromFile( gos_Texture_Detect, "Assets\\Graphics\\wall.bmp", gosHint_ReloadFromDisk );
	LightmapTexture = gos_NewTextureFromFile( gos_Texture_Detect, "Assets\\Graphics\\Lightmap.bmp", gosHint_ReloadFromDisk );

	RenderTexture=gos_NewEmptyTexture( gos_Texture_Keyed, "Render target", 256, gosHint_DisableMipmap|gosHint_DontShrink );

	Font_GDIArial8=gos_LoadFont("Arial.ttf",0);
	Font_Arial8=gos_LoadFont("Assets\\Graphics\\arial.d3f",0);

	Test=INITIAL_TEST;

	MaxSwap=8;

	NumPot=5;
	Polys=500;
	BackGroundColor=0x004000;
	Size=1.0f;
	Step=0.004f;
	SafeSize=1.0f;

	for( int t0=0; t0<NumLines; t0++ )
	{
		Lines[t0][0]=(640-512)/2+(gos_rand()&511);		
		Lines[t0][1]=(640-512)/2+(gos_rand()&511);		
		Lines[t0][2]=(480-256)/2+(gos_rand()&255);		
		Lines[t0][3]=(480-256)/2+(gos_rand()&255);		
		Lines[t0][4]=(gos_rand()&63)+32;
		Lines[t0][5]=0;
	}

	tex1=0;
	rtex1=0;
	UseTexture=0;
	Frame=0;
	WhichTexture=1;



	HandleRC=gos_OpenResourceDLL( "Assets\\Resources\\Resources.dll" );


//
// Create the teapot vertex buffer
//
	hTeapot=gos_CreateVertexBuffer( sizeof(Model1_v)/12, 1, VERTEX_gosD3DVERTEX );
	InitTeapot=1;

//
// Generate ellipse data vertex buffer for the Blend test
//
	pBananaIndices=(WORD*)gos_Malloc(((ELLIPSE_NUMRINGS+1) * ELLIPSE_NUMSECTIONS * 2) * 3 * sizeof(WORD) );

	hBanana=gos_CreateVertexBuffer( (ELLIPSE_NUMRINGS+1) * ELLIPSE_NUMSECTIONS + 2, 1, VERTEX_gosD3DBLENDVERTEX );

	BananaTexture = gos_NewTextureFromFile( gos_Texture_Solid, "Assets\\Graphics\\banana.jpg",gosHint_ReloadFromDisk );

	InitBanana=1;
}





void (__stdcall *OldUpdateRenderers)();
//
// Exit game display - prompt if the user wants to exit
//
void ExitGameDisplay()
{
//
// Render the current scene
//
	OldUpdateRenderers();
//
// Display a 'Are you sure message'
//
	gos_TextSetRegion( 0, 0, Environment.screenWidth, Environment.screenHeight );
	gos_TextDrawBackground( (Environment.screenWidth/2)-100, (Environment.screenHeight/2)-50, (Environment.screenWidth/2)+100, (Environment.screenHeight/2)+50, 0xff00c0c0 );
	gos_TextSetAttributes( Font_Arial8, 0xffffffff, -8, 0, 1, 0, 0 );
	gos_TextSetPosition( (Environment.screenWidth/2)-64, (Environment.screenHeight/2)-4 );
	gos_TextDraw( "EXIT - Are you sure? (Y/N)" );
}



void __stdcall TerminateGameEngine()
{
//
// Ask GameOS if this is a user quit
//
	if( gos_UserExit() )
	{
//
// Display a 'Are you sure you want to quit?' message until Y or N is pressed
//
		gos_AbortTermination();
		gos_KeyboardFlush();									// Clear any 'escape or ALT F4' keys in buffer
		OldUpdateRenderers = Environment.UpdateRenderers;
		Environment.UpdateRenderers	= ExitGameDisplay;
		DWORD temp=0;
		while( temp==0 )
		{
			if( gos_RunMainLoop() )
			{
				if( gos_UserExit() )
					gos_AbortTermination();						// If user shuts window again, do not allow app to exit
				else
					break;
			}
			temp=gos_GetKey()&(255-32);
		}
//
// If user answered no, do not quit
//
		if( temp=='N' )	
		{
			Environment.UpdateRenderers	= UpdateRenderers;
			return;
		}
//
// Otherwise, clean up and quit
//
	}
	if( pTeapot )
	{
		gos_Free( pTeapot );
		pTeapot=0;
	}
	if( hTeapot )
	{
		gos_DeleteVertexBuffer( hTeapot );
		hTeapot=0;
	}
	if( hBanana )
	{
		gos_DeleteVertexBuffer( hBanana );
		hBanana=0;
	}
	if( pBananaIndices )
	{
		gos_Free(pBananaIndices);
		pBananaIndices=0;
	}
	if( pROMImage )
	{
		free( (void *)pROMImage );
		pROMImage = NULL;
	}
	if( bumptex )
	{
		gos_DestroyTexture( bumptex );
		bumptex=0;
	}
	if( normtex )
	{
		gos_DestroyTexture( normtex );
		normtex=0;
	}
	if( watertex )
	{
		gos_DestroyTexture( watertex );
		watertex=0;
	}
	if( bumpenvtex )
	{
		gos_DestroyTexture( bumpenvtex );
		bumpenvtex=0;
	}
	for( int texno=0; texno < texturesCreated; texno++ )
	{
		gos_DestroyTexture( SwapTexData[texno].Handle );
		SwapTexData[texno].Handle = 0;
		texturesCreated = 0;
	}

	gos_TerminateApplication();
	gos_CloseResourceDLL( HandleRC );
}



//
// Gamelogic
//
void __stdcall DoGameLogic()
{
//
// Frame number
//
	Frame++;

//
// Test reading screen pixels colors
//
//	float Xpos, Ypos;
//	gos_GetMouseInfo( &Xpos, &Ypos, 0, 0, 0, 0 );
//	DWORD Pixel=gos_GetMachineInformation( gos_Info_GetPixelColor, (DWORD)(Xpos*Environment.screenWidth-1), (DWORD)(Ypos*Environment.screenHeight-1) );
//	SPEW(( 0, "Pixel=0x%08x", Pixel ));

//
// Test exceptiuon handling
//
//	if( Frame==500 )
//		*(BYTE*)0=0;


//
// Code to move lightmap etc.. in a circle
//
	SlowAngle=(float)(2*3.1415926*((Frame&8191)/8191.0));
	Angle=(float)(2*3.1415926*((Frame&255)/255.0));
	MoveX=(int)(sin(Angle)*45.0);
	MoveY=(int)(cos(Angle)*45.0);
//
// Animate stuff in the tests
//
	Size-=Step;
	if( Size>1.0f || Size<Step )
	{
		Step=-Step;
		Size-=Step;
	}
//
//
//
	Spin1+=1;
	Spin2+=2;
	Spin3+=3;
//
// Mess with the background color
//
	BackGroundColor+=1;
//
// Read keyboard - increment test?
//
	DWORD KeyPress=gos_GetKey();
	if( KeyPress )
		SPEW(( "", "Key=0x%x, '%c', Description='%s'",KeyPress, (KeyPress&255) ? KeyPress&255 : ' ', gos_DescribeKey(KeyPress) ));

	for( int t0=0; t0<256; t0++ )
	{
		gosEnum_KeyStatus temp=gos_GetKeyStatus((gosEnum_KeyIndex)t0);

		if( temp )
		{
			if( temp==KEY_PRESSED )
				SPEW(( "", "Pressed Key = 0x%x",t0 ));
			if( temp==KEY_HELD )
				SPEW(( "", "Held Key = 0x%x",t0 ));
			if( temp==KEY_RELEASED )
				SPEW(( "", "Release Key = 0x%x",t0 ));
		}
	}

	KeyPress&=255;

//
// Test setting the screen mode
//
	if( KeyPress=='5' )
	{
		gos_SetScreenMode( 640,480,16,0,0,0,0,1 );
	}
	if( KeyPress=='6' )
	{
		gos_SetScreenMode( 800,600,32,0,0,0,0,1 );
	}

//
// Test modal game loop (7 should freeze the game until 8 is pressed)
//
	if( KeyPress=='7' )
	{
		DWORD temp=0;
		while( temp!='8' )
		{
			if( gos_RunMainLoop() )
				break;
			temp=gos_GetKey()&255;
		}
	}


	if( KeyPress=='1' )
	{
		gos_RecreateTextureHeaps();
		Test++;
		if( Test==24 )
			Test=0;
	}
	if( KeyPress=='`' )
	{
		gos_RecreateTextureHeaps();
		Test--;
		if( Test==-1 )
			Test=23;
	}

	if( Test==11 )
	{
		if( KeyPress=='S' || KeyPress=='s' )
		{
			if( Environment.Stencil )
				gos_SetScreenMode( Environment.screenWidth, Environment.screenHeight, Environment.bitDepth, Environment.fullScreen ? Environment.FullScreenDevice : 0, 0, 0, 0, 0, 0, 0, 0 );
			else
				gos_SetScreenMode( Environment.screenWidth, Environment.screenHeight, Environment.bitDepth, Environment.fullScreen ? Environment.FullScreenDevice : 0, 0, 0, 0, 0, 0, 0, 1 );
		}
	}
	else
	{
		if( Environment.Stencil )
			gos_SetScreenMode( Environment.screenWidth, Environment.screenHeight, Environment.bitDepth, Environment.fullScreen ? Environment.FullScreenDevice : 0, 0, 0, 0, 0, 0, 0, 0 );
	}

	if( KeyPress=='2' )
	{
		if( Test==21 )
		{
			MaxSwap+=4;
			if( MaxSwap>80 )
				MaxSwap=80;
		}
		else
		{
			if( (Test==18 || Test==17) && NumPot<5 )
				NumPot++;
			Polys+=200;
		}
	}
	if( KeyPress=='3' )
	{
		if( Test==21 )
		{
			MaxSwap-=4;
			if( MaxSwap<4 )
				MaxSwap=4;
		}
		else
		{
			if( (Test==18 || Test==17) && NumPot>1 )
				NumPot--;
			Polys-=200;
			if( Polys<0 )
				Polys=0;
		}
	}
	if( KeyPress=='T' || KeyPress=='t' )
	{
		UseTexture=!UseTexture;
	}
	if( KeyPress=='M' || KeyPress=='m' )
	{
		WhichTexture=!WhichTexture;
	}
	if( KeyPress=='F' || KeyPress=='f' )
	{
		EnableFog=!EnableFog;
	}
	if( KeyPress=='0' )
	{
		TestStackWalk();
	}
	if( KeyPress=='G' || KeyPress=='g' )
	{
		if( Gamma==1.0f )
			Gamma=1.4f;
		else if( Gamma==1.4f )
			Gamma=1.8f;
		else if( Gamma==1.8f )
			Gamma=2.5f;
		else if( Gamma==2.5f )
			Gamma=0.8f;
		else if( Gamma==0.8f )
			Gamma=1.0f;
		gos_SetGammaValue( Gamma );
	}
//
// Now do logic for some of the tests
//
	if( Test==6 )
	{
		for( int t0=0; t0<NumLines; t0+=2 )
		{
			if( Lines[t0][4]!=Lines[t0][5] )
			{
				Lines[t0][5]++;
			}
			else
			{
				Lines[t0][0]=Lines[t0][1];		
				Lines[t0][1]=(640-512)/2+(gos_rand()&511);		
				Lines[t0][2]=Lines[t0][3];		
				Lines[t0][3]=(480-256)/2+(gos_rand()&255);		
				Lines[t0+1][0]=Lines[t0+1][1];		
				Lines[t0+1][1]=(640-512)/2+(gos_rand()&511);		
				Lines[t0+1][2]=Lines[t0+1][3];		
				Lines[t0+1][3]=(480-256)/2+(gos_rand()&255);		
				Lines[t0][5]=0;
			}
		}
	}
//
//
//
	if( Test==23 )
	{
		const int Repeats=5;
		double start;
		TEXTUREPTR Info;

		if( LoadTest )
		{
			start=gos_GetHiResTime();
//			for( t0=0; t0<Repeats; t0++ )
//			{
//				DWORD Dummy=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\SpeedTest.png",gosHint_DontShrink|gosHint_DisableMipmap );
//				gos_LockTexture( Dummy,  0, 1, &Info );
//				gos_UnLockTexture( Dummy );
//				gos_DestroyTexture( Dummy );
//			}
//			LoadPNG=(int)((gos_GetHiResTime()-start)*1000.0f/Repeats);
			LoadPNG=0;

			#if 1
			start=gos_GetHiResTime();
			for( int t0=0; t0<Repeats; t0++ )
			{
				DWORD Dummy=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\SpeedTest.jpg",gosHint_DontShrink|gosHint_DisableMipmap );
				gos_LockTexture( Dummy,  0, 1, &Info );
				gos_UnLockTexture( Dummy );
				gos_DestroyTexture( Dummy );
			}
			LoadJPG=(int)((gos_GetHiResTime()-start)*1000.0f/Repeats);

			start=gos_GetHiResTime();
			for( t0=0; t0<Repeats; t0++ )
			{
				DWORD Dummy=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\SpeedTest.tga",gosHint_DontShrink|gosHint_DisableMipmap );
				gos_LockTexture( Dummy,  0, 1, &Info );
				gos_UnLockTexture( Dummy );
				gos_DestroyTexture( Dummy );
			}
			LoadTGA=(int)((gos_GetHiResTime()-start)*1000.0f/Repeats);

			start=gos_GetHiResTime();
			for( t0=0; t0<Repeats; t0++ )
			{
				DWORD Dummy=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\SpeedTest.bmp",gosHint_DontShrink|gosHint_DisableMipmap );
				gos_LockTexture( Dummy,  0, 1, &Info );
				gos_UnLockTexture( Dummy );
				gos_DestroyTexture( Dummy );
			}
			LoadBMP=(int)((gos_GetHiResTime()-start)*1000.0f/Repeats);
		}
		if( KeyPress=='2' )
			LoadTest=!LoadTest;
		#endif
	}
//
//
//
	if( Test==22 )
	{
		if( bumptex == 0 )
		{
			watertex=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\water.jpg",gosHint_ReloadFromDisk );
			bumptex=gos_NewTextureFromFile(gos_Texture_Bump, "Assets\\Graphics\\waterbump.jpg",gosHint_ReloadFromDisk );
			normtex=gos_NewTextureFromFile(gos_Texture_Normal, "Assets\\Graphics\\waterbump.jpg",gosHint_ReloadFromDisk );
			bumpenvtex=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\waterenv.jpg",gosHint_ReloadFromDisk );

			int i;

			// create a 2D circle (later, vary radius)

			seaX[0] = 0.f;
			seaY[0] = 0.f;
			seaXBump[0] = 0.f;
			seaYBump[0] = 0.f;

			float randRadius = bumpRadius;

			for( i=1; i<numBumpVert; i++ )
			{
				seaX[i] = (float)(randRadius * sin((double)(i-1) * 3.141592653 * 2.0 / (double)(numBumpVert-2)));
				seaY[i] = (float)(randRadius * cos((double)(i-1) * 3.141592653 * 2.0 / (double)(numBumpVert-2)));
				seaXBump[i] = seaX[i] * ( 1.f + (float)(gos_rand()&255) / 4000.f * (float)sin((double)(i-1) * 3.141592653 * 2.0 / (double)(numBumpVert-2)) );
				seaYBump[i] = seaY[i];
				if( i*10 > numBumpVert*8 )
				{
					// time to tend towards bumpRadius so the perimeter matches up
					if( randRadius < bumpRadius )
						randRadius *= ( 1.f + (float)(gos_rand()&255) / 5000.f );
					else
						randRadius *= ( 1.f - (float)(gos_rand()&255) / 5000.f );
				}
				else if( randRadius < bumpRadius * 0.5f )
					randRadius *= ( 1.f + (float)(gos_rand()&255) / 10000.f );
				else if( randRadius > bumpRadius * 1.2f )
					randRadius *= ( 1.f - (float)(gos_rand()&255) / 10000.f );
				else
					randRadius *= ( 1.f + ((float)(gos_rand()&255) - 128.f) / 2000.f );
			}
			for( i=0; i<numBumpTri; i++ )
			{
				bumpIndices[i*3+0] = 0;
				bumpIndices[i*3+1] = (unsigned short)(i+1);
				bumpIndices[i*3+2] = (unsigned short)(i+2);
			}
		}

		// populate 3D vertices from 2d

		static float bumpPhase = 0.f;
		bumpPhase += 0.001f;
		if( bumpPhase > 4.f )
			bumpPhase -= 4.f;
		static float bumpPhase2 = 0.f;
		bumpPhase2 += 0.0002f;
		if( bumpPhase2 > 1.f )
			bumpPhase2 -= 1.f;
		static float bumpPhase3 = 0.f;
		bumpPhase3 += 0.0005f;
		if( bumpPhase3 > 7.f )
			bumpPhase3 -= float(3.141592*2);

		int doBump = 0;
		int doNorm = 0;
		int doPlain = 0;
		if( gos_GetMachineInformation( gos_Info_CanBumpEnvMap ) )
			doBump = 1;
		else if( gos_GetMachineInformation( gos_Info_CanBumpDotMap ) )
			doNorm = 1;
		else
			doPlain = 1;


		for( int i=0; i<numBumpVert; i++ )
		{
			bumpVert[i].x = 300.f + /* seaY[i] * 0.7f + */ seaX[i] * 3.f;
			if( bumpVert[i].x < 0 )
				bumpVert[i].x = 0;
			if( bumpVert[i].x > 639.f )
				bumpVert[i].x = 639.f;
			bumpVert[i].y = 200.f + seaY[i] * 1.3f /* + seaX[i] * 0.f */;
			if( bumpVert[i].y < 0 )
				bumpVert[i].y = 0;
			if( bumpVert[i].y > 479.f )
				bumpVert[i].y = 479.f;
			bumpVert[i].z = 0.f;
			bumpVert[i].rhw = 1.f;
			if(1)
			{
				// bump dot-product mapping
				double intens = (sin( bumpPhase3 + 3.14159/2.0+ (double)i/numBumpVert*3.14159*4.0)+1.0)/2.0;
				intens = intens * intens / 2.0;
				if( i == 0 )
					intens = 0.5;
				bumpVert[i].argb = 0xFF808080 + (((int)(intens*255.f))<<8);
	//			bumpVert[i].argb = 0xFF808080; // 0xffffffff;
	//			bumpVert[i].argb = 0xFF80FF80; // 0xffffffff;
			}
			else
			{
				// bump environment mapping
				bumpVert[i].argb = 0xFFFFFFFF;
			}
			bumpVert[i].u1 = ( seaXBump[i] + bumpRadius ) / bumpRadius / 2.f;	// base texture coords
			bumpVert[i].v1 = ( seaYBump[i] + bumpRadius ) / bumpRadius / 2.f;
			bumpVert[i].u2 = bumpVert[i].u1 + bumpPhase2;	// bump map coords
			bumpVert[i].v2 = bumpVert[i].v1 + bumpPhase2;
			if( i==0 )
			{
				bumpVert[i].u3 = 0.5f;		// env map coords
				bumpVert[i].v3 = 0.5f;
			}
			else
			{
				bumpVert[i].u3 = (float)sin((double)i / (double(numBumpTri)) * 2.0 * 3.14159 + bumpPhase3) / 2.f + 0.5f;
				bumpVert[i].v3 = (float)cos((double)i / (double(numBumpTri)) * 2.0 * 3.14159 + bumpPhase3) / 2.f + 0.5f;
			}
			bumpVert[i].u1 *= 2.f;
			bumpVert[i].v1 *= 2.f;
			bumpVert[i].u1 += bumpPhase / 2.f;
			bumpVert[i].u1 += bumpVert[i].v1;	// twist the base texture
			bumpVert[i].v1 *= 4.f;	// squish the base texture to get 3D depth
		}
		BackGroundColor = 0;
	}


	if( Test==7 )
	{
		if( 0==tex1 )
		{
			tex1=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t1.tga",gosHint_ReloadFromDisk );
			tex2=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t2.tga",gosHint_ReloadFromDisk );
			tex3=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t3.tga",gosHint_ReloadFromDisk );
			tex4=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t4.tga",gosHint_ReloadFromDisk );
			tex5=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t5.tga",gosHint_ReloadFromDisk );
			tex6=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t6.tga",gosHint_ReloadFromDisk );
			tex7=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t7.tga",gosHint_ReloadFromDisk );
			tex8=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t8.tga",gosHint_ReloadFromDisk );
			tex9=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t9.tga",gosHint_ReloadFromDisk );
			tex10=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t10.tga",gosHint_ReloadFromDisk );
			tex11=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t11.tga",gosHint_ReloadFromDisk );
			tex12=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t12.tga",gosHint_ReloadFromDisk );
			tex13=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t13.tga",gosHint_ReloadFromDisk );
			tex14=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t14.tga",gosHint_ReloadFromDisk );
			tex15=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t15.tga",gosHint_ReloadFromDisk );
			tex16=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t16.tga",gosHint_ReloadFromDisk );
			tex17=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t17.tga",gosHint_ReloadFromDisk );
		}
	}
	if( Test==20 )
	{
		if( 0==rtex1 )
		{
			rtex1=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t1.tga",gosHint_ReloadFromDisk );
			rtex2=gos_NewEmptyTexture(gos_Texture_Solid, "EmptyRebuild2", 32, 0, MyRebuildFunction, (void *)2 );
			MyRebuildFunction( rtex2, (void *)2 );
			rtex3=gos_NewEmptyTexture(gos_Texture_Solid, "EmptyRebuild3", 32, 0, MyRebuildFunction, (void *)3 );
			MyRebuildFunction( rtex3, (void *)3 );
			rtex4=gos_NewEmptyTexture(gos_Texture_Solid, "EmptyRebuild4", 32, 0, MyRebuildFunction, (void *)4 );
			MyRebuildFunction( rtex4, (void *)4 );
			rtex5=gos_NewEmptyTexture(gos_Texture_Solid, "EmptyRebuild5", 32, 0, MyRebuildFunction, (void *)5 );
			MyRebuildFunction( rtex5, (void *)5 );
			rtex6=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t6.tga",gosHint_ReloadFromDisk );
			rtex7=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t7.tga",gosHint_ReloadFromDisk );
			rtex8=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t8.tga",gosHint_ReloadFromDisk );

			rtex9=gos_NewTextureFromFile(gos_Texture_Detect, "ROM_Assets\\Graphics\\t9.tga",gosHint_ReloadFromDisk|gosHint_ROMFile );
			rtex10=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t10.tga",gosHint_ReloadFromDisk );
			rtex11=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t11.tga",gosHint_ReloadFromDisk );
			rtex12=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t12.tga",gosHint_ReloadFromDisk );
			rtex13=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t13.tga",gosHint_ReloadFromDisk );
			rtex14=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t14.tga",gosHint_ReloadFromDisk );
			rtex15=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t15.tga",gosHint_ReloadFromDisk );
			rtex16=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t16.tga",gosHint_ReloadFromDisk );
			rtex17=gos_NewTextureFromFile(gos_Texture_Detect, "Assets\\Graphics\\t17.tga",gosHint_ReloadFromDisk );
		}
	}
//
// To test texture animation, enable this
//
	#if 1
	TEXTUREPTR Info;
	
	if( Test==2 && WhichTexture )
	{
		CycleData1=GetCycles();

		gos_LockTexture( TestMipMap,  128, 0, &Info );

		for( int ra=0; ra<200; ra++ )
		{
			DWORD xp=gos_rand()&(Info.Width-1);
			DWORD yp=gos_rand()&(Info.Height-1);

			DWORD* Pixel=Info.pTexture+xp+yp*Info.Pitch;

			*Pixel=*Pixel+0x404040;
		}

		gos_UnLockTexture( TestMipMap );
//
// Test code for processor cycle timings.
//
		for( int t0=0; t0<1000; t0++ )
		{
			StartCycleTiming( &CycleData );
				TestData=(float)Seed/2.23345f+gos_rand();
				_asm
				{	
					mov eax,TestData
					test eax,1
					jz fred
					mov eax,3
					fred:
					mov ebx,TestData+1
					nop
				}
			
			EndCycleTiming( &CycleData );
		}

		CycleData1=GetCycles()-CycleData1;

	}
	#endif
//
// Make sure all random numbers on UpdateRenders are the same
//
	Seed=gos_rand();
}

char* __stdcall GetGameInformation()
{
	static char Buffer[128];
	sprintf( Buffer, "Test number = %d", Test );
	return Buffer;
}


//
// Test for hooking gos_GetFile
//
void __stdcall GetFileHook( const char* FileName, BYTE** MemoryImage, DWORD* Size )
{
	SPEW(( 0, "Reading file %s",FileName ));
	if( ( FileName[0] == 'R') &&
		( FileName[1] == 'O') &&
		( FileName[2] == 'M') &&
		( FileName[3] == '_') )
	{
		// simulate a ROMed file, - read it into memory here, copy to malloc'ed mem
		// and free the original
		// TBD: must free the malloced memory on program exit

		if( pROMImage )
		{
			// STOP(("This test currently can't support multiple ROMed files!"));
			*MemoryImage = pROMImage;
			*Size = ROMImageSize;
			return;
		}
		gos_GetFile( FileName+4, MemoryImage, Size );
		pROMImage = (BYTE *)malloc(*Size);
		ROMImageSize = *Size;
		memcpy( pROMImage, *MemoryImage, *Size );
		gos_Free( *MemoryImage );
		*MemoryImage = pROMImage;
		return;
	}
	gos_GetFile( FileName, MemoryImage, Size );
}



//
// Setup the GameOS structure
//
void __stdcall GetGameOSEnvironment( char* CommandLine )
{
	CommandLine=CommandLine;
	Environment.applicationName			= "Test3D";
	Environment.screenWidth				= 640;
	Environment.screenHeight			= 480;
	Environment.fullScreen				= 0;
	Environment.bitDepth				= 16;

	Environment.RenderToVram			= 0;			// When 1 blade renders directly to video memory (big speed increase unless using alpha)

	Environment.debugLog				= "";			//"DebugLog.txt";
	Environment.spew					= "";			//"GameOS_Texture GameOS_DirectDraw GameOS_Direct3D";
	Environment.memoryTraceLevel		= 5;

	Environment.MinimumTextureMemory	= 5*1024;

	Environment.UpdateRenderers			= UpdateRenderers;
	Environment.InitializeGameEngine	= InitializeGameEngine;
	Environment.TerminateGameEngine		= TerminateGameEngine;
	Environment.DoGameLogic				= DoGameLogic;
	Environment.GetGameInformation		= GetGameInformation;

	#ifdef TEST_DIRTYRECT
	Environment.DirtyRectangle			= 1;				// Bit 0=Enabled, Bit 1=Save Z buffer rectangles too, Bit 2=Save directly in system memory (don't try video memory).
	#endif

	Environment.FullScreenDevice		= 0;
	Environment.Renderer				= 0;
//
// Texture heap infomation
//
	Environment.Texture_S_256			= 0;
	Environment.Texture_S_128			= 0;
	Environment.Texture_S_64			= 0;
	Environment.Texture_S_32			= 0;
	Environment.Texture_S_16			= 0;

	Environment.Texture_K_256			= 0;
	Environment.Texture_K_128			= 0;
	Environment.Texture_K_64			= 0;
	Environment.Texture_K_32			= 0;
	Environment.Texture_K_16			= 0;

	Environment.Texture_A_256			= 0;
	Environment.Texture_A_128			= 0;
	Environment.Texture_A_64			= 0;
	Environment.Texture_A_32			= 0;
	Environment.Texture_A_16			= 0;
//
// Test for hooking gos_GetFile
//
	Environment.HookGetFile=GetFileHook;

//
// Raid Settings
//
	Environment.RaidCustomFields		= "AssignedTo=andyg;Project=GameOS;Client=GameOS;Area=3D Hardware Rasterizer;GOSRaid=Yes"; 
	Environment.RaidDataSource			= "GameTech :Raid4";
	Environment.RaidFilePath			= "\\\\aas1\\coretech\\Test\\Raid\\Exceptions";
}

