// DMapPreprocess.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

class CDistanceMap
{
public:
	bool Do( const int nDepth, const char* szInputTgaName, const char* szOutputTgaName )				//nDepth = how much slice do you want to compute up to 255
	{
		if( nDepth < 1 )
			return false;
		if( NULL == szOutputTgaName )
			return false;
		if( NULL == szInputTgaName )
			return false;

		m_nDepth = nDepth;

		//input
		unsigned char* pSourceData = Load8BitTGA( szInputTgaName );
		if( NULL == pSourceData )
			return false;

		//output
		unsigned char* pOutput = new unsigned char[ m_nWidth*m_nHeight*3 ];
		if( NULL == pOutput )
			return false;
		memset( pOutput, 0, sizeof(unsigned char)*m_nWidth*m_nHeight*3 );

		//flags
		m_pMAXData = new unsigned char[ (m_nWidth*m_nHeight*m_nDepth+7)/8 ];
		if( NULL == m_pMAXData )
			return false;
		//data
		m_pData = new unsigned short[ m_nWidth*m_nHeight*m_nDepth*3 ];
		if( NULL == m_pData )
			return false;
		//layer flags
		m_pActiveLayer = new unsigned char[ m_nDepth ];
		if( NULL == m_pActiveLayer )
			return false;

		//convert normal side
		DoOneSize(true, pSourceData, pOutput);

		//convert the other side
		DoOneSize(false, pSourceData, pOutput);


		PostProcess( pOutput );

		//save the tga
		Save24BitTGA( szOutputTgaName, pOutput, m_nWidth, m_nHeight );

		//release memory..
		SAFE_DELETE_ARRAY( pSourceData  );
		SAFE_DELETE_ARRAY( m_pMAXData  );
		SAFE_DELETE_ARRAY( m_pData );
		SAFE_DELETE_ARRAY( pOutput );
		return true;
	};

private:

	//generate downsampled versions with min box filter
	bool PostProcess( unsigned char* pOutput )
	{
		unsigned char nMin[3];

		unsigned char* pPPData = new unsigned char[ m_nHeight * m_nWidth * 3 ];
		if( NULL == pPPData )
			return false;

		for( int nBlockBits = 1; nBlockBits < 4; ++nBlockBits )
		{
			int nBlockHeight = m_nHeight >> nBlockBits;
			int nBlockWidth = m_nWidth >> nBlockBits;
			int nBlockSize = 1 << nBlockBits;
			for( int nBlockY = 0; nBlockY < nBlockHeight; ++nBlockY )
				for( int nBlockX = 0; nBlockX < nBlockWidth; ++nBlockX )
				{
					int nBlockOffset = nBlockY*nBlockSize*m_nWidth + nBlockX*nBlockSize;
					nMin[0] = nMin[1] = nMin[2] = 255;

					//search the min
					for( int y = 0; y < nBlockSize; ++y )
						for( int x = 0; x < nBlockSize; ++x )
						{
							register int nIndex = (nBlockOffset + y*m_nWidth+x)*3;
							nMin[0] = ( pOutput[ nIndex + 0 ] < nMin[0] ) ? pOutput[ nIndex + 0 ] : nMin[0];
							nMin[1] = ( pOutput[ nIndex + 1 ] < nMin[1] ) ? pOutput[ nIndex + 1 ] : nMin[1];
							nMin[2] = ( pOutput[ nIndex + 2 ] < nMin[2] ) ? pOutput[ nIndex + 2 ] : nMin[2];
						}
/*
						//set the min
						for( int y = 0; y < nBlockSize; ++y )
							for( int x = 0; x < nBlockSize; ++x )
							{
								register int nIndex = (nBlockOffset + y*m_nWidth+x)*3;
								pOutput[ nIndex + 0 ] = nMin[0];
								pOutput[ nIndex + 1 ] = nMin[1];
								pOutput[ nIndex + 2 ] = nMin[2];
							}
*/
						register int nPPIndex = (nBlockY*nBlockWidth+nBlockX)*3;
						pPPData[ nPPIndex+0 ] = nMin[0];
						pPPData[ nPPIndex+1 ] = nMin[1];
						pPPData[ nPPIndex+2 ] = nMin[2];
				}


				char szFileName[1024];

				sprintf_s( szFileName, 1024, "out_%dx%d.tga", nBlockSize, nBlockSize );
				Save24BitTGA( szFileName, pPPData, nBlockWidth, nBlockHeight );
		}

			return true;
	}

	bool	DoOneSize( const bool bNormalSide, unsigned char* pSourceData, unsigned char* pOutput )
	{
		if( NULL == pOutput || NULL == pSourceData )
			return false;

		memset( m_pActiveLayer, 0, sizeof(unsigned char)*m_nDepth );
		memset( m_pMAXData, 0, sizeof(unsigned char)*(m_nWidth*m_nHeight*m_nDepth+7)/8 );
		memset( m_pData, 0, sizeof(unsigned short)*(m_nWidth*m_nHeight*m_nDepth*3) );
		for( int y = 0; y < m_nHeight; ++y )
			for( int x = 0; x < m_nWidth; ++x )
			{
				int nD = (int)ceil( pSourceData[ y*m_nWidth + x ] / 255.f * m_nDepth );
				for( int z = 0; z < m_nDepth; ++z )
				{
					int nIndex = ( (z*m_nHeight+y)*m_nWidth + x );
					if( bNormalSide && ( z >= nD && z > 1 ) || 
						  !bNormalSide && ( z <= nD && z <= m_nDepth-2 ) )
					{
						m_pMAXData[ nIndex >> 3 ] |= 1<<(nIndex&0x7);
						m_pActiveLayer[z] = 1;		//activate that layer
					}
				}
			}

#if 0
			//show the slices
			char szF[1024];
			for( int i = 0; i < m_nDepth; ++i)
			{
				sprintf_s( szF, 1024, "debug_pass1_%d.tga", i );
				ConvertToDistance( pOutput, i, 0 );
				ConvertToDistance( pOutput, i, 1 );
				ConvertToDistance( pOutput, i, 2 );
				Save24BitTGA( szF, pOutput, m_nWidth, m_nHeight );
			}
			memset( pOutput, 0, sizeof(unsigned char)*m_nWidth*m_nHeight*3 );
#endif

			CalculateAllPass();
			ConvertToDistance( pOutput, bNormalSide ?  (m_nDepth-1) : 0, bNormalSide ? 2 : 1 );

			return true;
	}

	bool isInside( const int x, const int y, const int z ) const
	{
		return ( x >= 0 && x < m_nWidth && y >= 0 && y < m_nHeight && z >= 0 && z < m_nDepth );
	}


	_inline void OnePass( int nX, int nY, int nZ, const int nDistX, const int nDistY, const int nDistZ, const int nDirX )
	{
		unsigned short nAbsDistX = abs( nDistX );
		unsigned short nAbsDistY = abs( nDistY );
		unsigned short nAbsDistZ = abs( nDistZ );
		register unsigned short nNewDist[3];
		register int nIndex1,nIndex2;

		while( isInside( nX, nY, nZ ) && isInside( nX+nDistX, nY+nDistY, nZ+nDistZ ) && m_pActiveLayer[nZ] )
		{
			nIndex1 = ( (nZ*m_nHeight+nY)*m_nWidth + nX );
			nIndex2 = ( ((nZ+nDistZ)*m_nHeight+(nY+nDistY))*m_nWidth + (nX+nDistX) );
			nX += nDirX;
			//fast check...if the other part have not acceptable length, not spread it.
			if( (m_pMAXData[ nIndex2 >> 3 ]) & (1<<(nIndex2&0x7)) )
				continue;

			//the new distance
			nIndex2 *= 3;
			nNewDist[0] = m_pData[ nIndex2 + 0 ] + nAbsDistX;
			nNewDist[1] = m_pData[ nIndex2 + 1 ] + nAbsDistY;
			nNewDist[2] = m_pData[ nIndex2 + 2 ] + nAbsDistZ;

			//the current position have an infinity distance?
			unsigned char nBit = 1<<(nIndex1&0x7);
			unsigned char* pByte = &m_pMAXData[ nIndex1 >> 3 ];
			nIndex1*=3;
			unsigned short& nV0 = m_pData[ nIndex1 + 0 ];
			unsigned short& nV1 = m_pData[ nIndex1 + 1 ];
			unsigned short& nV2 = m_pData[ nIndex1 + 2 ];

			if( (*pByte) & nBit )
				*pByte -=  nBit;		//clear the MAX flag
			else
			{
				//can work the "normal" distance calculation

				//smaller.. better
				if( nV0*nV0+nV1*nV1+nV2*nV2 <= nNewDist[0]*nNewDist[0]+nNewDist[1]*nNewDist[1]+nNewDist[2]*nNewDist[2] )
					continue;
			}

			//include it..
			nV0 = nNewDist[0];
			nV1 = nNewDist[1];
			nV2 = nNewDist[2];
		}
	}

	//Optimized compiler
	void CalculateAllPass()
	{
		int z;

		int nWidthSub2 = m_nWidth-2;
		int nHeightSub2 = m_nHeight-2;

		int nLoopNum_Height = (m_nHeight+15) / 16;
		int nLoopStart_Height = m_nHeight % 16;
		int nLoopNum_1Height = (m_nHeight-1+15) / 16;
		int nLoopStart_1Height = (m_nHeight-1) % 16;

		int t,nLoop;

		for( z = 1; z < m_nDepth; ++z )
		{
			t = 0;
			nLoop = nLoopNum_Height;
			switch( nLoopStart_Height )
			{
				do 
				{
			case 0:
				OnePass( 0,t++,z, 0,0,-1, 1 );
			case 15:
				OnePass( 0,t++,z, 0,0,-1, 1 );
			case 14:
				OnePass( 0,t++,z, 0,0,-1, 1 );
			case 13:
				OnePass( 0,t++,z, 0,0,-1, 1 );
			case 12:
				OnePass( 0,t++,z, 0,0,-1, 1 );
			case 11:
				OnePass( 0,t++,z, 0,0,-1, 1 );
			case 10:
				OnePass( 0,t++,z, 0,0,-1, 1 );
			case 9:
				OnePass( 0,t++,z, 0,0,-1, 1 );
			case 8:
				OnePass( 0,t++,z, 0,0,-1, 1 );
			case 7:
				OnePass( 0,t++,z, 0,0,-1, 1 );
			case 6:
				OnePass( 0,t++,z, 0,0,-1, 1 );
			case 5:
				OnePass( 0,t++,z, 0,0,-1, 1 );
			case 4:
				OnePass( 0,t++,z, 0,0,-1, 1 );
			case 3:
				OnePass( 0,t++,z, 0,0,-1, 1 );
			case 2:
				OnePass( 0,t++,z, 0,0,-1, 1 );
			case 1:
				OnePass( 0,t++,z, 0,0,-1, 1 );
				} while( --nLoop );
			}


			t = 1;
			nLoop = nLoopNum_1Height;
			switch( nLoopStart_1Height )
			{
				do 
				{
			case 0:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 15:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 14:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 13:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 12:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 11:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 10:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 9:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 8:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 7:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 6:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 5:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 4:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 3:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 2:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 1:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
				} while( --nLoop );
			}

			t = nHeightSub2;
			nLoop = nLoopNum_1Height;
			switch( nLoopStart_1Height )
			{
				do 
				{
			case 0:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 15:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 14:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 13:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 12:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 11:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 10:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 9:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 8:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 7:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 6:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 5:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 4:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 3:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 2:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 1:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
				} while( --nLoop );
			}
		}

		for( z = m_nDepth-2; z >= 0; --z )
		{
			t = 0;
			nLoop = nLoopNum_Height;
			switch( nLoopStart_Height )
			{
				do 
				{
			case 0:
				OnePass( 0,t++,z, 0,0,1, 1 );
			case 15:
				OnePass( 0,t++,z, 0,0,1, 1 );
			case 14:
				OnePass( 0,t++,z, 0,0,1, 1 );
			case 13:
				OnePass( 0,t++,z, 0,0,1, 1 );
			case 12:
				OnePass( 0,t++,z, 0,0,1, 1 );
			case 11:
				OnePass( 0,t++,z, 0,0,1, 1 );
			case 10:
				OnePass( 0,t++,z, 0,0,1, 1 );
			case 9:
				OnePass( 0,t++,z, 0,0,1, 1 );
			case 8:
				OnePass( 0,t++,z, 0,0,1, 1 );
			case 7:
				OnePass( 0,t++,z, 0,0,1, 1 );
			case 6:
				OnePass( 0,t++,z, 0,0,1, 1 );
			case 5:
				OnePass( 0,t++,z, 0,0,1, 1 );
			case 4:
				OnePass( 0,t++,z, 0,0,1, 1 );
			case 3:
				OnePass( 0,t++,z, 0,0,1, 1 );
			case 2:
				OnePass( 0,t++,z, 0,0,1, 1 );
			case 1:
				OnePass( 0,t++,z, 0,0,1, 1 );
				} while( --nLoop );
			}


			t = 1;
			nLoop = nLoopNum_1Height;
			switch( nLoopStart_1Height )
			{
				do 
				{
			case 0:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 15:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 14:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 13:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 12:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 11:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 10:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 9:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 8:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 7:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 6:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 5:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 4:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 3:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 2:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
			case 1:
				OnePass(          0,t,z, 0,-1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				++t;
				} while( --nLoop );
			}

			t = nHeightSub2;
			nLoop = nLoopNum_1Height;
			switch( nLoopStart_1Height )
			{
				do 
				{
			case 0:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 15:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 14:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 13:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 12:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 11:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 10:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 9:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 8:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 7:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 6:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 5:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 4:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 3:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 2:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
			case 1:
				OnePass(          0,t,z, 0,+1,0, 1 );
				OnePass(          1,t,z, -1,0,0, 1 );
				OnePass( nWidthSub2,t,z,  1,0,0, -1 );
				--t;
				} while( --nLoop );
			}
		}
	}

	void ConvertToDistance( unsigned char* pBuffer, const int nDepth, const int nColorChannel )
	{
		int x,y;
		int nOffset = nDepth*m_nHeight*m_nWidth;

		for( y = 0; y < m_nHeight; ++y )
			for( x = 0; x < m_nWidth; ++x )
			{
				int nIndex = nOffset + y*m_nWidth + x;

				int nD;
				if( (m_pMAXData[ nIndex >> 3 ]) & (1<<(nIndex&0x7))  )
					nD = 255;
				else
				{
					nIndex*=3;
					unsigned short& nV0 = m_pData[ nIndex + 0 ];
					unsigned short& nV1 = m_pData[ nIndex + 1 ];
					unsigned short& nV2 = m_pData[ nIndex + 2 ];
					float fDist = (float)(nV0*nV0+nV1*nV1+nV2*nV2);
					fDist = sqrtf( fDist ) / (float)m_nDepth;
					fDist = ( fDist > 1.f ) ? 1.f : ( ( fDist < 0.f ) ? 0 : fDist );

					nD = (int)floor(fDist * 255.f) -1;			// -1 == safe area
					nD = ( nD < 0 ) ? 0 : nD;
				}

				pBuffer[ (y*m_nWidth+x)*3+nColorChannel ] = (unsigned char)nD;
			}
	}

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

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

		//header
		fread( uncompressed8BitTGAHeader, sizeof(unsigned char)*12, 1, f);
		fread( &width, sizeof(unsigned short), 1, f);
		fread( &height, sizeof(unsigned short), 1, f);
		fread( &bits, sizeof(unsigned char), 1, f);
		fread( &descriptor, sizeof(unsigned char), 1, f);

		//data
		unsigned char* p8Bit = new unsigned char[width*height];
		if( NULL == p8Bit )
		{
			fclose(f);
			return NULL;
		}

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

		m_nWidth = width;
		m_nHeight = height;

		fclose(f);
		return p8Bit;
	}

	/////////////////////////////////////////////////////////////////////////////////////////
	bool Save24BitTGA( const char* szFileName, unsigned char* p8Bit, const int nWidth, const int nHeight )
	{
		unsigned char		uncompressed8BitTGAHeader[12]= {0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0};
		unsigned short	width = nWidth;
		unsigned short	height = nHeight;
		unsigned char		bits = 8*3;
		unsigned char		descriptor = 0;	//x20;		//horizontal flip
		FILE*		f;

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

		//header
		fwrite( uncompressed8BitTGAHeader, sizeof(unsigned char)*12, 1, f);
		fwrite( &width, sizeof(unsigned short), 1, f);
		fwrite( &height, sizeof(unsigned short), 1, f);
		fwrite( &bits, sizeof(unsigned char), 1, f);
		fwrite( &descriptor, sizeof(unsigned char), 1, f);

		fwrite( p8Bit, nWidth*nHeight*sizeof(unsigned char)*3, 1, f );
		fclose(f);
		return true;
	}


	int							m_nWidth,m_nHeight,m_nDepth;															// the "parameters" of the file
	unsigned char*	m_pMAXData;																								// flag for every pixel - it is store a "maximum distance"
	unsigned short* m_pData;																									// the distance on the 3 axis
	unsigned char*	m_pActiveLayer;																						// helper - run only on active layers (good if the heightmap not between 0-255)
};



int _tmain(int argc, _TCHAR* argv[])
{
	CDistanceMap DM;

	DM.Do( 255, "test.tga", "out.tga" );
	return 0;
}

