#include <algorithm>

#include <gfname.hpp>
#include "gintex.h"

#include "vector3.h"
#include "matrix4x4.h"
#include "quat.h"

using namespace std;

/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
// Unconditional string compare
// REturns 1 on equal
int		IsStrSame(char *Str0,char *Str1,int Len)
{
		if (Len==-1)
			{
			Len=strlen(Str0);
			if (strlen(Str1)!=Len) return(0);
			}
		for (int Loop=0;Loop<Len;Loop++) 
			{
			char C0=Str0[Loop];
			char C1=Str1[Loop];
			if (C0>='a' && C0<='z') C0+='A'-'a';
			if (C1>='a' && C1<='z') C1+='A'-'a';
			if (C0!=C1) return(0);
			}
		return(1);
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
int CMat4::GetTexId(int v)
{
	int NumOfTextures;

	NumOfTextures=Mats.size();

	if (v>=NumOfTextures)
		{
		GObject::Error(ERR_WARNING,"erroneous material id of %d\n",v);
		v = 0;
		}
	
	if (v>=NumOfTextures)
		GObject::Error(ERR_FATAL,"material asked for when none exists",v);

	return Mats[v].TexId;
}


/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
void CMat4::Load(Gifstream & In)
{
	int m = In.Get32();
	int o = In.Get32();

	Mats.resize(m);
	for (int i=0; i<m; i++)
		{
		for (int j=0; j<8; j++)
			In.Get32();
		
		int tf = (int)In.Get32();
		int temp2 = In.Get32();
		
		if (temp2&1 == 0)
			{
			tf = -1;
			}
		Mats[i].TexId = tf;
		Mats[i].Flags = temp2;

		}
}

/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
void CMesh::Load(Gifstream & In)
{
	Obj = In.Get32();
	int NbMesh = In.Get32();

	Chunk.resize(NbMesh);
	
	for (int i=0; i<NbMesh; i++)
		{

		Chunk[i].MatId		= s16(In.Get16());
		Chunk[i].NumFace	= s16(In.Get16());
		Chunk[i].MeshNum	= In.Get32();
		Chunk[i].Attrib		= In.Get32();
		Chunk[i].Normals	= In.Get32();
		Chunk[i].Vcol		= In.Get32();
		Chunk[i].Tex		= In.Get32();
		}
}

/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
void CMod4::Load(Gifstream & In)
{
Mod4Chunk	ThisChunk;	

		In.read((char*)&ThisChunk.nCurObj	, sizeof(long));
		In.read(ThisChunk.Name, 32);
		In.read((char*)&ThisChunk.Radius, sizeof(float));
		In.read((char*)&ThisChunk.Centre.x, sizeof(float));
		In.read((char*)&ThisChunk.Centre.y, sizeof(float));
		In.read((char*)&ThisChunk.Centre.z, sizeof(float));
		In.read((char*)&ThisChunk.Ap.x, sizeof(float));
		In.read((char*)&ThisChunk.Ap.y, sizeof(float));
		In.read((char*)&ThisChunk.Ap.z, sizeof(float));
		Chunk.push_back(ThisChunk);
}

/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
void CTexName::Load(Gifstream & In)
{
	int	NumOfNames;

	NumOfNames=In.Get32();

	for (int f=0;f<NumOfNames;f++)
		{
		vector<char>	Str;
		bool			Done;
		
		Str.reserve(200);
		Done=false;

		In.Align(4);

		while (!Done)
			{
			char c;
			c=In.get();
			if (!c)
				Done=true;
			Str.push_back(c);
			}

		Names.push_back(&Str[0]);
		}
}

/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
void	CGinTree::Load(Gifstream & In)
{
		LoadTree(In,-1);
}

/*****************************************************************************/
void	CGinTree::LoadTree(Gifstream & In,int Parent)
{
CNode	ThisNode;

		In.Align(4);
		
		In.read(ThisNode.Name, 32);
		In.read((char*)&ThisNode.Pos.x, 4);
		In.read((char*)&ThisNode.Pos.y, 4);
		In.read((char*)&ThisNode.Pos.z, 4);

		In.read((char*)&ThisNode.Ang.x, 4);
		In.read((char*)&ThisNode.Ang.y, 4);
		In.read((char*)&ThisNode.Ang.z, 4);
		In.read((char*)&ThisNode.Ang.w, 4);

		In.read((char*)&ThisNode.apk.x, 4);
		In.read((char*)&ThisNode.apk.y, 4);
		In.read((char*)&ThisNode.apk.z, 4);

		In.read((char*)&ThisNode.apu.x, 4);
		In.read((char*)&ThisNode.apu.y, 4);
		In.read((char*)&ThisNode.apu.z, 4);
		In.read((char*)&ThisNode.apu.w, 4);

int		ChildCount= In.Get32();
		SceneTree[0].AddChild( SceneTree,ThisNode,Parent);

int		Idx=ThisNode.Idx;
		for (int Loop=0;Loop<ChildCount;Loop++)	LoadTree(In,Idx);

}

/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
void	CSkinTree::Load(Gifstream & In)
{
		In.Get32();	// Skip Obj number
		LoadTree(In,-1);
}

/*****************************************************************************/
void	CSkinTree::LoadTree(Gifstream & In,int Parent)
{
CNode	ThisNode;
int		WeightCount;
		In.Align(4);

		In.read(ThisNode.Name, 32);
		WeightCount=In.Get32();
	 	if (WeightCount)
			{
			ThisNode.Weights.resize(WeightCount);
			for (int Weight=0;Weight<WeightCount;Weight++)
				{
				ThisNode.Weights[Weight].VertNo=In.Get32();
				In.read((char*)&ThisNode.Weights[Weight].Weight, 4);
				In.read((char*)&ThisNode.Weights[Weight].Pos.x, 4);
				In.read((char*)&ThisNode.Weights[Weight].Pos.y, 4);
				In.read((char*)&ThisNode.Weights[Weight].Pos.z, 4);
				}
			}
	
int		ChildCount= In.Get32();
		SkinTree[0].AddChild( SkinTree,ThisNode,Parent);

int		Idx=ThisNode.Idx;
		for (int Loop=0;Loop<ChildCount;Loop++)	LoadTree(In,Idx);

}

/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
const   int	CHANNEL_TYPE_TREE  = 7;  // NODE ANIMATION

void	CAnimTree::Load(Gifstream & In)
{
int		AnimType=In.Get32();
		if (AnimType!=CHANNEL_TYPE_TREE) return;

int		FrameCount = In.Get32();
		LoadTree(In,-1,FrameCount);
}

/*****************************************************************************/
void	CAnimTree::LoadTree(Gifstream & In,int Parent,int FrameCount)
{
CNode	ThisNode;

		In.Align(4);
		
		ThisNode.Anim.resize(FrameCount);
		for (int Frame=0;Frame<FrameCount;Frame++)
			{
			In.read((char*)&ThisNode.Anim[Frame].Pos.x, 4);
			In.read((char*)&ThisNode.Anim[Frame].Pos.y, 4);
			In.read((char*)&ThisNode.Anim[Frame].Pos.z, 4);

			In.read((char*)&ThisNode.Anim[Frame].Ang.x, 4);
			In.read((char*)&ThisNode.Anim[Frame].Ang.y, 4);
			In.read((char*)&ThisNode.Anim[Frame].Ang.z, 4);
			In.read((char*)&ThisNode.Anim[Frame].Ang.w, 4);

			In.read((char*)&ThisNode.Anim[Frame].apk.x, 4);
			In.read((char*)&ThisNode.Anim[Frame].apk.y, 4);
			In.read((char*)&ThisNode.Anim[Frame].apk.z, 4);

			In.read((char*)&ThisNode.Anim[Frame].apu.x, 4);
			In.read((char*)&ThisNode.Anim[Frame].apu.y, 4);
			In.read((char*)&ThisNode.Anim[Frame].apu.z, 4); 
			In.read((char*)&ThisNode.Anim[Frame].apu.w, 4);
			}

int		ChildCount= In.Get32();
		AnimTree[0].AddChild( AnimTree,ThisNode,Parent);

int		Idx=ThisNode.Idx;
		for (int Loop=0;Loop<ChildCount;Loop++)	LoadTree(In,Idx,FrameCount);

}

/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
void	CKeyAnimTree::Load(Gifstream & In)
{
int		AnimType=In.Get32();
		if (AnimType!=CHANNEL_TYPE_TREE) return;
		AnimType=In.Get32();	// Skip Node type thingy

		LoadTree(In,-1);
}

/*****************************************************************************/
void	CKeyAnimTree::LoadTree(Gifstream & In,int Parent)
{
CNode	ThisNode;
int		KeyCount;
		In.Align(4);

		KeyCount=In.Get32();
		ThisNode.KeyAnim.resize(KeyCount);
		for (int Frame=0;Frame<KeyCount;Frame++)
			{
			ThisNode.KeyAnim[Frame].Frame=In.Get32();
			In.read((char*)&ThisNode.KeyAnim[Frame].Pos.x, 4);
			In.read((char*)&ThisNode.KeyAnim[Frame].Pos.y, 4);
			In.read((char*)&ThisNode.KeyAnim[Frame].Pos.z, 4);

			In.read((char*)&ThisNode.KeyAnim[Frame].Ang.x, 4);
			In.read((char*)&ThisNode.KeyAnim[Frame].Ang.y, 4);
			In.read((char*)&ThisNode.KeyAnim[Frame].Ang.z, 4);
			In.read((char*)&ThisNode.KeyAnim[Frame].Ang.w, 4);

			In.read((char*)&ThisNode.KeyAnim[Frame].apk.x, 4);
			In.read((char*)&ThisNode.KeyAnim[Frame].apk.y, 4);
			In.read((char*)&ThisNode.KeyAnim[Frame].apk.z, 4);

			In.read((char*)&ThisNode.KeyAnim[Frame].apu.x, 4);
			In.read((char*)&ThisNode.KeyAnim[Frame].apu.y, 4);
			In.read((char*)&ThisNode.KeyAnim[Frame].apu.z, 4); 
			In.read((char*)&ThisNode.KeyAnim[Frame].apu.w, 4);
		
			}

int		ChildCount= In.Get32();
		AnimTree[0].AddChild( AnimTree,ThisNode,Parent);

int		Idx=ThisNode.Idx;
		for (int Loop=0;Loop<ChildCount;Loop++)	LoadTree(In,Idx);
}

/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
bool	CScene::SetPruneNodes(int Idx)
{
CNode	&ThisNode=GetNode(Idx);
bool	NoPrune=false;
int		ChildCount=ThisNode.GetChildCount();
	
	for (int Loop=0;Loop<ChildCount;Loop++) NoPrune|= SetPruneNodes(ThisNode.ChildList[Loop]);

int		HasData=ThisNode.Weights.size() | ThisNode.Pts.size();

	if (!NoPrune && !HasData)
		{
		ThisNode.Active=false;
		return(false);
		} 
	else
		{
		return(true);
		}
}

/*****************************************************************************/
void	CScene::BuildPruneTree(int Idx, int ParentIdx)
{
CNode	&ThisNode=GetNode(Idx);
		if (!ThisNode.Active) return;

		ThisNode.AddPruneChild(SceneTree,PruneTree,ParentIdx);

int		ChildCount=ThisNode.GetChildCount();
		for (int Loop=0;Loop<ChildCount;Loop++)	BuildPruneTree(ThisNode.ChildList[Loop],ThisNode.Idx);
}

/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
int		IsAnimDiff(sGinAnim const &Frm0,sGinAnim const &Frm1)
{
		if (Frm0.Pos.x!=Frm1.Pos.x) return(1);
		if (Frm0.Pos.y!=Frm1.Pos.y) return(1);
		if (Frm0.Pos.z!=Frm1.Pos.z) return(1);

		if (Frm0.Ang.x!=Frm1.Ang.x) return(1);
		if (Frm0.Ang.y!=Frm1.Ang.y) return(1);
		if (Frm0.Ang.z!=Frm1.Ang.z) return(1);
		if (Frm0.Ang.w!=Frm1.Ang.w) return(1);
		return(0);
}

/*****************************************************************************/
void	LoadAndShrinkAnim(CNode const &KeyNode,CNode const &AnimNode,CNode &OutNode)
{
// Calc Extents from Key Frames
int		Key,Frame;
int		StartKey=0,EndKey=KeyNode.KeyAnim.size();

		if (!EndKey) // No keys, create 1 and return
			{
			sGinAnim	ForceKey;
			ForceKey.Frame=0;
			ForceKey.Pos.x=OutNode.Pos.x; ForceKey.Pos.y=OutNode.Pos.y; ForceKey.Pos.z=OutNode.Pos.z;
			ForceKey.Ang.x=OutNode.Ang.x; ForceKey.Ang.y=OutNode.Ang.y; ForceKey.Ang.z=OutNode.Ang.z; ForceKey.Ang.w=OutNode.Ang.w;
			OutNode.KeyAnim.push_back(ForceKey);
			OutNode.ShrunkKeyAnim.push_back(ForceKey);
			EndKey=0;
			OutNode.StartFrame=	0;
			OutNode.EndFrame=	0;
			}
		else
			{
			EndKey--;
			while ((!IsAnimDiff(KeyNode.KeyAnim[StartKey],	KeyNode.KeyAnim[StartKey+1]))	&& StartKey!=EndKey) StartKey++;
			while ((!IsAnimDiff(KeyNode.KeyAnim[EndKey  ],	KeyNode.KeyAnim[EndKey-1]))		&& StartKey!=EndKey) EndKey--;
			OutNode.StartFrame=	KeyNode.KeyAnim[StartKey].Frame; 
			OutNode.EndFrame=	KeyNode.KeyAnim[EndKey].Frame;
			EndKey++;
			}

		OutNode.EndFrame++;

// Transfer Key Frames
int		KeyAnimSize=KeyNode.KeyAnim.size();
			for (Key=0;Key<KeyAnimSize;Key++) OutNode.KeyAnim.push_back(KeyNode.KeyAnim[Key]);				// Transfer All key frames
			for (Key=StartKey; Key<EndKey; Key++) OutNode.ShrunkKeyAnim.push_back(KeyNode.KeyAnim[Key]);	// Transfer Shrunk key frames

// Transfer Normal frames
int		AnimSize=AnimNode.Anim.size();
		if (AnimSize)
			{
			for (Frame=0;Frame<AnimSize;Frame++) OutNode.Anim.push_back(AnimNode.Anim[Frame]);									// Transfer All Normal Anim
			for (Frame=OutNode.StartFrame; Frame<OutNode.EndFrame; Frame++) OutNode.ShrunkAnim.push_back(AnimNode.Anim[Frame]);	// Transfer Shrunk Normal Anim
			}

}

/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
void Gin4File::Load(char const * Name)
{
	MyFile.Load(Name);

	MyFile.FindChunks("VERS",VersionChunk);
	MyFile.FindChunks("TEX4",TexNamesChunk);
	MyFile.FindChunks("MAT4",MatChunk);
	MyFile.FindChunks("MOD4",Mod4Chunk);
	MyFile.FindChunks("MESH",MshChunk);
	MyFile.FindChunks("PTS4",PointsChunk);
	MyFile.FindChunks("POLY",TrisChunk);
	MyFile.FindChunks("VCOL",VColTrisChunk);
	MyFile.FindChunks("MAP4",UVtrisChunk);
	MyFile.FindChunks("TREE",SceneTreeChunk);
	MyFile.FindChunks("ANIM",AnimTreeChunk);
	MyFile.FindChunks("KEY4",KeyAnimTreeChunk);
	MyFile.FindChunks("BONE",SkinTreeChunk);
	MyFile.FindChunks("PROP",UserPropChunk);
	MyFile.FindChunks("CAM4",CameraChunk);
}


/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
void	CScene::Load(const char *Name)
{

Gin4File	GinFile;
	FileName=Name;
	GinFile.Load(Name);

std::vector<GinChunk  const *> &VersionChunk=GinFile.GetVersionChunk();
std::vector<GinChunk  const *> &TexNamesChunk=GinFile.GetTexNamesChunk();
std::vector<GinChunk  const *> &MatChunk=GinFile.GetMatChunk();
std::vector<GinChunk  const *> &MshChunk=GinFile.GetMshChunk();
std::vector<GinChunk  const *> &PointsChunk=GinFile.GetPointsChunk();
std::vector<GinChunk  const *> &TrisChunk=GinFile.GetTrisChunk();
std::vector<GinChunk  const *> &VColTrisChunk=GinFile.GetVColTrisChunk();
std::vector<GinChunk  const *> &UVtrisChunk=GinFile.GetUVtrisChunk();
std::vector<GinChunk  const *> &SceneTreeChunk=GinFile.GetSceneTreeChunk();
std::vector<GinChunk  const *> &AnimTreeChunk=GinFile.GetAnimTreeChunk();
std::vector<GinChunk  const *> &KeyAnimTreeChunk=GinFile.GetKeyAnimTreeChunk();
std::vector<GinChunk  const *> &SkinTreeChunk=GinFile.GetSkinTreeChunk();
std::vector<GinChunk  const *> &UserPropChunk=GinFile.GetUserPropChunk();
std::vector<GinChunk  const *> &CameraChunk=GinFile.GetCameraChunk();

int	Node,NodeCount;


// Build Scene Tree
CGinTree	*GT = (CGinTree*)SceneTreeChunk[0];
std::vector<CNode>	const &GinTree=GT->GetTree();

	NodeCount=GinTree.size();
	for (Node=0;Node<NodeCount;Node++)
		{
		CNode	ThisNode=GinTree[Node];
		SceneTree[0].AddChild(SceneTree,ThisNode,ThisNode.ParentIdx);
		}

// Build Node Mtx's
	for (Node=0;Node<NodeCount;Node++)
		{
		CNode	*ThisNode=&SceneTree[Node];
		int		ParentIdx=ThisNode->ParentIdx;
		ThisNode->Mtx.Identity();
// Build Node Mtx's
		if (ParentIdx!=-1)
			{
// LocalMtx
Matrix4x4	ThisMtx;
CNode		*ParentNode=&SceneTree[ParentIdx];		
			ThisMtx.Identity();
			ThisNode->Ang.ToMatrix(ThisMtx);
			ThisMtx.SetTranslation(ThisNode->Pos);
			ThisNode->Mtx=ThisMtx*ParentNode->Mtx;

// WorldMtx
			ThisNode->WorldMtx=GetWorldMatrix(SceneTree,ParentIdx);
			}
		}


//-----------------------------------------------------------------------------
// Load Materials
	int MatN = MatChunk.size();
	if (MatN)
	{
		CMat4 *	Materials = (CMat4*)MatChunk[0];
		AllMaterials = Materials->GetMaterials();

		if (TexNamesChunk.size())
			{
			CTexName * T=(CTexName *)(TexNamesChunk[0]);
			vector<GString> const & Strs=T->GetTexNames();
			TextureList = Strs;
			int		NumOfMeshes=MshChunk.size();
			for (int j=0; j<NumOfMeshes; j++)
				{
				CMesh *M = (CMesh*)MshChunk[j];
				vector<MeshChunk> const & Mat4Id = M->GetChunk();
				for (int i=0; i<Mat4Id.size(); i++)
					{
					if (Mat4Id[i].MatId>=0)
						{
						int tid = Materials->GetTexId(Mat4Id[i].MatId);
						if (tid >= Strs.size() || tid < 0)
							{
							GObject::Error(ERR_WARNING,"Texture index odd (asked for %d, max is %d) adjusting to 0\n",tid,Strs.size());
							tid=0;
							}
	//					else
							{
							GString const & TexFile=Strs[tid];
							/* Only add texture to list if it hasn't been on it before */
							if (find(AllTexNames.begin(),AllTexNames.end(),TexFile) == AllTexNames.end()) AllTexNames.push_back(TexFile);
							}
						}
					}
				}
			}
	}
	else
	{
		GObject::Error(ERR_WARNING,"No Materials\n");
	}

//-----------------------------------------------------------------------------
// Load Models and Meshes
	for (int m=0; m<MshChunk.size(); m++)
	{
		CMesh *M = (CMesh*)MshChunk[m];
		int CurMod = M->getObj();
		CNode	*ThisNode=GetNodePtr(GinFile.GetModelName(CurMod));

		if (loadPoints( CurMod, PointsChunk,ThisNode) != -1)
		{
			vector<MeshChunk> const &MeshChunks = M->GetChunk();
			for (int mn=0; mn<MeshChunks.size(); mn++)
			{
				if (loadTris( CurMod, MeshChunks[mn].MeshNum, TrisChunk,ThisNode)!=-1)
				{
					int MatIdx = addMaterialIdx(MeshChunks[mn].MatId);
					for (int i=0; i<MeshChunks[mn].NumFace; i++)	ThisNode->TriMaterial.push_back(MatIdx);
					loadVCol( CurMod, MeshChunks[mn].MeshNum, VColTrisChunk,ThisNode);
					loadUV(   CurMod, MeshChunks[mn].MeshNum, UVtrisChunk,ThisNode);
					int Size=ThisNode->Tris.size();
					ThisNode->UVTris.resize(Size);
					ThisNode->VColTris.resize(Size);
					ThisNode->TriMaterial.resize(Size);
				}
			}
		}
	}

//-----------------------------------------------------------------------------
// Load Anims
// Sort KeyFrame Anims
int	AnimCount=AnimTreeChunk.size();
		if (AnimCount)
		{
CKeyAnimTree			*KATC= (CKeyAnimTree*)KeyAnimTreeChunk[0];
CAnimTree				*NATC = (CAnimTree*)AnimTreeChunk[0];
std::vector<CNode>const &KeyAnimTree=KATC->GetTree();
std::vector<CNode>const &AnimTree=NATC->GetTree();

		NodeCount=KeyAnimTree.size();
		for (Node=0;Node<NodeCount;Node++)
		{
			LoadAndShrinkAnim(KeyAnimTree[Node],AnimTree[Node],SceneTree[Node]);
		}
		}


//-----------------------------------------------------------------------------
// Load Camera(s)
int	CamCount=CameraChunk.size();

		if (CamCount)
		{
		for (int Cam=0;Cam<CamCount;Cam++)
			{
			CCamera		*CamC= (CCamera	*)CameraChunk[Cam];
			Camera.push_back(CamC->GetCam());
			}
		}
	

//-----------------------------------------------------------------------------
// Load Skin Weight
	if (SkinTreeChunk.size())
	{
CSkinTree	*ST = (CSkinTree*)SkinTreeChunk[0];
std::vector<CNode>	const &SkinTree=ST->GetTree();
	NodeCount=SkinTree.size();
	for (Node=0;Node<NodeCount;Node++)
		{
		int WeightCount=SkinTree[Node].Weights.size();
		if (WeightCount)
			{
			SceneTree[Node].Weights.resize(WeightCount);
			for (int Weight=0;Weight<WeightCount;Weight++) SceneTree[Node].Weights[Weight]=SkinTree[Node].Weights[Weight];
			}
		}
	}

//-----------------------------------------------------------------------------
// Load User Props - Loaded as Ini File
/*
int		PropCount=UserPropChunk.size();
		for (int Loop=0;Loop<PropCount;Loop++)
			{
			CUserProp	*UP=(CUserProp*)UserPropChunk[Loop];
			if (UP)
				{
				CNode	*ThisNode=GetNodePtr(UP->GetModNum()+1);	// Skip SceneRoot);
				if (ThisNode)
					{
					std::vector<char> const & Prop=UP->GetUserProp();
					int Size=Prop.size()-1;
						if (Size>0)
						{

						char *PropPtr=(char*)&Prop[0];
						ThisNode->UserProp.Import(PropPtr);
						}
					}
				}
			}
*/
//-----------------------------------------------------------------------------
// Build Pruned Tree
		ResetPruneTree();
		SetPruneNodes(0);
		BuildPruneTree(0,-1);

//-----------------------------------------------------------------------------
// Print Trees

//	PrintSceneTree();
//	PrintPruneTree();

		
}

/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
void	CScene::PrintTreeNode(int Idx,const int Tree)
{
//#ifdef	_CONSOLE
CNode		&Node=SceneTree[Idx];
int			NodeIdx,NodeParentIdx;
std::vector<int>	ChildList;
	if (Tree==0)
		{
		ChildList=Node.ChildList;
		NodeIdx=Node.Idx;
		NodeParentIdx=Node.ParentIdx;
		}
	else
		{
		ChildList=Node.PruneChildList;
		NodeIdx=Node.PruneIdx;
		NodeParentIdx=Node.PruneParentIdx;
		}

int		ChildCount=ChildList.size();

		for (int Sp=0;Sp<PrintTreeSpace;Sp++) printf("| "); 
		printf("(P=%i I=%i C=%i) %s - T=%i, V=%i A=%i\n",NodeParentIdx,NodeIdx,ChildCount,Node.Name,Node.Tris.size(),Node.Pts.size(),Node.Anim.size());
		PrintTreeSpace++;

		for (int Child=0;Child<ChildCount;Child++) PrintTreeNode(ChildList[Child],Tree);
		PrintTreeSpace--;
//#endif
}

/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
int CScene::loadPoints( int CurMod, vector<GinChunk  const *> &Points ,CNode *ThisNode)
{
	for (int f=0; f<Points.size(); f++)
		{
		CPts4 * T;

		T=(CPts4 *)(Points[f]);

		if (T->GetModNum() == CurMod)
			{
			std::vector<Vector3> const & ThesePts=T->GetPts();
			int Size= ThesePts.size();
			ThisNode->Pts.resize(Size);
			ThisNode->RelPts.resize(Size);

Matrix4x4	IMtx=ThisNode->Mtx;
			IMtx.Invert();
			
			for (int g=0;g<Size;g++)
				{
/*Abs Pnt*/		ThisNode->Pts[g] = ThesePts[g];
/*Rel Pnt*/		ThisNode->RelPts[g]=IMtx*ThesePts[g];
				}
			return (Size);
			}
		}
	  return -1;
}

/*****************************************************************************/
int CScene::loadTris( int CurMod, int CurMesh, vector<GinChunk  const *> &Tris,CNode *ThisNode)
{
	for (int i=0; i<Tris.size(); i++)
		{
		CPoly * T;

		T=(CPoly *)(Tris[i]);
		if (T->GetModNum() == CurMod && T->GetMeshNum() == CurMesh)
			{
			std::vector<sGinTri> const & TheseTris=T->GetTris();
			int Size = TheseTris.size();

			ThisNode->TriBase=ThisNode->Tris.size();

			for (int j=0; j<Size; j++) ThisNode->Tris.push_back(TheseTris[j]);
			return (Size);
			}
		}
	  return -1;
}

/*****************************************************************************/
int CScene::loadUV( int CurMod, int CurMesh, vector<GinChunk  const *> &UVTris,CNode *ThisNode)
{
	for (int i=0; i<UVTris.size(); i++)
		{
		CUVtri *T;
		T = (CUVtri*)UVTris[i];
		if (T->GetModNum() == CurMod && T->GetMeshNum() == CurMesh)
			{
			std::vector<sUVTri> const & TheseTris=T->GetUVTris();
			int Size = TheseTris.size();

			for (int j=0; j<Size; j++) ThisNode->UVTris.push_back(TheseTris[j]);
			return (Size);
			}
		}
	return -1;
}

/*****************************************************************************/
int CScene::loadVCol( int CurMod, int CurMesh, vector<GinChunk  const *> &VColTris,CNode *ThisNode)
{
	for (int i=0; i<VColTris.size(); i++)
		{
		CVcol *T;
		T = (CVcol*)VColTris[i];
		if (T->GetModNum() == CurMod && T->GetMeshNum() == CurMesh)
			{
			std::vector<sVColTri> const & TheseTris=T->GetVcolTris();
			int Size = TheseTris.size();

			for (int j=0; j<Size; j++) ThisNode->VColTris.push_back(TheseTris[j]);
			return (Size);
			}
		}
	return -1;
}


/*****************************************************************************/
int CScene::addMaterialIdx( int idx )
{
	int c = UsedMaterials.size();
	for (int i=0; i<c; i++)
		{
		if (UsedMaterials[i] == idx) return i;
		}
	UsedMaterials.push_back(idx);
	return c;
}

/*****************************************************************************/
static GString GetNameAndExtOnly(char const * Name)
{
	GString	Rep(Name);

	Rep.Filter("/",'\\');

	GFName		FName(Rep);

	Rep=FName.File();
	Rep+=".";
	Rep+=FName.Ext();

	Rep.Lower();

	return(Rep);
}


/*****************************************************************************/
void CScene::GetNonSharedTextures(vector<GString> const & SharedTextures,vector<GString> & Dest)
{
	for (int f=0;f<AllTexNames.size();f++)
		{
		bool		Found;

		Found=false;

		GString	NameOnly(GetNameAndExtOnly(AllTexNames[f]));

		for (int t=0;t<SharedTextures.size() && !Found;t++)
			{
			GString TexNameOnly(GetNameAndExtOnly(SharedTextures[t]));
			Found=TexNameOnly==NameOnly;
			}

		if (!Found)
			{
			GFName	TexName(AllTexNames[f]);
			GFName	GinName(FileName);
			GinName.File(TexName.File());
			GinName.Ext(TexName.Ext());
			GString FinalName(GinName.FullName());
			
			FinalName.Lower();

			Dest.push_back(FinalName);
			}
		}
}

/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/

Matrix4x4	GetWorldMatrix(std::vector<CNode> const &Tree,int Idx)
{
CNode		ThisNode=Tree[Idx];
int			ParentIdx=ThisNode.ParentIdx;
Matrix4x4	ParentMtx, ThisMtx, PosMtx, RotMtx, StrMtx, SclMtx, IStrMtx;

		ParentMtx.Identity();

		if (ParentIdx!=-1) ParentMtx=GetWorldMatrix(Tree,ParentIdx);

// Pos
		PosMtx.Identity(); 
		PosMtx.SetTranslation(ThisNode.Pos);
		
// Rot
		ThisNode.Ang.ToMatrix(RotMtx);

// Stretch
		ThisNode.apu.ToMatrix(StrMtx);
		IStrMtx=StrMtx;
		IStrMtx.Invert();
// Scale
		SclMtx.Identity(); 
		SclMtx.ApplyScale(ThisNode.apk);
		
	ThisMtx= PosMtx*RotMtx*StrMtx*SclMtx*IStrMtx;

	return(ParentMtx*ThisMtx);
}

//----------------------------------------------------------------------------
Vector3	GetWorldPos(std::vector<CNode> const &Tree,int Idx)
{
CNode	ThisNode=Tree[Idx];
Matrix4x4	WorldMtx=GetWorldMatrix(Tree,ThisNode.ParentIdx);

		return(WorldMtx*ThisNode.Pos);
}

//----------------------------------------------------------------------------
Vector3	GetWorldPos(Matrix4x4 &WorldMtx,Vector3 &ThisPos)
{
	return(WorldMtx*ThisPos);
}

Vector3	CNode::GetWorldPos()
{

	return(::GetWorldPos(WorldMtx,Pos));
}