#include "stdafx.h"
#include "Renderer.h"
#include "BitmapDilation.h"
#include "..\Common\nvDXT\dxtlib.h"
#include "..\Common\nvDXT\dds.h"

#ifdef _DEBUG
	#pragma comment ( lib, "..\\Common\\nvDXT\\nvDXTlibMT.lib" )
//#pragma comment ( lib, "..\\Common\\nvDXT\\nvDXTlibMTd.lib" )
#else
	#pragma comment ( lib, "..\\Common\\nvDXT\\nvDXTlibMT.lib" )
#endif

#define DEBUGTEXT									1
//#define DEBUG_CHECKERBOARD				1

#define DISTRIBUTED_MAP_VERSION		1
#define OCTREE_FILE_VERSION				1

const f32 gf_PI  =  3.14159265358979323846264338327950288419716939937510f; // pi

uint8* MemBufferCounter=0;
int m_numMips=0;

long SaveCompessedMipmapLevel( void * data, int miplevel, uint32 size, int width, int height, void * user_data )
{
	assert( MemBufferCounter );
	uint8* src=(uint8*)data;
	for (uint32 i=0; i<size; i++) 
	{
		*MemBufferCounter=src[i];
		MemBufferCounter++;
	}
	m_numMips++;
	return 0;
}


bool ConvertToDXT( const char* szFileName, uint8* pData,int nWidth,int nHeight, int nSrcBytesPerPix,bool bGenMips )
{
	if( NULL == pData )
		return false;

	FILE*		f;

	fopen_s( &f, szFileName, "wb" );
	if( NULL == f )
		return false;


	uint8* pDXT=new uint8[nWidth*nHeight+4+sizeof(DDS_HEADER)];
	MemBufferCounter = pDXT;
	m_numMips=0;

	*MemBufferCounter='D'; MemBufferCounter++;
	*MemBufferCounter='D'; MemBufferCounter++;
	*MemBufferCounter='S'; MemBufferCounter++;
	*MemBufferCounter=' '; MemBufferCounter++;

	DDS_HEADER ddsh;
	memset(&ddsh, 0, sizeof(DDS_HEADER) );
	ddsh.dwSize = sizeof(DDS_HEADER);
	ddsh.dwWidth	= nWidth;
	ddsh.dwHeight = nHeight;
	ddsh.ddspf = DDSPF_L8;
	ddsh.dwHeaderFlags = DDS_HEADER_FLAGS_TEXTURE;
	ddsh.dwSurfaceFlags = DDS_SURFACE_FLAGS_TEXTURE;

	uint8* hsrcDXT =(uint8*)(&ddsh);
	for (uint32 i=0; i<sizeof(ddsh); i++) {
		*MemBufferCounter=hsrcDXT[i];	MemBufferCounter++;
	}


	CompressionOptions opt;
	opt.TextureFormat = kL8;
	opt.MIPFilterType = kMIPFilterQuadratic;
	opt.MipMapType = bGenMips ? dGenerateMipMaps : dNoMipMaps;

	nvDXTcompressBGRA(pData,nWidth,nHeight,nWidth*nSrcBytesPerPix,&opt,nSrcBytesPerPix,(MIPcallback)SaveCompessedMipmapLevel);

	DDS_HEADER* pHeader=(DDS_HEADER*)(pDXT+4);
	if( m_numMips > 1 )
	{
		pHeader->dwMipMapCount = m_numMips;
		pHeader->dwHeaderFlags |= DDS_HEADER_FLAGS_MIPMAP;
		pHeader->dwSurfaceFlags |= DDS_SURFACE_FLAGS_MIPMAP;

	}

	fwrite( pDXT, MemBufferCounter-pDXT, 1, f );
	fclose(f);

	SAFE_DELETE_ARRAY( pDXT );
	return true;
}


/////////////////////////////////////////////////////////////////////////////////////////
inline void CreateUniformDistribution( const f32 fsquareX, const f32 fsquareY, f32& fTheta, f32& fPhi )
{
	f32 x,y,fOctant;
	//from [0,1] to [-1,1]
	f32 fX = fsquareX*2-1;
	f32 fY = fsquareY*2-1;

	//check the octants
	if( fY > -fX )
	{
		if( fX > fY )
		{
			x = fX;
			if( 0 < fY )
			{
				fOctant = 0;
				y = fY;
			}
			else
			{
				fOctant = 7;
				y = fY + fX;
			}
		}
		else
		{
			x = fY;
			if( 0 < fX )
			{
				fOctant = 1;
				y = fY-fX;
			}
			else
			{
				fOctant = 2;
				y = -fX;
			}
		}
	}
	else
	{
		if( fX < fY )
		{
			x = -fX;
			if( 0 < fY )
			{
				fOctant = 3;
				y = -fY-fX;
			}
			else
			{
				fOctant = 4;
				y = -fY;
			}
		}
		else
		{
			x = -fY;
			if( 0 < fX )
			{
				fOctant = 6;
				y = fX;
			}
			else
			{
				if( fY != 0 )
				{
					fOctant = 5;
					y = fX-fY;
				}
				else
				{
					x = 0;
					y = 0;
					fOctant = 0;
				}
			}
		}
	}

	fTheta = acosf( 1 - x*x );
	fPhi = (fOctant + y / x ) * gf_PI* 0.25f;
}

/////////////////////////////////////////////////////////////////////////////////////////
void CIntersectionCacheCluster::Init( const int32 nSideSize )
{
	m_nSideSize = nSideSize;
	m_nFaceSize = nSideSize*nSideSize;
	m_fHalfSideSize = nSideSize*0.5f;


	SAFE_DELETE_ARRAY( m_pCluster );
	int32 nSize  = m_nFaceSize*6;
	m_pCluster = new COctreeCell*[nSize];
	memset( m_pCluster, 0, sizeof(COctreeCell*)*nSize);
}


/////////////////////////////////////////////////////////////////////////////////////////
void cOctree::GeneratePointersForCells( COctreeCell *pCell )
{
	//item pointer
	int32 nItemID = *(int32*)&(pCell->m_item);
	pCell->m_item = &m_pCellItemArray[ nItemID ];

	//update the childrens too...
	for( int32 i = 0; i < pCell->m_ChildrenNumber; ++i )
	{
		pCell->m_children[i] = &m_pCellArray[ *(int32*)&(pCell->m_children[i]) ];
		assert( pCell->m_children[i] );
		GeneratePointersForCells( pCell->m_children[i] );
	}
}


/////////////////////////////////////////////////////////////////////////////////////////
JobServerResult cOctree::Load( const char* szFileName )
{
	if( NULL == szFileName )
		return JSRESULT_FINISHED;

//	printf("DLC   Octree loading: %s\n", szFileName );

	FILE* fOctree;
	fopen_s( &fOctree, szFileName, "rb" );
//	fopen_s( &fOctree, "c:\\octree.dat", "rb" );
	if( NULL == fOctree )
	{
		Log("RAMJobServer: Octree file not found.\n");
		return JSRESULT_DATA_ERROR;
	}

	uint32 nData;
	fread( &nData, sizeof(uint32),1, fOctree );
	if( nData != OCTREE_FILE_VERSION )
	{
		Log("RAMJobServer: Octree file have a different version.\n");
		return JSRESULT_DATA_ERROR;
	}

	fread( &m_nTriangleNumber, sizeof(uint32),1, fOctree );

	int32 nTriSize = m_nTriangleNumber*18;
	m_pTriangles = new float[ nTriSize ];
	if( NULL == m_pTriangles )
	{
		Log("RAMJobServer:  Can't allocate the octree triangle memory!\n" );
		return JSRESULT_INTERNAL_ERROR;
	}

	size_t nPos,nLoaded,nActSize;

	//sequental loading because of the network issues
	nPos = 0;
	do 
	{
		nActSize = (nTriSize-nPos) > 1024*4 ? 1024*4 : (nTriSize-nPos);
		nLoaded = fread( &m_pTriangles[nPos], 1, nActSize*sizeof(float), fOctree );
		nPos += nLoaded / sizeof(float);
	} while(nPos < (size_t) nTriSize && 0 != nLoaded );


//	nTriSize *= sizeof(float);
//	if( nTriSize != fread( m_pTriangles, 1, nTriSize, fOctree ) )
	if( nTriSize != nPos )
	{
		Log("RAMJobServer:  Can't load the octree in the normal way (Triangle loading problem)!\n" );
		return JSRESULT_INTERNAL_ERROR;
	}

	int32 nNumberOfCell, nNumberOfItem;

	fread( &nNumberOfCell, sizeof(int32), 1, fOctree );
	m_pCellArray = new COctreeCell[ nNumberOfCell ];
	if( NULL == m_pCellArray )
	{
		Log("RAMJobServer:  Can't allocate the octree cell memory!\n" );
		return JSRESULT_INTERNAL_ERROR;
	}
//	fread( m_pCellArray, sizeof(COctreeCell)*nNumberOfCell,1,fOctree );
	//sequental loading because of the network issues
	nPos = 0;
	do 
	{
		nActSize = (nNumberOfCell-nPos) > 1024*4 ? 1024*4 : (nNumberOfCell-nPos);
		nLoaded = fread( &m_pCellArray[nPos], 1, nActSize*sizeof(COctreeCell), fOctree );
		nPos += nLoaded / sizeof(COctreeCell);
	} while(nPos < (size_t)nNumberOfCell && 0 != nLoaded );

	if( nNumberOfCell != nPos )
	{
		Log("RAMJobServer:  Can't load the octree in the normal way (Cell loading problem)!\n" );
		return JSRESULT_INTERNAL_ERROR;
	}

	fread( &nNumberOfItem, sizeof(int32), 1, fOctree );
	m_pCellItemArray = new int32[ nNumberOfItem ];
	if( NULL == m_pCellItemArray )
	{
		Log("RAMJobServer:  Can't allocate the octree cell item memory!\n" );
		return JSRESULT_INTERNAL_ERROR;
	}

//	fread( m_pCellItemArray, sizeof(int32)*nNumberOfItem,1,fOctree );
	//sequental loading because of the network issues
	nPos = 0;
	do 
	{
		nActSize = (nNumberOfItem-nPos) > 1024*4 ? 1024*4 : (nNumberOfItem-nPos);
		nLoaded = fread( &m_pCellItemArray[nPos], 1, nActSize*sizeof(int32), fOctree );
		nPos += nLoaded / sizeof(int32);
	} while(nPos < (size_t)nNumberOfItem && 0 != nLoaded );

	if( nNumberOfItem != nPos )
	{
		Log("RAMJobServer:  Can't load the octree in the normal way (item loading problem)!\n" );
		return JSRESULT_INTERNAL_ERROR;
	}


	//the first element is the root
	m_pRoot = &(m_pCellArray[0]);
	GeneratePointersForCells( m_pRoot );

	
#ifdef DEBUGTEXT
//	printf("DLC   TriangleNumber: %d\n", m_nTriangleNumber );
#endif
	fclose(fOctree);
	return JSRESULT_OK;
};

/////////////////////////////////////////////////////////////////////////////////////////
JobServerResult cRenderer::BlurIt( const char* szDirectory, const int32 nID )
{
	if( NULL == szDirectory )
	{
		Log("RAMJobServer: Bluring, directory is a NULL string\n");
		return JSRESULT_DATA_ERROR;
	}

	char szFileName[MAX_PATH];
	sprintf_s( szFileName, MAX_PATH, "%s%d.DM", szDirectory, nID );
	fopen_s( &f, szFileName, "rb" );
	if( NULL == f )
	{
		Log("RAMJobServer: DM File not found. (%s)!\n",szFileName );
		return JSRESULT_DATA_ERROR;
	}


	uint8 nChunk;
	uint32 nData;
	fread( &nChunk, sizeof(uint8), 1, f);

	if( 1 != nChunk )
	{
		Log("RAMJobServer:	WRONG DM File(%s)!\n",szFileName );
		return JSRESULT_DATA_ERROR;
	}

	fread( &nData, sizeof(uint32), 1, f);

	if( DISTRIBUTED_MAP_VERSION != nData )
	{
		Log("RAMJobServer:  WRONG DM File version (%s)!\n",szFileName );
		return JSRESULT_DATA_ERROR;
	}

	fread( &m_nHeight, sizeof(int32), 1, f);
	fread( &m_nWidth, sizeof(int32), 1, f);
	fread( &m_nSampleNumber, sizeof(uint32), 1, f);
	fread( &m_nBlockSize, sizeof(uint32), 1, f);

//	printf("DLC>  scan the file.\n" );
	uint32 nStartOffset = sizeof(uint8)+sizeof(uint32)*5;
	uint32 nOffset = nStartOffset;
	m_nPixelNumber = 0;

	CBitmapDilation* pBitmapDilation = new CBitmapDilation( m_nWidth, m_nHeight );
	if( NULL == pBitmapDilation )
	{
		Log("RAMJobServer: Can't allocate the CBitmapDilation\n");
		return JSRESULT_INTERNAL_ERROR;
	}

	while(true)
	{
		uint8 nChunk = 0;
		fread( &nChunk, sizeof(uint8), 1, f);
		if( 2 != nChunk )
		{
			m_RS = RS_POSTPROCESS;
			break;
		}

		fread( &m_nChunkWidth, sizeof(int32), 1, f );
		fread( &m_nChunkHeight, sizeof(int32), 1, f );
		fread( &m_nChunkComponentOffset, sizeof(int32), 1, f );
		fread( &m_nChunkSpanDirection, sizeof(uint8), 1, f );
		fread( &m_nChunkOctreeID, sizeof(int32), 1, f );

		m_pData = new uint8[ m_nChunkHeight*m_nChunkWidth*m_nBlockSize];
		if( NULL == m_pData )
		{
			Log("RAMJobServer:  Can't allocate the chunk memory!\n" );
			m_RS = RS_FINISHED;
			return JSRESULT_DATA_ERROR;
		}

		fread( m_pData, sizeof(uint8)*m_nChunkHeight*m_nChunkWidth*m_nBlockSize, 1, f );

		m_nPixelID = 0;

		for( int32 i = 0; i < m_nChunkHeight*m_nChunkWidth; ++i )
		{
			int32 nY = m_nPixelID / m_nChunkWidth;
			int32 nX = m_nPixelID - nY * m_nChunkWidth;
			int32 nPicturePosition =	GenerateIndexFromCoordiatesToSurface( m_nChunkSpanDirection, nX, nY, m_nWidth, m_nChunkWidth, m_nChunkHeight ) + m_nChunkComponentOffset;

			int32 nnY = nPicturePosition / 1024;
			int32 nnX = nPicturePosition  - nnY * 1024;

			//if it's a valid pixel
			if( 1 == m_pData[ m_nPixelID*m_nBlockSize ] )
				pBitmapDilation->SetValid( nnX, nnY );

			++m_nPixelID;
		}

		SAFE_DELETE_ARRAY( m_pData );
	}

	fclose(f);

	///load the tga file
	sprintf_s( szFileName, MAX_PATH, "%se%d.tga", szDirectory, nID );
	uint8* pOldData = Load8BitTGA( szFileName );
	if( NULL == pOldData )
	{
			Log("RAMJobServer: can't load the 8bit tga.\n");
			return JSRESULT_INTERNAL_ERROR;
	}

	m_pPicture = new float[ m_nWidth*m_nHeight ];
	if( NULL == m_pPicture )
	{
		Log("RAMJobServer:  Can't allocate the picture memory!\n" );
		return JSRESULT_INTERNAL_ERROR;
	}
	memset( m_pPicture, 0, m_nWidth*m_nHeight*sizeof(float) );


	//Bluring
	uint32 dwNoEnd = pBitmapDilation->ComputeEndNoAtCertainDistance(1);
	for( int Y = 0; Y < m_nHeight; ++Y )
		for( int X = 0; X < m_nWidth; ++X )
		{
			float fAccumlator = 0;
			int   nPointNumber = 0;

			if( pBitmapDilation->IsValidBorder( X, Y) )
				for( uint32 i = 0; i < dwNoEnd; ++i )
				{
					int iX,iY;
					if( pBitmapDilation->GetSpiralPoint( i, iX, iY ) )
					{
						if( X+iX >= 0 && Y+iY >= 0 && pBitmapDilation->IsValidBorder( X+iX, Y+iY) )
						{
							fAccumlator += pOldData[ (Y+iY)*m_nWidth+X+iX ]/256.f;
							++nPointNumber;
						}
					}
				}

			m_pPicture[ Y*m_nWidth+X ] = fAccumlator / (float)nPointNumber;
		}

	SAFE_DELETE_ARRAY( pOldData );
	SAFE_DELETE( pBitmapDilation );

	///save the tga file
	sprintf_s( szFileName, MAX_PATH, "%se%d.tga", szDirectory, nID );
	if( false == Save8BitTGA( szFileName, m_pPicture, m_nWidth, m_nHeight ) )
	{
		Log("RAMJobServer:  Can't save the TGA file (%s)!\n", szFileName );
		m_RS = RS_FINISHED;
		SAFE_DELETE_ARRAY( m_pPicture );
		return JSRESULT_DATA_ERROR;
	}
	sprintf_s( szFileName, MAX_PATH, "%se%d.dds", szDirectory, nID );
	if( false == Save8BitDDS( szFileName, m_pPicture, m_nWidth, m_nHeight ) )
	{
		Log("RAMJobServer:  Can't save the DDS file (%s)!\n", szFileName );
		m_RS = RS_FINISHED;
		SAFE_DELETE_ARRAY( m_pPicture );
		return JSRESULT_DATA_ERROR;
	}

	SAFE_DELETE_ARRAY( m_pPicture );
	return JSRESULT_FINISHED;
}


/////////////////////////////////////////////////////////////////////////////////////////
JobServerResult cRenderer::Init( const char* szDirectory, const int32 nID, const int32 nM1, const int32 nM2, const int32 nSSNumber, const int32 nSSID, const int32 nWorkID )
{
	//Setup datas
	m_nActualOctreeID = -1;
	m_nStatOctreeChanges =
	m_nStatChunkNumber = 0;
	strcpy_s( m_szDirectory, MAX_PATH, szDirectory );
	m_nFileID = nID;
	m_RS = RS_FINISHED;
	m_pOctree = NULL;
	m_iM1 = nM1 > 0 ? nM1 : 1;
	m_iM2 = nM2 > 0 ? nM2 : 1;
	m_nSSID = nSSID*6;
	m_iSSNumber = nSSNumber > 0 ? nSSNumber : 1;

	if( NULL == szDirectory )
	{
		Log("RAMJobServer: Init - the directory is a NULL string\n");
		return JSRESULT_DATA_ERROR;
	}

	char szFileName[MAX_PATH];
	sprintf_s( szFileName, MAX_PATH, "%s%d.DM", szDirectory, nID );
	fopen_s( &f, szFileName, "rb" );
	if( NULL == f )
	{
		Log("RAMJobServer:  DM File not found. (%s)!\n",szFileName );
		return JSRESULT_DATA_ERROR;
	}

	uint8 nChunk;
	uint32 nData;
	fread( &nChunk, sizeof(uint8), 1, f);

	if( 1 != nChunk )	
	{
		Log("RAMJobServer:  WRONG DM File(%s)!\n",szFileName );
		return JSRESULT_DATA_ERROR;
	}

	fread( &nData, sizeof(uint32), 1, f);

	if( DISTRIBUTED_MAP_VERSION != nData )
	{
		Log("RAMJobServer:  WRONG DM File version (%s)!\n",szFileName );
		return JSRESULT_DATA_ERROR;
	}

	fread( &m_nHeight, sizeof(int32), 1, f);
	fread( &m_nWidth, sizeof(int32), 1, f);

	fread( &m_nSampleNumber, sizeof(uint32), 1, f);

	//needed a check to not try to use more than we have
	m_iSSNumber = m_iSSNumber > (int32)m_nSampleNumber ? (int32)m_nSampleNumber : m_iSSNumber;

	// MartinM test
	m_iSSNumber=1;

	//don't care about them.. try to comile something which can't...
	if( m_nSSID > m_iSSNumber*6 )
	{
		Log("RAMJobServer: wrong supersampling number\n");
		return JSRESULT_DATA_ERROR;
	}

	fread( &m_nBlockSize, sizeof(uint32), 1, f);

	m_pPicture = new float[ m_nWidth*m_nHeight ];
	if( NULL == m_pPicture )
	{
		Log("RAMJobServer:  Can't allocate the picture memory!\n" );
		return JSRESULT_INTERNAL_ERROR;
	}
	memset( m_pPicture, 0, m_nWidth*m_nHeight*sizeof(float) );

	m_CacheCluster.Init(10);

	m_fSSDivider = 0;
	for( int32 nSuperSampling = 0; nSuperSampling < m_iSSNumber; ++nSuperSampling )
	{
		f32 fPhi,fTheta, fX, fY;
		float fCoss = 0;

		for( int32 i = 0; i < m_iM1; ++i )
			for( int32 j = 0; j < m_iM2; ++j )
			{
				fY = (i + (f32)rand() /(f32)RAND_MAX ) / (f32)(m_iM1);
				fX = (j + (f32)rand() /(f32)RAND_MAX ) / (f32)(m_iM2);
				CreateUniformDistribution( fX, fY, fTheta, fPhi );

				f32 fThetaCos = cosf(fTheta);
				fCoss += fThetaCos;
			}

		m_fSSDivider += fCoss;
	}

	m_fSSDivider = 1.f / m_fSSDivider;

//	printf("DLC>  scan the file.\n" );
	/*
		precache the size to setup a progress bar..
	*/
	uint32 nStartOffset = sizeof(uint8)+sizeof(uint32)*5;
	uint32 nOffset = nStartOffset;
	m_nPixelNumber = 0;

	while(true)
	{
		fseek( f, nOffset, SEEK_SET );

		uint8 nChunk = 0;
		fread( &nChunk, sizeof(uint8), 1, f);
		if( 2 != nChunk )
		{
			m_RS = RS_POSTPROCESS;
			break;
		}

		int32 nChunkWidth,nChunkHeight;
		int32 nData;
		int8  nData8;

		fread( &nChunkWidth, sizeof(int32), 1, f );
		fread( &nChunkHeight, sizeof(int32), 1, f );
		fread( &nData, sizeof(int32), 1, f );
		fread( &nData8, sizeof(uint8), 1, f );
		fread( &nData, sizeof(int32), 1, f );

		m_nPixelNumber += nChunkWidth*nChunkHeight;
		nOffset += sizeof(int8)*2 + sizeof(int32)*4 + sizeof(uint8)*nChunkHeight*nChunkWidth*m_nBlockSize;
	}

	//go back...
	fseek( f, nStartOffset, SEEK_SET );

//	printf("DLC>  %d pixel in that job\n", m_nPixelNumber );
	m_nPercent = 0;
	m_nPixelNumber /= 100;
	m_nActualPixelNumber = 0;


	//calculate the needed memory...
	m_nUsedMemory = 100;
	FILE* fOctree;
	char szOctreeName[ MAX_PATH ];
	sprintf_s( szOctreeName, MAX_PATH, "%sOctree.dat", m_szDirectory );
	fopen_s( &fOctree, szOctreeName, "rb" );
	if( fOctree )
	{
		fseek( fOctree, 0, SEEK_END );
		m_nUsedMemory += ftell( fOctree );
		fclose( fOctree );
	}

	m_RS = RS_LOAD_NEXT_CHUNK;
	return JSRESULT_OK;
}

/////////////////////////////////////////////////////////////////////////////////////////
void cRenderer::Done()
{
	if( f )
		fclose(f);

	SAFE_DELETE_ARRAY( m_pData );
	SAFE_DELETE_ARRAY( m_pPicture );
	SAFE_DELETE( m_pOctree );

//	printf("DLC   Statistics:\nDLC   %d chunk rendered.\nDLC   %d octree loaded.\n", m_nStatChunkNumber, m_nStatOctreeChanges );
}



/////////////////////////////////////////////////////////////////////////////////////////
JobServerResult cRenderer::Tick()
{
/*			CRASH EMULATION WITH DIVISION BY ZERO
	int a = 0;
	int b = 1;
	if( RS_LOAD_NEXT_CHUNK )
		b /= a;
//*/
	switch( m_RS )
	{
		case RS_FINISHED:
			Log("RS_FINISHED\n");
			return JSRESULT_FINISHED;
		case RS_POSTPROCESS:
			{
				Log("RS_POSTPROCESS\n");

				//full build
//				if( m_nSSID > m_nSampleNumber )
				{
					char szFileName[MAX_PATH];
					sprintf_s( szFileName, MAX_PATH, "%se%d.tga", m_szDirectory, m_nFileID );

					Log("Saving '%s'\n",szFileName);
					if( false == Save8BitTGA( szFileName, m_pPicture, m_nWidth, m_nHeight ) )
					{
						Log("RAMJobServer:  Can't save the TGA file (%s)!\n", szFileName );
						m_RS = RS_FINISHED;
						return JSRESULT_DATA_ERROR;
					}

					return BlurIt(m_szDirectory, m_nFileID );
				}
//				printf("DLC   Finished.\n" );
				return JSRESULT_FINISHED;
			}
		case RS_LOAD_NEXT_CHUNK:
			{
				Log("RS_LOAD_NEXT_CHUNK\n");
				m_nPixelID = 0;
				SAFE_DELETE_ARRAY( m_pData );

				uint8 nChunk = 0;
				fread( &nChunk, sizeof(uint8), 1, f);
				if( 2 != nChunk )
				{
					m_RS = RS_POSTPROCESS;
					break;
				}

				if( 2 != nChunk )
				{
					Log("RAMJobServer:  WRONG DM Chunk!\n" );
					m_RS = RS_FINISHED;
					return JSRESULT_DATA_ERROR;
				}

				fread( &m_nChunkWidth, sizeof(int32), 1, f );
				fread( &m_nChunkHeight, sizeof(int32), 1, f );
				fread( &m_nChunkComponentOffset, sizeof(int32), 1, f );
				fread( &m_nChunkSpanDirection, sizeof(uint8), 1, f );
				fread( &m_nChunkOctreeID, sizeof(int32), 1, f );

				m_pData = new uint8[ m_nChunkHeight*m_nChunkWidth*m_nBlockSize];
				if( NULL == m_pData )
				{
					Log("RAMJobServer: Can't allocate the chunk memory!\n" );
					m_RS = RS_FINISHED;
					return JSRESULT_DATA_ERROR;
				}

				fread( m_pData, sizeof(uint8)*m_nChunkHeight*m_nChunkWidth*m_nBlockSize, 1, f );



				//Octree management
				if( m_nActualOctreeID == -1 )
				{
					SAFE_DELETE( m_pOctree );
					m_pOctree = new cOctree;
					if( NULL == m_pOctree )
					{
						Log("RAMJobServer:  Can't create octree class!\n"  );
						m_RS = RS_FINISHED;
						return JSRESULT_INTERNAL_ERROR;
					}

					char szFileName[MAX_PATH];
					sprintf_s( szFileName, MAX_PATH, "%sOctree.dat", m_szDirectory );
					JobServerResult OctreeRR = m_pOctree->Load( szFileName );
					if( JSRESULT_OK != OctreeRR  )
					{
						Log("RAMJobServer:  Can't find the octree file (%s)!\n",szFileName );
						m_RS = RS_FINISHED;
						return OctreeRR;
					}

					++m_nStatOctreeChanges;
#ifdef DEBUGTEXT
//					printf("DLC   %d. Octree (%s) loaded.\n", m_nStatOctreeChanges, szFileName );
#endif
					m_nActualOctreeID = 1000;
				}
/*
				if( m_nActualOctreeID != m_nChunkOctreeID )
				{
					m_nActualOctreeID = m_nChunkOctreeID;

					SAFE_DELETE( m_pOctree );
					m_pOctree = new cOctree;
					if( NULL == m_pOctree )
					{
						printf("DLC>  Can't create octree class!\n"  );
						m_RS = RS_FINISHED;
						return JSRESULT_INTERNAL_ERROR;
					}

					char szFileName[MAX_PATH];
					sprintf_s( szFileName, MAX_PATH, "%s%d_octree.dat", m_szDirectory, m_nChunkOctreeID );
					JobServerResult OctreeRR = m_pOctree->Load( szFileName );
					if( JSRESULT_OK != OctreeRR  )
					{
						printf("DLC>  Can't find the octree file (%s)!\n",szFileName );
						m_RS = RS_FINISHED;
						return OctreeRR;
					}

					++m_nStatOctreeChanges;
#ifdef DEBUGTEXT
					printf("DLC   %d. Octree (%s) loaded.\n", m_nStatOctreeChanges, szFileName );
#endif
				}
*/
				m_RS= RS_PROCESS_CHUNK;
			}
			break;
		case RS_PROCESS_CHUNK:
			{
				Log("RS_PROCESS_CHUNK %d\n",m_nPercent);
				if( m_nActualPixelNumber > m_nPixelNumber )
				{
					m_nActualPixelNumber -= m_nPixelNumber;
					++m_nPercent;
//					printf("DLC>  %d percent finished.\n", m_nPercent );
				}

				int32 nOneProcess = m_nChunkHeight*m_nChunkWidth - m_nPixelID;

				//finished this chunk
				if( nOneProcess <= 0 )
				{
					++m_nStatChunkNumber;
					m_RS = RS_LOAD_NEXT_CHUNK;
					break;
				}

				nOneProcess = ( nOneProcess > 1024 ) ? 1024 : nOneProcess;
				m_nActualPixelNumber += nOneProcess;
				for( int32 i = 0; i < nOneProcess; ++i )
				{
					int32 nY = m_nPixelID / m_nChunkWidth;
					int32 nX = m_nPixelID - nY * m_nChunkWidth;
					int32 nPicturePosition =	GenerateIndexFromCoordiatesToSurface( m_nChunkSpanDirection, nX, nY, m_nWidth, m_nChunkWidth, m_nChunkHeight ) + m_nChunkComponentOffset;

					//if it's a valid pixel
					if( 1 == m_pData[ m_nPixelID*m_nBlockSize ] )
					{
#ifdef DEBUG_CHECKERBOARD
						int32 nnY = nPicturePosition / 1024;
						int32 nnX = nPicturePosition  - nnY * 1024;
						int8 nA = nnX % 2;
						int8 nB = nnY % 2;
						m_pPicture[ nPicturePosition ] = (1-nA)*nB + (1-nB)*nA;						
#else
						float* pFloatData = (float*)&m_pData[ m_nPixelID*m_nBlockSize+1 ];

						float fSSData = 0;
//						pFloatData += m_nSSID;			//which supersampling used

						assert(m_iSSNumber);			// MartinM

						for( int32 nSuperSampling = 0; nSuperSampling < m_iSSNumber; ++nSuperSampling )
						{
							m_Ray.Setup( pFloatData );

							float vTangent[3]; 
							float vBinromal[3]; 
							if( m_Ray.vOrigNormal[2]<-0.5f || m_Ray.vOrigNormal[2]>0.5f )	
							{
								vTangent[0] = m_Ray.vOrigNormal[2];
								vTangent[1] = m_Ray.vOrigNormal[1];
								vTangent[2] = -m_Ray.vOrigNormal[0];
							}
							else 
							{
								vTangent[0] = m_Ray.vOrigNormal[1];
								vTangent[1] = -m_Ray.vOrigNormal[0];
								vTangent[2] = m_Ray.vOrigNormal[2];
							}

							CROSS( vBinromal, m_Ray.vOrigNormal, vTangent );
							Normalize( vBinromal );

							CROSS( vTangent, m_Ray.vOrigNormal, vBinromal );
							Normalize( vTangent );

							f32 fPhi,fTheta, fX, fY;
							float fFullAO = 0;

							for( int32 i = 0; i < m_iM1; ++i )
								for( int32 j = 0; j < m_iM2; ++j )
								{
									fY = (i + (f32)rand() /(f32)RAND_MAX ) / (f32)(m_iM1);
									fX = (j + (f32)rand() /(f32)RAND_MAX ) / (f32)(m_iM2);
									CreateUniformDistribution( fX, fY, fTheta, fPhi );

									f32 fThetaSin = sinf(fTheta);
									f32 fThetaCos = cosf(fTheta);
									f32 fPhiCos = cosf( fPhi ) * fThetaSin;
									f32 fPhiSin = sinf( fPhi ) * fThetaSin;

									m_Ray.vDir[0] = vTangent[0] * fPhiCos + vBinromal[0] * fPhiSin + m_Ray.vOrigNormal[0] * fThetaCos;
									m_Ray.vDir[1] = vTangent[1] * fPhiCos + vBinromal[1] * fPhiSin + m_Ray.vOrigNormal[1] * fThetaCos;
									m_Ray.vDir[2] = vTangent[2] * fPhiCos + vBinromal[2] * fPhiSin + m_Ray.vOrigNormal[2] * fThetaCos;
									m_Ray.fT = 250;

									if( m_pOctree->FirstIntersect( &m_Ray, &m_CacheCluster, NULL ) )
										fFullAO += m_Ray.fT > 1.5 ? ( fThetaCos*(1.f-0.5f*m_Ray.fT/250.f)) : 0.f;
								}

								//Here is the secret spice :) -> we need the "direction" encoded in the RAE even when the surround is the same,
								float vAbsNormal[3];
								vAbsNormal[0] = fabs( m_Ray.vOrigNormal[0] );
								vAbsNormal[1] = fabs( m_Ray.vOrigNormal[1] );
								vAbsNormal[2] = fabs( m_Ray.vOrigNormal[2] );

								float fSize = vAbsNormal[0] + vAbsNormal[1] + vAbsNormal[2];
								float fSpice = (vAbsNormal[0] * 0.33f + vAbsNormal[1] *0.24f + vAbsNormal[2] * 0.36f) / fSize;

								fSSData += fFullAO * fSpice;

								pFloatData += 6;
						}

						m_pPicture[ nPicturePosition ] = fSSData*m_fSSDivider;						
#endif
					}

					++m_nPixelID;
				}
			}
			break;
	}

	return JSRESULT_OK;
}

/////////////////////////////////////////////////////////////////////////////////////////
uint8* cRenderer::Load8BitTGA( const char* szFileName )
{
	uint8		uncompressed8BitTGAHeader[12]= {0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0};
	uint16	width = 0;
	uint16	height = 0;
	uint8		bits = 8;
	uint8		descriptor = 0x20;		//horizontal flip
	FILE*		f;

	fopen_s( &f, szFileName, "rb" );
	if( NULL == f )
		return NULL;

	//header
	fread( uncompressed8BitTGAHeader, sizeof(uint8)*12, 1, f);
	fread( &width, sizeof(uint16), 1, f);
	fread( &height, sizeof(uint16), 1, f);
	fread( &bits, sizeof(uint8), 1, f);
	fread( &descriptor, sizeof(uint8), 1, f);

	//data
	uint8* p8Bit = new uint8[m_nWidth*m_nHeight];
	if( NULL == p8Bit )
	{
		fclose(f);
		return NULL;
	}

	fread( p8Bit, width*height*sizeof(uint8), 1, f );

	fclose(f);
	return p8Bit;
}

bool cRenderer::Save8BitDDS( const char* szFileName, float* pPicture, const int32 nWidth, const int32 nHeight )
{
	//data
	uint8* p8Bit = new uint8[nWidth*nHeight*3];
	if( NULL == p8Bit )
	{
		return false;
	}

	for( int i = 0; i < nWidth*nHeight; ++i )
	{
		p8Bit[i*3+0] =
		p8Bit[i*3+1] =
		p8Bit[i*3+2] = (uint8)(255*pPicture[i]);
	}

	bool bRes = ConvertToDXT( szFileName, p8Bit, nWidth, nHeight, 3, false );
	SAFE_DELETE_ARRAY(p8Bit);
	return bRes;
}

/////////////////////////////////////////////////////////////////////////////////////////
bool cRenderer::Save8BitTGA( const char* szFileName, float* pPicture, const int32 nWidth, const int32 nHeight )
{
	uint8		uncompressed8BitTGAHeader[12]= {0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0};
	uint16	width = nWidth;
	uint16	height = nHeight;
	uint8		bits = 8;
	uint8		descriptor = 0x20;		//horizontal flip
	FILE*		f;

	fopen_s( &f, szFileName, "wb" );
	if( NULL == f )
		return false;

	//header
	fwrite( uncompressed8BitTGAHeader, sizeof(uint8)*12, 1, f);
	fwrite( &width, sizeof(uint16), 1, f);
	fwrite( &height, sizeof(uint16), 1, f);
	fwrite( &bits, sizeof(uint8), 1, f);
	fwrite( &descriptor, sizeof(uint8), 1, f);

	//data
	uint8* p8Bit = new uint8[nWidth*nHeight];
	if( NULL == p8Bit )
	{
		fclose(f);
		return false;
	}

	for( int i = 0; i < nWidth*nHeight; ++i )
		p8Bit[i] = (uint8)(255*pPicture[i]);
	fwrite( p8Bit, nWidth*nHeight*sizeof(uint8), 1, f );
	SAFE_DELETE_ARRAY(p8Bit);
	fclose(f);
	return true;
}

/////////////////////////////////////////////////////////////////////////////////////////
bool cRenderer::SaveFloatMap( const char* szFileName, float* pPicture, const int32 nWidth, const int32 nHeight )
{
	uint16	width = nWidth;
	uint16	height = nHeight;

	FILE*		f;

	fopen_s( &f, szFileName, "wb" );
	if( NULL == f )
		return false;

	//header
	fwrite( &width, sizeof(uint16), 1, f);
	fwrite( &height, sizeof(uint16), 1, f);

	//data
	fwrite( pPicture, nWidth*nHeight*sizeof(float), 1, f );
	fclose(f);
	return true;
}



JobServerResult cPostProcess::ConvertToTGA( const char* szDirectory, const int32 nID, const int nSSNumber )
{
	FILE*		f;

	char szFileName[MAX_PATH];

	//try to load the first one.. it need to be on the disk...
	sprintf_s( szFileName, MAX_PATH, "%s%d__0.map", szDirectory, nID );
	fopen_s( &f, szFileName, "rb" );
	if( NULL == f )
	{
//		printf("DLC>  MAP File not found. (%s)!\n",szFileName );
		return JSRESULT_DATA_ERROR;
	}

	uint16 width = 0;
	uint16 height = 0;
	fread( &width, sizeof(uint16), 1, f);
	fread( &height, sizeof(uint16), 1, f);

	float* pData = new float[ width*height ];
	if( pData == NULL )
	{
//		printf("DLC>  can allocate memory. (%s) %dx%d float.!\n",szFileName, width, height );
		return JSRESULT_INTERNAL_ERROR;
	}

	fread( pData, sizeof(float)*width*height,1,f);
	fclose(f);

	float* pData2 = new float[ width*height ];
	if( pData2 == NULL )
	{
//		printf("DLC>  can allocate memory2. (%s) %dx%d float.!\n",szFileName, width, height );
		return JSRESULT_INTERNAL_ERROR;
	}

	//read the other datas...add add together
	for( int32 i = 1; i < nSSNumber; ++i )
	{
		sprintf_s( szFileName, MAX_PATH, "%s%d__%d.map", szDirectory, nID, i );
		fopen_s( &f, szFileName, "rb" );
		if( NULL == f )
			continue;

		uint16 width2 = 0;
		uint16 height2 = 0;
		fread( &width2, sizeof(uint16), 1, f);
		fread( &height2, sizeof(uint16), 1, f);

		if( width2 != width || height2 != height )
		{
//				printf("DLC>  Not matching picture sizes: (%s) %dx%d - %dx%d!\n",szFileName, width, height, width2, height2 );
				continue;
		}

		fread( pData2, sizeof(float)*width*height,1,f);
		fclose(f);

		//add pass
		for( int i = 0; i < width*height; ++i )
			pData[i]+= pData2[i];
	}

	//save tga file
	uint8		uncompressed8BitTGAHeader[12]= {0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0};
	uint8		bits = 8;
	uint8		descriptor = 0x20;		//horizontal flip

	sprintf_s( szFileName, MAX_PATH, "%s%d.tga", szDirectory, nID );
	fopen_s( &f, szFileName, "wb" );
	if( NULL == f )
	{
//		printf("DLC>  Can't open for write the tga file. (%s)!\n",szFileName );
		return JSRESULT_DATA_ERROR;
	}

	//header
	fwrite( uncompressed8BitTGAHeader, sizeof(uint8)*12, 1, f);
	fwrite( &width, sizeof(uint16), 1, f);
	fwrite( &height, sizeof(uint16), 1, f);
	fwrite( &bits, sizeof(uint8), 1, f);
	fwrite( &descriptor, sizeof(uint8), 1, f);

	//data
	uint8* p8Bit = new uint8[width*height];
	if( NULL == p8Bit )
	{
		fclose(f);
//		printf("DLC>  Can't allocate memory for 8bit. (%s)!\n",szFileName );
		return JSRESULT_INTERNAL_ERROR;
	}

	for( int i = 0; i < width*height; ++i )
		p8Bit[i] = (uint8)(255*pData[i]);

	fwrite( p8Bit, width*height*sizeof(uint8), 1, f );

	fclose(f);

	SAFE_DELETE_ARRAY( p8Bit );
	SAFE_DELETE_ARRAY( pData );
	SAFE_DELETE_ARRAY( pData2 );
	return JSRESULT_OK;
}


void WriteDTXnFile(DWORD count, void * buffer, void * userData)
{
}

void ReadDTXnFile(DWORD count, void * buffer, void * userData)
{
}
