#include "MLRHeaders.hpp"

extern DWORD gEnableTextureSort, gEnableAlphaSort, gEnableLightMaps, gShowBucketColors, gEnableSimpleLight;


MLRSortByOrder::ClassData*
	MLRSortByOrder::DefaultData = NULL;

//#############################################################################
//############################    MLRSortByOrder    ################################
//#############################################################################

static DWORD
	Trivial_Rejects=0;
DWORD
	Trivial_Accepts=0;

Scalar layerOffset = 1.f;	//SMALL;


int MLRSortByOrder::maxUsedAlphaPrimitives;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRSortByOrder::InitializeClass()
{
	Verify(!DefaultData);
	Verify(gos_GetCurrentHeap() == StaticHeap);
	DefaultData =
		new ClassData(
			MLRSortByOrderClassID,
			"MidLevelRenderer::MLRSortByOrder",
			MLRSorter::DefaultData
		);
	Register_Object(DefaultData);

	Trivial_Rejects = 0;
	Trivial_Accepts = 0;
	maxUsedAlphaPrimitives = 2*Limits::Max_Number_Vertices_Per_Frame;


#if !defined(NO_STATS)
	AddStatistic("Trivial Reject Cull Errors", "errors", gos_DWORD, &Trivial_Rejects, Stat_AutoReset);
	AddStatistic("Trivial Accept Cull Errors", "errors", gos_DWORD, &Trivial_Accepts, Stat_AutoReset);
#endif
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRSortByOrder::TerminateClass()
{
	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLRSortByOrder::MLRSortByOrder(MLRTexturePool *tp) :
	MLRSorter(DefaultData, tp)
{
	Verify(gos_GetCurrentHeap() == SorterHeap);
	int i;

	gos_PushCurrentHeap(StaticHeap);
	for(i=0;i<MLRState::PriorityCount;i++)
	{
		lastUsedInBucket[i] = 0;
		priorityBuckets[i].SetLength(Limits::Max_Number_Primitives_Per_Frame + Limits::Max_Number_ScreenQuads_Per_Frame);
	}
	alphaSort.SetLength(1); //2*Limits::Max_Number_Vertices_Per_Frame
	alphaSortArray.SetLength(1); //2*Limits::Max_Number_Vertices_Per_Frame
	for(i=0;i<alphaSort.GetLength();i++)
	{
		alphaSort[i] = &alphaSortArray[i];
	}
	gos_PopCurrentHeap();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLRSortByOrder::~MLRSortByOrder()
{
	alphaSortArray.SetLength(0);
	alphaSort.SetLength(0);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRSortByOrder::Reset ()
{
	Check_Object(this);

	int i;

	for(i=0;i<MLRState::PriorityCount;i++)
	{
		lastUsedInBucket[i] = 0;
	}

	MLRSorter::Reset();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRSortByOrder::AddPrimitive(MLRPrimitiveBase *pt, int pass)
{
	Check_Object(this); 
	Check_Object(pt);

	int index = -1;

	switch(pt->GetSortDataMode())
	{
		case SortData::TriList:
		case SortData::TriIndexedList:
			index = SetRawData(pt, pass);
		break;
	}

	unsigned priority = pt->GetCurrentState(pass).GetPriority();
	if(index >= 0)
	{
		priorityBuckets[priority][lastUsedInBucket[priority]++] = index;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRSortByOrder::AddEffect(MLREffect *ef, const MLRStateBase& state)
{
	Check_Object(this); 
	Check_Object(ef);

	int index = -1;

	AddEffect(ef, state, index);

	unsigned priority = state.GetPriority();
	if(index >= 0)
	{
		priorityBuckets[priority][lastUsedInBucket[priority]++] = index;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRSortByOrder::AddEffect(MLREffect *ef, const MLRStateBase& state, int& index)
{
	Check_Object(this); 
	Check_Object(ef);

	switch(ef->GetSortDataMode())
	{
		case SortData::PointCloud:
			index = SetRawData(
					ef->GetGOSVertices(),
					ef->GetNumGOSVertices(), 
					state,
					SortData::PointCloud
					);
			(*rawDrawData)[index].numIndices = ef->GetType(0);
		break;
		case SortData::LineCloud:
			index = SetRawData(
					ef->GetGOSVertices(),
					ef->GetNumGOSVertices(), 
					state,
					SortData::LineCloud
					);
			(*rawDrawData)[index].numIndices = ef->GetType(0);
		break;
		case SortData::TriList:
			index = SetRawData(
					ef->GetGOSVertices(),
					ef->GetNumGOSVertices(), 
					state,
					SortData::TriList
					);
		break;
		case SortData::TriIndexedList:
		{
			MLRIndexedTriangleCloud *itc = Cast_Object(MLRIndexedTriangleCloud*, ef);
			index = SetRawIndexedData(
					itc->GetGOSVertices(),
					itc->GetNumGOSVertices(), 
					itc->GetGOSIndices(),
					itc->GetNumGOSIndices(), 
					state,
					SortData::TriIndexedList
					);
		}
		break;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRSortByOrder::AddScreenQuads
		(
			GOSVertex *vertices, 
			const DrawScreenQuadsInformation *dInfo
		)
{
	Verify(dInfo->currentNrOfQuads != 0 && (dInfo->currentNrOfQuads&3) == 0);

	int index = SetRawData
		(
			vertices,
			dInfo->currentNrOfQuads,
			dInfo->state,
			SortData::Quads
		);

	unsigned priority = dInfo->state.GetPriority();
	if(index >= 0)
	{
		priorityBuckets[priority][lastUsedInBucket[priority]++] = index;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRSortByOrder::AddSortRawData(int index)
{
	Check_Object(this); 
	
	if(index<0)
	{
		return;
	}

	unsigned priority = (*rawDrawData)[index].state.GetPriority();
	priorityBuckets[priority][lastUsedInBucket[priority]++] = index;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
SortAlpha* 
	MLRSortByOrder::GetSortAlpha(int index)
{
	int length = alphaSort.GetLength();
	if (index >= length)
	{
		int newLength = length * 2;

		if (newLength > maxUsedAlphaPrimitives)
		{
			STOP(("Maximum number of alpha sorted primitives exceeded"));
		}

		gos_PushCurrentHeap(StaticHeap);
		alphaSort.SetLength(newLength);
		alphaSortArray.SetLength(newLength);
		gos_PopCurrentHeap();

		for(int i=0;i<newLength;i++)
		{
			alphaSort[i] = &alphaSortArray[i];
		}
	}
	return alphaSort[index];
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int _cdecl CompareTBDP(const void *e1, const void *e2)
{
	return static_cast<const ToBeDrawnPrimitiveIndex*>(e1)->handle - static_cast<const ToBeDrawnPrimitiveIndex*>(e2)->handle;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRSortByOrder::BinSorterTBDP (int bin, ToBeDrawnPrimitiveIndex *priorityBucketNotDrawn)
{
#if 0
	qsort(
		priorityBucketNotDrawn, 
		lastUsedInBucketNotDrawn[bin],
		sizeof(ToBeDrawnPrimitivePointer),
		CompareTBDP
	);
#else
	int ii, jj, hh;

	ToBeDrawnPrimitiveIndex tempSortData;

	for(hh=1;hh<lastUsedInBucketNotDrawn[bin]/9;hh=3*hh+1);

	for(;hh>0;hh/=3)
	{
		for(ii=hh;ii<lastUsedInBucketNotDrawn[bin];ii++)
		{
			tempSortData = priorityBucketNotDrawn[ii];

			jj = ii;
			while(jj>=hh && priorityBucketNotDrawn[jj-hh].handle > tempSortData.handle)
			{
				priorityBucketNotDrawn[jj] = priorityBucketNotDrawn[jj-hh];
				jj -= hh;
			}
			priorityBucketNotDrawn[jj] = tempSortData;
		}
	}
#endif
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRSortByOrder::BinSorterSD (int bin, int *priorityBucket)
{
	int ii, jj, hh;

	int tempSortData;

	for(hh=1;hh<lastUsedInBucket[bin]/9;hh=3*hh+1);

	for(;hh>0;hh/=3)
	{
		for(ii=hh;ii<lastUsedInBucket[bin];ii++)
		{
			tempSortData = priorityBucket[ii];

			jj = ii;

			while(
				jj>=hh &&
				(*rawDrawData)[priorityBucket[jj-hh]].state.GetTextureHandle() > (*rawDrawData)[tempSortData].state.GetTextureHandle()
			)
			{
				priorityBucket[jj] = priorityBucket[jj-hh];
				jj -= hh;
			}
			priorityBucket[jj] = tempSortData;
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRSortByOrder::RenderNow ()
{
	Check_Object(this);
//
// So GameOS knows how long the transform and clip and lighting took of update renderers
//

	Stuff::DynamicArrayOf<int>
		*priorityBucket;
	Stuff::DynamicArrayOf<ToBeDrawnPrimitiveIndex>
		*priorityBucketNotDrawn;

	GOSVertex::farClipReciprocal = farClipReciprocal;

	int i, j;
//	Limits::Max_Number_Primitives_Per_Frame + Max_Number_ScreenQuads_Per_Frame

	MLRPrimitiveBase *primitive;
	for(i=0;i<MLRState::PriorityCount;i++)
	{
		ToBeDrawnPrimitive *tbdp;
		int alphaToSort = 0;

		if(lastUsedInBucketNotDrawn[i])
		{
			Verify(lastUsedInBucketNotDrawn[i]<=Limits::Max_Number_Primitives_Per_Frame + Limits::Max_Number_ScreenQuads_Per_Frame);

			if( gEnableTextureSort && i != MLRState::AlphaPriority)
			{
				MLR_RENDER("Texture Sorting::MLRSortByOrder::RenderNow");
				Start_Timer(Texture_Sorting_Time);
				priorityBucketNotDrawn = &(*priorityBucketsNotDrawn[i]);
				BinSorterTBDP(i, priorityBucketNotDrawn->GetData());
				Stop_Timer(Texture_Sorting_Time);
			}

			paintMeColorDW = 0xffffffff;
			paintMeColorF = RGBAColor::White;

			for(j=0;j<lastUsedInBucketNotDrawn[i];j++)
			{
				SortData *sd = NULL;

				MLR_RENDER("DrawShape::RenderNow");
				Start_Timer(Shape_Setup_Time);

				tbdp = &(*MLRSorter::drawData)[(*priorityBucketsNotDrawn[i])[j].tbdpIndex];
				Check_Pointer(tbdp);

				int	nrOfLightMaps = 0;

				for(int k=0;k<tbdp->nrOfActiveLights;k++)
				{
					Check_Object(tbdp->activeLights[k]);
					nrOfLightMaps += (tbdp->activeLights[k]->GetLightMap() != NULL) ? 1 : 0;
					tbdp->activeLights[k]->SetLightToShapeMatrix(tbdp->worldToShape);
				}

				if(!gEnableLightMaps)
				{
					nrOfLightMaps = 0;
				}

				if(nrOfLightMaps)
				{
					MLRLightMap::SetDrawData
						(
							ToBeDrawnPrimitive::allVerticesToDraw,
							&tbdp->shapeToClipMatrix,
							tbdp->clippingFlags,
							tbdp->state
						);
				}

#if COLOR_AS_DWORD
	#ifdef LAB_ONLY
				if(gShowBucketColors>0)
				{
					paintMeColorDW = bucketColors[i];
				}
				else
				{
					paintMeColorDW = tbdp->paintMeColor;
				}
	#else
				paintMeColorDW = tbdp->paintMeColor;
	#endif
#else
				paintMeColorF = tbdp->paintMeColor;
				paintMeColorDW = GOSCopyColor(&tbdp->paintMeColor);
#endif

				Stop_Timer(Shape_Setup_Time);

				switch(tbdp->type)
				{
					case 0:
					{
						primitive = Cast_Object(MLRPrimitiveBase*, tbdp->primitive);
						Check_Object(primitive);
						primitive->InitializeDrawPrimitive(1, 1);

						if(primitive->FindBackFace(tbdp->cameraPosition, tbdp->cameraDirection))
						{
							if(gEnableSimpleLight>0)
							{
								DWORD center_color = primitive->CenterLighting(tbdp->activeLights, tbdp->nrOfActiveLights);
									
								const Scalar one_Over_65536 = 1.0f/65536.0f;
								Stuff::RGBAColor tc;

								tc.blue = (center_color & 0xff) * (paintMeColorDW & 0xff) * one_Over_65536;

								center_color >>= 8;
								paintMeColorDW >>= 8;

								tc.green = (center_color & 0xff) * (paintMeColorDW & 0xff) * one_Over_65536;

								center_color >>= 8;
								paintMeColorDW >>= 8;

								tc.red = (center_color & 0xff) * (paintMeColorDW & 0xff) * one_Over_65536;

								center_color >>= 8;
								paintMeColorDW >>= 8;

								tc.alpha = (center_color & 0xff) * (paintMeColorDW & 0xff) * one_Over_65536;

								paintMeColorDW = GOSCopyColor(&tc);
#if COLOR_AS_DWORD==0
								paintMeColorF = tc;
#endif

							}
							else
							{
								primitive->Lighting(tbdp->activeLights, tbdp->nrOfActiveLights);
							}

							FogData fogData;
							bool fog = primitive->FogMesh(&tbdp->worldToShape, &tbdp->cameraPosition, &fogData);

							if(tbdp->clippingFlags.GetClippingState() != 0)
							{
								if (
									!primitive->TransformAndClip(
										&tbdp->shapeToClipMatrix,
										tbdp->clippingFlags,
										ToBeDrawnPrimitive::allVerticesToDraw,
										fog ? &fogData: NULL,
#if COLOR_AS_DWORD>0
										paintMeColorDW,
#else
										GOSCopyColor(&paintMeColorF),
#endif
										true)
								)
								{
									Set_Statistic(Trivial_Rejects, Trivial_Rejects+1);
								}
							}
							else
							{
								primitive->TransformNoClip(
									&tbdp->shapeToClipMatrix,
									ToBeDrawnPrimitive::allVerticesToDraw,
									fog ? &fogData: NULL,
#if COLOR_AS_DWORD>0
									paintMeColorDW,
#else
									GOSCopyColor(&paintMeColorF),
#endif
									true);

							}
#ifdef LAB_ONLY
							Set_Statistic(Number_Of_Primitives, Number_Of_Primitives+1);

							if(primitive->IsDerivedFrom(MLRIndexedPrimitiveBase::DefaultData))
							{
								const Point3D *coords;
								const BYTE *indices;
								int nr;

								(Cast_Pointer(MLRIndexedPrimitiveBase*, primitive))->GetIndexData(&indices, &nr);
								Set_Statistic(NumAllIndices, NumAllIndices+nr);

								primitive->GetCoordData(&coords, &nr);
								Set_Statistic(NumAllVertices, NumAllVertices + nr);

								if(NumAllVertices == 0)
								{
									Set_Statistic(Index_Over_Vertex_Ratio, 1.0f);
								}
								else
								{
									Set_Statistic(Index_Over_Vertex_Ratio, (Scalar)NumAllIndices/(Scalar)NumAllVertices);
								}
							}
#endif
						}

						if(primitive->GetVisible())
						{
							for(int k=0;k<primitive->GetNumPasses();k++)
							{
								if(i != MLRState::AlphaPriority)
								{
									DrawPrimitive(primitive, k);
								}
								else
								{
									int index = SetRawData(primitive, k);
									sd = &(*rawDrawData)[index];
									Check_Pointer(sd);

									if( gEnableAlphaSort && (sd->type == SortData::TriList || sd->type == SortData::TriIndexedList) )
									{
										SortData::LoadSortAlphaFunc alphaFunc = sd->LoadSortAlpha[sd->type];

										alphaToSort += (sd->*alphaFunc)(this, alphaToSort, k==0?0.0f:layerOffset);
									}
									else
									{
										if(theCurrentState != sd->state.renderState)
										{
											SetDifferences(sd->state, sd->texture_2_3 & 0xffff, sd->texture_2_3>>16);
										}
										SortData::DrawFunc drawFunc = sd->Draw[sd->type];

										(sd->*drawFunc)();
									}
								}
							}
						}

					}
					break;
					case 1:
					{
						primitive = Cast_Object(MLRPrimitiveBase*, tbdp->primitive);
						Check_Object(primitive);
						primitive->InitializeDrawPrimitive(1, 1);

//						primitive->PaintMe(&tbdp->paintMeColor);

						if(tbdp->clippingFlags.GetClippingState() != 0)
						{
							if (!
								primitive->TransformAndClip(
									&tbdp->shapeToClipMatrix,
									tbdp->clippingFlags,
									ToBeDrawnPrimitive::allVerticesToDraw,
									NULL,
#if COLOR_AS_DWORD>0
									paintMeColorDW,
#else
									GOSCopyColor(&paintMeColorF),
#endif
									true)
							)
							{
								Set_Statistic(Trivial_Rejects, Trivial_Rejects+1);
							}
						}
						else
						{
							primitive->TransformNoClip(
								&tbdp->shapeToClipMatrix,
								ToBeDrawnPrimitive::allVerticesToDraw,
								NULL,
#if COLOR_AS_DWORD>0
								paintMeColorDW,
#else
								GOSCopyColor(&paintMeColorF),
#endif
								true);

						}
#ifdef LAB_ONLY
						Set_Statistic(Number_Of_Primitives, Number_Of_Primitives+1);

						if(primitive->IsDerivedFrom(MLRIndexedPrimitiveBase::DefaultData))
						{
							const Point3D *coords;
							const BYTE *indices;
							int nr;

							(Cast_Pointer(MLRIndexedPrimitiveBase*, primitive))->GetIndexData(&indices, &nr);
							Set_Statistic(NumAllIndices, NumAllIndices+nr);

							primitive->GetCoordData(&coords, &nr);
							Set_Statistic(NumAllVertices, NumAllVertices + nr);

							Set_Statistic(Index_Over_Vertex_Ratio, (Scalar)NumAllIndices/(Scalar)NumAllVertices);
						}
#endif
						if(primitive->GetVisible())
						{
							for(int k=0;k<primitive->GetNumPasses();k++)
							{
								if(i != MLRState::AlphaPriority)
								{
									DrawPrimitive(primitive, k);
								}
								else
								{
									int index = SetRawData(primitive, k);
									sd = &(*rawDrawData)[index];
									Check_Pointer(sd);

									if( gEnableAlphaSort && (sd->type == SortData::TriList || sd->type == SortData::TriIndexedList) )
									{
										SortData::LoadSortAlphaFunc alphaFunc = sd->LoadSortAlpha[sd->type];

										alphaToSort += (sd->*alphaFunc)(this, alphaToSort, k==0?0.0f:layerOffset);
									}
									else
									{
										if(theCurrentState != sd->state.renderState)
										{
											SetDifferences(sd->state, sd->texture_2_3 & 0xffff, sd->texture_2_3>>16);
										}
										SortData::DrawFunc drawFunc = sd->Draw[sd->type];

										(sd->*drawFunc)();
									}
								}
							}
						}
					}
					break;
					case 2:
					{
						MLREffect *effect = Cast_Object(MLREffect*, tbdp->primitive);

						if(tbdp->state.GetTextureHandle())
						{
							MLRTexture *texture = (*MLRTexturePool::Instance)[tbdp->state.GetTextureHandle()];

							if(texture!=NULL)
							{
								MLRState::SetCurrentTextureSize(texture->GetImage()->GetWidth());
							}
						}

						int index = effect->Draw(tbdp, this);

						if(index >= 0)
						{
							SortData *sd = &(*rawDrawData)[index];
							if(sd==NULL)
							{
								break;
							}
							Check_Pointer(sd);

							if(i == MLRState::AlphaPriority && 
								(gEnableAlphaSort && 
									(sd->type == SortData::TriList ||
									sd->type == SortData::TriIndexedList
									) 
								) 
							)
							{
								SortData::LoadSortAlphaFunc alphaFunc = sd->LoadSortAlpha[sd->type];

								alphaToSort += (sd->*alphaFunc)(this, alphaToSort, 0.0f);
							}
							else
							{
								if(theCurrentState != sd->state.renderState)
								{
									SetDifferences(sd->state, sd->texture_2_3 & 0xffff, sd->texture_2_3>>16);
								}
								SortData::DrawFunc drawFunc = sd->Draw[sd->type];

								(sd->*drawFunc)();
							}
						}
					}
					break;
				}

				if(nrOfLightMaps)
				{
					MLRLightMap::DrawLightMaps(this, true);
				}
			}
		}

		if(lastUsedInBucket[i])
		{
			Verify(lastUsedInBucket[i]<=Limits::Max_Number_Primitives_Per_Frame + Limits::Max_Number_ScreenQuads_Per_Frame);

			if( gEnableTextureSort && i != MLRState::AlphaPriority)
			{
				MLR_RENDER("Texture Sorting::MLRSortByOrder::RenderNow");
				Start_Timer(Texture_Sorting_Time);
				priorityBucket = &priorityBuckets[i];
				BinSorterSD(i, priorityBucket->GetData());
				Stop_Timer(Texture_Sorting_Time);
			}

			if(i != MLRState::AlphaPriority)
			{
				for(j=0;j<lastUsedInBucket[i];j++)
				{
					SortData *sd = &(*rawDrawData)[priorityBuckets[i][j]];
					Check_Pointer(sd);

					if(theCurrentState != sd->state.renderState)
					{
						SetDifferences(sd->state, sd->texture_2_3 & 0xffff, sd->texture_2_3>>16);
					}
					SortData::DrawFunc drawFunc = sd->Draw[sd->type];

	//				_clear87();
					(sd->*drawFunc)();
	//				_clear87();
				}
			}
			else
			{
				for(j=0;j<lastUsedInBucket[i];j++)
				{
					SortData *sd = &(*rawDrawData)[priorityBuckets[i][j]];
					Check_Pointer(sd);

					if( gEnableAlphaSort && (sd->type == SortData::TriList || sd->type == SortData::TriIndexedList) )
					{
						SortData::LoadSortAlphaFunc alphaFunc = sd->LoadSortAlpha[sd->type];

						alphaToSort += (sd->*alphaFunc)(this, alphaToSort, 0.0f);
					}
					else
					{
						if(theCurrentState != sd->state.renderState)
						{
							SetDifferences(sd->state, sd->texture_2_3 & 0xffff, sd->texture_2_3>>16);
						}
						SortData::DrawFunc drawFunc = sd->Draw[sd->type];

						(sd->*drawFunc)();
					}
				}
			}
		}

		if(alphaToSort > 0)
		{
			int ii, jj, hh;
			{
				MLR_RENDER("Alpha Sorting::RenderNow");
				Start_Timer(Alpha_Sorting_Time);
				// do a shell sort

				SortAlpha *tempSortAlpha;
				Stuff::DynamicArrayOf<SortAlpha*>
					*alphaArray;

				alphaArray = &alphaSort;

				for(hh=1;hh<alphaToSort/9;hh=3*hh+1);

				for(;hh>0;hh/=3)
				{
					for(ii=hh;ii<alphaToSort;ii++)
					{
						tempSortAlpha = (*alphaArray)[ii];

						jj = ii;

						while(jj>=hh && (*alphaArray)[jj-hh]->distance < tempSortAlpha->distance)
						{
							(*alphaArray)[jj] = (*alphaArray)[jj-hh];
							jj -= hh;

						}
						(*alphaArray)[jj] = tempSortAlpha;
					}
				}

				Stop_Timer(Alpha_Sorting_Time);
			}

			for(ii=0;ii<alphaToSort;ii++)
			{
				if(theCurrentState != alphaSort[ii]->render_state)
				{
					SetDifferences(alphaSort[ii]->render_state, (alphaSort[ii]->tex_2_3 & 0xffff), (alphaSort[ii]->tex_2_3 >> 16));
				}
				{
					static WORD renderIndex[] = {0, 1, 2};

					MLR_RENDER("GOS Draw::RenderNow");
					Start_Timer(GOS_Draw_Time);
					if(theCurrentState & MLRState::BumpMapMask)
					{
						gos_RenderIndexedArray( &(*MLRSorter::alphaBumpVertices)[alphaSort[ii]->triangle], 3, renderIndex, 3 );
					}
					else
					{
						gos_DrawTriangles( &(*MLRSorter::alphaVertices)[alphaSort[ii]->triangle], 3);
					}
					Stop_Timer(GOS_Draw_Time);
				}
			}
			Set_Statistic(NumberOfAlphaSortedTriangles, NumberOfAlphaSortedTriangles+alphaToSort);
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRSortByOrder::TestInstance() const
{
	Verify(IsDerivedFrom(DefaultData));
}

