/*KJL*********************************************************************
* krender.c - Kevin's scandrawing code. (New render, new danger.)        *
*                                                                        *
* The new scandraws are called by patching the functions below into the  *
* jumptables used in item.c. If the KRENDER_ON flag in krender.h is zero *
* then the old scandraws will be used.                                   *
*********************************************************************KJL*/

/* this file is a bit messy at the moment, but I'll be back later... */
#include "3dc.h"
#include "inline.h"
#include "module.h"
#include "gamedef.h"
#include "krender.h"
#include "vision.h"

#define UseLocalAssert Yes
#include "ourasert.h"

#define PENTIUM_PROFILING_ON 0
#if PENTIUM_PROFILING_ON
#include "pentime.h"
#else
#define ProfileStart();
#define ProfileStop(x);
#endif

int ReciprocalTable[321]; 
#if 1
#define DIVIDE(a,b) ((a)/(b))
#else
#define DIVIDE(a,b) (MUL_FIXED((a),ReciprocalTable[(b)]))
#endif


int Transparent;

/* assembler fns */
extern void ScanDraw2D_Gouraud(void);
extern void ScanDraw2D_GouraudTransparent(void);
extern void ScanDraw2D_VAlignedTransparent(void);
extern void ScanDraw2D_VAlignedOpaque(void);
extern void ScanDraw2D_Transparent(void);
extern void ScanDraw2D_TransparentLit(void);
extern void ScanDraw2D_Opaque(void);
extern void ScanDraw_GouraudScan(void);
extern void ScanDrawF3D_Gouraud(void);

/* globals accessed by the assembler routines */
unsigned char *SCASM_Lighting;
unsigned char *SCASM_Destination;
unsigned char *SCASM_Bitmap;
int SCASM_StartU;
int SCASM_StartV;
int SCASM_StartI;
int SCASM_DeltaU;
int SCASM_DeltaV;
int SCASM_DeltaI;
int SCASM_ScanLength;
int	SCASM_ShadingTableSize;
int	SCASM_TextureDeltaScan;

/* things from item.c */
extern int NumScans;
extern int ItemColour;
extern IMAGEHEADER *ImageHeaderPtrs[MaxImages];
extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock;
extern unsigned char *TextureLightingTable;
extern int MIP_Index;
extern int ScanData[maxpolys*maxscansize];
extern unsigned char *ScreenBuffer;
extern long BackBufferPitch;

void Draw_Gouraud3dTexture_Spans(int *itemptr);

int KRenderDrawMode = 0;

/***********/

void KR_ScanDraw_Item_Gouraud2dTexturePolygon_VideoModeType_8(int *itemptr)
{
	POLYHEADER *pheader = (POLYHEADER *) itemptr;
	I_GOURAUD2DTEXTUREPOLYGON_SCAN *sptr;

	if(NumScans)
	{
		int y = NumScans;
		/* Get the Image Data required for the Draw */
		{
			IMAGEHEADER *ImageHdr;
			{
				int TxIndex  = ItemColour & ClrTxDefn;
				ImageHdr = ImageHeaderPtrs[TxIndex];
			}
			if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip)
			{
				TEXTURE **TxImagePtr = &ImageHdr->ImagePtr;
				SCASM_Bitmap = TxImagePtr[MIP_Index];
				GLOBALASSERT(SCASM_Bitmap);
				SCASM_TextureDeltaScan = ImageHdr->ImageWidth >> MIP_Index;
				#if MIP_ROUNDUP
				if (ImageHdr->ImageWidth & (1<<MIP_Index)-1) ++SCASM_TextureDeltaScan;
				#endif


			}
			else
			{
				SCASM_TextureDeltaScan = ImageHdr->ImageWidth;
				SCASM_Bitmap = ImageHdr->ImagePtr;
				GLOBALASSERT(SCASM_Bitmap);
			}
		}
		SCASM_Lighting = TextureLightingTable;
		
		if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_Raw256) SCASM_ShadingTableSize = 256;
		else SCASM_ShadingTableSize = 64;

		sptr = (I_GOURAUD2DTEXTUREPOLYGON_SCAN *) ScanData;
		do
		{
			int dx = sptr->ig2s_x2 - sptr->ig2s_x1;
			if (dx>0 && !(sptr->ig2s_y & KRenderDrawMode) )
			{
				/* Fixed Point U for Interpolation */
				{
					int StartU = sptr->ig2s_u1;
					SCASM_DeltaU = DIVIDE((sptr->ig2s_u2 - StartU),dx);
					SCASM_StartU = StartU;
				}
				
				/* Fixed Point V for Interpolation */
				{
					int StartV = sptr->ig2s_v1;
					SCASM_DeltaV = DIVIDE((sptr->ig2s_v2 - StartV),dx);
					SCASM_StartV = StartV;
				}
				/* Fixed Point I for Interpolation */
				{
					int StartI = sptr->ig2s_c1;
					SCASM_DeltaI = DIVIDE((sptr->ig2s_c2 - StartI),dx);
					SCASM_StartI = StartI;
				}
				/* Draw the Gouraud 2d Texture Scan */

				SCASM_Destination = ScreenBuffer + (sptr->ig2s_y * BackBufferPitch) + sptr->ig2s_x1;
				SCASM_ScanLength = dx;
				
				if(pheader->PolyFlags & iflag_ignore0)
				{
					ScanDraw2D_GouraudTransparent();
				}
				else
				{
					ScanDraw2D_Gouraud();
				}	
			}
			sptr++;
			y--;
		}
		while(y);
	}
	
}

void Draw3DScan(I_GOURAUD3DTEXTUREPOLYGON_SCAN *scanPtr, POLYHEADER *pheader)
{
	int dx = scanPtr->ig3s_x2 - scanPtr->ig3s_x1;

	if(dx > 0)
	{
		float uf; 
		float vf; 
		float uf2;
		float vf2;
		/* Get start and end UVs */
		{
			float ooz1;
			ooz1 = 65536.0 / scanPtr->ig3s_z1;
			uf = scanPtr->ig3s_u1 * ooz1;
			vf = scanPtr->ig3s_v1 * ooz1;
		}
		{
			float ooz2;
			ooz2 = 65536.0 / scanPtr->ig3s_z2;
			uf2 = scanPtr->ig3s_u2 * ooz2;
			vf2 = scanPtr->ig3s_v2 * ooz2;
		}
		if ( (uf>16700000.0)
		   ||(uf<0.0)
		   ||(vf>16700000.0)
		   ||(vf<0.0) )
		{
			textprint("WARNING: UV coords invalid\n");
   // 		LOCALASSERT(0);
			return;
		}
		if ( (uf2>16700000.0)
		   ||(uf2<0.0)
		   ||(vf2>16700000.0)
		   ||(vf2<0.0) )
		{
			textprint("WARNING: UV coords invalid\n");
	//		LOCALASSERT(0);
			return;
		}
		/* For UV interpolation */
		f2i(SCASM_StartU,uf);
		f2i(SCASM_StartV,vf);
		{
			int EndU,EndV;
			f2i(EndU,uf2);
			f2i(EndV,vf2);
			SCASM_DeltaU =(EndU-SCASM_StartU)/dx;
			SCASM_DeltaV =(EndV-SCASM_StartV)/dx;
		}

		/* Fixed Point I for Interpolation */
		{
			int StartI = scanPtr->ig3s_c1;
			SCASM_DeltaI = (scanPtr->ig3s_c2 - StartI)/dx;
			SCASM_StartI = StartI;
		}
		
		/* Draw the 3d Texture Scan */
		SCASM_Destination = ScreenBuffer + (scanPtr->ig3s_y * BackBufferPitch) + scanPtr->ig3s_x1;
		SCASM_ScanLength = dx;

		if(pheader->PolyFlags & iflag_ignore0)
		{
			ScanDraw2D_GouraudTransparent();
		}
		else
		{
			ScanDraw2D_Gouraud();
		}	
	}
}


void KR_ScanDraw_Item_Gouraud3dTexturePolygon_Linear_S_VideoModeType_8(int *itemptr)
{
	POLYHEADER *pheader = (POLYHEADER *) itemptr;
	
	int num_scans_s;
	I_GOURAUD3DTEXTUREPOLYGON_SCAN *sptr_array_ptr;
	I_GOURAUD3DTEXTUREPOLYGON_SCAN *next_free_sptr;
	I_GOURAUD3DTEXTUREPOLYGON_SCAN sptr_array[lin_s_max + 1];
	int StillSubdividing;
	int i;

	
	if(NumScans)
	{
		I_GOURAUD3DTEXTUREPOLYGON_SCAN *sptr;
		int y;
		/* Get the Image Data required for the Draw */
		{
			IMAGEHEADER *ImageHdr;
			{
				int TxIndex  = ItemColour & ClrTxDefn;
				ImageHdr = ImageHeaderPtrs[TxIndex];
			}
			if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip)
			{
				TEXTURE **TxImagePtr = &ImageHdr->ImagePtr;
				SCASM_Bitmap = TxImagePtr[MIP_Index];
				GLOBALASSERT(SCASM_Bitmap);
				SCASM_TextureDeltaScan = ImageHdr->ImageWidth >> MIP_Index;
				#if MIP_ROUNDUP
				if (ImageHdr->ImageWidth & (1<<MIP_Index)-1) ++SCASM_TextureDeltaScan;
				#endif

			}
			else
			{
				SCASM_TextureDeltaScan = ImageHdr->ImageWidth;
				SCASM_Bitmap = ImageHdr->ImagePtr;
				GLOBALASSERT(SCASM_Bitmap);
			}
		}
		SCASM_Lighting = TextureLightingTable;
		
		if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_Raw256) SCASM_ShadingTableSize = 256;
		else SCASM_ShadingTableSize = 64;

		
		sptr = (I_GOURAUD3DTEXTUREPOLYGON_SCAN *) ScanData;

		for(y = NumScans; y!=0; y--)
		{
			int dx = sptr->ig3s_x2 - sptr->ig3s_x1;
			if (dx>0 && !(sptr->ig3s_y & KRenderDrawMode) )
			{
				float zmax, zmin, z_ratio;
				
				/* Have a look at the z-ratio */
				if(sptr->ig3s_z1 > sptr->ig3s_z2)
				{
					zmax = sptr->ig3s_z1;
					zmin = sptr->ig3s_z2;
				}
				else
				{
					zmax = sptr->ig3s_z2;
					zmin = sptr->ig3s_z1;
				}
				z_ratio = (zmax * 256);


				/* Draw if the z ratio is inside the threshold */
				if(z_ratio < lin_s_zthr*zmin)
				{
					Draw3DScan(sptr,pheader);
				}
				/* Else subdivide until scan segments are inside threshold */
				else
				{
					/* Copy the current scan to the subdivision array */
					sptr_array_ptr = sptr_array;
					num_scans_s    = 1;

					sptr_array_ptr->ig3s_u1 = sptr->ig3s_u1;
					sptr_array_ptr->ig3s_v1 = sptr->ig3s_v1;
					sptr_array_ptr->ig3s_z1 = sptr->ig3s_z1;
					sptr_array_ptr->ig3s_c1 = sptr->ig3s_c1;

					sptr_array_ptr->ig3s_u2 = sptr->ig3s_u2;
					sptr_array_ptr->ig3s_v2 = sptr->ig3s_v2;
					sptr_array_ptr->ig3s_z2 = sptr->ig3s_z2;
					sptr_array_ptr->ig3s_c2 = sptr->ig3s_c2;

					sptr_array_ptr->ig3s_x1 = sptr->ig3s_x1;
					sptr_array_ptr->ig3s_x2 = sptr->ig3s_x2;

					sptr_array_ptr->ig3s_y = sptr->ig3s_y;


					/* Subdivide until no further divisions are needed */

					next_free_sptr = sptr_array_ptr + 1;
					do
					{
						sptr_array_ptr = sptr_array;

						StillSubdividing = No;					/* Assume not */

						for(i = num_scans_s; i!=0; i--)
						{
							#if 0
							/* z ratio of this scan */
							if(sptr_array_ptr->ig3s_z1 > sptr_array_ptr->ig3s_z2)
							{
								z_ratio = (sptr_array_ptr->ig3s_z1 * 256) /
												sptr_array_ptr->ig3s_z2;
							}
							else
							{
								z_ratio = (sptr_array_ptr->ig3s_z2 * 256) /
												sptr_array_ptr->ig3s_z1;
							}
							/* Is it within the threshold? */
							if(z_ratio > lin_s_zthr && num_scans_s < lin_s_max)
							#endif
							int overThreshold=0;
							/* z ratio of this scan */
							if(sptr_array_ptr->ig3s_z1 > sptr_array_ptr->ig3s_z2)
							{
								if ( (sptr_array_ptr->ig3s_z1 * 256) > (lin_s_zthr*sptr_array_ptr->ig3s_z2))
									overThreshold=1;
							}
							else
							{
								if ( (sptr_array_ptr->ig3s_z2 * 256) > (lin_s_zthr*sptr_array_ptr->ig3s_z1))
									overThreshold=1;
							}
							/* Is it within the threshold? */
							if(overThreshold && num_scans_s < lin_s_max)
							{
								int mid_x, mid_c;
								float mid_u, mid_v, mid_z;
								/* No - subdivide */
								StillSubdividing = Yes;

								mid_u = (sptr_array_ptr->ig3s_u1 + sptr_array_ptr->ig3s_u2) / 2;

								mid_v = (sptr_array_ptr->ig3s_v1 + sptr_array_ptr->ig3s_v2) / 2;

								mid_z = (sptr_array_ptr->ig3s_z1 + sptr_array_ptr->ig3s_z2) / 2;

								mid_c = (sptr_array_ptr->ig3s_c1 + sptr_array_ptr->ig3s_c2) / 2;

								mid_x = (sptr_array_ptr->ig3s_x1 + sptr_array_ptr->ig3s_x2) / 2;

								/* Create new scan */

								next_free_sptr->ig3s_u1 = mid_u;
								next_free_sptr->ig3s_v1 = mid_v;
								next_free_sptr->ig3s_z1 = mid_z;
								next_free_sptr->ig3s_c1 = mid_c;
								next_free_sptr->ig3s_x1 = mid_x;
								next_free_sptr->ig3s_u2 = sptr_array_ptr->ig3s_u2;
								next_free_sptr->ig3s_v2 = sptr_array_ptr->ig3s_v2;
								next_free_sptr->ig3s_z2 = sptr_array_ptr->ig3s_z2;
								next_free_sptr->ig3s_c2 = sptr_array_ptr->ig3s_c2;
								next_free_sptr->ig3s_x2 = sptr_array_ptr->ig3s_x2;
								next_free_sptr->ig3s_y = sptr_array_ptr->ig3s_y;
								/* Redefine old scan */

								sptr_array_ptr->ig3s_u2 = mid_u;
								sptr_array_ptr->ig3s_v2 = mid_v;
								sptr_array_ptr->ig3s_z2 = mid_z;
								sptr_array_ptr->ig3s_c2 = mid_c;
								sptr_array_ptr->ig3s_x2 = mid_x;

								/* Update pointer and counter */

								next_free_sptr++;
								num_scans_s++;

							}
							sptr_array_ptr++;
						}

					}
					while(StillSubdividing);

			   		/* Draw the scan array */
			   		sptr_array_ptr = sptr_array;
			   		for(i = num_scans_s; i!=0; i--)
					{
						Draw3DScan(sptr_array_ptr,pheader);
						sptr_array_ptr++;
					}
				}
			}
			sptr++;
		}
	}
}



void KR_ScanDraw_Item_2dTexturePolygon_VideoModeType_8(int *itemptr)
{
	POLYHEADER *pheader = (POLYHEADER *) itemptr;
	if(NumScans)
	{
		if(pheader->PolyFlags & iflag_nolight)
		{
			int y;
			I_2DTEXTUREPOLYGON_SCAN *sptr = (I_2DTEXTUREPOLYGON_SCAN *) ScanData;

			/* Offset in Screen Buffer */
			{
				IMAGEHEADER *ImageHdr;
				{
					int TxIndex  = ItemColour & ClrTxDefn;
					ImageHdr = ImageHeaderPtrs[TxIndex];
				}
				if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip)
				{
					TEXTURE **TxImagePtr = &ImageHdr->ImagePtr;
					SCASM_Bitmap = TxImagePtr[MIP_Index];
					GLOBALASSERT(SCASM_Bitmap);
					SCASM_TextureDeltaScan = ImageHdr->ImageWidth >> MIP_Index;
					#if MIP_ROUNDUP
					if (ImageHdr->ImageWidth & (1<<MIP_Index)-1) ++SCASM_TextureDeltaScan;
					#endif
				}
				else
				{
					SCASM_TextureDeltaScan = ImageHdr->ImageWidth;
					SCASM_Bitmap = ImageHdr->ImagePtr;
					GLOBALASSERT(SCASM_Bitmap);
				}
			}
			
			/* Get the Image Data required for the Draw */
			for(y=NumScans; y!=0; y--)
			{
				int dx = sptr->i2s_x2 - sptr->i2s_x1;

				if (dx>0 && !(sptr->i2s_y & KRenderDrawMode) )
				{
					/* Fixed Point U for Interpolation */
					{
						int StartU = sptr->i2s_u1;
						SCASM_DeltaU = (sptr->i2s_u2 - StartU)/dx;
						SCASM_StartU = StartU;
					}
					
					/* Fixed Point V for Interpolation */
					{
						int StartV = sptr->i2s_v1;
						SCASM_DeltaV = (sptr->i2s_v2 - StartV)/dx;
						SCASM_StartV = StartV;
					}

					SCASM_Destination = ScreenBuffer + (sptr->i2s_y * BackBufferPitch) + sptr->i2s_x1;
					SCASM_ScanLength = dx;

	
					/* Is VDelta = 0? */
					if(SCASM_DeltaV == 0)
					{
						if(pheader->PolyFlags & iflag_ignore0)
						{
							ScanDraw2D_VAlignedTransparent();
						}
						else
						{
							ScanDraw2D_VAlignedOpaque();
						}

					}
					else
					{
						if(pheader->PolyFlags & iflag_ignore0)
						{
						   	ScanDraw2D_Transparent();
						}
						else
						{
							ScanDraw2D_Opaque();
						}
					}
				}
				sptr++;
			}
		}
		#if 1
		else
		{
			int y;
			I_2DTEXTUREPOLYGON_SCAN *sptr = (I_2DTEXTUREPOLYGON_SCAN *) ScanData;
			/* Offset in Screen Buffer */
			{
				IMAGEHEADER *ImageHdr;
				{
					int TxIndex  = ItemColour & ClrTxDefn;
					ImageHdr = ImageHeaderPtrs[TxIndex];
				}
				if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip)
				{
					TEXTURE **TxImagePtr = &ImageHdr->ImagePtr;
					SCASM_Bitmap = TxImagePtr[MIP_Index];
					GLOBALASSERT(SCASM_Bitmap);
					SCASM_TextureDeltaScan = ImageHdr->ImageWidth >> MIP_Index;
					#if MIP_ROUNDUP
					if (ImageHdr->ImageWidth & (1<<MIP_Index)-1) ++SCASM_TextureDeltaScan;
					#endif
				}
				else
				{
					SCASM_TextureDeltaScan = ImageHdr->ImageWidth;
					SCASM_Bitmap = ImageHdr->ImagePtr;
					GLOBALASSERT(SCASM_Bitmap);
				}
			}
			SCASM_StartI = ItemColour >> TxDefn;
			
			SCASM_Lighting = TextureLightingTable;
			
			if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_Raw256) SCASM_ShadingTableSize = 256;
			else SCASM_ShadingTableSize = 64;
			
		
			/* Get the Image Data required for the Draw */
			for(y=NumScans; y!=0; y--)
			{
				int dx = sptr->i2s_x2 - sptr->i2s_x1;
				if (dx>0 && !(sptr->i2s_y & KRenderDrawMode) )
				{
					/* Fixed Point U for Interpolation */
					{
						int StartU = sptr->i2s_u1;
						SCASM_DeltaU = (sptr->i2s_u2 - StartU)/dx;
						SCASM_StartU = StartU;
					}
					
					/* Fixed Point V for Interpolation */
					{
						int StartV = sptr->i2s_v1;
						SCASM_DeltaV = (sptr->i2s_v2 - StartV)/dx;
						SCASM_StartV = StartV;
					}

					SCASM_Destination = ScreenBuffer + (sptr->i2s_y * BackBufferPitch) + sptr->i2s_x1;
					SCASM_ScanLength = dx;

	   	  	   	 	ScanDraw2D_TransparentLit();
	   	  	   	 //	PredatorScanDraw();
				}
				sptr++;
			}


		}
		#endif
	}

}
unsigned char LighterTable[255];
int predatorTimer = 0;
void ScanDraw_CloakedScan(void)
{
	unsigned char *screen = SCASM_Destination;
	int x = SCASM_ScanLength;

	unsigned char buffer[1000];
	do
	{
		buffer[x] =	*screen++;
	}
	while(--x);

	screen = SCASM_Destination;
	x = SCASM_ScanLength;

	if (FastRandom()&3==3 && x>2)
	{
		x--;
		screen++;
	}
	if (FastRandom()&3==3 && x>2)
	{
		x--;
	}

	do
	{
		{
			extern sine[];
			extern cosine[];
			unsigned char colour;
			int offset = (GetCos( ((x*2047)/SCASM_ScanLength + predatorTimer)&4095 )+65536)/2;
	   		offset = MUL_FIXED(offset,offset);
		  	colour = (buffer[SCASM_ScanLength-x+1]);
	//	  	colour = (buffer[x]);
			#if 0
			int i;
			for (i=0; i<=255;i++)
			{
				if (colour==*(TextureLightingTable + 256*200 + i))	break;
			}
			#endif
	 		colour=*(TextureLightingTable + 256*(60+MUL_FIXED(4,GetCos(predatorTimer&4095)) ) + colour);
			*screen++ = colour;

		}
	}
	while(--x);

}
#if 0
void PredatorScanDraw(void)
{
	unsigned char *screen = SCASM_Destination;
	unsigned char *source;

	do
	{
		source = SCASM_Bitmap+ (SCASM_StartU>>16) + (SCASM_StartV>>16)*SCASM_TextureDeltaScan;

		*screen++ = *source++;

		SCASM_StartU += SCASM_DeltaU;
		SCASM_StartV += SCASM_DeltaV;
	}
	while(--SCASM_ScanLength);

}
#else
void PredatorScanDraw(void)						   
{
	unsigned char *screen = SCASM_Destination;
	unsigned char *source;
	int x = SCASM_ScanLength;
	do
	{
		source = SCASM_Bitmap+ (SCASM_StartU>>16) + (SCASM_StartV>>16)*SCASM_TextureDeltaScan;

		if (*source) 
		{
			extern sine[];
			extern cosine[];
			unsigned char colour = *(screen);
 	  		*screen = LighterTable[colour];
		}
		screen++;
		SCASM_StartU += SCASM_DeltaU;
		SCASM_StartV += SCASM_DeltaV;
	}
	while(--x);

}
#endif

void Draw_Item_CloakedPolygon(int *itemptr)
{
	POLYHEADER *pheader = (POLYHEADER *)itemptr;
	int minYVertex = 0;
	int maxYVertex = 0;
	int maxVertexNum = 0;

	{
		I_GOURAUDPOLYGON_PT *vertexPtr = (I_GOURAUDPOLYGON_PT*)&pheader->Poly1stPt;
		int minY = vertexPtr->i_y;
		int maxY = vertexPtr->i_y;
		vertexPtr++;

		do
		{
			maxVertexNum++;
		
			if (minY > vertexPtr->i_y)
			{
				minY = vertexPtr->i_y;
				minYVertex = maxVertexNum;
			}
			else if (maxY < vertexPtr->i_y)
			{
				maxY = vertexPtr->i_y;
				maxYVertex = maxVertexNum;
			}
			vertexPtr++;
		}
		while(vertexPtr->i_x != Term);

	}

	
	/* Initialise the Scan Data Buffer */
	{
		I_GOURAUDPOLYGON_PT *vertexPtr = (I_GOURAUDPOLYGON_PT*)&pheader->Poly1stPt;
		I_GOURAUDPOLYGON_SCAN *polyScan;
		int curVertex;
		int SecondOpinion=0;
			
		NumScans=0;
		/* scan out the right edge */
		polyScan = (I_GOURAUDPOLYGON_SCAN*)ScanData;
		curVertex = minYVertex;
		do
		{
			int height;
			int i,x,y;
			int deltaX,deltaI;

			int nextVertex = curVertex-1;
			if (nextVertex<0) nextVertex = maxVertexNum;
			
			height = vertexPtr[nextVertex].i_y - vertexPtr[curVertex].i_y;
			if (height!=0)
			{
				int width = vertexPtr[nextVertex].i_x - vertexPtr[curVertex].i_x;
				int contrast = vertexPtr[nextVertex].i_int - vertexPtr[curVertex].i_int;

				deltaX = (width<<16)/height;
				deltaI = contrast/height;

				x = vertexPtr[curVertex].i_x<<16;
				i = vertexPtr[curVertex].i_int;

				for (y=vertexPtr[curVertex].i_y; y<vertexPtr[nextVertex].i_y; y++)
				{
					polyScan->igs_x2 = x>>16;
					x+=deltaX;
					polyScan->igs_c2 = i;
					i+=deltaI;

					polyScan->igs_y = y;
					NumScans++;
					polyScan++;
				}
			}
			curVertex--;
			if (curVertex<0) curVertex = maxVertexNum;

		}
		while(curVertex!=maxYVertex);

		/* scan out the left edge */
		polyScan = (I_GOURAUDPOLYGON_SCAN*)ScanData;
		curVertex = minYVertex;
		do
		{
			int height;
			int i,x,y;
			int deltaX,deltaI;

			int nextVertex = curVertex+1;
			if (nextVertex>maxVertexNum) nextVertex = 0;
			
			height = vertexPtr[nextVertex].i_y - vertexPtr[curVertex].i_y;
			if (height!=0)
			{
				int width = vertexPtr[nextVertex].i_x - vertexPtr[curVertex].i_x;
				int contrast = vertexPtr[nextVertex].i_int - vertexPtr[curVertex].i_int;

				deltaX = (width<<16)/height;
				deltaI = contrast/height;

				x = vertexPtr[curVertex].i_x<<16;
				i = vertexPtr[curVertex].i_int;

				for (y=vertexPtr[curVertex].i_y; y<vertexPtr[nextVertex].i_y; y++)
				{
					polyScan->igs_x1 = x>>16;
					x+=deltaX;
					polyScan->igs_c1 = i;
					i+=deltaI;
					
					SecondOpinion++;
					polyScan++;
				}
			}
			curVertex++;
			if (curVertex>maxVertexNum) curVertex = 0;

		}
		while(curVertex!=maxYVertex);

		if (SecondOpinion<NumScans)
		{
			textprint("WARNING: Rasterization error\n");
			NumScans = SecondOpinion;
//			LOCALASSERT(0);
  			return;
  		}

	}

	//draw 'em
	
	{
		unsigned char colour= pheader->PolyColour;
		I_GOURAUDPOLYGON_SCAN *polyScan;
		polyScan = (I_GOURAUDPOLYGON_SCAN*)ScanData;
		SCASM_Lighting = TextureLightingTable+colour;
		SCASM_ShadingTableSize = 256;

		while(NumScans)
		{
			int dx = polyScan->igs_x2 - polyScan->igs_x1;
			if (dx>0)
			{
				SCASM_Destination = ScreenBuffer+(polyScan->igs_y * BackBufferPitch) + polyScan->igs_x1;
				SCASM_ScanLength = dx;
				SCASM_DeltaI = (polyScan->igs_c2-polyScan->igs_c1)/dx;
				SCASM_StartI = polyScan->igs_c1;
			   	ScanDraw_CloakedScan();
			}
			NumScans--;
			polyScan++;
		}
	}
}
#if 1
void KDraw_Item_GouraudPolygon(int *itemptr)
{
	POLYHEADER *pheader = (POLYHEADER *)itemptr;
	int minYVertex = 0;
	int maxYVertex = 0;
	int maxVertexNum = 0;

	{
		I_GOURAUDPOLYGON_PT *vertexPtr = (I_GOURAUDPOLYGON_PT*)&pheader->Poly1stPt;
		int minY = vertexPtr->i_y;
		int maxY = vertexPtr->i_y;
		vertexPtr++;

		do
		{
			maxVertexNum++;
		
			if (minY > vertexPtr->i_y)
			{
				minY = vertexPtr->i_y;
				minYVertex = maxVertexNum;
			}
			else if (maxY < vertexPtr->i_y)
			{
				maxY = vertexPtr->i_y;
				maxYVertex = maxVertexNum;
			}
			vertexPtr++;
		}
		while(vertexPtr->i_x != Term);

	}

	
	/* Initialise the Scan Data Buffer */
	{
		I_GOURAUDPOLYGON_PT *vertexPtr = (I_GOURAUDPOLYGON_PT*)&pheader->Poly1stPt;
		I_GOURAUDPOLYGON_SCAN *polyScan;
		int curVertex;
		int SecondOpinion=0;
			
		NumScans=0;
		/* scan out the right edge */
		polyScan = (I_GOURAUDPOLYGON_SCAN*)ScanData;
		curVertex = minYVertex;
		do
		{
			int height;
			int i,x,y;
			int deltaX,deltaI;

			int nextVertex = curVertex-1;
			if (nextVertex<0) nextVertex = maxVertexNum;
			
			height = vertexPtr[nextVertex].i_y - vertexPtr[curVertex].i_y;
			if (height!=0)
			{
				int width = vertexPtr[nextVertex].i_x - vertexPtr[curVertex].i_x;
				int contrast = vertexPtr[nextVertex].i_int - vertexPtr[curVertex].i_int;

				deltaX = (width<<16)/height;
				deltaI = contrast/height;

				x = vertexPtr[curVertex].i_x<<16;
				i = vertexPtr[curVertex].i_int;

				for (y=vertexPtr[curVertex].i_y; y<vertexPtr[nextVertex].i_y; y++)
				{
					polyScan->igs_x2 = x>>16;
					x+=deltaX;
					polyScan->igs_c2 = i;
					i+=deltaI;

					polyScan->igs_y = y;
					NumScans++;
					polyScan++;
				}
			}
			curVertex--;
			if (curVertex<0) curVertex = maxVertexNum;

		}
		while(curVertex!=maxYVertex);

		/* scan out the left edge */
		polyScan = (I_GOURAUDPOLYGON_SCAN*)ScanData;
		curVertex = minYVertex;
		do
		{
			int height;
			int i,x,y;
			int deltaX,deltaI;

			int nextVertex = curVertex+1;
			if (nextVertex>maxVertexNum) nextVertex = 0;
			
			height = vertexPtr[nextVertex].i_y - vertexPtr[curVertex].i_y;
			if (height!=0)
			{
				int width = vertexPtr[nextVertex].i_x - vertexPtr[curVertex].i_x;
				int contrast = vertexPtr[nextVertex].i_int - vertexPtr[curVertex].i_int;

				deltaX = (width<<16)/height;
				deltaI = contrast/height;

				x = vertexPtr[curVertex].i_x<<16;
				i = vertexPtr[curVertex].i_int;

				for (y=vertexPtr[curVertex].i_y; y<vertexPtr[nextVertex].i_y; y++)
				{
					polyScan->igs_x1 = x>>16;
					x+=deltaX;
					polyScan->igs_c1 = i;
					i+=deltaI;
					
					SecondOpinion++;
					polyScan++;
				}
			}
			curVertex++;
			if (curVertex>maxVertexNum) curVertex = 0;

		}
		while(curVertex!=maxYVertex);

		if (SecondOpinion<NumScans)
		{
			textprint("WARNING: Rasterization error\n");
			NumScans = SecondOpinion;
//			LOCALASSERT(0);
  			return;
  		}

	}

	//draw 'em
	
	{
		unsigned char colour= pheader->PolyColour;
		I_GOURAUDPOLYGON_SCAN *polyScan;
		polyScan = (I_GOURAUDPOLYGON_SCAN*)ScanData;
		SCASM_Lighting = TextureLightingTable+colour;
		SCASM_ShadingTableSize = 256;

		while(NumScans)
		{
			int dx = polyScan->igs_x2 - polyScan->igs_x1;
			if (dx>0)
			{
				SCASM_Destination = ScreenBuffer+(polyScan->igs_y * BackBufferPitch) + polyScan->igs_x1;
				SCASM_ScanLength = dx;
				SCASM_DeltaI = (polyScan->igs_c2-polyScan->igs_c1)/dx;
				SCASM_StartI = polyScan->igs_c1;
			   	ScanDraw_GouraudScan();
			}
			NumScans--;
			polyScan++;
		}
	}
}
void KDraw_Item_2dTexturePolygon(int *itemptr)
{
	
	POLYHEADER *pheader = (POLYHEADER *) itemptr;
	int TxIndex;
	IMAGEHEADER *ImageHdr;
	ItemColour = pheader->PolyColour;

	TxIndex  = ItemColour & ClrTxDefn;
	ImageHdr = ImageHeaderPtrs[TxIndex];


	/* Colour */
	
	/* If MIP Mapping, calculate the scale */

	if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip)
	{
		I_2DTEXTUREPOLYGON_PT *vector1;
		I_2DTEXTUREPOLYGON_PT *vector2;
		I_2DTEXTUREPOLYGON_PT *vector3;
		int mip1, mip2;
		int xyd, uvd;
		VECTOR2D s0, s1;
		VECTOR2D t0, t1;


		/* Screen and Texture Space Vectors */
		/* Express the "uvd / xyd" ratio as a binary scale */

		vector1 = (I_2DTEXTUREPOLYGON_PT *) &pheader->Poly1stPt;
		vector2 = &vector1[1];
		vector3 = &vector1[2];


		/* Vector 1 */

		s0.vx = vector1->i_x;
		s0.vy = vector1->i_y;
		s1.vx = vector2->i_x;
		s1.vy = vector2->i_y;

		t0.vx = vector1->i_u >> 16;
		t0.vy = vector1->i_v >> 16;
		t1.vx = vector2->i_u >> 16;
		t1.vy = vector2->i_v >> 16;

		xyd = FandVD_Distance_2d(&s0, &s1);
		uvd = FandVD_Distance_2d(&t0, &t1);

		mip1 = FindShift32(uvd, xyd);


		/* Vector 2 */

		s0.vx = vector2->i_x;
		s0.vy = vector2->i_y;
		s1.vx = vector3->i_x;
		s1.vy = vector3->i_y;

		t0.vx = t1.vx;
		t0.vy = t1.vy;
		t1.vx = vector3->i_u >> 16;
		t1.vy = vector3->i_v >> 16;

		xyd = FandVD_Distance_2d(&s0, &s1);
		uvd = FandVD_Distance_2d(&t0, &t1);

		mip2 = FindShift32(uvd, xyd);


		/* Choose the larger of the two */

		if(pheader->PolyFlags & iflag_no_mip) {

			MIP_Index = 0;

		}

		else {

			#if UseMIPMax
			if(mip1 > mip2)
				MIP_Index = mip1;
			else
				MIP_Index = mip2;
			#endif

			#if UseMIPMin
			if(mip1 > mip2)
				MIP_Index = mip2;
			else
				MIP_Index = mip1;
			#endif

			#if UseMIPAvg
			MIP_Index = (mip1 + mip2) >> 1;
			#endif

		}


		/* Clamp "MIP_Index" */

		#if MIP_INDEX_SUBTRACT

			MIP_Index -= MIP_INDEX_SUBTRACT;
			if(MIP_Index < 0) MIP_Index = 0;
			else if(MIP_Index > 6) MIP_Index = 6;

		#else

			if(MIP_Index > 6) MIP_Index = 6;

		#endif

	}

    {
		int minYVertex = 0;
		int maxYVertex = 0;
		int maxVertexNum = 0;

		{
			I_2DTEXTUREPOLYGON_PT *vertexPtr = (I_2DTEXTUREPOLYGON_PT*)&pheader->Poly1stPt;
			int minY = vertexPtr->i_y;
			int maxY = vertexPtr->i_y;
			
			if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip)
			{
				vertexPtr->i_u >>= MIP_Index;
				vertexPtr->i_v >>= MIP_Index;
			}
			vertexPtr++;

			do
			{
				maxVertexNum++;
			
				if (minY > vertexPtr->i_y)
				{
					minY = vertexPtr->i_y;
					minYVertex = maxVertexNum;
				}
				else if (maxY < vertexPtr->i_y)
				{
					maxY = vertexPtr->i_y;
					maxYVertex = maxVertexNum;
				}
				
				if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip)
				{
					vertexPtr->i_u >>= MIP_Index;
					vertexPtr->i_v >>= MIP_Index;
				}
							
				vertexPtr++;
			}
			while(vertexPtr->i_x != Term);

		}

		
		/* Initialise the Scan Data Buffer */
		{
			I_2DTEXTUREPOLYGON_PT *vertexPtr = (I_2DTEXTUREPOLYGON_PT*)&pheader->Poly1stPt;
			I_2DTEXTUREPOLYGON_SCAN *polyScan;
			int curVertex;
			int SecondOpinion = 0;
				
			NumScans=0;
			/* scan out the right edge */
			polyScan = (I_2DTEXTUREPOLYGON_SCAN*)ScanData;
			curVertex = minYVertex;
			do
			{
				int height;

				int nextVertex = curVertex-1;
				if (nextVertex<0) nextVertex = maxVertexNum;
				
				height = vertexPtr[nextVertex].i_y - vertexPtr[curVertex].i_y;
				if (height!=0)
				{
					int x,y,u,v;
					int deltaX,deltaU,deltaV;
					int width = vertexPtr[nextVertex].i_x - vertexPtr[curVertex].i_x;
					int widthU = vertexPtr[nextVertex].i_u - vertexPtr[curVertex].i_u;
					int widthV = vertexPtr[nextVertex].i_v - vertexPtr[curVertex].i_v;

					deltaX = (width<<16)/height;
					deltaU = widthU/height;
					deltaV = widthV/height;

					x = vertexPtr[curVertex].i_x<<16;
					u = vertexPtr[curVertex].i_u;
					v = vertexPtr[curVertex].i_v;

					for (y=vertexPtr[curVertex].i_y; y<vertexPtr[nextVertex].i_y; y++)
					{
						polyScan->i2s_x2 = x>>16;
						x+=deltaX;
						polyScan->i2s_u2 = u;
						u+=deltaU;
						polyScan->i2s_v2 = v;
						v+=deltaV;

						polyScan->i2s_y = y;
						NumScans++;
						polyScan++;
					}
				}
				curVertex--;
				if (curVertex<0) curVertex = maxVertexNum;

			}
			while(curVertex!=maxYVertex);
	
			/* scan out the left edge */
			polyScan = (I_2DTEXTUREPOLYGON_SCAN*)ScanData;
			curVertex = minYVertex;
			do
			{
				int height;

				int nextVertex = curVertex+1;
				if (nextVertex>maxVertexNum) nextVertex = 0;
				
				height = vertexPtr[nextVertex].i_y - vertexPtr[curVertex].i_y;
				if (height!=0)
				{
					int x,y,u,v;
					int deltaX,deltaU,deltaV;
					int width = vertexPtr[nextVertex].i_x - vertexPtr[curVertex].i_x;
					int widthU = vertexPtr[nextVertex].i_u - vertexPtr[curVertex].i_u;
					int widthV = vertexPtr[nextVertex].i_v - vertexPtr[curVertex].i_v;

					deltaX = (width<<16)/height;
					deltaU = widthU/height;
					deltaV = widthV/height;

					x = vertexPtr[curVertex].i_x<<16;
					u = vertexPtr[curVertex].i_u;
					v = vertexPtr[curVertex].i_v;

					for (y=vertexPtr[curVertex].i_y; y<vertexPtr[nextVertex].i_y; y++)
					{
						polyScan->i2s_x1 = x>>16;
						x+=deltaX;
						polyScan->i2s_u1 = u;
						u+=deltaU;
						polyScan->i2s_v1 = v;
						v+=deltaV;

						SecondOpinion++;
						polyScan++;
					}
				}
				curVertex++;
				if (curVertex>maxVertexNum) curVertex = 0;

			}
			while(curVertex!=maxYVertex);

			if (SecondOpinion<NumScans)
			{
				textprint("WARNING: Rasterization error\n");
				NumScans = SecondOpinion;
//				LOCALASSERT(0);
				return;
			}
		}

		//draw 'em
		KR_ScanDraw_Item_2dTexturePolygon_VideoModeType_8(itemptr);
		
	}	
}
void KDraw_Item_Gouraud2dTexturePolygon(int *itemptr)
{
	POLYHEADER *pheader = (POLYHEADER *) itemptr;
	int TxIndex;
	IMAGEHEADER *ImageHdr;
	ItemColour = pheader->PolyColour;

	TxIndex  = ItemColour & ClrTxDefn;
	ImageHdr = ImageHeaderPtrs[TxIndex];



	/* Colour */


	/* If MIP Mapping, calculate the scale */

	if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip)
	{
		I_GOURAUD2DTEXTUREPOLYGON_PT *vector1;
		I_GOURAUD2DTEXTUREPOLYGON_PT *vector2;
		I_GOURAUD2DTEXTUREPOLYGON_PT *vector3;
		int mip1, mip2;
		int xyd, uvd;
		VECTOR2D s0, s1;
		VECTOR2D t0, t1;


		/* Screen and Texture Space Vectors */
		/* Express the "uvd / xyd" ratio as a binary scale */

		vector1 = (I_GOURAUD2DTEXTUREPOLYGON_PT *) &pheader->Poly1stPt;
		vector2 = &vector1[1];
		vector3 = &vector1[2];


		/* Vector 1 */

		s0.vx = vector1->i_x;
		s0.vy = vector1->i_y;
		s1.vx = vector2->i_x;
		s1.vy = vector2->i_y;

		t0.vx = vector1->i_u >> 16;
		t0.vy = vector1->i_v >> 16;
		t1.vx = vector2->i_u >> 16;
		t1.vy = vector2->i_v >> 16;

		xyd = FandVD_Distance_2d(&s0, &s1);
		uvd = FandVD_Distance_2d(&t0, &t1);

		mip1 = FindShift32(uvd, xyd);


		/* Vector 2 */

		s0.vx = vector2->i_x;
		s0.vy = vector2->i_y;
		s1.vx = vector3->i_x;
		s1.vy = vector3->i_y;

		t0.vx = t1.vx;
		t0.vy = t1.vy;
		t1.vx = vector3->i_u >> 16;
		t1.vy = vector3->i_v >> 16;

		xyd = FandVD_Distance_2d(&s0, &s1);
		uvd = FandVD_Distance_2d(&t0, &t1);

		mip2 = FindShift32(uvd, xyd);


		/* Choose the larger of the two */

		if(pheader->PolyFlags & iflag_no_mip) {

			MIP_Index = 0;

		}

		else {

			#if UseMIPMax
			if(mip1 > mip2)
				MIP_Index = mip1;
			else
				MIP_Index = mip2;
			#endif

			#if UseMIPMin
			if(mip1 > mip2)
				MIP_Index = mip2;
			else
				MIP_Index = mip1;
			#endif

			#if UseMIPAvg
			MIP_Index = (mip1 + mip2) >> 1;
			#endif

		}


		/* Clamp "MIP_Index" */

		#if MIP_INDEX_SUBTRACT

			MIP_Index -= MIP_INDEX_SUBTRACT;
			if(MIP_Index < 0) MIP_Index = 0;
			else if(MIP_Index > 6) MIP_Index = 6;

		#else

			if(MIP_Index > 6) MIP_Index = 6;

		#endif

	}

    {
		int minYVertex = 0;
		int maxYVertex = 0;
		int maxVertexNum = 0;

		{
			I_GOURAUD2DTEXTUREPOLYGON_PT *vertexPtr = (I_GOURAUD2DTEXTUREPOLYGON_PT*)&pheader->Poly1stPt;
			int minY = vertexPtr->i_y;
			int maxY = vertexPtr->i_y;
			
			if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip)
			{
				vertexPtr->i_u >>= MIP_Index;
				vertexPtr->i_v >>= MIP_Index;
			}
			vertexPtr++;

			do
			{
				maxVertexNum++;
			
				if (minY > vertexPtr->i_y)
				{
					minY = vertexPtr->i_y;
					minYVertex = maxVertexNum;
				}
				else if (maxY < vertexPtr->i_y)
				{
					maxY = vertexPtr->i_y;
					maxYVertex = maxVertexNum;
				}
				
				if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip)
				{
					vertexPtr->i_u >>= MIP_Index;
					vertexPtr->i_v >>= MIP_Index;
				}
							
				vertexPtr++;
			}
			while(vertexPtr->i_x != Term);

		}

		
		/* Initialise the Scan Data Buffer */
		{
			I_GOURAUD2DTEXTUREPOLYGON_PT *vertexPtr = (I_GOURAUD2DTEXTUREPOLYGON_PT*)&pheader->Poly1stPt;
			I_GOURAUD2DTEXTUREPOLYGON_SCAN *polyScan;
			int curVertex;
			int SecondOpinion=0;
				
			NumScans=0;
			/* scan out the right edge */
			polyScan = (I_GOURAUD2DTEXTUREPOLYGON_SCAN*)ScanData;
			curVertex = minYVertex;
			do
			{
				int height;

				int nextVertex = curVertex-1;
				if (nextVertex<0) nextVertex = maxVertexNum;
				
				height = vertexPtr[nextVertex].i_y - vertexPtr[curVertex].i_y;
				if (height!=0)
				{
					int i,x,y,u,v;
					int deltaX,deltaI,deltaU,deltaV;
					int width = vertexPtr[nextVertex].i_x - vertexPtr[curVertex].i_x;
					int contrast = vertexPtr[nextVertex].i_i - vertexPtr[curVertex].i_i;
					int widthU = vertexPtr[nextVertex].i_u - vertexPtr[curVertex].i_u;
					int widthV = vertexPtr[nextVertex].i_v - vertexPtr[curVertex].i_v;

					deltaX = (width<<16)/height;
					deltaI = contrast/height;
					deltaU = widthU/height;
					deltaV = widthV/height;

					x = vertexPtr[curVertex].i_x<<16;
					i = vertexPtr[curVertex].i_i;
					u = vertexPtr[curVertex].i_u;
					v = vertexPtr[curVertex].i_v;

					for (y=vertexPtr[curVertex].i_y; y<vertexPtr[nextVertex].i_y; y++)
					{
						polyScan->ig2s_x2 = x>>16;
						x+=deltaX;
						polyScan->ig2s_c2 = i;
						i+=deltaI;
						polyScan->ig2s_u2 = u;
						u+=deltaU;
						polyScan->ig2s_v2 = v;
						v+=deltaV;

						polyScan->ig2s_y = y;
						NumScans++;
						polyScan++;
					}
				}
				curVertex--;
				if (curVertex<0) curVertex = maxVertexNum;

			}
			while(curVertex!=maxYVertex);
	
			/* scan out the left edge */
			polyScan = (I_GOURAUD2DTEXTUREPOLYGON_SCAN*)ScanData;
			curVertex = minYVertex;
			do
			{
				int height;

				int nextVertex = curVertex+1;
				if (nextVertex>maxVertexNum) nextVertex = 0;
				
				height = vertexPtr[nextVertex].i_y - vertexPtr[curVertex].i_y;
				if (height!=0)
				{
					int i,x,y,u,v;
					int deltaX,deltaI,deltaU,deltaV;
					int width = vertexPtr[nextVertex].i_x - vertexPtr[curVertex].i_x;
					int contrast = vertexPtr[nextVertex].i_i - vertexPtr[curVertex].i_i;
					int widthU = vertexPtr[nextVertex].i_u - vertexPtr[curVertex].i_u;
					int widthV = vertexPtr[nextVertex].i_v - vertexPtr[curVertex].i_v;

					deltaX = (width<<16)/height;
					deltaI = contrast/height;
					deltaU = widthU/height;
					deltaV = widthV/height;

					x = vertexPtr[curVertex].i_x<<16;
					i = vertexPtr[curVertex].i_i;
					u = vertexPtr[curVertex].i_u;
					v = vertexPtr[curVertex].i_v;

					for (y=vertexPtr[curVertex].i_y; y<vertexPtr[nextVertex].i_y; y++)
					{
						polyScan->ig2s_x1 = x>>16;
						x+=deltaX;
						polyScan->ig2s_c1 = i;
						i+=deltaI;
						polyScan->ig2s_u1 = u;
						u+=deltaU;
						polyScan->ig2s_v1 = v;
						v+=deltaV;

						SecondOpinion++;
						polyScan++;
					}
				}
				curVertex++;
				if (curVertex>maxVertexNum) curVertex = 0;

			}
			while(curVertex!=maxYVertex);
		
			if (SecondOpinion<NumScans)
			{
				textprint("WARNING: Rasterization error\n");
				NumScans = SecondOpinion;
//				LOCALASSERT(0);
				return;
			}
		}
		//draw 'em
		KR_ScanDraw_Item_Gouraud2dTexturePolygon_VideoModeType_8(itemptr);
		
		#if 0
		{
			unsigned char colour= pheader->PolyColour;
			I_GOURAUD2DTEXTUREPOLYGON_SCAN *polyScan;
			polyScan = (I_GOURAUD2DTEXTUREPOLYGON_SCAN*)ScanData;
			SCASM_Lighting = TextureLightingTable+colour;
			SCASM_ShadingTableSize = 256;

			while(NumScans)
			{
				int dx = polyScan->ig2s_x2 - polyScan->ig2s_x1;
				if (dx>0)
				{
					SCASM_Destination = ScreenBuffer+(polyScan->ig2s_y * BackBufferPitch) + polyScan->ig2s_x1;
					SCASM_ScanLength = dx;
					SCASM_DeltaI = (polyScan->ig2s_c2-polyScan->ig2s_c1)/dx;
					SCASM_StartI = polyScan->ig2s_c1;
				   	ScanDraw_GouraudScan();
				}
				NumScans--;
				polyScan++;
			}
		}
		#endif
	}	
}
#endif
#if 0
void KDraw_Item_Gouraud3dTexturePolygon(int *itemptr)
{
	POLYHEADER *pheader = (POLYHEADER *) itemptr;
	int TxIndex;
	IMAGEHEADER *ImageHdr;
	ItemColour = pheader->PolyColour;

	TxIndex  = ItemColour & ClrTxDefn;
	ImageHdr = ImageHeaderPtrs[TxIndex];



	/* Colour */


	/* If MIP Mapping, calculate the scale */

	if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip)
	{
		I_GOURAUD3DTEXTUREPOLYGON_PT *vector1;
		I_GOURAUD3DTEXTUREPOLYGON_PT *vector2;
		I_GOURAUD3DTEXTUREPOLYGON_PT *vector3;
		int mip1, mip2;
		int xyd, uvd;
		VECTOR2D s0, s1;
		VECTOR2D t0, t1;


		/* Screen and Texture Space Vectors */
		/* Express the "uvd / xyd" ratio as a binary scale */

		vector1 = (I_GOURAUD3DTEXTUREPOLYGON_PT *) &pheader->Poly1stPt;
		vector2 = &vector1[1];
		vector3 = &vector1[2];


		/* Vector 1 */

		s0.vx = vector1->i_x;
		s0.vy = vector1->i_y;
		s1.vx = vector2->i_x;
		s1.vy = vector2->i_y;

		t0.vx = vector1->i_gtx3d_u / vector1->i_gtx3d_z;
		t0.vy = vector1->i_gtx3d_v / vector1->i_gtx3d_z;
		t1.vx = vector2->i_gtx3d_u / vector2->i_gtx3d_z;
		t1.vy = vector2->i_gtx3d_v / vector2->i_gtx3d_z;

		xyd = FandVD_Distance_2d(&s0, &s1);
		uvd = FandVD_Distance_2d(&t0, &t1);

		mip1 = FindShift32(uvd, xyd);


		/* Vector 2 */

		s0.vx = vector2->i_x;
		s0.vy = vector2->i_y;
		s1.vx = vector3->i_x;
		s1.vy = vector3->i_y;

		t0.vx = t1.vx;
		t0.vy = t1.vy;
		t1.vx = vector3->i_gtx3d_u / vector3->i_gtx3d_z;
		t1.vy = vector3->i_gtx3d_v / vector3->i_gtx3d_z;

		xyd = FandVD_Distance_2d(&s0, &s1);
		uvd = FandVD_Distance_2d(&t0, &t1);

		mip2 = FindShift32(uvd, xyd);


		/* Choose the larger of the two */

		if(pheader->PolyFlags & iflag_no_mip) {

			MIP_Index = 0;

		}

		else {

			#if UseMIPMax
			if(mip1 > mip2)
				MIP_Index = mip1;
			else
				MIP_Index = mip2;
			#endif

			#if UseMIPMin
			if(mip1 > mip2)
				MIP_Index = mip2;
			else
				MIP_Index = mip1;
			#endif

			#if UseMIPAvg
			MIP_Index = (mip1 + mip2) >> 1;
			#endif

		}


		/* Clamp "MIP_Index" */

		#if MIP_INDEX_SUBTRACT

			MIP_Index -= MIP_INDEX_SUBTRACT;
			if(MIP_Index < 0) MIP_Index = 0;
			else if(MIP_Index > 6) MIP_Index = 6;

		#else

			if(MIP_Index > 6) MIP_Index = 6;

		#endif

	}

    {
		int minYVertex = 0;
		int maxYVertex = 0;
		int maxVertexNum = 0;
		float MIP_Divide = 1<<MIP_Index;

		{
			I_GOURAUD3DTEXTUREPOLYGON_PT *vertexPtr = (I_GOURAUD3DTEXTUREPOLYGON_PT*)&pheader->Poly1stPt;
			int minY = vertexPtr->i_y;
			int maxY = vertexPtr->i_y;
			
			if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip)
			{
				vertexPtr->i_gtx3d_u /= MIP_Divide;
				vertexPtr->i_gtx3d_v /= MIP_Divide;
			}
			vertexPtr++;

			do
			{
				maxVertexNum++;
			
				if (minY > vertexPtr->i_y)
				{
					minY = vertexPtr->i_y;
					minYVertex = maxVertexNum;
				}
				else if (maxY < vertexPtr->i_y)
				{
					maxY = vertexPtr->i_y;
					maxYVertex = maxVertexNum;
				}
				
				if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip)
				{
					vertexPtr->i_gtx3d_u /= MIP_Divide;
					vertexPtr->i_gtx3d_v /= MIP_Divide;
				}
							
				vertexPtr++;
			}
			while(vertexPtr->i_x != Term);

		}

		
		/* Initialise the Scan Data Buffer */
		{
			I_GOURAUD3DTEXTUREPOLYGON_PT *vertexPtr = (I_GOURAUD3DTEXTUREPOLYGON_PT*)&pheader->Poly1stPt;
			I_GOURAUD3DTEXTUREPOLYGON_SCAN *polyScan;
			int curVertex;
			int SecondOpinion=0;
				
			NumScans=0;
			
			/* scan out the right edge */
			polyScan = (I_GOURAUD3DTEXTUREPOLYGON_SCAN*)ScanData;
			curVertex = minYVertex;
			do
			{
				int height;

				int nextVertex = curVertex-1;
				if (nextVertex<0) nextVertex = maxVertexNum;
				
				height = vertexPtr[nextVertex].i_y - vertexPtr[curVertex].i_y;
				if (height!=0)
				{
					int i,x,y;
					float u,v,z;
					int deltaX,deltaI;
					float deltaU,deltaV,deltaZ;

					int width = vertexPtr[nextVertex].i_x - vertexPtr[curVertex].i_x;
					int contrast = vertexPtr[nextVertex].i_gtx3d_i - vertexPtr[curVertex].i_gtx3d_i;
					float widthU = vertexPtr[nextVertex].i_gtx3d_u - vertexPtr[curVertex].i_gtx3d_u;
					float widthV = vertexPtr[nextVertex].i_gtx3d_v - vertexPtr[curVertex].i_gtx3d_v;
					float widthZ = vertexPtr[nextVertex].i_gtx3d_z - vertexPtr[curVertex].i_gtx3d_z;

					deltaX = (width<<16)/height;
					deltaI = contrast/height;
					deltaU = widthU/height;
					deltaV = widthV/height;
					deltaZ = widthZ/height;

					x = vertexPtr[curVertex].i_x<<16;
					i = vertexPtr[curVertex].i_gtx3d_i;
					u = vertexPtr[curVertex].i_gtx3d_u;
					v = vertexPtr[curVertex].i_gtx3d_v;
					z = vertexPtr[curVertex].i_gtx3d_z;

					for (y=vertexPtr[curVertex].i_y; y<vertexPtr[nextVertex].i_y; y++)
					{
						polyScan->ig3s_x2 = x>>16;
						x+=deltaX;
						polyScan->ig3s_c2 = i;
						i+=deltaI;
						polyScan->ig3s_u2 = u;
						u+=deltaU;
						polyScan->ig3s_v2 = v;
						v+=deltaV;
						polyScan->ig3s_z2 = z;
						z+=deltaZ;

						polyScan->ig3s_y = y;
						NumScans++;
						polyScan++;
					}
				}
				curVertex--;
				if (curVertex<0) curVertex = maxVertexNum;

			}
			while(curVertex!=maxYVertex);
	
			/* scan out the left edge */
			polyScan = (I_GOURAUD3DTEXTUREPOLYGON_SCAN*)ScanData;
			curVertex = minYVertex;
			do
			{
				int height;

				int nextVertex = curVertex+1;
				if (nextVertex>maxVertexNum) nextVertex = 0;
				
				height = vertexPtr[nextVertex].i_y - vertexPtr[curVertex].i_y;
				if (height!=0)
				{
					int i,x,y;
					float u,v,z;
					int deltaX,deltaI;
					float deltaU,deltaV,deltaZ;

					int width = vertexPtr[nextVertex].i_x - vertexPtr[curVertex].i_x;
					int contrast = vertexPtr[nextVertex].i_gtx3d_i - vertexPtr[curVertex].i_gtx3d_i;
					float widthU = vertexPtr[nextVertex].i_gtx3d_u - vertexPtr[curVertex].i_gtx3d_u;
					float widthV = vertexPtr[nextVertex].i_gtx3d_v - vertexPtr[curVertex].i_gtx3d_v;
					float widthZ = vertexPtr[nextVertex].i_gtx3d_z - vertexPtr[curVertex].i_gtx3d_z;

					deltaX = (width<<16)/height;
					deltaI = contrast/height;
					deltaU = widthU/height;
					deltaV = widthV/height;
					deltaZ = widthZ/height;

					x = vertexPtr[curVertex].i_x<<16;
					i = vertexPtr[curVertex].i_gtx3d_i;
					u = vertexPtr[curVertex].i_gtx3d_u;
					v = vertexPtr[curVertex].i_gtx3d_v;
					z = vertexPtr[curVertex].i_gtx3d_z;

				 	for (y=vertexPtr[curVertex].i_y; y<vertexPtr[nextVertex].i_y; y++)
					{
						polyScan->ig3s_x1 = x>>16;
						x+=deltaX;
						polyScan->ig3s_c1 = i;
						i+=deltaI;
						polyScan->ig3s_u1 = u;
						u+=deltaU;
						polyScan->ig3s_v1 = v;
						v+=deltaV;
						polyScan->ig3s_z1 = z;
						z+=deltaZ;

						SecondOpinion++;
						polyScan++;
					}
				}
				curVertex++;
				if (curVertex>maxVertexNum) curVertex = 0;
			
			}
			while(curVertex!=maxYVertex);

			if (SecondOpinion<NumScans)
			{
				textprint("WARNING: Rasterization error\n");
				NumScans = SecondOpinion;
//				LOCALASSERT(0);
				return;
			}
		}

		//draw 'em
  		KR_ScanDraw_Item_Gouraud3dTexturePolygon_Linear_S_VideoModeType_8(itemptr);
	}
}
#else
void KDraw_Item_Gouraud3dTexturePolygon(int *itemptr)
{
	POLYHEADER *pheader = (POLYHEADER *) itemptr;
	int TxIndex;
	IMAGEHEADER *ImageHdr;
	ItemColour = pheader->PolyColour;

	TxIndex  = ItemColour & ClrTxDefn;
	ImageHdr = ImageHeaderPtrs[TxIndex];


  
    {
		int minYVertex = 0;
		int maxYVertex = 0;
		int maxVertexNum = 0;
  

		{
			I_GOURAUD3DTEXTUREPOLYGON_PT *vertexPtr = (I_GOURAUD3DTEXTUREPOLYGON_PT*)&pheader->Poly1stPt;
			int minY = vertexPtr->i_y;
			int maxY = vertexPtr->i_y;
			
			vertexPtr++;

			do
			{
				maxVertexNum++;
			
				if (minY > vertexPtr->i_y)
				{
					minY = vertexPtr->i_y;
					minYVertex = maxVertexNum;
				}
				else if (maxY < vertexPtr->i_y)
				{
					maxY = vertexPtr->i_y;
					maxYVertex = maxVertexNum;
				}
							
				vertexPtr++;
			}
			while(vertexPtr->i_x != Term);

		}

		
		/* Initialise the Scan Data Buffer */
		{
			I_GOURAUD3DTEXTUREPOLYGON_PT *vertexPtr = (I_GOURAUD3DTEXTUREPOLYGON_PT*)&pheader->Poly1stPt;
			I_GOURAUD3DTEXTUREPOLYGON_SCAN *polyScan;
			int curVertex;
			int SecondOpinion=0;
				
			NumScans=0;
			
			/* scan out the right edge */
			polyScan = (I_GOURAUD3DTEXTUREPOLYGON_SCAN*)ScanData;
			curVertex = minYVertex;
			do
			{
				int height;

				int nextVertex = curVertex-1;
				if (nextVertex<0) nextVertex = maxVertexNum;
				
				height = vertexPtr[nextVertex].i_y - vertexPtr[curVertex].i_y;
				if (height!=0)
				{
					int i,x,y;
					float u,v,z;
					int deltaX,deltaI;
					float deltaU,deltaV,deltaZ;

					int width = vertexPtr[nextVertex].i_x - vertexPtr[curVertex].i_x;
					int contrast = vertexPtr[nextVertex].i_gtx3d_i - vertexPtr[curVertex].i_gtx3d_i;
					float widthU = vertexPtr[nextVertex].i_gtx3d_u - vertexPtr[curVertex].i_gtx3d_u;
					float widthV = vertexPtr[nextVertex].i_gtx3d_v - vertexPtr[curVertex].i_gtx3d_v;
					float widthZ = vertexPtr[nextVertex].i_gtx3d_z - vertexPtr[curVertex].i_gtx3d_z;

					deltaX = (width<<16)/height;
					deltaI = contrast/height;
					deltaU = widthU/height;
					deltaV = widthV/height;
					deltaZ = widthZ/height;

					x = vertexPtr[curVertex].i_x<<16;
					i = vertexPtr[curVertex].i_gtx3d_i;
					u = vertexPtr[curVertex].i_gtx3d_u;
					v = vertexPtr[curVertex].i_gtx3d_v;
					z = vertexPtr[curVertex].i_gtx3d_z;

					for (y=vertexPtr[curVertex].i_y; y<vertexPtr[nextVertex].i_y; y++)
					{
						polyScan->ig3s_x2 = x>>16;
						x+=deltaX;
						polyScan->ig3s_c2 = i;
						i+=deltaI;
						polyScan->ig3s_u2 = u;
						u+=deltaU;
						polyScan->ig3s_v2 = v;
						v+=deltaV;
						polyScan->ig3s_z2 = z;
						z+=deltaZ;

						polyScan->ig3s_y = y;
						NumScans++;
						polyScan++;
					}
				}
				curVertex--;
				if (curVertex<0) curVertex = maxVertexNum;

			}
			while(curVertex!=maxYVertex);
	
			/* scan out the left edge */
			polyScan = (I_GOURAUD3DTEXTUREPOLYGON_SCAN*)ScanData;
			curVertex = minYVertex;
			do
			{
				int height;

				int nextVertex = curVertex+1;
				if (nextVertex>maxVertexNum) nextVertex = 0;
				
				height = vertexPtr[nextVertex].i_y - vertexPtr[curVertex].i_y;
				if (height!=0)
				{
					int i,x,y;
					float u,v,z;
					int deltaX,deltaI;
					float deltaU,deltaV,deltaZ;

					int width = vertexPtr[nextVertex].i_x - vertexPtr[curVertex].i_x;
					int contrast = vertexPtr[nextVertex].i_gtx3d_i - vertexPtr[curVertex].i_gtx3d_i;
					float widthU = vertexPtr[nextVertex].i_gtx3d_u - vertexPtr[curVertex].i_gtx3d_u;
					float widthV = vertexPtr[nextVertex].i_gtx3d_v - vertexPtr[curVertex].i_gtx3d_v;
					float widthZ = vertexPtr[nextVertex].i_gtx3d_z - vertexPtr[curVertex].i_gtx3d_z;

					deltaX = (width<<16)/height;
					deltaI = contrast/height;
					deltaU = widthU/height;
					deltaV = widthV/height;
					deltaZ = widthZ/height;

					x = vertexPtr[curVertex].i_x<<16;
					i = vertexPtr[curVertex].i_gtx3d_i;
					u = vertexPtr[curVertex].i_gtx3d_u;
					v = vertexPtr[curVertex].i_gtx3d_v;
					z = vertexPtr[curVertex].i_gtx3d_z;

				 	for (y=vertexPtr[curVertex].i_y; y<vertexPtr[nextVertex].i_y; y++)
					{
						polyScan->ig3s_x1 = x>>16;
						x+=deltaX;
						polyScan->ig3s_c1 = i;
						i+=deltaI;
						polyScan->ig3s_u1 = u;
						u+=deltaU;
						polyScan->ig3s_v1 = v;
						v+=deltaV;
						polyScan->ig3s_z1 = z;
						z+=deltaZ;

						SecondOpinion++;
						polyScan++;
					}
				}
				curVertex++;
				if (curVertex>maxVertexNum) curVertex = 0;
			
			}
			while(curVertex!=maxYVertex);

			if (SecondOpinion<NumScans)
			{
				textprint("WARNING: Rasterization error\n");
				NumScans = SecondOpinion;
//				LOCALASSERT(0);
				return;
			}
		}

		//draw 'em
  		Draw_Gouraud3dTexture_Spans(itemptr);
	}
}

#define PERS_STEP 16
void Draw_Gouraud3dTexture_Spans(int *itemptr)
{
	I_GOURAUD3DTEXTUREPOLYGON_SCAN *sptr;

	if(NumScans)
	{
		int y = NumScans;
		/* Get the Image Data required for the Draw */
		{
			IMAGEHEADER *ImageHdr;
			{
				int TxIndex  = ItemColour & ClrTxDefn;
				ImageHdr = ImageHeaderPtrs[TxIndex];
			}
			{
				SCASM_TextureDeltaScan = ImageHdr->ImageWidth;
				SCASM_Bitmap = ImageHdr->ImagePtr;
				GLOBALASSERT(SCASM_Bitmap);
			}
		}
		SCASM_Lighting = TextureLightingTable;
		
		sptr = (I_GOURAUD3DTEXTUREPOLYGON_SCAN *) ScanData;
		do
		{
			int length = sptr->ig3s_x2 - sptr->ig3s_x1;
			int dx=length;

			if (dx>0 && !(sptr->ig3s_y & KRenderDrawMode) )
			{
				float deltaZ;
				float endZ;
				
				float endU,endV;
				float deltaU,deltaV;

				{
					int StartI = sptr->ig3s_c1;
					SCASM_DeltaI = (sptr->ig3s_c2 - StartI)/dx;
					SCASM_StartI = StartI;
				}

				SCASM_Destination = ScreenBuffer + (sptr->ig3s_y * BackBufferPitch) + sptr->ig3s_x1;
				SCASM_ScanLength = PERS_STEP;
				
				{
					float oneOverdx = 1.0/dx;

					endZ = sptr->ig3s_z1;
					deltaZ = (sptr->ig3s_z2 - endZ)*oneOverdx;

					endU = sptr->ig3s_u1;
					deltaU = (sptr->ig3s_u2 - endU)*oneOverdx;

					endV = sptr->ig3s_v1;
					deltaV = (sptr->ig3s_v2 - endV)*oneOverdx;
				}
				{
					float z = 65536.0/endZ;
					SCASM_StartU = endU*z;
					SCASM_StartV = endV*z;
				}
				while(dx>PERS_STEP)
				{
					/* subdivide! */
					int u,v;

					dx -= PERS_STEP;

					endZ += PERS_STEP*deltaZ;
					endU += PERS_STEP*deltaU;
					endV += PERS_STEP*deltaV;

					{
						float z = 65536.0/endZ;
						u = endU*z;
						v = endV*z;
					}
					SCASM_DeltaU = (u-SCASM_StartU)/PERS_STEP;
					SCASM_DeltaV = (v-SCASM_StartV)/PERS_STEP;
					
					/* draw PERS_STEP pixels */
					ScanDraw2D_Gouraud();
				
					SCASM_StartU = u;
					SCASM_StartV = v;
					
					SCASM_Destination +=PERS_STEP;
					SCASM_StartI += PERS_STEP*SCASM_DeltaI;
				}
				if (dx>0)
				{
					int u,v;
					SCASM_ScanLength = dx;
					{
						float z = 65536.0/sptr->ig3s_z2;
						u = sptr->ig3s_u2*z;
						v = sptr->ig3s_v2*z;
					}
					SCASM_DeltaU = (u-SCASM_StartU)/dx;
					SCASM_DeltaV = (v-SCASM_StartV)/dx;

					/* draw 8 pixels */
					ScanDraw2D_Gouraud();
				}



				
				
			}
			sptr++;
			y--;
		}
		while(y);
	}
	
}
#endif











#if 0
void MakeInverseLightingTable(void)
{
	int lookingForColour;

	for(lookingForColour=1; lookingForColour<=255; lookingForColour++)
	{
		int exit =0;
		int table;
		for (table=128; (table>0 && (!exit)); table--)
		{
			int entry;
			for(entry=1; (entry<=255 && (!exit)); entry++)
			{
				if(lookingForColour == *(TextureLightingTable + 256*(table) + entry))
				{
				LighterTable[lookingForColour] = entry;
				exit=1; 
				}
			}
		}
		if (exit==0) LighterTable[lookingForColour] = 255;
	}
}
#endif
struct ColourVector
{
	VECTORCH Direction;
	int	Magnitude;
};

struct ColourVector ColourTable[256];

void MakeInverseLightingTable(void)
{
	extern unsigned char TestPalette[];
	unsigned char *palPtr = TestPalette;
	int i;
	
	for(i = 0; i < 256; i++)
	{
		VECTORCH colour;
		int mag;

		colour.vx = *palPtr++;
		colour.vy = *palPtr++;
		colour.vz = *palPtr++;
		mag = Magnitude(&colour);
		
		if (mag!=0)
		{		
			colour.vx = (colour.vx*32)/mag;
			colour.vy = (colour.vy*32)/mag;
			colour.vz = (colour.vz*32)/mag;
		}
		ColourTable[i].Magnitude = mag;
		ColourTable[i].Direction = colour;
	}

	for(i = 0; i < 256; i++)
	{
		int entry;
		int brightest=0;

		for(entry = 0; entry < 256; entry++)
		{
			VECTORCH v1 = ColourTable[i].Direction;
			VECTORCH v2 = ColourTable[entry].Direction;
	
			if ((v1.vx == v2.vx)
			  &&(v1.vy == v2.vy)
			  &&(v1.vz == v2.vz)
			  &&(ColourTable[i].Magnitude < ColourTable[entry].Magnitude)
			  &&(ColourTable[brightest].Magnitude > ColourTable[entry].Magnitude ||(!brightest)))
				brightest = entry;
		}
		if (brightest==0)
		{
			for(entry = 0; entry < 256; entry++)
			{
				VECTORCH v1 = ColourTable[i].Direction;
				VECTORCH v2 = ColourTable[entry].Direction;
		
				if ((v1.vx>>2 == v2.vx>>1)
				  &&(v1.vy>>2 == v2.vy>>1)
				  &&(v1.vz>>2 == v2.vz>>1)
				  &&(ColourTable[i].Magnitude < ColourTable[entry].Magnitude)
				  &&(ColourTable[brightest].Magnitude > ColourTable[entry].Magnitude ||(!brightest)))

					brightest = entry;
			}
		}

		if (brightest==0)
		{
			for(entry = 0; entry < 256; entry++)
			{
				VECTORCH v1 = ColourTable[i].Direction;
				VECTORCH v2 = ColourTable[entry].Direction;
		
				if ((v1.vx>>2 == v2.vx>>2)
				  &&(v1.vy>>2 == v2.vy>>2)
				  &&(v1.vz>>2 == v2.vz>>2)
				  &&(ColourTable[i].Magnitude < ColourTable[entry].Magnitude)
			      &&(ColourTable[brightest].Magnitude > ColourTable[entry].Magnitude ||(!brightest)))
					brightest = entry;
			}
		}
		#if 0
		if (brightest==0)
		{
			for(entry = 0; entry < 256; entry++)
			{
				VECTORCH v1 = ColourTable[i].Direction;
				VECTORCH v2 = ColourTable[entry].Direction;
		
				if ((v1.vx>>3 == v2.vx>>3)
				  &&(v1.vy>>3 == v2.vy>>3)
				  &&(v1.vz>>3 == v2.vz>>3)
				  &&(ColourTable[i].Magnitude < ColourTable[entry].Magnitude)
			  	  &&(ColourTable[brightest].Magnitude > ColourTable[entry].Magnitude ||(!brightest)))
					brightest = entry;
			}
		}

		#endif
		if (brightest==0) brightest = i;
		
		LighterTable[i] = brightest;
	}
	

}


void DrawPaletteScreen(void)
{
	int sortedColours[256];
	{
		extern unsigned char TestPalette[];
		unsigned char *palPtr = TestPalette;
		int i;

		for(i = 0; i < 256; i++)
		{
			VECTORCH colour;
			int mag;

			colour.vx = *palPtr++;
			colour.vy = *palPtr++;
			colour.vz = *palPtr++;
			mag = Magnitude(&colour);
			
			if (mag!=0)
			{		
				colour.vx = (colour.vx*7)/mag;
				colour.vy = (colour.vy*7)/mag;
				colour.vz = (colour.vz*7)/mag;
			}
			ColourTable[i].Magnitude = mag;
			ColourTable[i].Direction = colour;
		}
		
		for(i = 0; i<256; i++)
		{
			int e;
			int maxKey=-1;
			int selectedEntry=0;

			for (e=0; e<256; e++)
			{
				int key = ColourTable[e].Direction.vx + ColourTable[e].Direction.vy*64+ColourTable[e].Direction.vz*64*64;
				if (key>maxKey)
				{
					maxKey = key;
					selectedEntry = e;
				}
				else if (key==maxKey)
				{
					if (ColourTable[e].Magnitude<ColourTable[selectedEntry].Magnitude)
					selectedEntry = e;
				}
			}

			sortedColours[i] = selectedEntry;
			ColourTable[selectedEntry].Direction.vx=-1;
			ColourTable[selectedEntry].Direction.vy=-1;
			ColourTable[selectedEntry].Direction.vz=-1;
		}

	}
	{
		char colour = 0;
		int *bufferPtr = (int*)ScreenBuffer;
		int i,x,y;

		for (i=0; i<=12; i++)
		{
			for (y=0; y<=6; y++)
			{
				for (x=0; x<=19; x++)
				{
					unsigned int c=colour+x;

					if (c<256)
					{
						c = sortedColours[c];
						c = c + (c<<8) + (c<<16) +(c<<24);
						*bufferPtr++=c;	
						*bufferPtr++=c;	
						*bufferPtr++=c;
						*bufferPtr++=c;
					}
					else
					{
						bufferPtr++;
						bufferPtr++;
						bufferPtr++;
						bufferPtr++;
					}
				}
			}
			colour+=20;
		}
	}

	#if 0
	{
		extern unsigned char TestPalette[];
		unsigned char *palPtr = TestPalette;
		int i;

		for(i = 0; i < 256; i++)
		{
			VECTORCH colour;
			int mag;

			colour.vx = *palPtr++;
			colour.vy = *palPtr++;
			colour.vz = *palPtr++;
			mag = Magnitude(&colour);
			if (mag!=0)
			{		
				colour.vx = (colour.vx*63)/mag;
				colour.vy = (colour.vy*63)/mag;
				colour.vz = (colour.vz*63)/mag;
			}
			
			ColourTable[i].Direction = colour;
			ColourTable[i].Magnitude = mag;
		}
		
		for(i = 0; i<256; i++)
		{
			int e;
			int maxKey=-1;
			int selectedEntry=0;

			for (e=0; e<256; e++)
			{
				int key = ColourTable[e].Magnitude;
				
				if (key>maxKey)
				{
					maxKey = key;
					selectedEntry = e;
				}
				else if (key==maxKey)
				{
					int key2 = ColourTable[e].Direction.vx + ColourTable[e].Direction.vy*64+ColourTable[e].Direction.vz*64*64;
					int key3 = ColourTable[selectedEntry].Direction.vx
							 + ColourTable[selectedEntry].Direction.vy*64
							 + ColourTable[selectedEntry].Direction.vz*64*64;

					if (key2<key3)
						selectedEntry=e;
				}

			}

			sortedColours[i] = selectedEntry;
			ColourTable[selectedEntry].Magnitude=-1;
		}

	}
	{
		char colour = 0;
		int *bufferPtr = (int*)(ScreenBuffer+32000);
		int i,x,y;

		for (i=0; i<=12; i++)
		{
			for (y=0; y<=6; y++)
			{
				for (x=0; x<=19; x++)
				{
					unsigned int c=colour+x;

					if (c<256)
					{
						c = sortedColours[c];
						c = c + (c<<8) + (c<<16) +(c<<24);
						*bufferPtr++=c;	
						*bufferPtr++=c;	
						*bufferPtr++=c;
						*bufferPtr++=c;
					}
					else
					{
						bufferPtr++;
						bufferPtr++;
						bufferPtr++;
						bufferPtr++;
					}
				}
			}
			colour+=20;
		}
	}
	#else
	{
		extern unsigned char TestPalette[];
		char colour = 0;
		int *bufferPtr = (int*)(ScreenBuffer+32000);
		int i,x,y;

		for (i=0; i<=12; i++)
		{
			for (y=0; y<=6; y++)
			{
				for (x=0; x<=19; x++)
				{
					unsigned int c=colour+x;

					if (c<256)
					{
						c = c + (c<<8) + (c<<16) +(c<<24);
						*bufferPtr++=c;	
						*bufferPtr++=c;	
						*bufferPtr++=c;
						*bufferPtr++=c;
					}
					else
					{
						bufferPtr++;
						bufferPtr++;
						bufferPtr++;
						bufferPtr++;
					}
				}
			}
			colour+=20;
		}
	}
	#endif
}

void OddLineScreenCopy(unsigned int *source,unsigned int *dest)
{
	int lines = 240;

	do
	{
		int i = 640/4;
		
		dest += 640/4;
		source += 640/4;

		do
		{
			*dest++=*source++;
		}
		while(--i);
	}
	while(--lines);
		
}



/*KJL*****************************************************
* Palette fading; a value of 65536 corresponds to normal *
* palette, 0 is completely black.                        *
*****************************************************KJL*/
void SetPaletteFadeLevel(int fadeLevel)
{
	extern int ScanDrawMode;
	if(ScanDrawDirectDraw == ScanDrawMode)
	{
		extern unsigned char TestPalette[];
		extern unsigned char TestPalette2[];
		{
			int x;
			for (x=0; x<768; x++)
			{
				TestPalette2[x] = ((unsigned int)TestPalette[x]*fadeLevel)>>16;
			}
		}
		ChangePalette(TestPalette2);
	}
	else
	{
		d3d_light_ctrl.ctrl = LCCM_CONSTCOLOUR;
		d3d_light_ctrl.r = fadeLevel;
		d3d_light_ctrl.g = fadeLevel;
		d3d_light_ctrl.b = fadeLevel;
	}
}

void FadeBetweenPalettes(unsigned char *palPtr, int fadeLevel)
{
	extern unsigned char TestPalette[];
	unsigned char TestPalette3[768];
	{
		int x;
		for (x=0; x<768; x++)
		{
			TestPalette3[x] = ( (unsigned int)TestPalette[x]*fadeLevel + (unsigned int)(palPtr[x])*(65536-fadeLevel) )>>16;
		}
	}
	ChangePalette(TestPalette3);
}
void FadePaletteToWhite(unsigned char *palPtr,int fadeLevel)
{
	unsigned char TestPalette3[768];
	{
		int x;
		for (x=0; x<768; x++)
		{
			TestPalette3[x] = ( (unsigned int)(palPtr[x])*fadeLevel + 63*(65536-fadeLevel) )>>16;
		}
	}
	ChangePalette(TestPalette3);
}


void BlankScreen(void)
{
	extern int ScanDrawMode;
	
	if (ScanDrawDirectDraw==ScanDrawMode)
	{
		extern unsigned char *ScreenBuffer;
		extern unsigned char TestPalette[];
		unsigned int *screenPtr;
		int i;							   
		
		screenPtr = (unsigned int *)ScreenBuffer;
		i = ScreenDescriptorBlock.SDB_Width * ScreenDescriptorBlock.SDB_Height /4;
		do
		{
			*screenPtr++=0;	
		}
		while(--i);
	}
	else
	{
		ColourFillBackBuffer(0);
	}

 //	FlipBuffers();
}




void GenerateReciprocalTable(void)
{
	int i=320;
	
	do
	{
		ReciprocalTable[i] = 65536/i;
	}
	while(--i);
}




#if 0
#define NO_OF_STARS 500
typedef struct
{
	VECTORCH Position;
	int Colour;

} STARDESC;
static STARDESC StarArray[NO_OF_STARS];
#endif
void CreateStarArray(void)
{
	#if 0
	int i;
	extern int sine[],cosine[];
	for(i=0; i<NO_OF_STARS; i++)
	{
		int phi = FastRandom()&4095;
		int theta = FastRandom()&4095;

		StarArray[i].Position.vx = MUL_FIXED(GetCos(phi),GetSin(theta));
		StarArray[i].Position.vy = MUL_FIXED(GetSin(phi),GetSin(theta));
		StarArray[i].Position.vz = GetCos(theta);
		StarArray[i].Colour = FastRandom()&32767;
	}
	#endif
}

/* KJL 12:10:36 9/30/97 - starfield, currently implemented for 8 & 16 bit displays */
void DrawStarfilledSky(void)
{
	#if 0
	int i;
	extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr;
	extern int ScanDrawMode;
	
	/* blank the screen */
	ColourFillBackBuffer(0);

	LockSurfaceAndGetBufferPointer();
	
	if(AvP.PlayerType==I_Alien)	/* wide frustrum */
	{
		for(i=0; i<NO_OF_STARS; i++)
		{
			VECTORCH rotatedPosition = StarArray[i].Position;
			
			/* rotate star into view space */
			RotateVector(&rotatedPosition,&(Global_VDB_Ptr->VDB_Mat));
			
			/* is star within alien (wide) view frustrum ? */
			if((-rotatedPosition.vx <= rotatedPosition.vz*2)
			&&(rotatedPosition.vx <= rotatedPosition.vz*2)
			&&(-rotatedPosition.vy*2 <= rotatedPosition.vz*3)
			&&(rotatedPosition.vy*2 <= rotatedPosition.vz*3))
			{
				/* project into screen space */
				int y = (rotatedPosition.vy*(Global_VDB_Ptr->VDB_ProjY))/rotatedPosition.vz+Global_VDB_Ptr->VDB_CentreY;
				int x = (rotatedPosition.vx*(Global_VDB_Ptr->VDB_ProjX))/rotatedPosition.vz+Global_VDB_Ptr->VDB_CentreX;
				
				/* draw pixel of required bit depth */
				if (ScanDrawMode == ScanDrawDirectDraw)
				{
					/* 8 bit mode */
					*(ScreenBuffer + x + y*BackBufferPitch) = StarArray[i].Colour&255;
				}
				else
				{
					/* 16 bit mode */
					*(unsigned short*)(ScreenBuffer + (x*2 + y*BackBufferPitch)) = StarArray[i].Colour;
				}
			}
		}
	}
	else /* normal frustrum */
	{
		for(i=0; i<NO_OF_STARS; i++)
		{
			VECTORCH rotatedPosition = StarArray[i].Position;
			
			/* rotate star into view space */
			RotateVector(&rotatedPosition,&(Global_VDB_Ptr->VDB_Mat));

			/* is star within normal view frustrum ? */
			if((-rotatedPosition.vx <= rotatedPosition.vz)
			&&(rotatedPosition.vx <= rotatedPosition.vz)
			&&(-rotatedPosition.vy*4 <= rotatedPosition.vz*3)
			&&(rotatedPosition.vy*4 <= rotatedPosition.vz*3))
			{
				/* project into screen space */
				int y = (rotatedPosition.vy*(Global_VDB_Ptr->VDB_ProjY))/rotatedPosition.vz+Global_VDB_Ptr->VDB_CentreY;
				int x = (rotatedPosition.vx*(Global_VDB_Ptr->VDB_ProjX))/rotatedPosition.vz+Global_VDB_Ptr->VDB_CentreX;
				
				/* draw pixel of required bit depth */
				if (ScanDrawMode == ScanDrawDirectDraw)
				{
					/* 8 bit mode */
					*(ScreenBuffer + x + y*BackBufferPitch) = StarArray[i].Colour&255;
				}
				else
				{
					/* 16 bit mode */
					*(unsigned short*)(ScreenBuffer + (x*2 + y*BackBufferPitch)) = StarArray[i].Colour;
				}
			}
		}
	}
	
	UnlockSurface();
	#endif
}