// MaxMeshFrame.cpp: implementation of the CMaxMeshFrame class.
//
//////////////////////////////////////////////////////////////////////

#include "MaxMeshFrame.h"

#include "MaxKernel.h"

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

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

CMaxMeshFrame::CMaxMeshFrame()
{
	m_dwNumMeshs = 0;
	m_dwNumKeyNodes = 0;

	m_pKeyNodeFixup = NULL;
}

CMaxMeshFrame::~CMaxMeshFrame()
{
	Destroy();
}

void CMaxMeshFrame::Destroy()
{
	if (m_pKeyNodeFixup)
	{
		delete [] m_pKeyNodeFixup;
		m_pKeyNodeFixup = NULL;
	}

	CMeshFrame::Destroy();
}

CMaxMesh* CMaxMeshFrame::LookupMesh(LPSTR lpszName)
{
	DWORD dwIndex = 0xffffffff;

	CMaxMesh* pMesh = (CMaxMesh*) m_pMeshs;
	for (int i=0; i<(int) m_dwNumMeshs; i++)
	{
		if (!strcmp(pMesh->GetName(), lpszName))
		{
			dwIndex = i;
			break;
		}

		pMesh = (CMaxMesh*) pMesh->GetNext();
	}

	if (dwIndex == 0xffffffff)
	{
		// count material
		dwIndex = m_dwNumMeshs;
		m_dwNumMeshs ++;

		pMesh = new CMaxMesh;
		if (!pMesh)
			return NULL;

		if (!pMesh->Create(lpszName))
			return NULL;


		// Insert Mesh
		if (!m_pMeshs)
		{
			m_pMeshs = pMesh;
		}
		else
		{
			m_pMeshs->SetLast(pMesh);
		}
	}

	return pMesh;
}

bool CMaxMeshFrame::CreateNodes(DWORD dwNumNodes)
{
	m_pKeyNodes = new CMaxKeyNode [dwNumNodes+1];
	if (!m_pKeyNodes)
		return false;

	m_pKeyNodeFixup = new KEYNODEFIXUP [dwNumNodes+1];
	if (!m_pKeyNodeFixup)
		return false;


	m_dwNumKeyNodes = dwNumNodes;

	return true;
}

void CMaxMeshFrame::WriteHeader(CFileStream* lpStream)
{
	CFileStream* pStream = lpStream;

	// Write file header
	pStream->WriteString("RIFF");

	DWORD dwVersion = 100;
	pStream->Write(&dwVersion, sizeof(DWORD), 1);
}

bool CMaxMeshFrame::Save(LPSTR lpszFileName)
{
	CFileStream stream;
	if (!stream.Open(lpszFileName, CFileStream::CREATE))
		return false;

	WriteHeader(&stream);

	CMaxKernel::WriteMaterial(&stream);

	///////////////////////////////////////////////////////////////////////////////////////////////
	stream.Write(&m_dwNumKeyNodes, sizeof(DWORD), 1);

	CMaxKeyNode* pKeyNode = (CMaxKeyNode*) m_pKeyNodes;
	for (int i=0; i<(int) m_dwNumKeyNodes; i++)
	{
		pKeyNode->Write(&stream);

		pKeyNode ++;
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	stream.Write(&m_dwNumMeshs, sizeof(DWORD), 1);

	CMaxMesh* pMesh = (CMaxMesh*) m_pMeshs;
	for (i=0; i<(int) m_dwNumMeshs; i++)
	{
		pMesh->Write(&stream);

		pMesh = (CMaxMesh*) pMesh->GetNext();
	}
	
	stream.Close();

	return true;
}

void CMaxMeshFrame::BuildReference()
{
	MATRIX	m;

	CMaxKeyNode* pKeyNode = (CMaxKeyNode*) m_pKeyNodes;
	for (int i=0; i<(int) m_dwNumKeyNodes; i++)
	{
		int nParent = pKeyNode->GetParent();
		if (nParent == -1) 
		{
			// scale the done pos.
			// calc rotational matrices
			AngleMatrix(&pKeyNode->m_rotate, &m_pKeyNodeFixup[i].m );
			AngleIMatrix(&pKeyNode->m_rotate, &m_pKeyNodeFixup[i].im);

			CopyVector(&pKeyNode->m_kinematics.translate, &m_pKeyNodeFixup[i].world);
		}
		else
		{
			// calc compound rotational matrices
			// FIXME : Hey, it's orthogical so inv(A) == transpose(A)
			AngleMatrix(&pKeyNode->m_rotate, &m);
			MatrixMultiply(&m_pKeyNodeFixup[nParent].m, &m, &m_pKeyNodeFixup[i].m);

			AngleIMatrix(&pKeyNode->m_rotate, &m);
			MatrixMultiply(&m, &m_pKeyNodeFixup[nParent].im, &m_pKeyNodeFixup[i].im);

			// calc true world coord.
			VECTOR3D v;
			TransformVector(&pKeyNode->m_kinematics.translate, &m_pKeyNodeFixup[nParent].m, &v);

			AddVector(&v, &m_pKeyNodeFixup[nParent].world, &m_pKeyNodeFixup[i].world);
		}

		pKeyNode ++;
	}
}


