/*
	File	:	drawprimitive.cpp
	Author	:	Richard Flower (c) 1998 Core Design
	----------------------------------------------------------------------------------
	Functions
	----------------------------------------------------------------------------------
	InitDrawPrimitive	-	Initialise Drawprimitive
	HWDrawPrimitive		-	Hardware Drawprimitive pass through to DirectX
	SWDrawPrimitive		-	Software Drawprimitive pass to emulator
	EmulateDrawPrimitve -	Emulates Drawprimitive in Software
	----------------------------------------------------------------------------------
*/


#include "standard.h"
#include "global.h"
#include "winmain.h"
#include "drawprimitive.h"
#include "texture.h"
#include "../game/text.h"
#include "input.h"
#include "template.h"
#include "picture.h"
#include "../3dsystem/3d_gen.h"
#include "scanlines.h"



#ifdef GAMEDEBUG
	int DrawPrimitiveCnt;
	int PolysDrawn;
	int TextureLockCnt;
	int affinepolys;
	int perspolys;
#endif


// Global Ptrs

HRESULT (*DrawPrimitive)(D3DPRIMITIVETYPE dptPrimitiveType,D3DVERTEXTYPE dvtVertexType,        
		  				 LPVOID lpvVertices,DWORD dwVertexCount,DWORD dwFlags);
HRESULT (*BeginScene)();
HRESULT (*EndScene)();
HRESULT (*SetRenderState)(D3DRENDERSTATETYPE dwRenderStateType,DWORD dwRenderState);

void (*DrawScanLines)(GRADIENT* Gradients,EDGE* pLeft,EDGE* pRight,EDGE* StepLeft,EDGE* StepRight);
void (*CalcGradientsPersp)(GRADIENT* Gradients,D3DTLVERTEX* v1,D3DTLVERTEX* v2,D3DTLVERTEX* v3);
void (*CalcEdgePersp)(EDGE* Edge,GRADIENT* Gradients,D3DTLVERTEX* Top,D3DTLVERTEX* Bottom,int nTop,int nBottom);

void (*DrawScanLinesAffine)(GRADIENT* Gradients,EDGE* pLeft,EDGE* pRight,EDGE* StepLeft,EDGE* StepRight);
void (*CalcGradientsAffine)(GRADIENT* Gradients,D3DTLVERTEX* v1,D3DTLVERTEX* v2,D3DTLVERTEX* v3);
void (*CalcEdgeAffine)(EDGE* Edge,GRADIENT* Gradients,D3DTLVERTEX* Top,D3DTLVERTEX* Bottom,int nTop,int nBottom);

void (*DrawScanLinesBlack)(GRADIENT* Gradients,EDGE* pLeft,EDGE* pRight,EDGE* StepLeft,EDGE* StepRight);
void (*CalcGradientsBlack)(GRADIENT* Gradients,D3DTLVERTEX* v1,D3DTLVERTEX* v2,D3DTLVERTEX* v3);
void (*CalcEdgeBlack)(EDGE* Edge,GRADIENT* Gradients,D3DTLVERTEX* Top,D3DTLVERTEX* Bottom,int nTop,int nBottom);

void (*DrawScanLinesFlat)(GRADIENT* Gradients,EDGE* pLeft,EDGE* pRight,EDGE* StepLeft,EDGE* StepRight);
void (*CalcGradientsFlat)(GRADIENT* Gradients,D3DTLVERTEX* v1,D3DTLVERTEX* v2,D3DTLVERTEX* v3);
void (*CalcEdgeFlat)(EDGE* Edge,GRADIENT* Gradients,D3DTLVERTEX* Top,D3DTLVERTEX* Bottom,int nTop,int nBottom);

void (*DrawScanLinesFlatAffine)(GRADIENT* Gradients,EDGE* pLeft,EDGE* pRight,EDGE* StepLeft,EDGE* StepRight);
void (*CalcGradientsFlatAffine)(GRADIENT* Gradients,D3DTLVERTEX* v1,D3DTLVERTEX* v2,D3DTLVERTEX* v3);
void (*CalcEdgeFlatAffine)(EDGE* Edge,GRADIENT* Gradients,D3DTLVERTEX* Top,D3DTLVERTEX* Bottom,int nTop,int nBottom);


void NullCalculateGradient(GRADIENT* Gradients,D3DTLVERTEX* v1,D3DTLVERTEX* v2,D3DTLVERTEX* v3){};
void NullCalculateEdge(EDGE* Edge,GRADIENT* Gradients,D3DTLVERTEX* Top,D3DTLVERTEX* Bottom,int nTop,int nBottom){};
void NullScanLines(GRADIENT* Gradients,EDGE* pLeft,EDGE* pRight,EDGE* StepLeft,EDGE* StepRight){};



static LPDIRECTDRAWSURFACE3	lpSurface;
static LPDIRECT3DDEVICE2	lpD3DDevice;
static LPDIRECTDRAWSURFACE3 lpTexture;

static long  tpitch;
static unsigned long  TextureHandle;
unsigned short* Output;
unsigned short* Texture;
long  pitch;
long  bytepitch;
long* YTable;
float* WidthTable;
long*  WidthTablef;

unsigned short* RGBTable;


int bForceAffineMap;

#define GETR(rgb) ((rgb>>16)&0xff)
#define GETG(rgb) ((rgb>>8)&0xff)
#define GETB(rgb) ((rgb)&0xff)
#define GETA(rgb) ((rgb>>24)&0xff)




/*
	Function	:	InitDrawPrimitive
	Useage		:	Initialise DP ptrs, etc
*/

void InitDrawPrimitive(LPDIRECT3DDEVICE2 lpD3D,LPDIRECTDRAWSURFACE3 lpSurf,bool HW)
{
	lpD3DDevice = lpD3D;
	lpTexture = NULL;
	TextureHandle = 0;

	if(HW)
	{
		DrawPrimitive    = HWDrawPrimitive;
		BeginScene       = HWBeginScene;
		EndScene         = HWEndScene;
		SetRenderState   = HWSetRenderState;
	}
	else
	{
		lpSurface = lpSurf;
		DrawPrimitive  = SWDrawPrimitive;
		BeginScene     = SWBeginScene;
		EndScene       = SWEndScene;
		SetRenderState = SWSetRenderState;
	
		DrawScanLines       = ScanLinesTG;
		CalcGradientsPersp  = CalculateGradientsTG;
		CalcEdgePersp       = CalculateEdgeTG;

		DrawScanLinesAffine = ScanLinesTGAffine;
		CalcGradientsAffine = CalculateGradientsTGA;
		CalcEdgeAffine      = CalculateEdgeTGA;

		DrawScanLinesBlack  = ScanLinesBlack;
		CalcGradientsBlack  = NullCalculateGradient;
		CalcEdgeBlack       = CalculateEdgeBlack;

		DrawScanLinesFlat   = ScanLinesTF;
		CalcGradientsFlat   = CalculateGradientsTF;
		CalcEdgeFlat        = CalculateEdgeT;
		
		DrawScanLinesFlatAffine = ScanLinesTFAffine;
		CalcGradientsFlatAffine = CalculateGradientsTFA;
		CalcEdgeFlatAffine      = CalculateEdgeTA;

		// ** ToDo : Free Tables
	
		BuildXYTables();	
		BuildRGBTable();
			
		bForceAffineMap = 0;
	}
}

// EOF : InitDrawPrimitive




/*
	Function	:	BuildXYTables
	Useage		:	Build XY Tables For Current Pitch & Screen Resolution
*/

void BuildXYTables()
{
	unsigned int n;
	DDSURFACEDESC ddsd;
	double fconv;

	// Lock Surface To Get Pitch
	DXInit(ddsd);
	lpSurface->Lock(NULL,&ddsd,DDLOCK_NOSYSLOCK,NULL);	
	lpSurface->Unlock(NULL);

	// Malloc YTable Based On Surface Height
	YTable = (long*) malloc((ddsd.dwHeight+1)*sizeof(long));
	
	// Build Table
	for(n=0;n<(ddsd.dwHeight+1);n++)
		YTable[n] = n*ddsd.lPitch;


	// Malloc YTable Based On Surface Height
	WidthTable = (float*) malloc((ddsd.dwWidth+1)*sizeof(float));

	// Build Table
	WidthTable[0] = 0.0f;
	for(n=1;n<(ddsd.dwWidth+1);n++)
		WidthTable[n] = 1.0f/float(n);

	WidthTablef = (long*) malloc((ddsd.dwWidth+1)*sizeof(long));

	// Build Table
	WidthTablef[0] = 0;
	for(n=1;n<(ddsd.dwWidth+1);n++)
		WidthTablef[n] = FTOLFIX((1.0f/float(n)));

}

// EOF : BuildXYTables



/*
	Function	:	BuildRGBTable
	Useage		:	Build Gouraud/Texture Lookup
*/

void BuildRGBTable()
{
	unsigned int i,j;
	RGBTable = (unsigned short*) malloc(sizeof(short)*32*32);

	for(j=0;j<32;j++)
	{
		for(i=0;i<32;i++)
			RGBTable[i+(j*32)] = (unsigned short) ((i*j)>>5);
	}
}

// EOF : BuildRGBTable





HRESULT HWBeginScene()
{
#ifdef GAMEDEBUG
	DrawPrimitiveCnt = 0;
	PolysDrawn = 0;
#endif
	WinFrameRate();
	
	return lpD3DDevice->BeginScene();
}


HRESULT HWEndScene()
{
	return lpD3DDevice->EndScene();
}




HRESULT SWBeginScene()
{
#ifdef GAMEDEBUG
	DrawPrimitiveCnt = 0;
	PolysDrawn = 0;
	affinepolys = 0;
	perspolys = 0;
#endif

	WinFrameRate();

	DDSURFACEDESC ddsd;
	DXInit(ddsd);
	lpSurface->Lock(NULL,&ddsd,DDLOCK_NOSYSLOCK|DDLOCK_WAIT,NULL);	
	Output = (unsigned short*) ddsd.lpSurface;
	pitch = ddsd.lPitch>>1;		
	bytepitch = ddsd.lPitch;
	return D3D_OK;
}


HRESULT SWEndScene()
{
	lpSurface->Unlock(NULL);
#ifdef GAMEDEBUG
//	WinDisplayString(0,0,"fps %.2f",App.fps);
//	WinDisplayString(0,1,"DP Calls %d",DrawPrimitiveCnt);
//	WinDisplayString(0,2,"BF List %d",surfacenumbf);
//	WinDisplayString(0,1,"Polys %d",PolysDrawn);
//	WinDisplayString(0,4,"Room Verts %d",RoomVerts);
//	WinDisplayString(0,5,"Obj Verts %d",ObjVerts);
//	WinDisplayString(0,6,"Span Pixels %d",SpanPixels);
//	WinDisplayString(0,7,"TG Spans %d",TGSpans);
	TextureLockCnt = 0;
#endif
	return D3D_OK;
}



HRESULT HWSetRenderState(D3DRENDERSTATETYPE dwRenderStateType,DWORD dwRenderState)
{
	return lpD3DDevice->SetRenderState(dwRenderStateType,dwRenderState);
}


HRESULT SWSetRenderState(D3DRENDERSTATETYPE dwRenderStateType,DWORD dwRenderState)
{
	switch(dwRenderStateType)
	{
		case D3DRENDERSTATE_COLORKEYENABLE:
			if(TextureHandle != NULL)
			{
				if(dwRenderState)
				{
					// Textured Gouraud Decal
					
					DrawScanLines      = ScanLinesTGDecal;			
					CalcGradientsPersp = CalculateGradientsTG;
					CalcEdgePersp      = CalculateEdgeTG;

					DrawScanLinesAffine = ScanLinesTGDecalAffine;
					CalcGradientsAffine = CalculateGradientsTGA;
					CalcEdgeAffine      = CalculateEdgeTGA;

					DrawScanLinesBlack  = ScanLinesTGDecalAffine;
					CalcGradientsBlack  = CalculateGradientsTGA;
					CalcEdgeBlack       = CalculateEdgeTGA;
					
					DrawScanLinesFlatAffine = ScanLinesTFDecalAffine;
					CalcGradientsFlatAffine = CalculateGradientsTFA;
					CalcEdgeFlatAffine      = CalculateEdgeTA;
				
					DrawScanLinesFlat   = ScanLinesTFDecal;
					CalcGradientsFlat   = CalculateGradientsTF;
					CalcEdgeFlat        = CalculateEdgeT;
				
				}
				else
				{
					// Textured Gouraud
					
					DrawScanLines      = ScanLinesTG;
					CalcGradientsPersp = CalculateGradientsTG;
					CalcEdgePersp      = CalculateEdgeTG;

					DrawScanLinesAffine = ScanLinesTGAffine;
					CalcGradientsAffine = CalculateGradientsTGA;
					CalcEdgeAffine		= CalculateEdgeTGA;
					
					DrawScanLinesBlack  = ScanLinesBlack;
					CalcGradientsBlack  = NullCalculateGradient;
					CalcEdgeBlack       = CalculateEdgeBlack;

					DrawScanLinesFlat   = ScanLinesTF;
					CalcGradientsFlat   = CalculateGradientsTF;
					CalcEdgeFlat        = CalculateEdgeT;
					
					DrawScanLinesFlatAffine = ScanLinesTFAffine;
					CalcGradientsFlatAffine = CalculateGradientsTFA;
					CalcEdgeFlatAffine      = CalculateEdgeTA;
					
				}
			}

			return D3D_OK;	
	
		case D3DRENDERSTATE_ALPHABLENDENABLE:
			if(TextureHandle != NULL)
			{
				if(dwRenderState)
				{
					// Textured Goruaud Alpha
					
					DrawScanLines       = ScanLinesTDecal;
					CalcGradientsPersp  = CalculateGradientsT;
					CalcEdgePersp       = CalculateEdgeT;
					
					DrawScanLinesAffine = ScanLinesTGAlphaDecalAffine;
					CalcGradientsAffine = CalculateGradientsTGA;
					CalcEdgeAffine      = CalculateEdgeTGA;

					DrawScanLinesBlack  = NullScanLines;
					CalcGradientsBlack  = NullCalculateGradient;
					CalcEdgeBlack       = NullCalculateEdge;
					
					DrawScanLinesFlatAffine = ScanLinesTFAlphaDecalAffine;
					CalcGradientsFlatAffine = CalculateGradientsTFA;
					CalcEdgeFlatAffine      = CalculateEdgeTA;
				
					bForceAffineMap = 1;

				}
				else
				{
					// Textured Gouraud

					bForceAffineMap = 0;

					DrawScanLines       = ScanLinesTG;
					CalcGradientsPersp  = CalculateGradientsTG;
					CalcEdgePersp       = CalculateEdgeTG;
					
					DrawScanLinesAffine = ScanLinesTGAffine;
					CalcGradientsAffine = CalculateGradientsTGA;
					CalcEdgeAffine      = CalculateEdgeTGA;

					DrawScanLinesBlack  = ScanLinesBlack;
					CalcGradientsBlack  = NullCalculateGradient;
					CalcEdgeBlack       = CalculateEdgeBlack;
				
					DrawScanLinesFlat   = ScanLinesTF;
					CalcGradientsFlat   = CalculateGradientsTF;
					CalcEdgeFlat        = CalculateEdgeT;
					
					DrawScanLinesFlatAffine = ScanLinesTFAffine;
					CalcGradientsFlatAffine = CalculateGradientsTFA;
					CalcEdgeFlatAffine      = CalculateEdgeTA;
				}

			}
			return D3D_OK;


		case D3DRENDERSTATE_TEXTUREHANDLE:
		{
			// Set Renderer To Gouraud If Null

			if(dwRenderState == NULL)
				DrawScanLines = NULL;		// Gouraud Only
			
			// Same Texture Just Return
	
			if(dwRenderState == TextureHandle) return D3D_OK;
	
			// Unlock the current texture	
	
			if(lpTexture  != NULL)
			{
			//	lpTexture->Unlock(NULL);
				lpTexture = NULL;
			}
			
			// Don't Search For NULL Texture Handle
		
			if(dwRenderState != 0)
			{
				// Search for texture handle

				for(int n=0;n<MAX_D3D_TEXTURES;n++)
				{
					if(DXTextureList[n].hTexture == dwRenderState)
						break;
				}

				// Get System Texture Surface	

				if(DXTextureList[n].pDeviceSurface != NULL)
				{
				//	lpTexture = DXTextureList[n].pSystemSurface;
				
					Texture = DXTextureList[n].pSoftwareSurface;
				
				}
				else
				{

					for(int n=0;n<MAX_D3D_TEXTURES;n++)
					{
						if(PicTextureList[n].hTexture == dwRenderState)
							break;
					}

				//	lpTexture = PicTextureList[n].pSystemSurface;

					Texture = PicTextureList[n].pSoftwareSurface;
					
				}


			//	DDSURFACEDESC ddsd;
			//	DXInit(ddsd);
			//	lpTexture->Lock(NULL,&ddsd,DDLOCK_NOSYSLOCK|DDLOCK_READONLY|DDLOCK_WAIT,NULL);	
		
			//	Texture = (unsigned short*) ddsd.lpSurface;

#ifdef GAMEDEBUG
				TextureLockCnt++;
#endif
//				tpitch = ddsd.lPitch;		
			
				tpitch = 512;
			
			}

			TextureHandle = dwRenderState;

			return D3D_OK;
		}
		break;

	}

	return D3D_OK;
}




/*
	Function	:	HWDrawPrimitive
	Useage		:	Pass Through to DirectX
*/

extern int bDraw;

HRESULT HWDrawPrimitive(D3DPRIMITIVETYPE dptPrimitiveType,D3DVERTEXTYPE dvtVertexType,        
						LPVOID lpvVertices,DWORD dwVertexCount,DWORD dwFlags)
{
#ifdef GAMEDEBUG
	DrawPrimitiveCnt++;
	switch(dptPrimitiveType)
	{
		case D3DPT_TRIANGLELIST:
			PolysDrawn += dwVertexCount/3;
			break;
		case D3DPT_TRIANGLEFAN:
			PolysDrawn += 1+(dwVertexCount-3);
			break;
	}

	if(!bDraw) return D3D_OK;

#endif

	return lpD3DDevice->DrawPrimitive(dptPrimitiveType,dvtVertexType,lpvVertices,dwVertexCount,dwFlags);	
}

// EOF : HWDrawPrimitive



/*
	Function	:	SWDrawPrimitive
	Useage		:	Pass Through To DrawPrimitive emulator
*/

HRESULT SWDrawPrimitive(D3DPRIMITIVETYPE dptPrimitiveType,D3DVERTEXTYPE dvtVertexType,        
					    LPVOID lpvVertices,DWORD dwVertexCount,DWORD dwFlags)
{

#ifdef GAMEDEBUG
	DrawPrimitiveCnt++;

//	if(!bDraw) return D3D_OK;

#endif

	return EmulateDrawPrimitive(dptPrimitiveType,dvtVertexType,lpvVertices,dwVertexCount,dwFlags);	
}

// EOF : SWDrawPrimitive

void PrepareTriangleList(LPD3DTLVERTEX v,DWORD vcnt)
{
	DWORD n;
	double fconv;
	
	for(n=0;n<vcnt;n++,v++)
	{
		// Reduce Fractional Part Of Verts
		v->sx = FIX284TOFLOAT(FTOLFIX284(v->sx));
		v->sy = FIX284TOFLOAT(FTOLFIX284(v->sy));
			
		// Remove Alpha
		v->color = v->color&0xffffff;
	}
}

// EOF : PrepareTriangleList



/*
	Function	:	EmulateDrawPrimitive
	Useage		:	Emulates Direct3D DrawPrimitive Call in Software
*/

HRESULT EmulateDrawPrimitive(D3DPRIMITIVETYPE dptPrimitiveType,D3DVERTEXTYPE dvtVertexType,        
				 LPVOID lpvVertices,DWORD dwVertexCount,DWORD dwFlags)
{
	DDSURFACEDESC ddsd;
	DXInit(ddsd);
		
	PrepareTriangleList((LPD3DTLVERTEX)lpvVertices,dwVertexCount);

	switch(dptPrimitiveType)
	{
		case D3DPT_TRIANGLELIST:
			DrawTriangleList((LPD3DTLVERTEX) lpvVertices,dwVertexCount);
			break;
				
		case D3DPT_TRIANGLEFAN:	
			DrawTriangleFan((LPD3DTLVERTEX) lpvVertices,dwVertexCount);
			break;
			
		case D3DPT_TRIANGLESTRIP:
			DrawTriangleStrip((LPD3DTLVERTEX) lpvVertices,dwVertexCount);
			break;
	}

	return 0;

}

// EOF : EmulateDrawPrimitive



/*
	Function	:	DrawTriangleList
	Useage		:	Outputs D3DTLVERTEX Triangle List
*/


void DrawTriangleList(LPD3DTLVERTEX v,DWORD vcnt)
{
	int n;
	D3DTLVERTEX *v1,*v2,*v3;
	
	for(n=vcnt;n>0;n-=3)
	{
	
		v1 = v;
		v++;
		v2 = v;
		v++;
		v3 = v;
		v++;

		DrawTriangle(v1,v2,v3);
	}
}

// EOF : DrawTriangleList


/*
	Function	:	DrawTriangleList
	Useage		:	Outputs D3DTLVERTEX Triangle List
*/


void DrawTriangleFan(LPD3DTLVERTEX v,DWORD vcnt)
{
	int n;
	D3DTLVERTEX *v1,*v2,*v3;

	v1 = v;
	v++;
	v2 = v;
	v++;
	v3 = v;
	v++;

	DrawTriangle(v1,v2,v3);

	vcnt -= 3;

	for(n=vcnt;n>0;n--)
	{
		v2 = v3;
		v3 = v;
		v++;
		DrawTriangle(v1,v2,v3);
	}
}

// EOF : DrawTriangleFan




/*
	Function	:	DrawTriangleStrip
	Useage		:	Outputs D3DTLVERTEX Triangle Strip
*/


void DrawTriangleStrip(LPD3DTLVERTEX v,DWORD vcnt)
{
	int n;
	D3DTLVERTEX *v1,*v2,*v3;

	v1 = v;
	v++;
	v2 = v;
	v++;
	v3 = v;
	v++;

	DrawTriangle(v1,v2,v3);

	vcnt -= 3;

	for(n=vcnt;n>0;n--)
	{
		v1 = v2;
		v2 = v;
		v3 = v3;
		v++;
		DrawTriangle(v1,v2,v3);
	}
}

// EOF : DrawTriangleStrip




inline void FloorDivMod(long Numerator,long Denominator, long &Floor,long &Modulus)
{
		_asm
		{
			mov	ecx,dword ptr [Floor]
			mov	ebx,dword ptr [Modulus]
			mov edx,dword ptr [Numerator]
			xor eax,eax
			cmp edx,0
			jl Minus
			je Zero
			mov eax,edx
			cdq				
			idiv dword ptr [Denominator]
Zero:
			mov dword ptr [ecx],eax
			mov dword ptr [ebx],edx
			jmp End
Minus:			
			sub eax,edx
			cdq
			idiv dword ptr [Denominator]
			cmp edx,0
			je Store
			
			inc eax
			mov dword ptr [ecx],0
			sub	dword ptr [ecx],eax
			mov eax,dword ptr [Denominator]
			mov dword ptr [ebx],eax
			sub dword ptr [ebx],edx
			jmp End
Store:
			mov dword ptr [ecx],0
			sub	dword ptr [ecx],eax
			mov dword ptr [ebx],edx 
End:		
		}
}



inline long ceilint(float v)
{
	long val;
	long frac;
	double fconv;
	val = FTOLFIX(v);
	if(val > 0)
	{
		frac = val&0xffff;
		if(!frac)	
			return val>>16;
		else
			return (val>>16)+1;
	}
	else
		return val>>16;
}



inline float ceilfloat(float v)
{
	long val;
	long frac;
	double fconv;
	
	val = FTOLFIX(v);
	if(val > 0)
	{
		frac = val&0xffff;
		if(!frac)	
			return float(val>>16);
		else
			return float((val>>16)+1);
	}
	else
		return float(val>>16);
}



inline long ceil1616(long val)
{
	long frac;
	if(val > 0)
	{
		frac = val&0xffff;
		if(!frac)	
			return (val>>16)<<16;
		else
			return ((val>>16)+1)<<16;
	}
	else
		return (val>>16)<<16;
}



void CalculateGradientsTG(GRADIENT* Gradients,D3DTLVERTEX* v1,D3DTLVERTEX* v2,D3DTLVERTEX* v3)
{
	float oodx,oody;
	float v1v3y,v2v3y,v1v3x,v2v3x;
	float u2u3,u1u3;
	float v2v3,v1v3;
	float z2z3,z1z3;
	float c2c3,c1c3;
	
	v1v3y = v1->sy - v3->sy;
	v2v3y = v2->sy - v3->sy;
	v1v3x = v1->sx - v3->sx;
	v2v3x = v2->sx - v3->sx;
	
	oodx = 1.0f/((v2v3x*v1v3y)-(v1v3x*v2v3y));
	oody = -oodx;
		
	Gradients->r[0] = (float) GETR(v1->color);
	Gradients->g[0] = (float) GETG(v1->color);
	Gradients->b[0] = (float) GETB(v1->color);

	Gradients->r[1] = (float) GETR(v2->color);
	Gradients->g[1] = (float) GETG(v2->color);
	Gradients->b[1] = (float) GETB(v2->color);

	Gradients->r[2] = (float) GETR(v3->color);
	Gradients->g[2] = (float) GETG(v3->color);
	Gradients->b[2] = (float) GETB(v3->color);

	Gradients->uoz[0] = v1->tu * v1->rhw * 256.0f;
	Gradients->voz[0] = v1->tv * v1->rhw * 256.0f;
	
	Gradients->uoz[1] = v2->tu * v2->rhw * 256.0f;
	Gradients->voz[1] = v2->tv * v2->rhw * 256.0f;

	Gradients->uoz[2] = v3->tu * v3->rhw * 256.0f;
	Gradients->voz[2] = v3->tv * v3->rhw * 256.0f;

	u2u3  = Gradients->uoz[1] - Gradients->uoz[2];
	u1u3  = Gradients->uoz[0] - Gradients->uoz[2];

	v2v3  = Gradients->voz[1] - Gradients->voz[2];
	v1v3  = Gradients->voz[0] - Gradients->voz[2];

	Gradients->duzx = oodx * (((u2u3) * (v1v3y)) - ((u1u3) * (v2v3y)));
	Gradients->duzy = oody * (((u2u3) * (v1v3x)) - ((u1u3) * (v2v3x)));

	Gradients->dvzx = oodx * (((v2v3) * (v1v3y)) - ((v1v3) * (v2v3y)));
	Gradients->dvzy = oody * (((v2v3) * (v1v3x)) - ((v1v3) * (v2v3x)));

	z1z3 = v1->rhw-v3->rhw;
	z2z3 = v2->rhw-v3->rhw;

	Gradients->dozx = oodx * (((z2z3) * (v1v3y)) - ((z1z3) * (v2v3y)));
	Gradients->dozy = oody * (((z2z3) * (v1v3x)) - ((z1z3) * (v2v3x)));

	c2c3 = Gradients->r[1] - Gradients->r[2];
	c1c3 = Gradients->r[0] - Gradients->r[2];
	
	Gradients->drx = oodx * (((c2c3) * (v1v3y)) - ((c1c3) * (v2v3y)));
	Gradients->dry = oody * (((c2c3) * (v1v3x)) - ((c1c3) * (v2v3x)));

	c2c3 = Gradients->g[1] - Gradients->g[2];
	c1c3 = Gradients->g[0] - Gradients->g[2];

	Gradients->dgx = oodx * (((c2c3) * (v1v3y)) - ((c1c3) * (v2v3y)));
	Gradients->dgy = oody * (((c2c3) * (v1v3x)) - ((c1c3) * (v2v3x)));

	c2c3 = Gradients->b[1] - Gradients->b[2];
	c1c3 = Gradients->b[0] - Gradients->b[2];

	Gradients->dbx = oodx * (((c2c3) * (v1v3y)) - ((c1c3) * (v2v3y)));
	Gradients->dby = oody * (((c2c3) * (v1v3x)) - ((c1c3) * (v2v3x)));
}



void CalculateEdgeTG(EDGE* Edge,GRADIENT* Gradients,D3DTLVERTEX* Top,D3DTLVERTEX* Bottom,int nTop,int nBottom)
{
	float YPreStep;
	float XPreStep;
	long  dn,dm,ndm,ndn;
	long  inum;
	double fconv;

	Edge->y      = ceilint(Top->sy);
	Edge->height = ceilint(Bottom->sy) - Edge->y;

	if(Edge->height)
	{
		long tsx,tsy;
	
		tsx = FTOLFIX284(Top->sx);
		tsy = FTOLFIX284(Top->sy);
			
		ndm = FTOLFIX284(Bottom->sx) - tsx;
		ndn = FTOLFIX284(Bottom->sy) - tsy;
		
		dn = ndn<<4;
		dm = ndm<<4;
		
		inum = dm*Edge->y - ndm*tsy + ndn*tsx - 1 + dn;
		
		FloorDivMod(inum,dn,Edge->x,Edge->ErrorTerm);
		FloorDivMod(dm,dn,Edge->xstep,Edge->Numerator);
		
		Edge->Denominator = dn;

		XPreStep = FIX284TOFLOAT((Edge->x<<4) - tsx);
		YPreStep = FIX284TOFLOAT((Edge->y<<4) - tsy);

		Edge->oozxtra = Gradients->dozx;
		Edge->uozxtra = Gradients->duzx;
		Edge->vozxtra = Gradients->dvzx;
	
		Edge->rxtraf   = FTOLFIX(Gradients->drx);
		Edge->gxtraf   = FTOLFIX(Gradients->dgx);
		Edge->bxtraf   = FTOLFIX(Gradients->dbx);
		
		Edge->ooz     = Top->rhw + YPreStep * Gradients->dozy + XPreStep * Gradients->dozx;
		Edge->oozstep = Edge->xstep * Gradients->dozx + Gradients->dozy;			

		Edge->uoz     = Gradients->uoz[nTop] + YPreStep * Gradients->duzy + XPreStep * Gradients->duzx;
		Edge->uozstep = Edge->xstep * Gradients->duzx + Gradients->duzy;			
	
		Edge->voz     = Gradients->voz[nTop] + YPreStep * Gradients->dvzy + XPreStep * Gradients->dvzx;
		Edge->vozstep = Edge->xstep * Gradients->dvzx + Gradients->dvzy;			
	
		float r,g,b;
		float rstep,gstep,bstep;
				
		r		= Gradients->r[nTop] + YPreStep * Gradients->dry + XPreStep * Gradients->drx;
		rstep   = Edge->xstep * Gradients->drx + Gradients->dry;
		g		= Gradients->g[nTop] + YPreStep * Gradients->dgy + XPreStep * Gradients->dgx;
		gstep   = Edge->xstep * Gradients->dgx + Gradients->dgy;
		b		= Gradients->b[nTop] + YPreStep * Gradients->dby + XPreStep * Gradients->dbx;
		bstep   = Edge->xstep * Gradients->dbx + Gradients->dby;
		
		Edge->rf	 = FTOLFIX(r);
		Edge->rstepf = FTOLFIX(rstep);
		Edge->gf	 = FTOLFIX(g);
		Edge->gstepf = FTOLFIX(gstep);
		Edge->bf	 = FTOLFIX(b);
		Edge->bstepf = FTOLFIX(bstep);
	}
}


void CalculateEdgeT(EDGE* Edge,GRADIENT* Gradients,D3DTLVERTEX* Top,D3DTLVERTEX* Bottom,int nTop,int nBottom)
{
	float YPreStep;
	float XPreStep;
	long  dn,dm,ndm,ndn;
	long  inum;
	double fconv;

	Edge->y = ceilint(Top->sy);
	Edge->height = ceilint(Bottom->sy)-Edge->y;

	if(Edge->height)
	{
		long tsx,tsy;

		tsx = FTOLFIX284(Top->sx);
		tsy = FTOLFIX284(Top->sy);

		ndm = FTOLFIX284(Bottom->sx - Top->sx);
		ndn = FTOLFIX284(Bottom->sy - Top->sy);
		
		dn = ndn<<4;
		dm = ndm<<4;

		Edge->Denominator = dn;

		inum = (((dm*Edge->y)-(ndm*tsy))+((ndn*tsx)-1))+dn;

		FloorDivMod(inum,dn,Edge->x,Edge->ErrorTerm);

		FloorDivMod(dm,dn,Edge->xstep,Edge->Numerator);
		
		XPreStep = FIX284TOFLOAT((Edge->x<<4) - tsx);
		YPreStep = FIX284TOFLOAT((Edge->y<<4) - tsy);

		Edge->oozxtra = Gradients->dozx;
		Edge->uozxtra = Gradients->duzx;
		Edge->vozxtra = Gradients->dvzx;
	
		Edge->ooz     = Top->rhw + YPreStep * Gradients->dozy + XPreStep * Gradients->dozx;
		Edge->uoz     = Gradients->uoz[nTop] + YPreStep * Gradients->duzy + XPreStep * Gradients->duzx;
		Edge->voz     = Gradients->voz[nTop] + YPreStep * Gradients->dvzy + XPreStep * Gradients->dvzx;
			
		Edge->oozstep = Edge->xstep * Gradients->dozx + Gradients->dozy;			
		Edge->uozstep = Edge->xstep * Gradients->duzx + Gradients->duzy;			
		Edge->vozstep = Edge->xstep * Gradients->dvzx + Gradients->dvzy;			
	}	
}



void CalculateGradientsT(GRADIENT* Gradients,D3DTLVERTEX* v1,D3DTLVERTEX* v2,D3DTLVERTEX* v3)
{
	float oodx,oody;
	float v1v3y,v2v3y,v1v3x,v2v3x;
	float u2u3,u1u3;
	float v2v3,v1v3;
	float z2z3,z1z3;
	
	v1v3y = v1->sy - v3->sy;
	v2v3y = v2->sy - v3->sy;
	v1v3x = v1->sx - v3->sx;
	v2v3x = v2->sx - v3->sx;
	
	oodx = 1.0f/((v2v3x*v1v3y)-(v1v3x*v2v3y));
	oody = -oodx;

	Gradients->uoz[0] = v1->tu * v1->rhw * 256.0f;
	Gradients->voz[0] = v1->tv * v1->rhw * 256.0f;
	
	Gradients->uoz[1] = v2->tu * v2->rhw * 256.0f;
	Gradients->voz[1] = v2->tv * v2->rhw * 256.0f;

	Gradients->uoz[2] = v3->tu * v3->rhw * 256.0f;
	Gradients->voz[2] = v3->tv * v3->rhw * 256.0f;

	u2u3  = Gradients->uoz[1] - Gradients->uoz[2];
	u1u3  = Gradients->uoz[0] - Gradients->uoz[2];

	v2v3  = Gradients->voz[1] - Gradients->voz[2];
	v1v3  = Gradients->voz[0] - Gradients->voz[2];

	Gradients->duzx = oodx * (((u2u3) * (v1v3y)) - ((u1u3) * (v2v3y)));
	Gradients->duzy = oody * (((u2u3) * (v1v3x)) - ((u1u3) * (v2v3x)));

	Gradients->dvzx = oodx * (((v2v3) * (v1v3y)) - ((v1v3) * (v2v3y)));
	Gradients->dvzy = oody * (((v2v3) * (v1v3x)) - ((v1v3) * (v2v3x)));

	z1z3 = v1->rhw-v3->rhw;
	z2z3 = v2->rhw-v3->rhw;

	Gradients->dozx = oodx * (((z2z3) * (v1v3y)) - ((z1z3) * (v2v3y)));
	Gradients->dozy = oody * (((z2z3) * (v1v3x)) - ((z1z3) * (v2v3x)));
}




void CalculateGradientsTF(GRADIENT* Gradients,D3DTLVERTEX* v1,D3DTLVERTEX* v2,D3DTLVERTEX* v3)
{
	float oodx,oody;
	float v1v3y,v2v3y,v1v3x,v2v3x;
	float u2u3,u1u3;
	float v2v3,v1v3;
	float z2z3,z1z3;
	
	v1v3y = v1->sy - v3->sy;
	v2v3y = v2->sy - v3->sy;
	v1v3x = v1->sx - v3->sx;
	v2v3x = v2->sx - v3->sx;
	
	oodx = 1.0f/((v2v3x*v1v3y)-(v1v3x*v2v3y));
	oody = -oodx;

	Gradients->uoz[0] = v1->tu * v1->rhw * 256.0f;
	Gradients->voz[0] = v1->tv * v1->rhw * 256.0f;
	
	Gradients->uoz[1] = v2->tu * v2->rhw * 256.0f;
	Gradients->voz[1] = v2->tv * v2->rhw * 256.0f;

	Gradients->uoz[2] = v3->tu * v3->rhw * 256.0f;
	Gradients->voz[2] = v3->tv * v3->rhw * 256.0f;

	u2u3  = Gradients->uoz[1] - Gradients->uoz[2];
	u1u3  = Gradients->uoz[0] - Gradients->uoz[2];

	v2v3  = Gradients->voz[1] - Gradients->voz[2];
	v1v3  = Gradients->voz[0] - Gradients->voz[2];

	Gradients->duzx = oodx * (((u2u3) * (v1v3y)) - ((u1u3) * (v2v3y)));
	Gradients->duzy = oody * (((u2u3) * (v1v3x)) - ((u1u3) * (v2v3x)));

	Gradients->dvzx = oodx * (((v2v3) * (v1v3y)) - ((v1v3) * (v2v3y)));
	Gradients->dvzy = oody * (((v2v3) * (v1v3x)) - ((v1v3) * (v2v3x)));

	z1z3 = v1->rhw-v3->rhw;
	z2z3 = v2->rhw-v3->rhw;

	Gradients->dozx = oodx * (((z2z3) * (v1v3y)) - ((z1z3) * (v2v3y)));
	Gradients->dozy = oody * (((z2z3) * (v1v3x)) - ((z1z3) * (v2v3x)));

	Gradients->rf = short(GETR(v1->color));
	Gradients->gf = short(GETG(v1->color));
	Gradients->bf = short(GETB(v1->color));
}








void CalculateEdgeBlack(EDGE* Edge,GRADIENT* Gradients,D3DTLVERTEX* Top,D3DTLVERTEX* Bottom,int nTop,int nBottom)
{
	double fconv;

	Edge->y = ceilint(Top->sy);
	Edge->height = ceilint(Bottom->sy)-Edge->y;

	if(Edge->height)
	{
		float w;
		w = Bottom->sx - Top->sx;
		Edge->x = FTOLFIX(ceilfloat(Top->sx));
		Edge->xstep = FTOLFIX(w/Edge->height);
	 }	
}






/*
	Function	:	CalculateGradientsTFA
	Useage		:	Gradients Textured Flat Affine
*/

void CalculateGradientsTA(GRADIENT* Gradients,D3DTLVERTEX* v1,D3DTLVERTEX* v2,D3DTLVERTEX* v3)
{
	float oodx,oody;
	float v1v3y,v2v3y,v1v3x,v2v3x;
	float u2u3,u1u3;
	float v2v3,v1v3;
	
	v1v3y = v1->sy - v3->sy;
	v2v3y = v2->sy - v3->sy;
	v1v3x = v1->sx - v3->sx;
	v2v3x = v2->sx - v3->sx;
	
	oodx = 1.0f/((v2v3x*v1v3y)-(v1v3x*v2v3y));
	oody = -oodx;

	Gradients->uoz[0] = v1->tu * 256.0f;
	Gradients->voz[0] = v1->tv * 256.0f;
	
	Gradients->uoz[1] = v2->tu * 256.0f;
	Gradients->voz[1] = v2->tv * 256.0f;

	Gradients->uoz[2] = v3->tu * 256.0f;
	Gradients->voz[2] = v3->tv * 256.0f;

	u2u3  = Gradients->uoz[1] - Gradients->uoz[2];
	u1u3  = Gradients->uoz[0] - Gradients->uoz[2];

	v2v3  = Gradients->voz[1] - Gradients->voz[2];
	v1v3  = Gradients->voz[0] - Gradients->voz[2];

	Gradients->duzx = oodx * (((u2u3) * (v1v3y)) - ((u1u3) * (v2v3y)));
	Gradients->duzy = oody * (((u2u3) * (v1v3x)) - ((u1u3) * (v2v3x)));

	Gradients->dvzx = oodx * (((v2v3) * (v1v3y)) - ((v1v3) * (v2v3y)));
	Gradients->dvzy = oody * (((v2v3) * (v1v3x)) - ((v1v3) * (v2v3x)));
}

// EOF : CalculateGradientsTFA



void CalculateGradientsTFA(GRADIENT* Gradients,D3DTLVERTEX* v1,D3DTLVERTEX* v2,D3DTLVERTEX* v3)
{
	float oodx,oody;
	float v1v3y,v2v3y,v1v3x,v2v3x;
	float u2u3,u1u3;
	float v2v3,v1v3;
	
	v1v3y = v1->sy - v3->sy;
	v2v3y = v2->sy - v3->sy;
	v1v3x = v1->sx - v3->sx;
	v2v3x = v2->sx - v3->sx;
	
	oodx = 1.0f/((v2v3x*v1v3y)-(v1v3x*v2v3y));
	oody = -oodx;

	Gradients->uoz[0] = v1->tu * 256.0f;
	Gradients->voz[0] = v1->tv * 256.0f;
	
	Gradients->uoz[1] = v2->tu * 256.0f;
	Gradients->voz[1] = v2->tv * 256.0f;

	Gradients->uoz[2] = v3->tu * 256.0f;
	Gradients->voz[2] = v3->tv * 256.0f;

	u2u3  = Gradients->uoz[1] - Gradients->uoz[2];
	u1u3  = Gradients->uoz[0] - Gradients->uoz[2];

	v2v3  = Gradients->voz[1] - Gradients->voz[2];
	v1v3  = Gradients->voz[0] - Gradients->voz[2];

	Gradients->duzx = oodx * (((u2u3) * (v1v3y)) - ((u1u3) * (v2v3y)));
	Gradients->duzy = oody * (((u2u3) * (v1v3x)) - ((u1u3) * (v2v3x)));

	Gradients->dvzx = oodx * (((v2v3) * (v1v3y)) - ((v1v3) * (v2v3y)));
	Gradients->dvzy = oody * (((v2v3) * (v1v3x)) - ((v1v3) * (v2v3x)));

	Gradients->rf = short(GETR(v1->color));
	Gradients->gf = short(GETG(v1->color));
	Gradients->bf = short(GETB(v1->color));
}



/*
	Function	:	CalculateEdgeTFA
	Usage		:	Calculate Edge Gradients Textured Flat Affine
*/

void CalculateEdgeTA(EDGE* Edge,GRADIENT* Gradients,D3DTLVERTEX* Top,D3DTLVERTEX* Bottom,int nTop,int nBottom)
{
	float YPreStep;
	float XPreStep;
	long  dn,dm,ndm,ndn;
	long  inum;
	double fconv;

	Edge->y = ceilint(Top->sy);
	Edge->height = ceilint(Bottom->sy)-Edge->y;

	if(Edge->height)
	{
		long tsx,tsy;

		tsx = FTOLFIX284(Top->sx);
		tsy = FTOLFIX284(Top->sy);

		ndm = FTOLFIX284(Bottom->sx - Top->sx);
		ndn = FTOLFIX284(Bottom->sy - Top->sy);

		dn = ndn<<4;
		dm = ndm<<4;

		Edge->Denominator = dn;

		inum = (((dm*Edge->y)-(ndm*tsy))+((ndn*tsx)-1))+dn;

		FloorDivMod(inum,dn,Edge->x,Edge->ErrorTerm);
		FloorDivMod(dm,dn,Edge->xstep,Edge->Numerator);
		
		XPreStep = FIX284TOFLOAT((Edge->x<<4) - tsx);
		YPreStep = FIX284TOFLOAT((Edge->y<<4) - tsy);
	
		float u,v,us,vs;

		u = Gradients->uoz[nTop] + YPreStep * Gradients->duzy + XPreStep * Gradients->duzx;
		v = Gradients->voz[nTop] + YPreStep * Gradients->dvzy + XPreStep * Gradients->dvzx;
			
		us = Edge->xstep * Gradients->duzx + Gradients->duzy;			
		vs = Edge->xstep * Gradients->dvzx + Gradients->dvzy;			
	
		Edge->uozf	   = FTOLFIX(u);
		Edge->vozf	   = FTOLFIX(v);
		Edge->uozstepf = FTOLFIX(us);
		Edge->vozstepf = FTOLFIX(vs);
		Edge->uozxtraf = FTOLFIX(Gradients->duzx);
		Edge->vozxtraf = FTOLFIX(Gradients->dvzx);
	}	
}

// EOF : CalculateEdgeTFA


/*
	Function	:	CalculateGradientsTGA
	Useage		:	Gradients Textured Gouraud Affine
*/

void CalculateGradientsTGA(GRADIENT* Gradients,D3DTLVERTEX* v1,D3DTLVERTEX* v2,D3DTLVERTEX* v3)
{
	float oodx,oody;
	float v1v3y,v2v3y,v1v3x,v2v3x;
	float u2u3,u1u3;
	float v2v3,v1v3;
	float c2c3,c1c3;

	v1v3y = v1->sy - v3->sy;
	v2v3y = v2->sy - v3->sy;
	v1v3x = v1->sx - v3->sx;
	v2v3x = v2->sx - v3->sx;
	
	oodx = 1.0f/((v2v3x*v1v3y)-(v1v3x*v2v3y));
	oody = -oodx;

	Gradients->uoz[0] = v1->tu * 256.0f;
	Gradients->voz[0] = v1->tv * 256.0f;
	
	Gradients->uoz[1] = v2->tu * 256.0f;
	Gradients->voz[1] = v2->tv * 256.0f;

	Gradients->uoz[2] = v3->tu * 256.0f;
	Gradients->voz[2] = v3->tv * 256.0f;

	u2u3  = Gradients->uoz[1] - Gradients->uoz[2];
	u1u3  = Gradients->uoz[0] - Gradients->uoz[2];

	v2v3  = Gradients->voz[1] - Gradients->voz[2];
	v1v3  = Gradients->voz[0] - Gradients->voz[2];

	Gradients->duzx = oodx * (((u2u3) * (v1v3y)) - ((u1u3) * (v2v3y)));
	Gradients->duzy = oody * (((u2u3) * (v1v3x)) - ((u1u3) * (v2v3x)));

	Gradients->dvzx = oodx * (((v2v3) * (v1v3y)) - ((v1v3) * (v2v3y)));
	Gradients->dvzy = oody * (((v2v3) * (v1v3x)) - ((v1v3) * (v2v3x)));

	Gradients->r[0] = (float) GETR(v1->color);
	Gradients->g[0] = (float) GETG(v1->color);
	Gradients->b[0] = (float) GETB(v1->color);

	Gradients->r[1] = (float) GETR(v2->color);
	Gradients->g[1] = (float) GETG(v2->color);
	Gradients->b[1] = (float) GETB(v2->color);

	Gradients->r[2] = (float) GETR(v3->color);
	Gradients->g[2] = (float) GETG(v3->color);
	Gradients->b[2] = (float) GETB(v3->color);

	c2c3 = Gradients->r[1] - Gradients->r[2];
	c1c3 = Gradients->r[0] - Gradients->r[2];
	
	Gradients->drx = oodx * (((c2c3) * (v1v3y)) - ((c1c3) * (v2v3y)));
	Gradients->dry = oody * (((c2c3) * (v1v3x)) - ((c1c3) * (v2v3x)));

	c2c3 = Gradients->g[1] - Gradients->g[2];
	c1c3 = Gradients->g[0] - Gradients->g[2];

	Gradients->dgx = oodx * (((c2c3) * (v1v3y)) - ((c1c3) * (v2v3y)));
	Gradients->dgy = oody * (((c2c3) * (v1v3x)) - ((c1c3) * (v2v3x)));

	c2c3 = Gradients->b[1] - Gradients->b[2];
	c1c3 = Gradients->b[0] - Gradients->b[2];

	Gradients->dbx = oodx * (((c2c3) * (v1v3y)) - ((c1c3) * (v2v3y)));
	Gradients->dby = oody * (((c2c3) * (v1v3x)) - ((c1c3) * (v2v3x)));
}

// EOF : CalculateGradientsTGA



/*
	Function	:	CalculateEdgeTGA
	Usage		:	Calculate Edge Gradients Textured Gouraud Affine
*/

void CalculateEdgeTGA(EDGE* Edge,GRADIENT* Gradients,D3DTLVERTEX* Top,D3DTLVERTEX* Bottom,int nTop,int nBottom)
{
	float YPreStep;
	float XPreStep;
	long  dn,dm,ndm,ndn;
	long  inum;
	double fconv;

	Edge->y = ceilint(Top->sy);
	Edge->height = ceilint(Bottom->sy)-Edge->y;

	if(Edge->height)
	{
		long tsx,tsy;

		tsx = FTOLFIX284(Top->sx);
		tsy = FTOLFIX284(Top->sy);

		ndm = FTOLFIX284(Bottom->sx - Top->sx);
		ndn = FTOLFIX284(Bottom->sy - Top->sy);

		dn = ndn<<4;
		dm = ndm<<4;

		Edge->Denominator = dn;

		inum = (((dm*Edge->y)-(ndm*tsy))+((ndn*tsx)-1))+dn;

		FloorDivMod(inum,dn,Edge->x,Edge->ErrorTerm);
		
		FloorDivMod(dm,dn,Edge->xstep,Edge->Numerator);

		XPreStep = FIX284TOFLOAT((Edge->x<<4) - tsx);
		YPreStep = FIX284TOFLOAT((Edge->y<<4) - tsy);
	
		float u,v,us,vs;

		u = Gradients->uoz[nTop] + YPreStep * Gradients->duzy + XPreStep * Gradients->duzx;
		v = Gradients->voz[nTop] + YPreStep * Gradients->dvzy + XPreStep * Gradients->dvzx;
			
		us = Edge->xstep * Gradients->duzx + Gradients->duzy;			
		vs = Edge->xstep * Gradients->dvzx + Gradients->dvzy;			
	
		Edge->uozf	   = FTOLFIX(u);
		Edge->vozf	   = FTOLFIX(v);
		Edge->uozstepf = FTOLFIX(us);
		Edge->vozstepf = FTOLFIX(vs);
		Edge->uozxtraf = FTOLFIX(Gradients->duzx);
		Edge->vozxtraf = FTOLFIX(Gradients->dvzx);

		float r,g,b,rstep,gstep,bstep;

		r = Gradients->r[nTop] + YPreStep * Gradients->dry + XPreStep * Gradients->drx;
		g = Gradients->g[nTop] + YPreStep * Gradients->dgy + XPreStep * Gradients->dgx;
		b = Gradients->b[nTop] + YPreStep * Gradients->dby + XPreStep * Gradients->dbx;

		rstep = Edge->xstep * Gradients->drx + Gradients->dry;
		gstep = Edge->xstep * Gradients->dgx + Gradients->dgy;
		bstep = Edge->xstep * Gradients->dbx + Gradients->dby;	

		Edge->rf	 = FTOLFIX(r);
		Edge->rstepf = FTOLFIX(rstep);
	
		Edge->gf	 = FTOLFIX(g);
		Edge->gstepf = FTOLFIX(gstep);
	
		Edge->bf	 = FTOLFIX(b);
		Edge->bstepf = FTOLFIX(bstep);

		Edge->rxtraf = FTOLFIX(Gradients->drx);
		Edge->gxtraf = FTOLFIX(Gradients->dgx);
		Edge->bxtraf = FTOLFIX(Gradients->dbx);

	}	
}

// EOF : CalculateEdgeTGA





void DrawTriangle(D3DTLVERTEX* v1,D3DTLVERTEX* v2,D3DTLVERTEX* v3)
{

	D3DTLVERTEX *Top,*Middle,*Bottom;
	GRADIENT Gradients;

	EDGE TopToBottom;
	EDGE TopToMiddle;
	EDGE MiddleToBottom;
	EDGE *pLeft,*pRight;
	
	float y0,y1,y2;
	int nTop,nMiddle,nBottom;
	int MiddleIsLeft;
	

	if(DrawScanLines == NULL) return;

	// Sort Vertices In Y

	y0 = v1->sy;
	y1 = v2->sy;
	y2 = v3->sy;

	if(y0 < y1)
	{
		if(y2 < y0)
		{
			Top     = v3;
			Middle  = v1;
			Bottom  = v2;
			nTop    = 2;
			nMiddle = 0;
			nBottom = 1;
			MiddleIsLeft = 0;
		}
		else
		{
			Top  = v1;
			nTop = 0;
			
			if(y1 < y2)
			{
				Middle = v2; 
				Bottom = v3;
				nMiddle = 1;
				nBottom = 2;
				MiddleIsLeft = 0;
			}
			else
			{
				Middle  = v3;
				Bottom  = v2;
				nMiddle = 2;
				nBottom = 1;
				MiddleIsLeft = 1;
			}
		}
	}
	else
	{
		if(y2 < y1)
		{
			Top    = v3;
			Middle = v2;
			Bottom = v1;
			nTop	= 2;
			nMiddle = 1;
			nBottom = 0;
			MiddleIsLeft = 1;
		}
		else
		{
			Top  = v2;
			nTop = 1;

			if(y0 < y2)
			{
				Middle = v1;
				Bottom = v3;
				nMiddle = 0;
				nBottom = 2;
				MiddleIsLeft = 1;
			}
			else
			{
				Middle = v3;
				Bottom = v1;
				nMiddle = 2;
				nBottom = 0;
				MiddleIsLeft = 0;
			}
		}
	}

	if(v1->color == 0 && v2->color == 0 && v3->color == 0)
	{
		
		CalcGradientsBlack(&Gradients,v1,v2,v3);
		CalcEdgeBlack(&TopToBottom,&Gradients,Top,Bottom,nTop,nBottom);
		CalcEdgeBlack(&TopToMiddle,&Gradients,Top,Middle,nTop,nMiddle);
		CalcEdgeBlack(&MiddleToBottom,&Gradients,Middle,Bottom,nMiddle,nBottom);
	
		if(MiddleIsLeft)
		{
			pLeft  = &TopToMiddle;
			pRight = &TopToBottom;
		}
		else
		{
			pLeft  = &TopToBottom;
			pRight = &TopToMiddle;
		}

		if(!bDraw) return;

		DrawScanLinesBlack(&Gradients,pLeft,pRight,&TopToMiddle,&TopToBottom);

		if(MiddleIsLeft)
		{
			pLeft  = &MiddleToBottom;
			pRight = &TopToBottom;
		}
		else 
		{
			pLeft  = &TopToBottom;
			pRight = &MiddleToBottom;
		}

		DrawScanLinesBlack(&Gradients,pLeft,pRight,&MiddleToBottom,&TopToBottom);
	
		PolysDrawn++;

		return;
		
	}

//	bForceAffineMap = 1;

	if(bForceAffineMap == 0)
	{
		float maxwidth;
		float h;
		float grad = 0;
		maxwidth  = (Middle->sy-Top->sy);
		h = Bottom->sy-Top->sy;
		if(h != 0)
		{
			grad = (Bottom->sx - Top->sx)/h;
			maxwidth *= grad;
		}
		else
			maxwidth = 0;
		maxwidth += Top->sx;
		maxwidth -= Middle->sx;
		if(maxwidth < 0)
			maxwidth = 0-maxwidth;
		
		
		static float val = 0.9895f;
	
		if((((v1->sz+v2->sz+v3->sz)*(1.0f/3.0f)) < val))
		{
			if(maxwidth > 32 || (h > 32) )
			{
	
				if(v1->color == v2->color)
				{
					if(v2->color == v3->color)
					{
						CalcGradientsFlat(&Gradients,v1,v2,v3);
						CalcEdgeFlat(&TopToBottom,&Gradients,Top,Bottom,nTop,nBottom);
						CalcEdgeFlat(&TopToMiddle,&Gradients,Top,Middle,nTop,nMiddle);
						CalcEdgeFlat(&MiddleToBottom,&Gradients,Middle,Bottom,nMiddle,nBottom);
	
						if(MiddleIsLeft)
						{
							pLeft  = &TopToMiddle;
							pRight = &TopToBottom;
						}
						else
						{
							pLeft  = &TopToBottom;
							pRight = &TopToMiddle;
						}

						if(!bDraw) return;

						DrawScanLinesFlat(&Gradients,pLeft,pRight,&TopToMiddle,&TopToBottom);

						if(MiddleIsLeft)
						{
							pLeft  = &MiddleToBottom;
							pRight = &TopToBottom;
						}
						else 
						{
							pLeft  = &TopToBottom;
							pRight = &MiddleToBottom;
						}
	
						DrawScanLinesFlat(&Gradients,pLeft,pRight,&MiddleToBottom,&TopToBottom);

						PolysDrawn++;
						return;
					}
				}
				
				
				CalcGradientsPersp(&Gradients,v1,v2,v3);
				CalcEdgePersp(&TopToBottom,&Gradients,Top,Bottom,nTop,nBottom);
				CalcEdgePersp(&TopToMiddle,&Gradients,Top,Middle,nTop,nMiddle);
				CalcEdgePersp(&MiddleToBottom,&Gradients,Middle,Bottom,nMiddle,nBottom);
	
				if(MiddleIsLeft)
				{
					pLeft  = &TopToMiddle;
					pRight = &TopToBottom;
				}
				else
				{
					pLeft  = &TopToBottom;
					pRight = &TopToMiddle;
				}

				if(!bDraw) return;

				DrawScanLines(&Gradients,pLeft,pRight,&TopToMiddle,&TopToBottom);

				if(MiddleIsLeft)
				{
					pLeft  = &MiddleToBottom;
					pRight = &TopToBottom;
				}
				else 
				{
					pLeft  = &TopToBottom;
					pRight = &MiddleToBottom;
				}

				DrawScanLines(&Gradients,pLeft,pRight,&MiddleToBottom,&TopToBottom);

				perspolys++;
				PolysDrawn++;
				return;		

			}
		}		
	}		

	if(v1->color == v2->color)
	{
		if(v2->color == v3->color)
		{
			CalcGradientsFlatAffine(&Gradients,v1,v2,v3);
			CalcEdgeFlatAffine(&TopToBottom,&Gradients,Top,Bottom,nTop,nBottom);
			CalcEdgeFlatAffine(&TopToMiddle,&Gradients,Top,Middle,nTop,nMiddle);
			CalcEdgeFlatAffine(&MiddleToBottom,&Gradients,Middle,Bottom,nMiddle,nBottom);
	
			if(MiddleIsLeft)
			{
				pLeft  = &TopToMiddle;
				pRight = &TopToBottom;
			}
			else
			{
				pLeft  = &TopToBottom;
				pRight = &TopToMiddle;
			}

			if(!bDraw) return;

			DrawScanLinesFlatAffine(&Gradients,pLeft,pRight,&TopToMiddle,&TopToBottom);

			if(MiddleIsLeft)
			{
				pLeft  = &MiddleToBottom;
				pRight = &TopToBottom;
			}
			else 
			{
				pLeft  = &TopToBottom;
				pRight = &MiddleToBottom;
			}
	
			DrawScanLinesFlatAffine(&Gradients,pLeft,pRight,&MiddleToBottom,&TopToBottom);

			PolysDrawn++;
			return;
		}
	}


	CalcGradientsAffine(&Gradients,v1,v2,v3);
	CalcEdgeAffine(&TopToBottom,&Gradients,Top,Bottom,nTop,nBottom);
	CalcEdgeAffine(&TopToMiddle,&Gradients,Top,Middle,nTop,nMiddle);
	CalcEdgeAffine(&MiddleToBottom,&Gradients,Middle,Bottom,nMiddle,nBottom);

	if(MiddleIsLeft)
	{
		pLeft  = &TopToMiddle;
		pRight = &TopToBottom;
	}
	else
	{
		pLeft  = &TopToBottom;
		pRight = &TopToMiddle;
	}

	if(!bDraw) return;

	
	DrawScanLinesAffine(&Gradients,pLeft,pRight,&TopToMiddle,&TopToBottom);

	if(MiddleIsLeft)
	{
		pLeft  = &MiddleToBottom;
		pRight = &TopToBottom;
	}
	else 
	{
		pLeft  = &TopToBottom;
		pRight = &MiddleToBottom;
	}
	
		
	DrawScanLinesAffine(&Gradients,pLeft,pRight,&MiddleToBottom,&TopToBottom);

	affinepolys++;


#ifdef GAMEDEBUG
	PolysDrawn++;
#endif

}








