// MaxMesh.cpp: implementation of the CMaxMesh class.
//
//////////////////////////////////////////////////////////////////////

#include "MaxMesh.h"

#include "MaxKernel.h"

#include "..\Common\FileStream.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CMaxMesh::CMaxMesh()
{
	m_pMeshFace = NULL;

	m_dwNumVertices = 0;
	m_dwNumMeshFaces = 0;
}

CMaxMesh::~CMaxMesh()
{
}

static float normalBlend = (float) cos( 2.0f * (Q_PI / 180.0f) );
bool CMaxMesh::LookupVertex(LPVERTEX lpVertex, int nNode)
{
	DWORD dwIndex = 0xffffffff;

	LPVERTEX pVertex = m_pVertices;
	for (int i=0; i<(int) m_dwNumVertices; i++)
	{
		if (m_pBones[i] == nNode)
		{
			VECTOR3D n1 = { lpVertex->nx, lpVertex->ny, lpVertex->nz };
			VECTOR3D n2 = { pVertex->nx,  pVertex->ny,  pVertex->nz };

			if (DotProductVector(&n1, &n2) > normalBlend)
			{
				VECTOR3D v1 = { pVertex->x, pVertex->y, pVertex->z };
				VECTOR3D v2;

				// assume 2 digits of accurcy
				v2.x = (int) (lpVertex->x * 100.0f ) / 100.0f;
				v2.y = (int) (lpVertex->y * 100.0f ) / 100.0f;
				v2.z = (int) (lpVertex->z * 100.0f ) / 100.0f;
				if (CompareVector(&v1, &v2))
				{
					if (pVertex->tu == lpVertex->tu && pVertex->tv == lpVertex->tv)
					{
						dwIndex = i;
						break;
					}
				}
			}
		}

		pVertex ++;
	}

	if (dwIndex == 0xffffffff)
	{
		// count num vector
		dwIndex = m_dwNumVertices;
		m_dwNumVertices ++;

		m_pBones = (LPINT) realloc(m_pBones, sizeof(int) * m_dwNumVertices);
		if (!m_pBones)
			return false;

		m_pBones[dwIndex] = nNode;

		///////////////////////////////////////////////////////////////////////////////////////////
		m_pVertices = (LPVERTEX) realloc(m_pVertices, sizeof(VERTEX) * m_dwNumVertices);
		if (!m_pVertices)
			return false;

		// Copy Vertex Array
		pVertex = m_pVertices + dwIndex;
		
		pVertex->tu = lpVertex->tu;
		pVertex->tv = lpVertex->tv;

		pVertex->nx = lpVertex->nx;
		pVertex->ny = lpVertex->ny;
		pVertex->nz = lpVertex->nz;

		pVertex->x = lpVertex->x;
		pVertex->y = lpVertex->y;
		pVertex->z = lpVertex->z;
	}
///////////////////////////////////////////////////////////////////////////////////////////////////

	m_pMeshFace->Append(dwIndex);

	return true;
}

bool CMaxMesh::LookupMaterial(CMaxMaterial* lpMaterial)
{
	bool bFound = false;

	DWORD dwIndex = CMaxKernel::LookupMaterial(lpMaterial);
	if (dwIndex == 0xffffffff)
		return false;

	m_pMeshFace = (CMaxMeshFace*) m_pMeshFaces;
	for (int i = 0; i < (int) m_dwNumMeshFaces; i ++)
	{
		if (m_pMeshFace->GetIndex() == dwIndex)
		{
			bFound = true;
			break;
		}

		m_pMeshFace = (CMaxMeshFace*) m_pMeshFace->GetNext();
	}

	if (!bFound)
	{
		m_dwNumMeshFaces ++;

		m_pMeshFace = new CMaxMeshFace;
		if (!m_pMeshFace)
			return false;

		m_pMeshFace->SetIndex(dwIndex);


		// Insert IndexBuffer
		if (!m_pMeshFaces)
			m_pMeshFaces = m_pMeshFace;
		else
		{
			CMaxMeshFace* pMeshFaces = (CMaxMeshFace*) m_pMeshFaces;
			pMeshFaces->SetLast(m_pMeshFace);
		}
	}

	if (!m_pMeshFace->Append())
		return false;

	return true;
}

void CMaxMesh::Write(CFileStream* lpStream)
{
	CFileStream* pStream = lpStream;

	pStream->WriteString(m_pszName);

	///////////////////////////////////////////////////////////////////////////////////////////////
	pStream->Write(&m_dwNumVertices, sizeof(DWORD), 1);
	pStream->Write(m_pVertices, sizeof(VERTEX), m_dwNumVertices);

	pStream->Write(m_pBones, sizeof(int), m_dwNumVertices);

	///////////////////////////////////////////////////////////////////////////////////////////////
	pStream->Write(&m_dwNumMeshFaces, sizeof(DWORD), 1);

	CMaxMeshFace* pMeshFace = (CMaxMeshFace*) m_pMeshFaces;
	for (int i=0; i<(int) m_dwNumMeshFaces; i++)
	{
		pMeshFace->Write(pStream);
		pMeshFace = (CMaxMeshFace*) pMeshFace->GetNext();
	}
}


