/****************************************************************************************/
/*  TRaster.C                                                                           */
/*                                                                                      */
/*  Author: Mike Sandige	                                                            */
/*  Description:  API layer for Triangle Rasterizer                                     */
/*                                                                                      */
/*  Code fragments from Chris Hecker's texture mapping articles used with               */
/*  permission.  http://www.d6.com/users/checker                                        */
/*                                                                                      */
/*  The contents of this file are subject to the Jet3D Public License                   */
/*  Version 1.02 (the "License"); you may not use this file except in                   */
/*  compliance with the License. You may obtain a copy of the License at                */
/*  http://www.jet3d.com                                                                */
/*                                                                                      */
/*  Software distributed under the License is distributed on an "AS IS"                 */
/*  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See                */
/*  the License for the specific language governing rights and limitations              */
/*  under the License.                                                                  */
/*                                                                                      */
/*  The Original Code is Jet3D, released December 12, 1999.                             */
/*  Copyright (C) 1996-1999 Eclipse Entertainment, L.L.C. All Rights Reserved           */
/*                                                                                      */
/****************************************************************************************/
#include <assert.h>

#include "TRaster.h"
#include "Triangle.h"
#include "span.h"
#include "spanbuffer.h"
#include "errorlog.h"

Span_DrawFunction TRaster_DrawSpan;		// used to draw for current triangle
void JETCC TRaster_LightMapSetup(void);

// Construct different edge-walkers depending on the various rops:

//SPANEDGES OPTIONS:  TMAP  LSHADE  ZBUF  SBUF

#define SPANEDGES LSHADE
static void JETCC TRaster_SpanEdges_LSHADE(int Height)
	{
		#include "SpanEdges_Factory.h"
	}

#define SPANEDGES LSHADE + ZBUF
static void JETCC TRaster_SpanEdges_LSHADE_ZBUF(int Height)
	{
		#include "SpanEdges_Factory.h"
	}

#define SPANEDGES TMAP + LSHADE 
static void JETCC TRaster_SpanEdges_TMAP_LSHADE(int Height)
	{
		#include "SpanEdges_Factory.h"
	}

#define SPANEDGES TMAP + LSHADE + ZBUF
static void JETCC TRaster_SpanEdges_TMAP_LSHADE_ZBUF(int Height)
	{
		#include "SpanEdges_Factory.h"
	}

#define SPANEDGES TMAP + LMAP + ZBUF + SBUF
static void JETCC TRaster_SpanEdges_TMAP_LMAP_ZBUF_SBUF(int Height)
	{
		#include "SpanEdges_Factory.h"
	}

#define SPANEDGES TMAP + LSHADE + ZBUF + SBUF
static void JETCC TRaster_SpanEdges_TMAP_LSHADE_ZBUF_SBUF(int Height)
	{
		#include "SpanEdges_Factory.h"
	}

#define SPANEDGES TMAP + LMAP
static void JETCC TRaster_SpanEdges_TMAP_LMAP(int Height)
	{
		#include "SpanEdges_Factory.h"
	}

#define SPANEDGES TMAP + LMAP + ZBUF
static void JETCC TRaster_SpanEdges_TMAP_LMAP_ZBUF(int Height)
	{
		#include "SpanEdges_Factory.h"
	}


typedef void  ( JETCC *TRaster_SpanEdgesFunction)(int Height);

typedef struct
{
	jeROP ROP;
	int Flags;
	TRaster_SpanEdgesFunction SpanEdges;
} TRaster_RopInfo;


TRaster_RopInfo TRaster_RopTable[JE_ROP_END] =
//								
{//ROP ID						
{JE_ROP_LSHADE,	  					LSHADE,											TRaster_SpanEdges_LSHADE },		
{JE_ROP_LSHADE_ZSET,  				LSHADE | ZBUF | ZSET,							TRaster_SpanEdges_LSHADE_ZBUF },	
{JE_ROP_LSHADE_ZTEST,  				LSHADE | ZBUF | ZTEST,							TRaster_SpanEdges_LSHADE_ZBUF },	
{JE_ROP_LSHADE_ZTESTSET,  			LSHADE | ZBUF | ZTEST | ZSET,					TRaster_SpanEdges_LSHADE_ZBUF },	
{JE_ROP_LSHADE_AFLAT,				LSHADE | AFLAT,									TRaster_SpanEdges_LSHADE_ZBUF },	
{JE_ROP_LSHADE_AFLAT_ZSET,			LSHADE | AFLAT | ZBUF | ZSET,					TRaster_SpanEdges_LSHADE_ZBUF },	
{JE_ROP_LSHADE_AFLAT_ZTEST,			LSHADE | AFLAT | ZBUF | ZTEST,					TRaster_SpanEdges_LSHADE_ZBUF },	
{JE_ROP_LSHADE_AFLAT_ZTESTSET,		LSHADE | AFLAT | ZBUF | ZTEST | ZSET,			TRaster_SpanEdges_LSHADE_ZBUF },	
//texturing
{JE_ROP_TMAP_LSHADE,  				TMAP | LSHADE,									TRaster_SpanEdges_TMAP_LSHADE },	
{JE_ROP_TMAP_LSHADE_ZSET,			TMAP | LSHADE | ZBUF | ZSET,					TRaster_SpanEdges_TMAP_LSHADE_ZBUF},
{JE_ROP_TMAP_LSHADE_ZTEST,  		TMAP | LSHADE | ZBUF | ZTEST,					TRaster_SpanEdges_TMAP_LSHADE_ZBUF},
{JE_ROP_TMAP_LSHADE_ZTESTSET,		TMAP | LSHADE | ZBUF | ZTEST | ZSET,			TRaster_SpanEdges_TMAP_LSHADE_ZBUF},
{JE_ROP_TMAP_LMAP_ZSET_SBUF,  		TMAP | LMAP | ZBUF | ZSET | SBUF,				TRaster_SpanEdges_TMAP_LMAP_ZBUF_SBUF },
{JE_ROP_TMAP_LSHADE_ZSET_SBUF,		TMAP | LSHADE | ZBUF | ZSET | SBUF,				TRaster_SpanEdges_TMAP_LSHADE_ZBUF_SBUF },
{JE_ROP_TMAP_LMAP_ZTESTSET,			TMAP | LMAP | ZBUF | ZTEST | ZSET,				TRaster_SpanEdges_TMAP_LMAP_ZBUF },
{JE_ROP_TMAP_LSHADE_AFLAT,			TMAP | LSHADE | AFLAT ,							TRaster_SpanEdges_TMAP_LSHADE },		
{JE_ROP_TMAP_LSHADE_AFLAT_ZSET,		TMAP | LSHADE | AFLAT | ZBUF | ZSET,			TRaster_SpanEdges_TMAP_LSHADE_ZBUF },	
{JE_ROP_TMAP_LSHADE_AFLAT_ZTEST,	TMAP | LSHADE | AFLAT | ZBUF | ZTEST,			TRaster_SpanEdges_TMAP_LSHADE_ZBUF },	
{JE_ROP_TMAP_LSHADE_AFLAT_ZTESTSET,	TMAP | LSHADE | AFLAT | ZBUF | ZTEST | ZSET,	TRaster_SpanEdges_TMAP_LSHADE_ZBUF },	
{JE_ROP_TMAP_LSHADE_AMAP,			TMAP | LSHADE | AMAP,							TRaster_SpanEdges_TMAP_LSHADE },	
{JE_ROP_TMAP_LSHADE_AMAP_ZSET,		TMAP | LSHADE | AMAP | ZBUF | ZSET,				TRaster_SpanEdges_TMAP_LSHADE_ZBUF },	
{JE_ROP_TMAP_LSHADE_AMAP_ZTEST,		TMAP | LSHADE | AMAP | ZBUF | ZTEST,			TRaster_SpanEdges_TMAP_LSHADE_ZBUF },	
{JE_ROP_TMAP_LSHADE_AMAP_ZTESTSET,	TMAP | LSHADE | AMAP | ZBUF | ZTEST | ZSET,		TRaster_SpanEdges_TMAP_LSHADE_ZBUF },	
{JE_ROP_TMAP_LMAP_AMAP,				TMAP | LMAP | AMAP,								TRaster_SpanEdges_TMAP_LMAP },		
{JE_ROP_TMAP_LMAP_AMAP_ZSET,		TMAP | LMAP | AMAP | ZBUF | ZSET,				TRaster_SpanEdges_TMAP_LMAP_ZBUF },	
{JE_ROP_TMAP_LMAP_AMAP_ZTEST,		TMAP | LMAP | AMAP | ZBUF | ZTEST,				TRaster_SpanEdges_TMAP_LMAP_ZBUF },	
{JE_ROP_TMAP_LMAP_AMAP_ZTESTSET,	TMAP | LMAP | AMAP | ZBUF | ZTEST | ZSET,		TRaster_SpanEdges_TMAP_LMAP_ZBUF },
{JE_ROP_TMAP_LMAP_AFLAT_ZTESTSET,	TMAP | LMAP | AFLAT | ZBUF |  ZTEST | ZSET,		TRaster_SpanEdges_TMAP_LMAP_ZBUF },
{JE_ROP_TMAP_LSHADE_AMAP_AFLAT,			TMAP | LSHADE | AMAP | AFLAT, 							TRaster_SpanEdges_TMAP_LSHADE },
{JE_ROP_TMAP_LSHADE_AMAP_AFLAT_ZSET,	TMAP | LSHADE | AMAP | AFLAT | ZBUF |  ZSET,			TRaster_SpanEdges_TMAP_LSHADE_ZBUF },
{JE_ROP_TMAP_LSHADE_AMAP_AFLAT_ZTEST,	TMAP | LSHADE | AMAP | AFLAT | ZBUF |  ZTEST,			TRaster_SpanEdges_TMAP_LSHADE_ZBUF },
{JE_ROP_TMAP_LSHADE_AMAP_AFLAT_ZTESTSET,TMAP | LSHADE | AMAP | AFLAT | ZBUF |  ZTEST | ZSET,	TRaster_SpanEdges_TMAP_LSHADE_ZBUF },
// texturing with filter
{JE_ROP_TMAP_BFILT_LSHADE,  				TMAP | BFILT | LSHADE,									TRaster_SpanEdges_TMAP_LSHADE },	
{JE_ROP_TMAP_BFILT_LSHADE_ZSET,			TMAP | BFILT | LSHADE | ZBUF | ZSET,					TRaster_SpanEdges_TMAP_LSHADE_ZBUF},
{JE_ROP_TMAP_BFILT_LSHADE_ZTEST,  		TMAP | BFILT | LSHADE | ZBUF | ZTEST,					TRaster_SpanEdges_TMAP_LSHADE_ZBUF},
{JE_ROP_TMAP_BFILT_LSHADE_ZTESTSET,		TMAP | BFILT | LSHADE | ZBUF | ZTEST | ZSET,			TRaster_SpanEdges_TMAP_LSHADE_ZBUF},
{JE_ROP_TMAP_BFILT_LMAP_ZSET_SBUF,  		TMAP | BFILT | LMAP | ZBUF | ZSET | SBUF,				TRaster_SpanEdges_TMAP_LMAP_ZBUF_SBUF },
{JE_ROP_TMAP_BFILT_LSHADE_ZSET_SBUF,		TMAP | BFILT | LSHADE | ZBUF | ZSET | SBUF,				TRaster_SpanEdges_TMAP_LSHADE_ZBUF_SBUF },
{JE_ROP_TMAP_BFILT_LMAP_ZTESTSET,			TMAP | BFILT | LMAP | ZBUF | ZTEST | ZSET,				TRaster_SpanEdges_TMAP_LMAP_ZBUF },
{JE_ROP_TMAP_BFILT_LSHADE_AFLAT,			TMAP | BFILT | LSHADE | AFLAT ,							TRaster_SpanEdges_TMAP_LSHADE },		
{JE_ROP_TMAP_BFILT_LSHADE_AFLAT_ZSET,		TMAP | BFILT | LSHADE | AFLAT | ZBUF | ZSET,			TRaster_SpanEdges_TMAP_LSHADE_ZBUF },	
{JE_ROP_TMAP_BFILT_LSHADE_AFLAT_ZTEST,	TMAP | BFILT | LSHADE | AFLAT | ZBUF | ZTEST,			TRaster_SpanEdges_TMAP_LSHADE_ZBUF },	
{JE_ROP_TMAP_BFILT_LSHADE_AFLAT_ZTESTSET,	TMAP | BFILT | LSHADE | AFLAT | ZBUF | ZTEST | ZSET,	TRaster_SpanEdges_TMAP_LSHADE_ZBUF },	
{JE_ROP_TMAP_BFILT_LSHADE_AMAP,			TMAP | BFILT | LSHADE | AMAP,							TRaster_SpanEdges_TMAP_LSHADE },	
{JE_ROP_TMAP_BFILT_LSHADE_AMAP_ZSET,		TMAP | BFILT | LSHADE | AMAP | ZBUF | ZSET,				TRaster_SpanEdges_TMAP_LSHADE_ZBUF },	
{JE_ROP_TMAP_BFILT_LSHADE_AMAP_ZTEST,		TMAP | BFILT | LSHADE | AMAP | ZBUF | ZTEST,			TRaster_SpanEdges_TMAP_LSHADE_ZBUF },	
{JE_ROP_TMAP_BFILT_LSHADE_AMAP_ZTESTSET,	TMAP | BFILT | LSHADE | AMAP | ZBUF | ZTEST | ZSET,		TRaster_SpanEdges_TMAP_LSHADE_ZBUF },	
{JE_ROP_TMAP_BFILT_LMAP_AMAP,				TMAP | BFILT | LMAP | AMAP,								TRaster_SpanEdges_TMAP_LMAP },		
{JE_ROP_TMAP_BFILT_LMAP_AMAP_ZSET,		TMAP | BFILT | LMAP | AMAP | ZBUF | ZSET,				TRaster_SpanEdges_TMAP_LMAP_ZBUF },	
{JE_ROP_TMAP_BFILT_LMAP_AMAP_ZTEST,		TMAP | BFILT | LMAP | AMAP | ZBUF | ZTEST,				TRaster_SpanEdges_TMAP_LMAP_ZBUF },	
{JE_ROP_TMAP_BFILT_LMAP_AMAP_ZTESTSET,	TMAP | BFILT | LMAP | AMAP | ZBUF | ZTEST | ZSET,		TRaster_SpanEdges_TMAP_LMAP_ZBUF },
{JE_ROP_TMAP_BFILT_LMAP_AFLAT_ZTESTSET,	TMAP | BFILT | LMAP | AFLAT | ZBUF |  ZTEST | ZSET,		TRaster_SpanEdges_TMAP_LMAP_ZBUF },
{JE_ROP_TMAP_BFILT_LSHADE_AMAP_AFLAT,			TMAP | BFILT | LSHADE | AMAP | AFLAT, 							TRaster_SpanEdges_TMAP_LSHADE },
{JE_ROP_TMAP_BFILT_LSHADE_AMAP_AFLAT_ZSET,	TMAP | BFILT | LSHADE | AMAP | AFLAT | ZBUF |  ZSET,			TRaster_SpanEdges_TMAP_LSHADE_ZBUF },
{JE_ROP_TMAP_BFILT_LSHADE_AMAP_AFLAT_ZTEST,	TMAP | BFILT | LSHADE | AMAP | AFLAT | ZBUF |  ZTEST,			TRaster_SpanEdges_TMAP_LSHADE_ZBUF },
{JE_ROP_TMAP_BFILT_LSHADE_AMAP_AFLAT_ZTESTSET,TMAP | BFILT | LSHADE | AMAP | AFLAT | ZBUF |  ZTEST | ZSET,	TRaster_SpanEdges_TMAP_LSHADE_ZBUF },

};


	// turns clamping on or off for bilinear filtered rops
void JETCC TRaster_SetClamping(jeBoolean Mode)
{
	UVClamping = Mode;
}


void JETCC TRaster_LightMapSetup(void)
{
	TRaster_Lightmap LM;
	Triangle.IsLightMapSetup=JE_TRUE;
	LM.MipIndex = Triangle.MipIndex;

	Triangle.LightMapSetup(&LM);

	Triangle.LightMapBits = (LIGHTMAPPIXEL *)LM.BitPtr; 
	Triangle.LightMapWidth  = LM.Width;
	Triangle.LightMapHeight = LM.Height;

	Triangle.LightMapShiftU = (int)(65536.0f * LM.LightMapShiftU);
	Triangle.LightMapScaleU = (int)(256.0f   * LM.LightMapScaleU);

	Triangle.LightMapShiftV = (int)(65536.0f * LM.LightMapShiftV);
	Triangle.LightMapScaleV = (int)(256.0f   * LM.LightMapScaleV);

	Triangle.LightMapStride = Triangle.LightMapWidth * 3;
	Triangle.LightMapMaxU   = (Triangle.LightMapWidth-1)<<16;
	Triangle.LightMapMaxV   = (Triangle.LightMapHeight-1)<<16;
}


void JETCC TRaster_Setup(int MaxAffineSize,
	int Width, 
	uint16 *DestPtr,
	uint16 *ZPtr, 
	void (*LightMapSetup)(TRaster_Lightmap *LM))
{
	int i;
	
	assert( MaxAffineSize > 0);
	assert( MaxAffineSize < TRASTER_SMALL_DIVIDE_TABLESIZE);
	assert( DestPtr != NULL );
	assert( Width > 0 );
	assert( LightMapSetup != NULL );
	
	Triangle.MaxAffineSize = (float)MaxAffineSize;


	for (i=1; i<TRASTER_SMALL_DIVIDE_TABLESIZE; i++)
		{
			Triangle.SmallDivideTable[i] = 0x10000/i;
		}
	#ifdef 	NOISE_FILTER
		for (i=0; i<256; i++)
			{
				Triangle.RandomTable[i] = (rand() & 0x03)<<24;
			}
	#endif

	Triangle.DestPtr   = DestPtr;
	Triangle.DestWidth = Width;
	Triangle.ZMapPtr   = ZPtr;
	Triangle.LightMapSetup = LightMapSetup;
}


		
		// expected ranges for pVertices elements:
		//   x,y  (pretty much anything)  but these are in screen space...
		//   z  (0..65536)  
		//   r,g,b:  0..255
		//   a: 0..255
		//   pVertices expected in clockwise winding order.  Counter clockwise will not be rasterized.
		// future: for larger polys, add parameter that allows previous gradient to be reused. (if it was computed)
jeBoolean JETCC TRaster_Rasterize( 
		jeROP ROP,
		jeRDriver_THandle *Texture,
		int MipIndex,
		const jeTLVertex 	*pVertices)
{
	uint32 DestPtr;
	int32  DestWidth;
	int Top,Middle,Bottom;
	jeRDriver_THandle *PalHandle;
	 			
	float Y0 = pVertices[0].y; 
	float Y1 = pVertices[1].y;
	float Y2 = pVertices[2].y;


	
	Triangle_Edge TopToBottom, TopToSplit, SplitToBottom;
	int SplitRight;		// set if triangle has two right-side edges (and one left-side edge)

	#ifdef NOISE_FILTER
	Triangle.RandomIndex=0;
	#endif

	assert( ROP >=0 ) ;
	assert( ROP <= JE_ROP_END );

	Triangle.ROPFlags = TRaster_RopTable[ROP].Flags;

	assert( TRaster_RopTable[ROP].SpanEdges != NULL );
	assert( ((Triangle.ROPFlags & AFLAT)  && (pVertices[0].a>=0.0f && pVertices[0].a<=255.1f)) || !(Triangle.ROPFlags & AFLAT));
	assert( ((Triangle.ROPFlags & LSHADE) && (pVertices[0].r>=0.0f && pVertices[0].r<=255.1f)) || !(Triangle.ROPFlags & LSHADE));
	assert( ((Triangle.ROPFlags & LSHADE) && (pVertices[1].r>=0.0f && pVertices[1].r<=255.1f)) || !(Triangle.ROPFlags & LSHADE));
	assert( ((Triangle.ROPFlags & LSHADE) && (pVertices[2].r>=0.0f && pVertices[2].r<=255.1f)) || !(Triangle.ROPFlags & LSHADE));
	assert( ((Triangle.ROPFlags & LSHADE) && (pVertices[0].g>=0.0f && pVertices[0].g<=255.1f)) || !(Triangle.ROPFlags & LSHADE));
	assert( ((Triangle.ROPFlags & LSHADE) && (pVertices[1].g>=0.0f && pVertices[1].g<=255.1f)) || !(Triangle.ROPFlags & LSHADE));
	assert( ((Triangle.ROPFlags & LSHADE) && (pVertices[2].g>=0.0f && pVertices[2].g<=255.1f)) || !(Triangle.ROPFlags & LSHADE));
	assert( ((Triangle.ROPFlags & LSHADE) && (pVertices[0].b>=0.0f && pVertices[0].b<=255.1f)) || !(Triangle.ROPFlags & LSHADE));
	assert( ((Triangle.ROPFlags & LSHADE) && (pVertices[1].b>=0.0f && pVertices[1].b<=255.1f)) || !(Triangle.ROPFlags & LSHADE));
	assert( ((Triangle.ROPFlags & LSHADE) && (pVertices[2].b>=0.0f && pVertices[2].b<=255.1f)) || !(Triangle.ROPFlags & LSHADE));
	
	if (Triangle.ROPFlags & TMAP)
		{
			int W,H;
			jeRDriver_THandleInfo TextureInfo;
			assert( Texture != NULL );
			assert( MipIndex >= 0 );

			if (SWTHandle_GetInfo(Texture,MipIndex,&TextureInfo)==JE_FALSE)
				{
					jeErrorLog_AddString(JE_ERR_SUBSYSTEM_FAILURE,"TRaster_Rasterize: unable to get texture info",NULL);
					return JE_FALSE;	
				}
			W = TextureInfo.Width;
			H = TextureInfo.Height;

			if (Triangle_GradientsCompute(&(Triangle.Gradients),
						pVertices,(float)(W),(float)(H))==JE_FALSE)
				return JE_TRUE;  // poly has no area.

			if (SWTHandle_LockTextureHandle(Texture,MipIndex,&(Triangle.TextureBits))==JE_FALSE)
				{
					jeErrorLog_AddString(JE_ERR_SUBSYSTEM_FAILURE,"TRaster_Rasterize: unable to lock texture",NULL);
					return JE_FALSE; 
				}

			for(Triangle.StrideShift=1;((1<<Triangle.StrideShift) < W); Triangle.StrideShift++);
			assert( (1<<Triangle.StrideShift) == W );
			if (Triangle.ROPFlags & LMAP)
				{
					Triangle.IsLightMapSetup = JE_FALSE;
				}
			
			Triangle.UMask = W-1;
			Triangle.VMask = H-1;
			Triangle.MipIndex = MipIndex;
			PalHandle = SWTHandle_GetPalette(Texture);
			if (PalHandle)
				{
					if (SWTHandle_LockTextureHandle(PalHandle,0,&(Triangle.Palette))==JE_FALSE)
						{
							SWTHandle_UnLockTextureHandle(Texture,MipIndex);
							jeErrorLog_AddString(JE_ERR_SUBSYSTEM_FAILURE,"TRaster_Rasterize: unable to lock palette",NULL);
							return JE_FALSE;
						}
				}
			else Triangle.Palette = NULL;
		}
	else
		{
			if (Triangle_GradientsCompute(&(Triangle.Gradients),pVertices,1.0f,1.0f)==JE_FALSE)
				return JE_TRUE;  // poly has no area.
		}
	if (Triangle.ROPFlags & ZBUF)
		{
			assert(Triangle.ZMapPtr != NULL );

			Triangle.ZBufferAddressDelta = ((int)(Triangle.ZMapPtr) - ((int)(Triangle.DestPtr)));
		}
	TRaster_DrawSpan = Span_GetDrawFunction(ROP);
	A = (int32)(pVertices[0].a / (255.0f/16.0f) );
	OneMinusA = 16 - A;
		
	// sort vertices in y
	if(Y0 < Y1) 
		{
			if(Y2 < Y0) 
				{			Top = 2; Middle = 0; Bottom = 1; SplitRight = 1; } 
			else 
				{
					if(Y1 < Y2) 
						{	Top = 0; Middle = 1; Bottom = 2; SplitRight = 1; } 
					else 
						{	Top = 0; Middle = 2; Bottom = 1; SplitRight = 0; }
				}
		} 
	else 
		{
			if(Y2 < Y1) 
				{			Top = 2; Middle = 1; Bottom = 0; SplitRight = 0; } 
			else 
				{
					if(Y0 < Y2) 
						{	Top = 1; Middle = 0; Bottom = 2; SplitRight = 0; } 
					else 
						{	Top = 1; Middle = 2; Bottom = 0; SplitRight = 1; }
				}
		}

	
	Triangle_EdgeCompute(&TopToBottom,   &(Triangle.Gradients),pVertices,Top,   Bottom, SplitRight);
	Triangle_EdgeCompute(&TopToSplit,    &(Triangle.Gradients),pVertices,Top,   Middle, !SplitRight);
	Triangle_EdgeCompute(&SplitToBottom,&(Triangle.Gradients),pVertices,Middle,Bottom, !SplitRight);

	// to maximize mmx optimization, there is no floating point from this point on
	if(SplitRight) 
		{
			Triangle.Left  = TopToBottom;
			Triangle.Right = TopToSplit;
		} 
	else 
		{
			Triangle.Left  = TopToSplit;
			Triangle.Right = TopToBottom;
		}

	DestPtr   = ( uint32 )(Triangle.DestPtr); 
	DestWidth = TOPDOWN_OR_BOTTOMUP(Triangle.DestWidth);
	Triangle.Left.Dest		  = DestPtr + ((Triangle.Left.X  + Triangle.Left.Y * DestWidth)<<DESTPIXEL_SHIFTER);
	Triangle.Left.DestStep    = (Triangle.Left.XStep + DestWidth)<<DESTPIXEL_SHIFTER;


	TRaster_RopTable[ROP].SpanEdges(TopToSplit.Height);

	if(SplitRight) 
		{
			Triangle.Right = SplitToBottom;
		}
	else
		{
			Triangle.Left = SplitToBottom;
			Triangle.Left.Dest		  = DestPtr + ((Triangle.Left.X  + Triangle.Left.Y * DestWidth)<<DESTPIXEL_SHIFTER);
			Triangle.Left.DestStep    = (Triangle.Left.XStep + DestWidth)<<DESTPIXEL_SHIFTER;
		}

	TRaster_RopTable[ROP].SpanEdges(SplitToBottom.Height);

	if (Triangle.ROPFlags & TMAP)
		{
			SWTHandle_UnLockTextureHandle(Texture,MipIndex);
			if (Triangle.Palette != NULL)
				{
					SWTHandle_UnLockTextureHandle(PalHandle,0);
				}
		}
	return JE_TRUE;
}
