//#include "RenderPCH.h"										// precompiled headers
#include "stdafx.h"
#include <assert.h>										// assert()
#include "pbclonemapdest.h"						// CPBCloneMapDest
#include "TGA.h"											// PIX_LoadTGA,PIX_SaveTGA
#include "RGBPackedBase.h"						// CRGBPackedBase Base orthogonal base stored in 3 Bytes



// constructor
CPBCloneMapDest::CPBCloneMapDest( void )
{
	assert(6*g_dwCMSideLength*g_dwCMSideLength*g_dwCMAngleLength<=0xffffff);

	m_pBitmap=0;
	m_dwBitmapWidth=0;
	m_dwBitmapHeight=0;
}



// destructor
CPBCloneMapDest::~CPBCloneMapDest( void )
{
	FreeData();
}


// load the clonemap (same directory and filename (except extension) as objectspace bumpmap is recommended)
bool CPBCloneMapDest::LoadCloneMap( const char *inszFileName )
{
	FreeData();

	DWORD dwWidth,dwHeight;
	int iBytesPerPixel;
	bool bAlpha;


	if(PIX_LoadTGA(inszFileName,0,0,(int *)&dwWidth,(int*)&dwHeight,iBytesPerPixel,bAlpha))
	{
		if(!Create(dwWidth,dwHeight))return(false);

		if(PIX_LoadTGA(inszFileName,(unsigned char *)m_pBitmap,0,(int *)&dwWidth,(int *)&dwHeight,iBytesPerPixel,bAlpha))
			return(true);
	}



	FreeData();
	return(false);
}







void CPBCloneMapDest::FreeData( void )
{
	if(m_pBitmap)delete[] m_pBitmap;m_pBitmap=0;

	m_dwBitmapWidth=0;m_dwBitmapHeight=0;
}



//
bool CPBCloneMapDest::Create( DWORD indwWidth, DWORD indwHeight )
{
	FreeData();

	if(indwWidth==0)return(false);
	if(indwHeight==0)return(false);

	m_pBitmap=new DWORD[indwWidth*indwHeight];

	if(m_pBitmap)
	{
		DWORD *pPtr=m_pBitmap;

		for(DWORD i=0;i<indwWidth*indwHeight;i++)
			*pPtr++=0;

		m_dwBitmapWidth=indwWidth;
		m_dwBitmapHeight=indwHeight;
		return(true);
	}

	else return(false);
}


/*
class CPixelSumBaseCallback: public CSimpleTriangleFiller::CPixelCallback
{
public:

	//! constructor
	CPixelSumBaseCallback()
	{
		for(int i=0;i<3;i++)
		{
			m_fBaseA[i]=0;m_fBaseB[i]=0;m_fBaseC[i]=0;
		}

		m_iSamples=0;
	}

	//! callback function
	virtual void ReturnPixel( DWORD inX, DWORD inY, DWORD &inoutdwColor )
	{
		if(m_iSamples)return;

		if(inoutdwColor)
		{
			CRGBPackedBase pack;

			pack.SetRGB(inoutdwColor-g_dwCMStartBaseColor);

			float fBaseA[3],fBaseB[3],fBaseC[3];
			pack.GetBase(fBaseA,fBaseB,fBaseC);

			for(int i=0;i<3;i++)
			{
				m_fBaseA[i]+=fBaseA[i];
				m_fBaseB[i]+=fBaseB[i];
				m_fBaseC[i]+=fBaseC[i];
			}
			m_iSamples++;
		}
	}

	float		m_fBaseA[3];	//!<
	float		m_fBaseB[3];	//!<
	float		m_fBaseC[3];	//!<
	int			m_iSamples;		//!<
};
*/

// get the base for a UV triangle definition
bool CPBCloneMapDest::Get( float infU[3], float infV[3], float outvBaseA[3], float outvBaseB[3], float outvBaseC[3] )
{
	if(!m_pBitmap)return(false);
/*
	// sampling the inner part of the triangle
	float fX[3]={ infU[0]*m_dwBitmapWidth, infU[1]*m_dwBitmapWidth, infU[2]*m_dwBitmapWidth };
	float fY[3]={ infV[0]*m_dwBitmapHeight, infV[1]*m_dwBitmapHeight, infV[2]*m_dwBitmapHeight  }; 

	// shrink because I don't want near triangles in the integration
	for(int f=0;f<3;f++)
		CSimpleTriangleFiller::ShrinkTriangle(fX,fY);

	CPixelSumBaseCallback callback;

	CSimpleTriangleFiller::CallbackFill(m_pBitmap,m_dwBitmapWidth,m_dwBitmapHeight,
						fX[0],fY[0],fX[1],fY[1],fX[2],fY[2],&callback);

	for(int i=0;i<3;i++)
	{
		outvBaseA[i]=callback.m_fBaseA[i];
		outvBaseB[i]=callback.m_fBaseB[i];
		outvBaseC[i]=callback.m_fBaseC[i];
	}

	if(callback.m_iSamples!=0)
	{
		CRGBPackedBase::Orthogonalize(outvBaseA,outvBaseB,outvBaseC);	// could be done better?
	}
	else																// no samples found (shrink too much?)
	{
*/		// one midpoint sample
		float fU=(infU[0]+infU[1]+infU[2])/3.0f;
		float fV=(infV[0]+infV[1]+infV[2])/3.0f;

		DWORD dwX=(DWORD)(fU*m_dwBitmapWidth);		dwX=dwX%m_dwBitmapWidth;
		DWORD dwY=(DWORD)(fV*m_dwBitmapHeight);		dwY=dwY%m_dwBitmapHeight;

		DWORD dwColor=m_pBitmap[dwX+dwY*m_dwBitmapWidth];		// one sample might be not enougth

		if(dwColor==0)
			return(false);												// invalid color (no base information stored)

		CRGBPackedBase pack;

		pack.SetRGB(dwColor-g_dwCMStartBaseColor);
		pack.GetBase(outvBaseA,outvBaseB,outvBaseC);
//	}
	return(true);
}



bool CPBCloneMapDest::IsAvailable( void )
{
	return(m_pBitmap!=0);
}



//
DWORD CPBCloneMapDest::GetWidth( void )
{
	return(m_dwBitmapWidth);
}

//
DWORD CPBCloneMapDest::GetHeight( void )
{
	return(m_dwBitmapHeight);
}
