#include "stdafx.h"																								// precompiled header
#include "polybumpworkerthread.h"
#include "resource.h"
#include <mmsystem.h>																							// timeGetTime()
#include <assert.h>																								// assert()
#include "tga.h"																									// PIX_LoadTGA32()
#include "PbTri.h"																								// CPbTri
#include "SimpleTriangleRasterizer.h"															// CSimpleTriangleRasterizer
#include "PolyBump.h"																							// CPbMesh




// constructor
CPolyBumpWorkerThread::CPolyBumpWorkerThread()
{
	m_hThreadderWnd=0;
	m_lphKillReceiveEvent=0;

//	m_pBumpMapBuffer=0;
	m_dwStartTime=0;
	m_bUserHasStopped=false;
	m_nImageSizeX=0;
	m_nImageSizeY=0;
}

// destructor
CPolyBumpWorkerThread::~CPolyBumpWorkerThread()
{ 
}
 





// /return 
bool CPolyBumpWorkerThread::ThreadPollMessages( float infPercent, const char *inszPassName )
{
	char str[256];
	HWND dlgitem=::GetDlgItem(m_hThreadderWnd,IDC_PROGRESSPERCENT);

	DWORD dwTimeSoFar=timeGetTime()-m_dwStartTime;		// in ms
	DWORD dwSecToGo=0;
	
	if(infPercent>=1.0f)
	{
		dwSecToGo=(DWORD)(((float)dwTimeSoFar/infPercent)*(100.0f-infPercent)/1000.0f);

		DWORD dwMinToGo=dwSecToGo/60;					dwSecToGo-=dwMinToGo*60;
		DWORD dwHToGo=dwMinToGo/60;						dwMinToGo-=dwHToGo*60;

		sprintf(str,"%.0f%% %s (%d:%d:%.2d to go)",infPercent,inszPassName,dwHToGo,dwMinToGo,dwSecToGo);
	}
	else sprintf(str,"%s %.0f %%",inszPassName,infPercent);


	SetWindowText(m_hThreadderWnd,str);


	MSG msg;

	while(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	if(WaitForMultipleObjects(1,m_lphKillReceiveEvent,FALSE,0)!=WAIT_TIMEOUT)
		return false;

	return true;
}

//
HWND CPolyBumpWorkerThread::GetThreadderHWND()
{
	return m_hThreadderWnd;
}

//
void CPolyBumpWorkerThread::SetThreadderHWND( HWND inhWnd )
{
	m_hThreadderWnd=inhWnd;
}






//
void CPolyBumpWorkerThread::SetKillEvent( HANDLE *inlphHnd )
{
	m_lphKillReceiveEvent=inlphHnd;
}



std::string CPolyBumpWorkerThread::ExtendFilename( std::string insFilename )
{
	if(!m_Properties.m_bExtendFilename)return(insFilename);				// don't extend filename

	std::string sRet=insFilename;
	std::string sExt;
	int len=sRet.size();

	// Extension
	if(len>=4)
	if(sRet[len-4]=='.')							
	{
		// extract extension
		sExt= std::string(".") + sRet[len-3] + sRet[len-2] + sRet[len-1];

		// remove extensiuon
		sRet.resize(len-4);
	}

	char szParams[80];
	char *szLateNear="";
	
	switch(m_Properties.m_nHitMode)
	{
		case 0:	szLateNear="nearest";
			break;
		case 1: szLateNear="latest";
			break;
		default:
			assert(0);
			break;
	}
/*
	if(m_pBumpMapBuffer)
		sprintf(szParams,"_%s@R%.1f@B%.1f",szLateNear,m_Properties.m_fRayLength*100.0f,m_Properties.m_fBumpmapStrength);
	 else
*/
	sprintf(szParams,"_%s@R%.1f",szLateNear,m_Properties.m_fRayLength*100.0f);

	// replace '.' with '_'
	{
		char *pPtr=szParams;
		while(*pPtr!=0)
		{
			if(*pPtr=='.')*pPtr='_';

			pPtr++;
		}
	}

	sRet += std::string(szParams) + sExt;

	return sRet.c_str();
}


/*
// set the optional bump TARGA (.TGA) filename
void CPolyBumpWorkerThread::LoadBumpMapPathName( const char *inszPathName )
{
	bool alpha=false;
	int BytesPerPixel=8;

	free(m_pBumpMapBuffer);m_pBumpMapBuffer=0;

	if(!PIX_LoadTGA32(inszPathName,0,(int &)m_dwBumpmapWidth,(int &)m_dwBumpmapHeight,alpha))
		return;

	m_pBumpMapBuffer=(DWORD *)malloc(4*m_dwBumpmapWidth*m_dwBumpmapHeight);

	if(!PIX_LoadTGA32(inszPathName,m_pBumpMapBuffer,(int &)m_dwBumpmapWidth,(int &)m_dwBumpmapHeight,alpha))
	{
		free(m_pBumpMapBuffer);m_pBumpMapBuffer=0;
	}
}
*/




/*
float InterpretColorAsGray( DWORD indwV )
{
	DWORD r=(indwV>>16)&0xff;
	DWORD g=(indwV>>8)&0xff;
	DWORD b=indwV&0xff;

	return((r+g+b)*(1.0f/3.0f/255.0f));		// BTW: luminance can be calculated the the term: 0.3*r + 0.59*g + 0.11*b
}


// return the derivate values from the bumpmap
bool CPolyBumpWorkerThread::GetBumpMapDerivate( float infX, float infY, float &outfDX, float &outfDY )
{
	DWORD dwBMWidth=m_dwBumpmapWidth;
	DWORD dwBMHeight=m_dwBumpmapHeight;

	if(!m_pBumpMapBuffer)
	{
		outfDX=0.0f;outfDY=0.0f;
		return false;
	}

	DWORD x1=(DWORD)(infX*(float)dwBMWidth-0.5f);
	DWORD y1=(DWORD)(infY*(float)dwBMHeight-0.5f);

	if(x1<0)x1=0;
	if(y1<0)y1=0;
	
	if(x1>=dwBMWidth-2)x1=dwBMWidth-2;
	if(y1>=dwBMHeight-2)y1=dwBMHeight-2;

	DWORD x2=x1+1;
	DWORD y2=y1+1;

	float value11=InterpretColorAsGray(m_pBumpMapBuffer[x1+y1*dwBMWidth]);
	float value21=InterpretColorAsGray(m_pBumpMapBuffer[x2+y1*dwBMWidth]);
	float value12=InterpretColorAsGray(m_pBumpMapBuffer[x1+y2*dwBMWidth]);
	float value22=InterpretColorAsGray(m_pBumpMapBuffer[x2+y2*dwBMWidth]);

	outfDX=-m_Properties.m_fBumpmapStrength*( value21-value11 + value22-value12 )*0.5f;	// right-left
	outfDY=-m_Properties.m_fBumpmapStrength*( value12-value11 + value22-value21 )*0.5f;	// bottom-up

	return true;
}
*/



//draw triangle in software
//////////////////////////////////////////////////////////////////////
void CPolyBumpWorkerThread::DrawTriPointer( uint16 *pTriIndices, CPbLowTri &rTri, int color, const bool inbConservative )
{ 
	float fU[3],fV[3];

	for(int i=0;i<3;i++)
	{
		fU[i]=(float)(rTri.m_fS[i]*(float)m_nImageSizeX);
		fV[i]=(float)(rTri.m_fT[i]*(float)m_nImageSizeY);
	}

	CSimpleTriangleRasterizer Raster(m_nImageSizeX,m_nImageSizeY);

	assert(color<0xffff);
	Raster.DTFlatFill<uint16>(pTriIndices,m_nImageSizeX,fU,fV,(uint16)color,inbConservative);
}


// draw low res tris pointers
void CPolyBumpWorkerThread::DrawTrisPointers( uint16 *pTriIndices, CPbLowMesh *pLowMesh )
{
	bool bDebug = m_Properties.m_bOutputDebugInfo;
	uint32 k;

	// conservative
  for(k=0;k<pLowMesh->m_nNumTris;k++)  
    if(m_Properties.m_iMaterialID==-1 || pLowMesh->m_pMesh[k].m_iTriMaterialID==m_Properties.m_iMaterialID)
			DrawTriPointer(pTriIndices,pLowMesh->m_pMesh[k],k,true);

//	if(bDebug)
//		PIX_SaveTGA32("DrawTrisPointersCon.tga",(unsigned char *)m_pnTriPointer,m_nImageSizeX,m_nImageSizeY,false,false);

	// non conservative
	for(k=0;k<pLowMesh->m_nNumTris;k++)  
		if(m_Properties.m_iMaterialID==-1 || pLowMesh->m_pMesh[k].m_iTriMaterialID==m_Properties.m_iMaterialID)
			DrawTriPointer(pTriIndices,pLowMesh->m_pMesh[k],k,false);

//	if(bDebug)
//		PIX_SaveTGA32("DrawTrisPointersBoth.tga",(unsigned char *)m_pnTriPointer,m_nImageSizeX,m_nImageSizeY,false,false);
}


// set attribute
void CPolyBumpWorkerThread::SetStartTime( DWORD indwStartTime )
{
	m_dwStartTime=indwStartTime;
}


// get attribute
DWORD CPolyBumpWorkerThread::GetStartTime()
{
	return m_dwStartTime;
}


void CPolyBumpWorkerThread::DebugLog( const char *sFormat, ... )
{
	if(!m_Properties.m_bOutputDebugInfo)
		return;

	FILE *out=fopen("PolyBumpDebug.txt","ab");

	if(!out)
		return;

	va_list vl;
	static char sTraceString[1024];

	va_start(vl, sFormat);
	vsprintf(sTraceString, sFormat, vl);
	va_end(vl);

	OutputDebugString(sTraceString);	
	OutputDebugString("\n");	

	fprintf(out,"%s\r\n",sTraceString);

	m_Properties.m_bSummariesString+=sTraceString;
	m_Properties.m_bSummariesString+="\n";

	fclose(out);
}



