#include "CompostHeaders.hpp"
#include <ElementRenderer\ListElement.hpp>
#include <ElementRenderer\ShapeElement.hpp>
#include <ElementRenderer\GridElement.hpp>
#include <MLR\MLRTexture.hpp>
#include <MLR\MLRTexturePool.hpp>
#include <MLR\MLRShape.hpp>
#include <MLR\MLR_Terrain2.hpp>
#include <Adept\Tile.hpp>

using namespace MidLevelRenderer;

//#define HUNT_FOR_THE_RED_TILE "micgaert"

TerrainTextureLogistic *TerrainTextureLogistic::Instance = NULL;
#ifdef LAB_ONLY
DWORD TerrainTextureLogistic::borderColor;
bool TerrainTextureLogistic::borderKey;
#endif

const unsigned char BasePriority = 32;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CompostQueue::CompostQueue()
{
	firstInQueue = 0;
	lastInQueue = 0;
	flipAround = 0;

	int i;
	for(i=0;i<Length_Of_Compost_Queue;i++)
	{
		compostQueuePointer[i] = NULL;
	}
	for(i=0;i<Length_Of_Compost_Queue_Tracker;i++)
	{
		compostQueueTracker[i] = 0;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	CompostQueue::Restart()
{
	firstInQueue = 0;
	lastInQueue = 0;
	flipAround = 0;

	int i, j, k;

	for(i=0,k=0;i<Length_Of_Compost_Queue_Tracker;i++)
	{
		if(compostQueueTracker[i] > 0)
		{
			int mask = 1;
			for(j=0;j<sizeof(DWORD)*8;j++,k++,mask<<=1)
			{
				if(mask & compostQueueTracker[i])
				{
					compostQueue[k].textureHolder->ShutDown();
				}
			}
		}
		else
		{
			k += sizeof(DWORD)*8;
		}
	}

	for(i=0;i<Length_Of_Compost_Queue;i++)
	{
		compostQueuePointer[i] = NULL;
	}
	for(i=0;i<Length_Of_Compost_Queue_Tracker;i++)
	{
		compostQueueTracker[i] = 0;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	CompostQueue::GetFirstFreeSpot()
{
	int i, j;

	for(i=0;i<Length_Of_Compost_Queue_Tracker;i++)
	{
		if(compostQueueTracker[i] == 0)
		{
			compostQueueTracker[i] |= 1;
			return i*sizeof(DWORD)*8;
		}

		if(compostQueueTracker[i] < 0xffffffff)
		{
			int mask = 1;
			for(j=0;j<sizeof(DWORD)*8;j++,mask<<=1)
			{
				if(!(mask & compostQueueTracker[i]))
				{
					compostQueueTracker[i] |= mask;
					return i*sizeof(DWORD)*8+j;
				}
			}
		}
	}

	return -1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	CompostQueue::SetCompostQueue(
		FeatureGrid *featureGrid,
		int row, 
		int column,
		TextureHolder *textureHolder,
		int downSample,
		int type
	)	
{	
#if 1
	int freeSpot = GetFirstFreeSpot();

	if(freeSpot<0)
	{
		return false;
	}

	compostQueue[freeSpot].featureGrid = featureGrid;
	compostQueue[freeSpot].row = row; 
	compostQueue[freeSpot].column = column;

	Verify(textureHolder->pix_dest != NULL);

#ifdef LAB_ONLY
	if(textureHolder->flags != TextureHolder::Free)
	{
		PAUSE(("Compost: Trying to work on a piece of texture already %s !",
			textureHolder->flags == TextureHolder::InWork?"in work":"done" ));
	}
#endif
	textureHolder->flags = TextureHolder::InWork;

	compostQueue[freeSpot].textureHolder = textureHolder;
	compostQueue[freeSpot].downSample = downSample;
	compostQueue[freeSpot].type = type;

	compostQueue[freeSpot].done = freeSpot;

	#ifdef _ARMOR
	compostQueue[freeSpot].textureHolder->queuePosition = freeSpot;
	#endif

#else
	compostQueue[lastInQueue].featureGrid = featureGrid;
	compostQueue[lastInQueue].row = row; 
	compostQueue[lastInQueue].column = column;
	compostQueue[lastInQueue].textureHolder = textureHolder;
	compostQueue[lastInQueue].downSample = downSample;
	compostQueue[lastInQueue].type = type;
	compostQueue[lastInQueue].done = done;

	#ifdef _ARMOR
	compostQueue[lastInQueue].textureHolder->queuePosition = lastInQueue;
	#endif

	if(++lastInQueue>=Length_Of_Compost_Queue)
	{
		lastInQueue = 0;
		flipAround++;
	}
#endif
	return true;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	CompostQueue::DoWork()
{
#if 1
	int i, j, k, workToDo = 0;

	for(i=0,k=0;i<Length_Of_Compost_Queue_Tracker;i++)
	{
		if(compostQueueTracker[i] > 0)
		{
			int mask = 1;
			for(j=0;j<sizeof(DWORD)*8;j++,k++,mask<<=1)
			{
				if(mask & compostQueueTracker[i])
				{
					if(
						(*compostQueue[k].textureHolder->priority < 0) ||
						(compostQueue[k].textureHolder->pix_dest == NULL)
					)
					{
						compostQueueTracker[i] &= ~mask;
					}
					else
					{
						compostQueuePointer[workToDo++] = &compostQueue[k];
					}
				}
			}
		}
		else
		{
			k += sizeof(DWORD)*8;
		}
	}

	if(workToDo == 0)
	{
		return;
	}

	int ii, jj, hh;

	CompostQueueStruct *tempCQS;

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

	for(;hh>0;hh/=3)
	{
		for(ii=hh;ii<workToDo;ii++)
		{
			tempCQS = compostQueuePointer[ii];

			jj = ii;

			while(jj>=hh && *compostQueuePointer[jj-hh]->textureHolder->priority < *tempCQS->textureHolder->priority)
			{
				compostQueuePointer[jj] = compostQueuePointer[jj-hh];
				jj -= hh;

			}
			compostQueuePointer[jj] = tempCQS;
		}
	}

	int workNotToDo = 0;

	while((workNotToDo<workToDo) && (*compostQueuePointer[workNotToDo]->textureHolder->priority <= 0))
	{
// do something with prio 0 one's
		EraseCompostQueueFlag(compostQueuePointer[workNotToDo]->done);

		workNotToDo++;
	}

	Set_Statistic(Number_Of_Worked_On_Textures, workToDo-workNotToDo);

	if(workToDo-workNotToDo <= 0)
	{
		return;
	}

	int advanceInQueue = 1;

	if(workToDo-workNotToDo > 32)
	{
		advanceInQueue = 4;
	}
	else if(workToDo-workNotToDo > 16)
	{
		advanceInQueue = 2;
	}
	else
	{
		advanceInQueue = 1;
	}

	for(i=workToDo-1,j=0;(i>=0)&&(j<advanceInQueue)&&(i>=workNotToDo);i--)
	{
		if(compostQueuePointer[i]->textureHolder->lastLine < 256)
		{
			Verify(compostQueuePointer[i]->textureHolder->pix_dest != NULL);
			compostQueuePointer[i]->Compose();
		}
		else
		{
			int index = compostQueuePointer[i]->textureHolder->textureHandle;

			if(index>0)
			{
				MLRTexture *texture = (*MidLevelRenderer::MLRTexturePool::Instance)[index];
				GOSImage *image = texture->GetImage();
#ifdef LAB_ONLY
				static char str[128];

				sprintf(str, "l:%d r:%d c:%d", 
					compostQueuePointer[i]->downSample ? 2 : 3,
					compostQueuePointer[i]->row, 
					compostQueuePointer[i]->column
				);
				Check_Object(image);
				gos_SetTextureName(image->GetHandle(), str);

	#ifdef HUNT_FOR_THE_RED_TILE
				SPEWALWAYS((HUNT_FOR_THE_RED_TILE, "%s", str));
	#endif
#endif

				image->UnlockImage();
			}

			compostQueuePointer[i]->textureHolder->flags = TextureHolder::Done;

			if(compostQueuePointer[i]->textureHolder->aelp!=NULL)
			{
				compostQueuePointer[i]->textureHolder->aelp_ptr = compostQueuePointer[i]->textureHolder->aelp;
				
				while(compostQueuePointer[i]->textureHolder->aelp_ptr->next!=NULL)
				{
					compostQueuePointer[i]->textureHolder->aelp_ptr = compostQueuePointer[i]->textureHolder->aelp_ptr->next;
				}

				while(compostQueuePointer[i]->textureHolder->aelp_ptr->prev!=NULL)
				{
					compostQueuePointer[i]->textureHolder->taelp = compostQueuePointer[i]->textureHolder->aelp_ptr->prev;

					Unregister_Pointer(compostQueuePointer[i]->textureHolder->aelp_ptr);
					delete compostQueuePointer[i]->textureHolder->aelp_ptr;

					compostQueuePointer[i]->textureHolder->aelp_ptr = compostQueuePointer[i]->textureHolder->taelp;
					compostQueuePointer[i]->textureHolder->aelp_ptr->next = NULL;
				}
				Unregister_Pointer(compostQueuePointer[i]->textureHolder->aelp_ptr);
				delete compostQueuePointer[i]->textureHolder->aelp_ptr;
				compostQueuePointer[i]->textureHolder->aelp_ptr = NULL;
			}

			EraseCompostQueueFlag(compostQueuePointer[i]->done);
		}
	}

#else
// let compose a bit
	int advanceInQueue = 1;

	if(lastInQueue+flipAround*Length_Of_Compost_Queue - firstInQueue > 32)
	{
		advanceInQueue = 4;
	}
	else if(lastInQueue+flipAround*Length_Of_Compost_Queue - firstInQueue > 16)
	{
		advanceInQueue = 2;
	}
	else
	{
		advanceInQueue = 1;
	}

//	SPEW(("micgaert", "%d %d", firstInQueue, lastInQueue));


	if(firstInQueue < lastInQueue+flipAround*Length_Of_Compost_Queue)
	{
		while(compostQueue[firstInQueue].done==true)
		{
			firstInQueue++;
			if(firstInQueue>=Length_Of_Compost_Queue)
			{
				firstInQueue = 0;
				flipAround--;
			}

			if(firstInQueue>=lastInQueue+flipAround*Length_Of_Compost_Queue)
			{
				break;
			}
		}
	}

	int i, j, k;
	i = k = firstInQueue;
	j = firstInQueue+advanceInQueue;

	for(;i<j;i++)
	{
		if(k>=lastInQueue+flipAround*Length_Of_Compost_Queue)
		{
			break;
		}

		if(*compostQueue[k].textureHolder->priority>0)
		{
			if(compostQueue[k].textureHolder->lastLine < 256)
			{
				compostQueue[k].Compose();
			}
			else
			{
				int index = compostQueue[k].textureHolder->textureHandle;

				if(index>0)
				{
					MLRTexture *texture = (*MidLevelRenderer::MLRTexturePool::Instance)[index];
					GOSImage *image = texture->GetImage();

#ifdef LAB_ONLY
					static char str[128];

					sprintf(str, "l:%d r:%d c:%d", 
						compostQueuePointer[i]->downSample ? 2 : 3,
						compostQueuePointer[i]->row,
						compostQueuePointer[i]->column 
					);
					Check_Object(image);
					gos_SetTextureName(image->GetHandle(), str);

	#ifdef HUNT_FOR_THE_RED_TILE
					SPEWALWAYS((HUNT_FOR_THE_RED_TILE, "%s", str));
	#endif
#endif
					image->UnlockImage();
				}

				compostQueue[k].textureHolder->flags = TextureHolder::Done;

				if(compostQueue[k].textureHolder->aelp!=NULL)
				{
					compostQueue[k].textureHolder->aelp_ptr = compostQueue[k].textureHolder->aelp;
					
					while(compostQueue[k].textureHolder->aelp_ptr->next!=NULL)
					{
						compostQueue[k].textureHolder->aelp_ptr = compostQueue[k].textureHolder->aelp_ptr->next;
					}

					while(compostQueue[k].textureHolder->aelp_ptr->prev!=NULL)
					{
						compostQueue[k].textureHolder->taelp = compostQueue[k].textureHolder->aelp_ptr->prev;

						Unregister_Pointer(compostQueue[k].textureHolder->aelp_ptr);
						delete compostQueue[k].textureHolder->aelp_ptr;

						compostQueue[k].textureHolder->aelp_ptr = compostQueue[k].textureHolder->taelp;
						compostQueue[k].textureHolder->aelp_ptr->next = NULL;
					}
					Unregister_Pointer(compostQueue[k].textureHolder->aelp_ptr);
					delete compostQueue[k].textureHolder->aelp_ptr;
					compostQueue[k].textureHolder->aelp_ptr = NULL;
				}

				compostQueue[k].done = true;
				if(firstInQueue>=Length_Of_Compost_Queue)
				{
					firstInQueue = 0;
					flipAround--;
				}
			}
		}
		else
		{
			compostQueue[k].done = true;
		}

		if(++k>=Length_Of_Compost_Queue)
		{
			k = 0;
		}
	}
#endif
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CompostQueueStruct*
	CompostQueue::IsInQueue(int row, int column, int downSample)
{
	int i, k;
	for(i=firstInQueue,k=firstInQueue;i<lastInQueue+flipAround*Length_Of_Compost_Queue;i++)
	{
		if(	compostQueue[k].row==row &&
			compostQueue[k].column==column &&
			compostQueue[k].downSample==downSample
		)
		{
			return &compostQueue[k];
		}

		if(++k>=Length_Of_Compost_Queue)
		{
			k = 0;
		}
	}
	return NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
TerrainTextureLogistic::TerrainTextureLogistic(
	int xg, int zg,
	Scalar xl, Scalar zl,
	const char *fileName
) :	x_grid(xg), z_grid(zg), x_grid_length(xl), z_grid_length(zl)
{
	Verify(gos_GetCurrentHeap() == Heap);
	Verify(Instance == NULL);

	featurePool = new FeaturePool();
	Register_Pointer(featurePool);
	
	Stuff::FileStream fstr(fileName);
	featurePool->LoadIndex(&fstr);
	featureGrid = new FeatureGrid(&fstr, featurePool);
	Register_Pointer(featureGrid);
	fstr.Close();

	int i, j;
	terrainMeshes.SetLength(x_grid*z_grid);

	textureHolder[0].SetLength(x_grid*z_grid);
	textureHolder[1].SetLength(x_grid*z_grid);

	if(featureGrid->gridSize > 256)
	{
		textureHolder[2].SetLength(x_grid*z_grid);
	}

	resolutionTracker[DesiredResolution].SetLength(x_grid*z_grid);
	resolutionTracker[CurrentResolution].SetLength(x_grid*z_grid);
	resolutionTracker[Priority].SetLength(x_grid*z_grid);
	resolutionTracker[DirtyFlag].SetLength(x_grid*z_grid);

	for(i=0;i<x_grid*z_grid;i++)
	{
		terrainMeshes[i].SetLength(0);
		resolutionTracker[CurrentResolution][i] = 0;
		resolutionTracker[Priority][i] = 0;
		resolutionTracker[DirtyFlag][i] = 0;

		textureHolder[0][i].priority = &resolutionTracker[Priority][i];
		textureHolder[1][i].priority = &resolutionTracker[Priority][i];
	}

	int endres = featureGrid->gridSize > 256 ? 5 : 4;

	for(j=2;j<endres;j++)
	{
		nrOfAllocatedTexture[j] = (unsigned char)((Number_Of_Reserved_Textures/8) << (5-j));
		nrOfUsedTextures[j] = 0;
		firstUnusedTexture[j] = 0;

//		SPEWALWAYS((0, "%d true", j));

		textureAvailable[j] = true;

		textures[j].SetLength(nrOfAllocatedTexture[j]);
		textureFlags[j].SetLength(nrOfAllocatedTexture[j]);
		
		char str[256];
		for(i=0;i<nrOfAllocatedTexture[j];i++)
		{
			sprintf(str, "tex_%1d_%03d", j, i);
			DWORD hints = 
//				gosHint_DisableMipmap | 
//				gosHint_UserMipMaps |
				gosHint_AGPMemory;

			textures[j][i] = MLRTexturePool::Instance->Add(str, gos_Texture_Solid, 32<<j, (gos_TextureHints)hints);
			textureFlags[j][i] = 0;
		}
	}

	Verify(x_grid == featureGrid->GetColumns());
	Verify(z_grid == featureGrid->GetRows());

#ifdef LAB_ONLY
	borderKey = false;
	borderColor = 0;
#endif
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
TerrainTextureLogistic::TerrainTextureLogistic(
	int xg, int zg,
	Scalar xl, Scalar zl,
	Stuff::MemoryStream *stream
) :	x_grid(xg), z_grid(zg), x_grid_length(xl), z_grid_length(zl)
{
	Verify(gos_GetCurrentHeap() == Heap);
	Verify(Instance == NULL);

#ifdef THE03HACK
	x_grid *= 2;
	z_grid *= 2;

	x_grid_length /= 2.0f;
	z_grid_length /= 2.0f;
#endif

	featurePool = new FeaturePool();
	Register_Pointer(featurePool);
	
	featurePool->LoadIndex(stream);
	featureGrid = new FeatureGrid(stream, featurePool);
	Register_Pointer(featureGrid);

	Verify(x_grid == featureGrid->GetColumns());
	Verify(z_grid == featureGrid->GetRows());

	int i, j;
	terrainMeshes.SetLength(x_grid*z_grid);

	textureHolder[0].SetLength(x_grid*z_grid);
	textureHolder[1].SetLength(x_grid*z_grid);

	if(featureGrid->gridSize > 256)
	{
		textureHolder[2].SetLength(x_grid*z_grid);
	}

	resolutionTracker[DesiredResolution].SetLength(x_grid*z_grid);
	resolutionTracker[CurrentResolution].SetLength(x_grid*z_grid);
	resolutionTracker[Priority].SetLength(x_grid*z_grid);
	resolutionTracker[DirtyFlag].SetLength(x_grid*z_grid);

	for(i=0;i<x_grid*z_grid;i++)
	{
		terrainMeshes[i].SetLength(0);
		resolutionTracker[CurrentResolution][i] = 0;
		resolutionTracker[Priority][i] = 0;
		resolutionTracker[DirtyFlag][i] = 0;

		textureHolder[0][i].priority = &resolutionTracker[Priority][i];
		textureHolder[1][i].priority = &resolutionTracker[Priority][i];
	}

	int endres = featureGrid->gridSize > 256 ? 5 : 4;

	for(j=2;j<endres;j++)
	{
		nrOfAllocatedTexture[j] = (unsigned char)((Number_Of_Reserved_Textures/8) << (5-j));

		nrOfUsedTextures[j] = 0;
		firstUnusedTexture[j] = 0;

//		SPEWALWAYS((0, "%d true", j));
		textureAvailable[j] = true;

		textures[j].SetLength(nrOfAllocatedTexture[j]);
		textureFlags[j].SetLength(nrOfAllocatedTexture[j]);
		
		gos_PushCurrentHeap(MidLevelRenderer::TexturePoolHeap);
		char str[256];
		for(i=0;i<nrOfAllocatedTexture[j];i++)
		{
			sprintf(str, "image_%1d_%03d", j, i);
			DWORD hints = 
//				gosHint_DisableMipmap |
//				gosHint_UserMipMaps |
				gosHint_AGPMemory | gosHint_DontShrink;

			textures[j][i] = MLRTexturePool::Instance->Add(str, gos_Texture_Solid, 32<<j, (gos_TextureHints)hints);
			textureFlags[j][i] = 0;
		}
		gos_PopCurrentHeap();
	}

#ifdef LAB_ONLY
	borderKey = false;
	borderColor = 0;
#endif
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
TerrainTextureLogistic::TerrainTextureLogistic(
	int xg, int zg,
	Scalar xl, Scalar zl,
	Stuff::NotationFile *notation
) :	x_grid(xg), z_grid(zg), x_grid_length(xl), z_grid_length(zl)
{
	Verify(gos_GetCurrentHeap() == Heap);
	Verify(Instance == NULL);

#ifdef THE03HACK
	x_grid *= 2;
	z_grid *= 2;

	x_grid_length /= 2.0f;
	z_grid_length /= 2.0f;
#endif

	featurePool = new FeaturePool();
	Register_Pointer(featurePool);
	
	featurePool->LoadIndex(notation);
	featureGrid = new FeatureGrid(notation, featurePool);
	Register_Pointer(featureGrid);

	Verify(x_grid == featureGrid->GetColumns());
	Verify(z_grid == featureGrid->GetRows());

	int i, j;
	terrainMeshes.SetLength(x_grid*z_grid);

	textureHolder[0].SetLength(x_grid*z_grid);
	textureHolder[1].SetLength(x_grid*z_grid);

	if(featureGrid->gridSize > 256)
	{
		textureHolder[2].SetLength(x_grid*z_grid);
	}

	resolutionTracker[DesiredResolution].SetLength(x_grid*z_grid);
	resolutionTracker[CurrentResolution].SetLength(x_grid*z_grid);
	resolutionTracker[Priority].SetLength(x_grid*z_grid);
	resolutionTracker[DirtyFlag].SetLength(x_grid*z_grid);

	for(i=0;i<x_grid*z_grid;i++)
	{
		terrainMeshes[i].SetLength(0);
		resolutionTracker[CurrentResolution][i] = 0;
		resolutionTracker[Priority][i] = 0;
		resolutionTracker[DirtyFlag][i] = 0;

		textureHolder[0][i].priority = &resolutionTracker[Priority][i];
		textureHolder[1][i].priority = &resolutionTracker[Priority][i];
	}

	int endres = featureGrid->gridSize > 256 ? 5 : 4;

	for(j=2;j<endres;j++)
	{
		nrOfAllocatedTexture[j] = (unsigned char)((Number_Of_Reserved_Textures/8) << (5-j));

		nrOfUsedTextures[j] = 0;
		firstUnusedTexture[j] = 0;

//		SPEWALWAYS((0, "%d true", j));
		textureAvailable[j] = true;

		textures[j].SetLength(nrOfAllocatedTexture[j]);
		textureFlags[j].SetLength(nrOfAllocatedTexture[j]);
		
		gos_PushCurrentHeap(MidLevelRenderer::TexturePoolHeap);
		char str[256];
		for(i=0;i<nrOfAllocatedTexture[j];i++)
		{
			sprintf(str, "image_%1d_%03d", j, i);
			DWORD hints = 
//				gosHint_DisableMipmap |
//				gosHint_UserMipMaps |
				gosHint_AGPMemory | gosHint_DontShrink;

			textures[j][i] = MLRTexturePool::Instance->Add(str, gos_Texture_Solid, 32<<j, (gos_TextureHints)hints);
			textureFlags[j][i] = 0;
		}
		gos_PopCurrentHeap();
	}

#ifdef LAB_ONLY
	borderKey = false;
	borderColor = 0;
#endif
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
TerrainTextureLogistic::~TerrainTextureLogistic()
{
	int i, j, len = terrainMeshes.GetLength();

//---------------------
//	Unlock all textures
//---------------------
	GOSImage *image = NULL;
	for(j=2;j<4;j++)
	{

		for(i=0;i<nrOfAllocatedTexture[j];i++)
		{
			image = textures[j][i]->GetImage();
			image->UnlockImage();
		}
	}

	for(i=0;i<len;i++)
	{
		terrainMeshes[i].SetLength(0);
	}

	len = textureHolder[0].GetLength();

	for(i=0;i<len;i++)
	{
		if(textureHolder[0][i].lastLine >= 0 && textureHolder[0][i].lastLine < featureGrid->gridSize)
		{
//			gos_UnLockTexture(textureHolder[0][i].imageHandle);

			int index = textureHolder[0][i].textureHandle;

			if(index > 0)
			{
				MLRTexture *texture = (*MidLevelRenderer::MLRTexturePool::Instance)[index];
				GOSImage *image = texture->GetImage();

				image->flags &= ~GOSImage::Locked;
			}

			if(textureHolder[0][i].aelp!=NULL)
			{
				textureHolder[0][i].aelp_ptr = textureHolder[0][i].aelp;
				
				while(textureHolder[0][i].aelp_ptr->next!=NULL)
				{
					textureHolder[0][i].aelp_ptr = textureHolder[0][i].aelp_ptr->next;
				}

				while(textureHolder[0][i].aelp_ptr->prev!=NULL)
				{
					textureHolder[0][i].taelp = textureHolder[0][i].aelp_ptr->prev;

					Unregister_Pointer(textureHolder[0][i].aelp_ptr);
					delete textureHolder[0][i].aelp_ptr;

					textureHolder[0][i].aelp_ptr = textureHolder[0][i].taelp;
					textureHolder[0][i].aelp_ptr->next = NULL;
				}
				Unregister_Pointer(textureHolder[0][i].aelp_ptr);
				delete textureHolder[0][i].aelp_ptr;
				textureHolder[0][i].aelp_ptr = NULL;
			}
		}
	}
	textureHolder[0].SetLength(0);

	len = textureHolder[1].GetLength();

	for(i=0;i<len;i++)
	{
		if(textureHolder[1][i].lastLine >= 0 && textureHolder[1][i].lastLine < featureGrid->gridSize)
		{
//			gos_UnLockTexture(textureHolder[1][i].imageHandle);

			int index = textureHolder[1][i].textureHandle;

			if(index > 0)
			{
				MLRTexture *texture = (*MidLevelRenderer::MLRTexturePool::Instance)[textureHolder[1][i].textureHandle];
				GOSImage *image = texture->GetImage();

				image->flags &= ~GOSImage::Locked;
			}

			if(textureHolder[1][i].aelp!=NULL)
			{
				textureHolder[1][i].aelp_ptr = textureHolder[1][i].aelp;
				
				while(textureHolder[1][i].aelp_ptr->next!=NULL)
				{
					textureHolder[1][i].aelp_ptr = textureHolder[1][i].aelp_ptr->next;
				}

				while(textureHolder[1][i].aelp_ptr->prev!=NULL)
				{
					textureHolder[1][i].taelp = textureHolder[1][i].aelp_ptr->prev;

					Unregister_Pointer(textureHolder[1][i].aelp_ptr);
					delete textureHolder[1][i].aelp_ptr;

					textureHolder[1][i].aelp_ptr = textureHolder[1][i].taelp;
					textureHolder[1][i].aelp_ptr->next = NULL;
				}
				Unregister_Pointer(textureHolder[1][i].aelp_ptr);
				delete textureHolder[1][i].aelp_ptr;
				textureHolder[1][i].aelp_ptr = NULL;
			}
		}
	}
	textureHolder[1].SetLength(0);

	for(i=0;i<4;i++)
	{
		textures[i].SetLength(0);
		textureFlags[i].SetLength(0);
	}

	Unregister_Pointer(featureGrid);
	delete featureGrid;

	Unregister_Pointer(featurePool);
	delete featurePool;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	TerrainTextureLogistic::Restart()
{
	Verify(gos_GetCurrentHeap() == Heap);
	compostQueue.Restart();

	int i, j;
	terrainMeshes.SetLength(x_grid*z_grid);

	j = resolutionTracker[DesiredResolution].GetLength();
	for(i=0;i<j;i++)
	{
		resolutionTracker[DesiredResolution][i] = 0xff;
		resolutionTracker[CurrentResolution][i] = 0xff;
		resolutionTracker[Priority][i] = 0;
	}

	int endres = (featureGrid->gridSize > 256 ? 5 : 4) - 2;

	for(i=0;i<endres;i++)
	{
		nrOfUsedTextures[i+2] = 0;
		firstUnusedTexture[i+2] = 0;

		for(j=0;j<nrOfAllocatedTexture[i+2];j++)
		{
			textureFlags[i+2][j] = 0;
			textureHolder[i][j].ShutDown();
		}
	}
}

void 
	ExtractAllMeshes(ElementRenderer::GroupElement*, DynamicArrayOf<MidLevelRenderer::MLR_Terrain2*>&, int&);
void 
	ExtractAllMeshes(ElementRenderer::ListElement*, DynamicArrayOf<MidLevelRenderer::MLR_Terrain2*>&, int&);
void 
	ExtractAllMeshes(ElementRenderer::ShapeElement*, DynamicArrayOf<MidLevelRenderer::MLR_Terrain2*>&, int&);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void 
	ExtractAllMeshes(ElementRenderer::GroupElement *gelement, DynamicArrayOf<MidLevelRenderer::MLR_Terrain2*>& array, int& count)
{
	Stuff::ChainIteratorOf<ElementRenderer::Element*> *gelements = gelement->MakeIterator();
	Register_Object(gelements);

	ElementRenderer::Element *element = NULL;

	while((element = gelements->ReadAndNext())!=NULL)
	{
		switch(element->GetClassID())
		{
			case ElementRenderer::GroupElementClassID:
				ExtractAllMeshes(Cast_Pointer(ElementRenderer::GroupElement*, element), array, count);
			break;
			case ElementRenderer::ListElementClassID:
				ExtractAllMeshes(Cast_Pointer(ElementRenderer::ListElement*, element), array, count);
			break;
			case ElementRenderer::ShapeElementClassID:
				ExtractAllMeshes(Cast_Pointer(ElementRenderer::ShapeElement*, element), array, count);
			break;
		}
	}
	Unregister_Object(gelements);
	delete gelements;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void 
	ExtractAllMeshes(ElementRenderer::ListElement *lelement, DynamicArrayOf<MidLevelRenderer::MLR_Terrain2*>& array, int& count)
{
	WORD i, len = lelement->GetActiveCount();

	for(i=0;i<len;i++)
	{
		ElementRenderer::Element *element = lelement->GetIndexedElement(i);

		switch(element->GetClassID())
		{
			case ElementRenderer::GroupElementClassID:
				ExtractAllMeshes(Cast_Pointer(ElementRenderer::GroupElement*, element), array, count);
			break;
			case ElementRenderer::ListElementClassID:
				ExtractAllMeshes(Cast_Pointer(ElementRenderer::ListElement*, element), array, count);
			break;
			case ElementRenderer::ShapeElementClassID:
				ExtractAllMeshes(Cast_Pointer(ElementRenderer::ShapeElement*, element), array, count);
			break;
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void 
	ExtractAllMeshes(ElementRenderer::ShapeElement *selement, DynamicArrayOf<MidLevelRenderer::MLR_Terrain2*>& array, int& count)
{
	MLRShape *shape = selement->GetMLRShape();

	int i, len = shape->GetNum();
	MidLevelRenderer::MLRPrimitiveBase *mesh = NULL;

	for(i=0;i<len;i++)
	{
		mesh = shape->Find(i);
		Check_Object(mesh);
		if(mesh->GetClassID() == MidLevelRenderer::MLR_Terrain2ClassID)
		{
			array[count] = Cast_Pointer(MLR_Terrain2*, mesh);
			array[count]->SetDepthData(3, 3);
			count++;
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void 
	ExtractAllMeshes(ElementRenderer::Element *element, DynamicArrayOf<MidLevelRenderer::MLR_Terrain2*>& array, int& count)
{
	switch(element->GetClassID())
	{
		case ElementRenderer::GroupElementClassID:
			ExtractAllMeshes(Cast_Pointer(ElementRenderer::GroupElement*, element), array, count);
		break;
		case ElementRenderer::ListElementClassID:
			ExtractAllMeshes(Cast_Pointer(ElementRenderer::ListElement*, element), array, count);
		break;
		case ElementRenderer::ShapeElementClassID:
			ExtractAllMeshes(Cast_Pointer(ElementRenderer::ShapeElement*, element), array, count);
		break;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	TerrainTextureLogistic::AttachZone(ElementRenderer::GridElement *grid, BYTE z_off, BYTE x_off)
{
	gos_PushCurrentHeap(Heap);
	Check_Object(grid);
	Check_Pointer(this);

	BYTE x_size, z_size;
	grid->GetSize(&z_size, &x_size);

#ifdef LAB_ONLY
	Scalar xdim, zdim, s1, s2;
	grid->GetDimensions(&s1, &s2, &zdim, &xdim);

#ifndef THE03HACK
	Verify(xdim==x_grid_length);
	Verify(zdim==z_grid_length);

	Verify(x_off+x_size<=x_grid);
	Verify(z_off+z_size<=z_grid);
#else
	Verify(xdim==2*x_grid_length);
	Verify(zdim==2*z_grid_length);

	Verify(x_off+x_size<=x_grid/2);
	Verify(z_off+z_size<=z_grid/2);
#endif

#endif

	Adept::Tile *element;
	BYTE i, j;
	int k, count;

	for(j=z_off;j<z_off+z_size;j++)
	{
		for(i=x_off;i<x_off+x_size;i++)
		{
			count = 0;

#ifndef THE03HACK
			terrainMeshes[j*x_grid + i].SetLength(32);

			element = Cast_Pointer(Adept::Tile*, grid->GetIndexedElement(static_cast<BYTE>(j-z_off), static_cast<BYTE>(i-x_off)));
			
			ExtractAllMeshes(element->m_ground, terrainMeshes[j*x_grid + i], count);

			terrainMeshes[j*x_grid + i].SetLength(count);

			for(k=0;k<count;k++)
			{
				Check_Object(terrainMeshes[j*x_grid + i][k]);
				terrainMeshes[j*x_grid + i][k]->SetCurrentDepth(0);
				terrainMeshes[j*x_grid + i][k]->CalculateUVs();
			}
#else
			terrainMeshes[2*j*x_grid + 2*i].SetLength(32);

			element = Cast_Pointer(Adept::Tile*, grid->GetIndexedElement(j-z_off, i-x_off));
			
			ExtractAllMeshes(element->m_ground, terrainMeshes[2*j*x_grid + 2*i], count);

			Verify(count==4);

			Scalar x0, x1, z0, z1;

			x0 = terrainMeshes[2*j*x_grid + 2*i][0]->GetFrame(2, 0);
			z0 = terrainMeshes[2*j*x_grid + 2*i][0]->GetFrame(2, 1);
			x1 = terrainMeshes[2*j*x_grid + 2*i][0]->GetFrame(2, 2);
			z1 = terrainMeshes[2*j*x_grid + 2*i][0]->GetFrame(2, 3);

			Verify(xdim == x1 - x0);
			Verify(zdim == z1 - z0);

#ifdef _ARMOR
			for(k=0;k<4;k++)
			{
				for(int l=2;l<8;l++)
				{
					Verify(x0 == terrainMeshes[2*j*x_grid + 2*i][k]->GetFrame(l, 0));
					Verify(z0 == terrainMeshes[2*j*x_grid + 2*i][k]->GetFrame(l, 1));
					Verify(x1 == terrainMeshes[2*j*x_grid + 2*i][k]->GetFrame(l, 2));
					Verify(z1 == terrainMeshes[2*j*x_grid + 2*i][k]->GetFrame(l, 3));
					
				}

				SPEW(("micgaert", "%d %d %d %x", i, j, k, (int)&terrainMeshes[2*j*x_grid + 2*i][k]));
			}
#endif
			Stuff::ExtentBox box;

			terrainMeshes[2*j*x_grid + 2*i + 1].SetLength(1);
			terrainMeshes[2*j*x_grid + 2*i + 1][0] = terrainMeshes[2*j*x_grid + 2*i][1];

			terrainMeshes[2*j*x_grid + 2*i + 1][0]->GetExtend(&box);

			Verify(box.minX>=x0+x_grid_length);
			Verify(box.maxX<=x1);
			Verify(box.minZ>=z0);
			Verify(box.maxZ<=z0+z_grid_length);

			for(k=2;k<8;k++)
			{
				terrainMeshes[2*j*x_grid + 2*i + 1][0]->SetFrame(k, x0+x_grid_length, z0, x1, z0+z_grid_length);
			}
			
			terrainMeshes[2*j*x_grid + 2*i + 1][0]->SetCurrentDepth(0);
			terrainMeshes[2*j*x_grid + 2*i + 1][0]->CalculateUVs();


			terrainMeshes[(2*j+1)*x_grid + 2*i].SetLength(1);
			terrainMeshes[(2*j+1)*x_grid + 2*i][0] = terrainMeshes[2*j*x_grid + 2*i][2];

			terrainMeshes[(2*j+1)*x_grid + 2*i][0]->GetExtend(&box);

			Verify(box.minX>=x0);
			Verify(box.maxX<=x0+x_grid_length);
			Verify(box.minZ>=z0+x_grid_length);
			Verify(box.maxZ<=z1);

			for(k=2;k<8;k++)
			{
				terrainMeshes[(2*j+1)*x_grid + 2*i][0]->SetFrame(k, x0, z0+z_grid_length, x0+x_grid_length, z1);
			}
			
			terrainMeshes[(2*j+1)*x_grid + 2*i][0]->SetCurrentDepth(0);
			terrainMeshes[(2*j+1)*x_grid + 2*i][0]->CalculateUVs();


			terrainMeshes[(2*j+1)*x_grid + 2*i + 1].SetLength(1);
			terrainMeshes[(2*j+1)*x_grid + 2*i + 1][0] = terrainMeshes[2*j*x_grid + 2*i][3];

			terrainMeshes[(2*j+1)*x_grid + 2*i + 1][0]->GetExtend(&box);

			Verify(box.minX>=x0+x_grid_length);
			Verify(box.maxX<=x1);
			Verify(box.minZ>=z0+z_grid_length);
			Verify(box.maxZ<=z1);

			for(k=2;k<8;k++)
			{
				terrainMeshes[(2*j+1)*x_grid + 2*i + 1][0]->SetFrame(k, x0+x_grid_length, z0+z_grid_length, x1, z1);
			}
			
			terrainMeshes[(2*j+1)*x_grid + 2*i + 1][0]->SetCurrentDepth(0);
			terrainMeshes[(2*j+1)*x_grid + 2*i + 1][0]->CalculateUVs();

			terrainMeshes[2*j*x_grid + 2*i][0] = terrainMeshes[2*j*x_grid + 2*i][0];
			terrainMeshes[2*j*x_grid + 2*i].SetLength(1);

			terrainMeshes[2*j*x_grid + 2*i][0]->GetExtend(&box);

			Verify(box.minX>=x0);
			Verify(box.maxX<=x0+x_grid_length);
			Verify(box.minZ>=z0);
			Verify(box.maxZ<=z0+z_grid_length);

			for(k=2;k<8;k++)
			{
				terrainMeshes[2*j*x_grid + 2*i][0]->SetFrame(k, x0, z0, x0+x_grid_length, z0+z_grid_length);
			}
			
			terrainMeshes[2*j*x_grid + 2*i][0]->SetCurrentDepth(0);
			terrainMeshes[2*j*x_grid + 2*i][0]->CalculateUVs();
#endif
		}
	}
	gos_PopCurrentHeap();

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	TerrainTextureLogistic::DetachMeshes(int z_off, int x_off, int z_size, int x_size)
{
	Check_Pointer(this);
	int i, j;

	Verify(x_off+x_size<=x_grid);
	Verify(z_off+z_size<=z_grid);

	for(j=z_off;j<z_off+z_size;j++)
	{
		for(i=x_off;i<x_off+x_size;i++)
		{
			terrainMeshes[j*x_grid + i].SetLength(0);
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	TerrainTextureLogistic::NextUnusedTexture(int res, int lastUnused)
{
	textureFlags[res][lastUnused] |= 1;

	unsigned char i;
	for(i=0;i<nrOfAllocatedTexture[res];i++)
	{
		if(!(textureFlags[res][i] & 1))
		{
			firstUnusedTexture[res] = i;

//			SPEWALWAYS((0, "%d true, %d", res, i));
			textureAvailable[res] = true;

			return;
		}
	}
//	SPEWALWAYS((0, "%d false, %d", res, nrOfAllocatedTexture[res]));
	textureAvailable[res] = false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	TerrainTextureLogistic::FreeUsedTexture(int res, int lastUsed)
{
	textureFlags[res][lastUsed] &= ~1;

	unsigned char i;
	for(i=0;i<nrOfAllocatedTexture[res];i++)
	{
		if(!(textureFlags[res][i] & 1))
		{
			firstUnusedTexture[res] = i;
//			SPEWALWAYS((0, "%d true, %d", res, i));
			textureAvailable[res] = true;

			return;
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	TerrainTextureLogistic::AddFeature(int index, Scalar x, Scalar z, int scale)
{
	Feature *feature = featurePool->GetFeature(index);

	if(feature==NULL)
	{
		return false;
	}

	int xg = (int)( ((x_grid*x_grid_length-(x-x_offset))*256.0f)/x_grid_length);
	int zg = (int)( ((z_grid*z_grid_length-(z-z_offset))*256.0f)/z_grid_length);

	xg -= feature->GetFeatureWidth()/2;
	zg -= feature->GetFeatureHeight()/2;

	xg &= ~3;
	zg &= ~3;

	gos_PushCurrentHeap(Compost::Heap);
	featureGrid->Add( feature, (WORD)xg, (WORD)zg );
	gos_PopCurrentHeap();
	
	compostQueue.Restart();

	int i, j, r_start, r_end, c_start, c_end;

	r_start = zg>>featureGrid->GetGridShift();
	r_start = r_start<0 ? 0 : r_start;

	r_end = ((zg+feature->GetFeatureHeight())>>featureGrid->GetGridShift())+1;
	r_end = r_end>featureGrid->GetRows() ? featureGrid->GetRows() : r_end;

	c_start = xg>>featureGrid->GetGridShift();
	c_start = c_start<0 ? 0 : c_start;

	c_end = ((xg+feature->GetFeatureWidth())>>featureGrid->GetGridShift())+1;
	c_end = c_end>featureGrid->GetColumns() ? featureGrid->GetColumns() : c_end;
	
	for(j=r_start;j<r_end;j++)
	{
		for(i=c_start;i<c_end;i++)
		{
// mark tiles as dirty
			int offset = (z_grid-j-1)*x_grid + (x_grid-i-1);
			resolutionTracker[CurrentResolution][offset] = 0;
			resolutionTracker[DirtyFlag][offset] = 1;

//			textureHolder[1][offset].textureHandle = -1;
//			textureHolder[0][offset].textureHandle = -1;
		}
	}

	return false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	TerrainTextureLogistic::SetNewPosition(
	const Stuff::LinearMatrix4D *now,
	const Stuff::LinearMatrix4D *soon,
	const Stuff::LinearMatrix4D *later
)
{

	Check_Object(now);
	if(soon!=NULL)
	{
		Check_Object(soon);
	}
	if(later!=NULL)
	{
		Check_Object(later);
	}

	static LinearMatrix4D lastPosition = LinearMatrix4D::Identity;
	static double lastTime = -1.0;

	double nowTime = gos_GetElapsedTime();

	Point3D gridLoc = Point3D::Identity, loc = Point3D::Identity, diff = Point3D::Identity;
	UnitVector3D forward;

	loc = *now;
	now->GetLocalForwardInWorld(&forward);

//	int column = (int)floor(loc.x/x_grid_length);
//	int row = (int)floor(loc.z/z_grid_length);


//	lets find out what we really want for a resolution

	int i, j, k, d, len;
	Scalar squaredDistance, dot;

	int count[5] = {0, 0, 0, 0, 0};

	for(j=0;j<z_grid;j++)
	{
		for(i=0;i<x_grid;i++)
		{
			gridLoc.x = (i+0.5f)*x_grid_length + x_offset;
			gridLoc.y = 0.0f;
			gridLoc.z = (j+0.5f)*z_grid_length + z_offset;
			
			diff.Subtract(gridLoc, loc);

			squaredDistance = diff.GetLengthSquared();

			dot = diff*forward;

			dot *= 2.0f*static_cast<Scalar>(fabs(dot));

			resolutionTracker[Priority][j*x_grid + i] = BasePriority;

			Scalar stretch = 1.0f;

			if(dot>squaredDistance)
			{
				resolutionTracker[Priority][j*x_grid + i] += 4;
			} else if(dot>0.0f)
			{
				resolutionTracker[Priority][j*x_grid + i] += 2;
			} else if(dot>-squaredDistance)
			{
				resolutionTracker[Priority][j*x_grid + i] -= 2;
			}
			else 
			{
				resolutionTracker[Priority][j*x_grid + i] -= 4;
			}


			if(squaredDistance < 10000.f*stretch)
			{
				resolutionTracker[DesiredResolution][j*x_grid + i] = 4;
				count[4]++;

			} else if(squaredDistance < 55000.f*stretch)
			{
				resolutionTracker[DesiredResolution][j*x_grid + i] = 3;
				count[3]++;

			} else if(squaredDistance < 300000.f*stretch)
			{
				resolutionTracker[DesiredResolution][j*x_grid + i] = 2;
				count[2]++;
			} else if(squaredDistance < 1440000.f*stretch)
			{
				resolutionTracker[DesiredResolution][j*x_grid + i] = 1;
				count[1]++;
			} else {
				resolutionTracker[DesiredResolution][j*x_grid + i] = 0;
				count[0]++;
			}
		}
#if 0
		SPEW(("micgaert", "%3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) %3x(%1d) ", 
			resolutionTracker[Priority][j*x_grid + 0], resolutionTracker[DesiredResolution][j*x_grid + 0],
			resolutionTracker[Priority][j*x_grid + 1], resolutionTracker[DesiredResolution][j*x_grid + 1],
			resolutionTracker[Priority][j*x_grid + 2], resolutionTracker[DesiredResolution][j*x_grid + 2],
			resolutionTracker[Priority][j*x_grid + 3], resolutionTracker[DesiredResolution][j*x_grid + 3],
			resolutionTracker[Priority][j*x_grid + 4], resolutionTracker[DesiredResolution][j*x_grid + 4],
			resolutionTracker[Priority][j*x_grid + 5], resolutionTracker[DesiredResolution][j*x_grid + 5],
			resolutionTracker[Priority][j*x_grid + 6], resolutionTracker[DesiredResolution][j*x_grid + 6],
			resolutionTracker[Priority][j*x_grid + 7], resolutionTracker[DesiredResolution][j*x_grid + 7],
			resolutionTracker[Priority][j*x_grid + 8], resolutionTracker[DesiredResolution][j*x_grid + 8],
			resolutionTracker[Priority][j*x_grid + 9], resolutionTracker[DesiredResolution][j*x_grid + 9],
			resolutionTracker[Priority][j*x_grid + 10], resolutionTracker[DesiredResolution][j*x_grid + 10],
			resolutionTracker[Priority][j*x_grid + 11], resolutionTracker[DesiredResolution][j*x_grid + 11],
			resolutionTracker[Priority][j*x_grid + 12], resolutionTracker[DesiredResolution][j*x_grid + 12],
			resolutionTracker[Priority][j*x_grid + 13], resolutionTracker[DesiredResolution][j*x_grid + 13],
			resolutionTracker[Priority][j*x_grid + 14], resolutionTracker[DesiredResolution][j*x_grid + 14],
			resolutionTracker[Priority][j*x_grid + 15], resolutionTracker[DesiredResolution][j*x_grid + 15],
			resolutionTracker[Priority][j*x_grid + 16], resolutionTracker[DesiredResolution][j*x_grid + 16],
			resolutionTracker[Priority][j*x_grid + 17], resolutionTracker[DesiredResolution][j*x_grid + 17],
			resolutionTracker[Priority][j*x_grid + 18], resolutionTracker[DesiredResolution][j*x_grid + 18],
			resolutionTracker[Priority][j*x_grid + 19], resolutionTracker[DesiredResolution][j*x_grid + 19],
			resolutionTracker[Priority][j*x_grid + 20], resolutionTracker[DesiredResolution][j*x_grid + 20],
			resolutionTracker[Priority][j*x_grid + 21], resolutionTracker[DesiredResolution][j*x_grid + 21],
			resolutionTracker[Priority][j*x_grid + 22], resolutionTracker[DesiredResolution][j*x_grid + 22],
			resolutionTracker[Priority][j*x_grid + 23], resolutionTracker[DesiredResolution][j*x_grid + 23],
			resolutionTracker[Priority][j*x_grid + 24], resolutionTracker[DesiredResolution][j*x_grid + 24],
			resolutionTracker[Priority][j*x_grid + 25], resolutionTracker[DesiredResolution][j*x_grid + 25],
			resolutionTracker[Priority][j*x_grid + 26], resolutionTracker[DesiredResolution][j*x_grid + 26],
			resolutionTracker[Priority][j*x_grid + 27], resolutionTracker[DesiredResolution][j*x_grid + 27],
			resolutionTracker[Priority][j*x_grid + 28], resolutionTracker[DesiredResolution][j*x_grid + 28],
			resolutionTracker[Priority][j*x_grid + 29], resolutionTracker[DesiredResolution][j*x_grid + 29],
			resolutionTracker[Priority][j*x_grid + 30], resolutionTracker[DesiredResolution][j*x_grid + 30],
			resolutionTracker[Priority][j*x_grid + 31], resolutionTracker[DesiredResolution][j*x_grid + 31]
		));
#endif
	}
//	SPEW(("micgaert", "\n"));

//	SPEW(("micgaert", "%d %d %d %d %d", count[0], count[1], count[2], count[3], count[4]));
//	lets see what we can do about it
	for(j=0;j<z_grid;j++)
	{
		for(i=0;i<x_grid;i++)
		{
			int offset = j*x_grid + i;
			len = terrainMeshes[offset].GetLength();
			d = 0;

			int res = resolutionTracker[DesiredResolution][offset] > terrainTextureResolution ? terrainTextureResolution : resolutionTracker[DesiredResolution][offset];

			while(res>1 && textureAvailable[res]==false)
			{
//				SPEWALWAYS((0, "%d down", res));
				res--;
			}

			switch(res)
			{
				case 3:
				{
					if(resolutionTracker[CurrentResolution][offset] !=3)
					{
						if(textureHolder[1][offset].textureHandle < 0)
						{
							textureHolder[1][offset].handle = firstUnusedTexture[3];
							textureHolder[1][offset].textureHandle = textures[3][firstUnusedTexture[3]]->GetTextureHandle();

							MLRTexture *texture = (*MidLevelRenderer::MLRTexturePool::Instance)[textureHolder[1][offset].textureHandle];
							GOSImage *image = texture->GetImage();

							textureHolder[1][offset].linesToProcess = 16;
							
#ifdef LAB_ONLY
							textureHolder[1][offset].borderKey = borderKey;
							textureHolder[1][offset].borderColor = borderColor;
#endif

							image->LockImage();

							textureHolder[1][offset].lastLine = -1;

							textureHolder[1][offset].aelp = NULL;
							textureHolder[1][offset].aelp_ptr = NULL;
							textureHolder[1][offset].taelp = NULL;

							textureHolder[1][offset].pix_dest = image->GetImagePtr();
							textureHolder[1][offset].pitch = image->GetPitch();

							compostQueue.SetCompostQueue(
								featureGrid,
								z_grid-j-1, 
								x_grid-i-1,
								&textureHolder[1][offset],
								0,
								0
							);

							NextUnusedTexture(3, firstUnusedTexture[3]);
						}
						else
						{
							if(textureHolder[1][offset].lastLine >= featureGrid->gridSize && textureHolder[1][offset].flags == TextureHolder::Done)
							{
								textureHolder[1][offset].flags = TextureHolder::Free;

								if(resolutionTracker[DirtyFlag][offset] > 0)
								{
									MLRTexture *texture = (*MidLevelRenderer::MLRTexturePool::Instance)[textureHolder[1][offset].textureHandle];
									GOSImage *image = texture->GetImage();

									textureHolder[1][offset].linesToProcess = 16;
									
#ifdef LAB_ONLY
									textureHolder[1][offset].borderKey = borderKey;
									textureHolder[1][offset].borderColor = borderColor;
#endif

									image->LockImage();

									textureHolder[1][offset].lastLine = -1;

									textureHolder[1][offset].aelp = NULL;
									textureHolder[1][offset].aelp_ptr = NULL;
									textureHolder[1][offset].taelp = NULL;

									textureHolder[1][offset].pix_dest = image->GetImagePtr();
									textureHolder[1][offset].pitch = image->GetPitch();

									compostQueue.SetCompostQueue(
										featureGrid,
										z_grid-j-1, 
										x_grid-i-1,
										&textureHolder[1][offset],
										0,
										0
									);

									resolutionTracker[DirtyFlag][offset] = 0;
								}
								else
								{
#if defined(LAB_ONLY) && defined(HUNT_FOR_THE_RED_TILE)
									MLRTexture *tex = (*MLRTexturePool::Instance)[textureHolder[1][offset].textureHandle];
									GOSImage *image = tex->GetImage();
									const char *tex_name = gos_GetTextureName(image->GetHandle());

									int lev, tX, tZ;

									sscanf(tex_name, "l:%d r:%d c:%d", &lev, &tZ, &tX);

									if(lev!=3 || tZ!=(z_grid-j-1) || tX!=(x_grid-i-1))
									{
										SPEWALWAYS((HUNT_FOR_THE_RED_TILE, "l:%d r:%d c:%d - %s", 3, z_grid-j-1, x_grid-i-1, tex_name));
									}
									else
									{
										SPEWALWAYS((HUNT_FOR_THE_RED_TILE, "l:%d r:%d c:%d - Y", 3, z_grid-j-1, x_grid-i-1));
									}
#endif
									for(k=0;k<len;k++)
									{
										//	get here composed texture

#if defined(LAB_ONLY) && defined(HUNT_FOR_THE_RED_TILE)
										BYTE itX, itZ;

										terrainMeshes[offset][k]->GetTileData(itX, itZ);

										if((tZ&0x7)!=(7-itZ) || (tX&0x7)!=(7-itX))
										{
											SPEWALWAYS((HUNT_FOR_THE_RED_TILE, "k:%d l:%d r:%d c:%d - N %d %d", k, 3, z_grid-j-1, x_grid-i-1, (7-itZ), (7-itX)));
										}
										else
										{
											SPEWALWAYS((HUNT_FOR_THE_RED_TILE, "k:%d l:%d r:%d c:%d - Y", k, 3, z_grid-j-1, x_grid-i-1, tex_name));
										}
#endif

										terrainMeshes[offset][k]->SetLevelTexture(3, textureHolder[1][offset].textureHandle);
			//							terrainMeshes[offset][k]->SetBorderPixel(1.0f/256.0f);
										terrainMeshes[offset][k]->SetCurrentDepth(3);
									}
								}
								resolutionTracker[CurrentResolution][offset] = 3;
							}
							else
							{
								if(resolutionTracker[DirtyFlag][offset] > 0)
								{
									MLRTexture *texture = (*MidLevelRenderer::MLRTexturePool::Instance)[textureHolder[1][offset].textureHandle];
									GOSImage *image = texture->GetImage();
									Check_Object(image);

									image->LockImage();

									if(textureHolder[1][offset].aelp!=NULL)
									{
										textureHolder[1][offset].aelp_ptr = textureHolder[1][offset].aelp;

										
										while(textureHolder[1][offset].aelp_ptr->next!=NULL)
										{
											textureHolder[1][offset].aelp_ptr = textureHolder[1][offset].aelp_ptr->next;
										}

										while(textureHolder[1][offset].aelp_ptr->prev!=NULL)
										{
											textureHolder[1][offset].taelp = textureHolder[1][offset].aelp_ptr->prev;

											Unregister_Pointer(textureHolder[1][offset].aelp_ptr);
											delete textureHolder[1][offset].aelp_ptr;

											textureHolder[1][offset].aelp_ptr = textureHolder[1][offset].taelp;
											textureHolder[1][offset].aelp_ptr->next = NULL;
										}
										Unregister_Pointer(textureHolder[1][offset].aelp_ptr);
										delete textureHolder[1][offset].aelp_ptr;
										textureHolder[1][offset].aelp_ptr = NULL;
									}

									textureHolder[1][offset].flags = TextureHolder::Free;

									textureHolder[1][offset].linesToProcess = 16;
									
#ifdef LAB_ONLY
									textureHolder[1][offset].borderKey = borderKey;
									textureHolder[1][offset].borderColor = borderColor;
#endif

									textureHolder[1][offset].lastLine = -1;

									textureHolder[1][offset].aelp = NULL;
									textureHolder[1][offset].aelp_ptr = NULL;
									textureHolder[1][offset].taelp = NULL;

									textureHolder[1][offset].pix_dest = image->GetImagePtr();
									textureHolder[1][offset].pitch = image->GetPitch();

									compostQueue.SetCompostQueue(
										featureGrid,
										z_grid-j-1, 
										x_grid-i-1,
										&textureHolder[1][offset],
										0,
										0
									);

									resolutionTracker[DirtyFlag][offset] = 0;

								}

#ifdef _ARMOR
/*							else
							{
								int ii, jj, kk;

								ii = kk = firstInQueue;
								jj = lastInQueue+flipAround*Length_Of_Compost_Queue;

							//	SPEW(("micgaert", "%d %d", firstInQueue, lastInQueue));
								if(kk>=lastInQueue+flipAround*Length_Of_Compost_Queue)
								{
									STOP(("Compost should process tile %d x %d !", i, j));
								}

								for(;ii<jj;ii++)
								{
									if(compostQueue[kk].textureHolder == &textureHolder[1][offset])
									{
										break;
									}
									if(++kk>=Length_Of_Compost_Queue)
									{
										kk = 0;
									}
								}
								if(ii>=jj)
								{
									STOP(("Compost should process tile %d x %d !", i, j));
								}

							}
*/
#endif
							}
						}
					}
				}
				break;
				case 2:
				{
					if(resolutionTracker[CurrentResolution][offset]!=2)
					{
						if(textureHolder[0][offset].textureHandle < 0)
						{
							textureHolder[0][offset].handle = firstUnusedTexture[2];
							textureHolder[0][offset].textureHandle = textures[2][firstUnusedTexture[2]]->GetTextureHandle();

							MLRTexture *texture = (*MidLevelRenderer::MLRTexturePool::Instance)[textureHolder[0][offset].textureHandle];
							GOSImage *image = texture->GetImage();

							textureHolder[0][offset].lastLine = -1;
							textureHolder[0][offset].linesToProcess = 32;

#ifdef LAB_ONLY
							textureHolder[0][offset].borderKey = borderKey;
							textureHolder[0][offset].borderColor = borderColor;
#endif

							image->LockImage();

							textureHolder[0][offset].aelp = NULL;
							textureHolder[0][offset].aelp_ptr = NULL;
							textureHolder[0][offset].taelp = NULL;

							textureHolder[0][offset].pix_dest = image->GetImagePtr();
							textureHolder[0][offset].pitch = image->GetPitch();

							compostQueue.SetCompostQueue(
								featureGrid,
								z_grid-j-1, 
								x_grid-i-1,
								&textureHolder[0][offset],
								1,
								0
							);

							NextUnusedTexture(2, firstUnusedTexture[2]);
						}
						else
						{
							if(textureHolder[0][offset].lastLine >= featureGrid->gridSize && textureHolder[0][offset].flags == TextureHolder::Done)
							{
								textureHolder[0][offset].flags = TextureHolder::Free;

								if(resolutionTracker[DirtyFlag][offset] > 0)
								{
									MLRTexture *texture = (*MidLevelRenderer::MLRTexturePool::Instance)[textureHolder[0][offset].textureHandle];
									GOSImage *image = texture->GetImage();

									textureHolder[0][offset].lastLine = -1;
									textureHolder[0][offset].linesToProcess = 32;

#ifdef LAB_ONLY
									textureHolder[0][offset].borderKey = borderKey;
									textureHolder[0][offset].borderColor = borderColor;
#endif

									image->LockImage();

									textureHolder[0][offset].aelp = NULL;
									textureHolder[0][offset].aelp_ptr = NULL;
									textureHolder[0][offset].taelp = NULL;

									textureHolder[0][offset].pix_dest = image->GetImagePtr();
									textureHolder[0][offset].pitch = image->GetPitch();

									compostQueue.SetCompostQueue(
										featureGrid,
										z_grid-j-1, 
										x_grid-i-1,
										&textureHolder[0][offset],
										1,
										0
									);
								}
								else
								{
#if defined(LAB_ONLY) && defined(HUNT_FOR_THE_RED_TILE)
									MLRTexture *tex = (*MLRTexturePool::Instance)[textureHolder[0][offset].textureHandle];
									GOSImage *image = tex->GetImage();
									const char *tex_name = gos_GetTextureName(image->GetHandle());

									int lev, tX, tZ;

									sscanf(tex_name, "l:%d r:%d c:%d", &lev, &tZ, &tX);

									if(lev!=2 || tZ!=(z_grid-j-1) || tX!=(x_grid-i-1))
									{
										SPEWALWAYS((HUNT_FOR_THE_RED_TILE, "l:%d r:%d c:%d - %s", 2, z_grid-j-1, x_grid-i-1, tex_name));
									}
									else
									{
										SPEWALWAYS((HUNT_FOR_THE_RED_TILE, "l:%d r:%d c:%d - Y", 2, z_grid-j-1, x_grid-i-1));
									}
#endif
									for(k=0;k<len;k++)
									{
					//	get here composed texture
#if defined(LAB_ONLY) && defined(HUNT_FOR_THE_RED_TILE)
										BYTE itX, itZ;

										terrainMeshes[offset][k]->GetTileData(itX, itZ);

										if((tZ&0x7)!=(7-itZ) || (tX&0x7)!=(7-itX))
										{
											SPEWALWAYS((HUNT_FOR_THE_RED_TILE, "k:%d l:%d r:%d c:%d - N %d %d", k, 2, z_grid-j-1, x_grid-i-1, (7-itZ), (7-itX)));
										}
										else
										{
											SPEWALWAYS((HUNT_FOR_THE_RED_TILE, "k:%d l:%d r:%d c:%d - Y", k, 2, z_grid-j-1, x_grid-i-1, tex_name));
										}
#endif
										terrainMeshes[offset][k]->SetLevelTexture(3, textureHolder[0][offset].textureHandle);
/*
#ifdef _DEBUG
//										Verify(textureHolder[0][offset].

										MLRTexture *texture = (*MidLevelRenderer::MLRTexturePool::Instance)[textureHolder[0][offset].textureHandle];
										GOSImage *image = texture->GetImage();
										int l1, r1, c1;

										const char *img_name = gos_GetTextureName(image->GetHandle());

										SPEW(("micgaert", "%s", img_name));
										if(img_name[0]=='l' && img_name[1]==':')
										{
											sscanf(img_name, "l:%d r:%d c:%d", &l1, &r1, &c1);
							
											Verify(l1==2);
											Verify(r1==z_grid-j-1);
											Verify(c1==x_grid-i-1);
										}
#endif
*/

//										terrainMeshes[offset][k]->SetBorderPixel(0.0f);
										terrainMeshes[offset][k]->SetCurrentDepth(3);
									}

									resolutionTracker[CurrentResolution][offset] = 2;
								}
							}
							else
							{
								if(resolutionTracker[DirtyFlag][offset] > 0)
								{
									MLRTexture *texture = (*MidLevelRenderer::MLRTexturePool::Instance)[textureHolder[0][offset].textureHandle];
									GOSImage *image = texture->GetImage();
									Check_Object(image);

									image->LockImage();

									if(textureHolder[0][offset].aelp!=NULL)
									{
										textureHolder[0][offset].aelp_ptr = textureHolder[0][offset].aelp;

										
										while(textureHolder[0][offset].aelp_ptr->next!=NULL)
										{
											textureHolder[0][offset].aelp_ptr = textureHolder[0][offset].aelp_ptr->next;
										}

										while(textureHolder[0][offset].aelp_ptr->prev!=NULL)
										{
											textureHolder[0][offset].taelp = textureHolder[0][offset].aelp_ptr->prev;

											Unregister_Pointer(textureHolder[0][offset].aelp_ptr);
											delete textureHolder[0][offset].aelp_ptr;

											textureHolder[0][offset].aelp_ptr = textureHolder[0][offset].taelp;
											textureHolder[0][offset].aelp_ptr->next = NULL;
										}
										Unregister_Pointer(textureHolder[0][offset].aelp_ptr);
										delete textureHolder[0][offset].aelp_ptr;
										textureHolder[0][offset].aelp_ptr = NULL;
									}

									textureHolder[0][offset].flags = TextureHolder::Free;

									textureHolder[0][offset].linesToProcess = 16;
									
#ifdef LAB_ONLY
									textureHolder[0][offset].borderKey = borderKey;
									textureHolder[0][offset].borderColor = borderColor;
#endif

									textureHolder[0][offset].lastLine = -1;

									textureHolder[0][offset].aelp = NULL;
									textureHolder[0][offset].aelp_ptr = NULL;
									textureHolder[0][offset].taelp = NULL;

									textureHolder[0][offset].pix_dest = image->GetImagePtr();
									textureHolder[0][offset].pitch = image->GetPitch();

									compostQueue.SetCompostQueue(
										featureGrid,
										z_grid-j-1, 
										x_grid-i-1,
										&textureHolder[0][offset],
										1,
										0
									);

									resolutionTracker[DirtyFlag][offset] = 0;

								}
#ifdef _ARMOR
/*							else
							{
								int ii, jj, kk;

								ii = kk = firstInQueue;
								jj = lastInQueue+flipAround*Length_Of_Compost_Queue;

							//	SPEW(("micgaert", "%d %d", firstInQueue, lastInQueue));
								if(kk>=lastInQueue+flipAround*Length_Of_Compost_Queue)
								{
									STOP(("Compost should process tile %d x %d !", i, j));
								}

								for(;ii<jj;ii++)
								{
									if(compostQueue[kk].textureHolder == &textureHolder[0][offset])
									{
										break;
									}
									if(++kk>=Length_Of_Compost_Queue)
									{
										kk = 0;
									}
								}
								if(ii>=jj)
								{
									STOP(("Compost should process tile %d x %d !", i, j));
								}

							}
*/
#endif
							}
						}
					}
				}
				break;
				case 1:
				{
					resolutionTracker[Priority][offset] = 0;	// not interesting anymore

					if(resolutionTracker[CurrentResolution][offset]!=1)
					{
						for(k=0;k<len;k++)
						{
#ifdef BORDERPIXEL
							terrainMeshes[j*x_grid + i][k]->SetBorderPixel(0.0f);
#endif
							terrainMeshes[j*x_grid + i][k]->SetCurrentDepth(1);
						}

						resolutionTracker[CurrentResolution][offset] = 1;
					}
				}
				break;
				default:
				{
					resolutionTracker[Priority][offset] = 0;	// not interesting anymore

					if(resolutionTracker[CurrentResolution][offset]!=0)
					{
						for(k=0;k<len;k++)
						{
#ifdef BORDERPIXEL
							terrainMeshes[j*x_grid + i][k]->SetBorderPixel(0.0f);
#endif
							terrainMeshes[j*x_grid + i][k]->SetCurrentDepth(0);
						}

						resolutionTracker[CurrentResolution][offset] = 0;
					}
				}
				break;
			}

#if 0
			for(k=0;k<len;k++)
			{
				MLRState state;

				state = terrainMeshes[j*x_grid + i][k]->GetReferenceState();

				MLRTexture *texture = (*MidLevelRenderer::MLRTexturePool::Instance)[state.GetTextureHandle()];

				SPEW(("jmalbert", "%d %d %d %d %s", i, j, resolutionTracker[DesiredResolution][offset], resolutionTracker[CurrentResolution][offset], texture->GetTextureName()));
			}
#endif
		}
	}

#if defined(LAB_ONLY) && defined(HUNT_FOR_THE_RED_TILE)

 	for(int jj=0;jj<z_grid;jj++)
	{
		for(int ii=0;ii<x_grid;ii++)
		{
			int offoff = jj*x_grid + ii;
			int lenlen = terrainMeshes[offoff].GetLength();

			for(k=0;k<lenlen;k++)
			{

				MLRTexture *tex = (*MLRTexturePool::Instance)[&terrainMeshes[offoff][k]->GetReferenceState()];
				GOSImage *image = tex->GetImage();
				const char *tex_name = gos_GetTextureName(image->GetHandle());

				int lev, tX, tZ;

				if(*tex_name=='l')
				{
					sscanf(tex_name, "l:%d r:%d c:%d", &lev, &tZ, &tX);

					if(tZ!=(z_grid-jj-1) || tX!=(x_grid-ii-1))
					{
						SPEWALWAYS((HUNT_FOR_THE_RED_TILE, "!r:%d c:%d - %s", z_grid-jj-1, x_grid-ii-1, tex_name));
					}
					else
					{
	//					SPEWALWAYS((HUNT_FOR_THE_RED_TILE, "l:%d r:%d c:%d - Y", 2, z_grid-j-1, x_grid-i-1));
					}
					
					
	//	get here composed texture
					BYTE itX, itZ;

					terrainMeshes[offoff][k]->GetTileData(itX, itZ);

					if((tZ&0x7)!=(7-itZ) || (tX&0x7)!=(7-itX))
					{
						SPEWALWAYS((HUNT_FOR_THE_RED_TILE, "!k:%d r:%d c:%d - N %d %d", k, z_grid-jj-1, x_grid-ii-1, (7-itZ), (7-itX)));
					}
					else
					{
	//					SPEWALWAYS((HUNT_FOR_THE_RED_TILE, "k:%d l:%d r:%d c:%d - Y", k, 2, z_grid-j-1, x_grid-i-1, tex_name));
					}
				}
			}
		}
	}
#endif


	compostQueue.DoWork();

//	free what we dont need

	int subtractor = 1;

	if(lastTime > 0.0f)
	{
		subtractor = (int)(30 * (nowTime-lastTime));

		if(subtractor<1)
		{
			subtractor = 1;
		}
	}

	for(j=0;j<z_grid;j++)
	{
		for(i=0;i<x_grid;i++)
		{
			int offset = j*x_grid + i;

			if(resolutionTracker[Priority][offset]>0)
			{
				resolutionTracker[Priority][offset] = (BYTE)(resolutionTracker[Priority][offset] - (subtractor<256 ? subtractor : 255));
			}

			for(k=0;k<2;k++)
			{
				if(textureHolder[k][offset].textureHandle>0 && resolutionTracker[Priority][offset]<=0)
				{
#if defined(LAB_ONLY) && defined(HUNT_FOR_THE_RED_TILE)
					MLRTexture *tex = (*MLRTexturePool::Instance)[textureHolder[k][offset].textureHandle];
					GOSImage *image = tex->GetImage();
					const char *tex_name = gos_GetTextureName(image->GetHandle());

					SPEWALWAYS((HUNT_FOR_THE_RED_TILE, "Free: %s", tex_name));
#endif
					FreeUsedTexture(k+2, textureHolder[k][offset].handle);
					textureHolder[k][offset].ShutDown();
				}
			}

			if(resolutionTracker[Priority][offset]<=0 && resolutionTracker[CurrentResolution][offset]>1)
			{
				len = terrainMeshes[offset].GetLength();

				for(k=0;k<len;k++)
				{
#ifdef BORDERPIXEL
					terrainMeshes[offset][k]->SetBorderPixel(0.0f);
#endif
					terrainMeshes[offset][k]->SetCurrentDepth(1);
				}

				resolutionTracker[CurrentResolution][offset] = 1;
			}
		}
	}

#ifdef LAB_ONLY
	for(i=0;i<nrOfAllocatedTexture[2];i++)
	{
		if(textureFlags[2][i] & 1)
		{
			Number_Of_Used_128_Textures++;
		}
	}

	for(i=0;i<nrOfAllocatedTexture[3];i++)
	{
		if(textureFlags[3][i] & 1)
		{
			Number_Of_Used_256_Textures++;
		}
	}
#endif

	lastTime = nowTime;
	lastPosition = *now;
}
