// Node.cpp

//#include <windows.h>
#include <stdio.h>
#include <string.h>
#include "dosfile.h"

#include "Types.h"
#include "Math.h"
#include "Misc.h"
#include "Object.h"
#include "Model.h"
#include "Box.h"
#include "Node.h"


extern CModel
	Model;


bool32 CNode::ContainsPoint( Vector3 *v )
{
	CBox
		*box;
	Plane
		*plane;
	s32
		b,
		p;
	bool32
		inside,
		contains;
	float
		d;

	contains = AllTagged;

	for (b=0; b<Tags.Count; b++)
	{
		box = Tags[b];
		inside = TRUE;

		for (p=0; p<box->Planes.Count; p++)
		{
			plane = box->Planes[p];

			d = DotProduct( v, &plane->Normal );

			if (d < plane->Dist)
				inside = FALSE;
		}

		if (inside)
			contains = TRUE;
	}

	for (b=0; b<UnTags.Count; b++)
	{
		box = UnTags[b];
		inside = TRUE;

		for (p=0; p<box->Planes.Count; p++)
		{
			plane = box->Planes[p];

			d = DotProduct( v, &plane->Normal );

			if (d < plane->Dist)
				inside = FALSE;
		}

		if (inside)
			contains = FALSE;
	}

	return( contains );
}


CNode::CNode()
{
	NumVerts = 0;
	VertNums = NULL;
	Reorder = NULL;
	VertList = NULL;
	AllTagged = FALSE;
}


CNode::~CNode()
{
	NumVerts = 0;
	delete [] VertNums;
	delete [] Reorder;
	VertNums = NULL;
	Reorder = NULL;
	delete [] VertList;
	VertList = NULL;
	AllTagged = FALSE;
}


void CNode::Tag( const char *name )
{
	CObject
		*obj;
	CBox
		*box;

	obj = Model.Find( name );
	if (!obj)
	{
		Error( "Cannot find object: '%s'", name );
		return;
	}


	box = new CBox;
	box->Load( obj );
	Tags.Add( box );
}


void CNode::UnTag( const char *name )
{
	CObject
		*obj;
	CBox
		*box;

	obj = Model.Find( name );
	if (!obj)
	{
		Error( "Cannot find object: '%s'", name );
		return;
	}


	box = new CBox;
	box->Load( obj );
	UnTags.Add( box );
}


void CNode::TagAll()
{
	AllTagged = TRUE;
}


void CNode::SetBase( const char *name )
{
	CObject
		*obj;

	obj = Model.Find( name );
	if (!obj)
	{
		Error( "Cannot find object: '%s'", name );
		return;
	}


	Base.Set( 0, obj->GetBase( 0 ) );
	Base.Set( 1, obj->GetBase( 1 ) );
}


void CNode::AddShared( const char *name )
{
	CObject
		*obj;
	CBox
		*box;

	obj = Model.Find( name );
	if (!obj)
	{
		Error( "Cannot find object: '%s'", name );
		return;
	}


	box = new CBox;
	strcpy( box->Name, name );
	box->Load( obj );
	Shared.Add( box );
}


void CNode::Grab( const char *name )
{
	CObject
		*obj;
	s32
		i,
		count;

	obj = Model.Find( name );
	if (!obj)
	{
		Error( "Cannot find object: '%s'", name );
		return;
	}


	// How many vertices in node?

	count = 0;
	for (i=0; i<obj->NumVerts; i++)
	{
		if (ContainsPoint( obj->GetVert( 0, i ) ))
			count++;
	}

//	printf( "%d verts.\n", count );

	NumVerts = count;
	VertNums = new s32[count];
	VertList = new CTwinVert[count];

	count = 0;
	for (i=0; i<obj->NumVerts; i++)
	{
		if (ContainsPoint( obj->GetVert( 0, i ) ))
		{
			VertNums[count] = i;
			VertList[count].Set( 0, obj->GetVert( 0, i ) );
			VertList[count].Set( 1, obj->GetVert( 1, i ) );
			count++;
		}
	}
}


void CNode::CalcReorder()
{
	CBox
		*box;
	s32
		i,
		j,
		r,
		count;
	u8
		*used;

	Reorder = new s32[NumVerts];
	used = new u8[NumVerts];
	memset( used, 0, NumVerts );
	//ZeroMemory( used, NumVerts );
	r = 0;

	for (i=0; i<Shared.Count; i++)
	{
		box = Shared[i];
		count = 0;

		for (j=0; j<NumVerts; j++)
		{
			if (box->ContainsPoint( VertList[j].Get( 0 ) ))
			{
				used[j] = TRUE;
				Reorder[j] = r;
				r++;
				count++;
			}
		}

		if (count != 1)
			Error( "Shared: '%s' contains %d points!", box->Name, count );
	}


	for (i=0; i<NumVerts; i++)
	{
		if (!used[i])
		{
			Reorder[i] = r;
			r++;
		}
	}


	delete [] used;
}


Vector3 *CNode::GetBase( const s32 frame )
{
	return( Base.Get( frame ) );
}


Vector3 *CNode::GetVert( const s32 frame, const s32 index )
{
	return( VertList[index].Get( frame ) );
}


ENode FindNode( const char *name )
{
	static const char
		*names[NODE_COUNT] =
		{
			"Head",
			"Jaw",
			"Mouth",
			"LowerLip",
			"UpperLip",
			"Eyes",
			"Brow",
		};
	s32
		i;

	for (i=0; i<NODE_COUNT; i++)
	{
		if (!stricmp( name, names[i] ))
			return( (ENode)i );
	}

	return( (ENode)-1 );
}
